1/*
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#import "WebFrameInternal.h"
30
31#import "DOMCSSStyleDeclarationInternal.h"
32#import "DOMDocumentFragmentInternal.h"
33#import "DOMDocumentInternal.h"
34#import "DOMElementInternal.h"
35#import "DOMHTMLElementInternal.h"
36#import "DOMNodeInternal.h"
37#import "DOMRangeInternal.h"
38#import "WebArchiveInternal.h"
39#import "WebChromeClient.h"
40#import "WebDataSourceInternal.h"
41#import "WebDocumentLoaderMac.h"
42#import "WebDynamicScrollBarsView.h"
43#import "WebElementDictionary.h"
44#import "WebFrameLoaderClient.h"
45#import "WebFrameViewInternal.h"
46#import "WebHTMLView.h"
47#import "WebHTMLViewInternal.h"
48#import "WebKitStatisticsPrivate.h"
49#import "WebKitVersionChecks.h"
50#import "WebNSObjectExtras.h"
51#import "WebNSURLExtras.h"
52#import "WebScriptDebugger.h"
53#import "WebScriptWorldInternal.h"
54#import "WebViewInternal.h"
55#import <JavaScriptCore/APICast.h>
56#import <JavaScriptCore/JSContextInternal.h>
57#import <WebCore/AXObjectCache.h>
58#import <WebCore/AccessibilityObject.h>
59#import <WebCore/AnimationController.h>
60#import <WebCore/CSSStyleDeclaration.h>
61#import <WebCore/CachedResourceLoader.h>
62#import <WebCore/Chrome.h>
63#import <WebCore/ColorMac.h>
64#import <WebCore/DOMImplementation.h>
65#import <WebCore/DatabaseManager.h>
66#import <WebCore/DocumentFragment.h>
67#import <WebCore/DocumentLoader.h>
68#import <WebCore/DocumentMarkerController.h>
69#import <WebCore/Editor.h>
70#import <WebCore/EventHandler.h>
71#import <WebCore/EventNames.h>
72#import <WebCore/FrameLoadRequest.h>
73#import <WebCore/FrameLoader.h>
74#import <WebCore/FrameLoaderStateMachine.h>
75#import <WebCore/FrameTree.h>
76#import <WebCore/GraphicsContext.h>
77#import <WebCore/HTMLFrameOwnerElement.h>
78#import <WebCore/HTMLNames.h>
79#import <WebCore/HistoryItem.h>
80#import <WebCore/HitTestResult.h>
81#import <WebCore/JSNode.h>
82#import <WebCore/LegacyWebArchive.h>
83#import <WebCore/MainFrame.h>
84#import <WebCore/Page.h>
85#import <WebCore/PlatformEventFactoryMac.h>
86#import <WebCore/PluginData.h>
87#import <WebCore/PrintContext.h>
88#import <WebCore/RenderView.h>
89#import <WebCore/RenderWidget.h>
90#import <WebCore/RuntimeApplicationChecks.h>
91#import <WebCore/ScriptController.h>
92#import <WebCore/SecurityOrigin.h>
93#import <WebCore/SmartReplace.h>
94#import <WebCore/StyleProperties.h>
95#import <WebCore/SubframeLoader.h>
96#import <WebCore/TextIterator.h>
97#import <WebCore/ThreadCheck.h>
98#import <WebCore/VisibleUnits.h>
99#import <WebCore/htmlediting.h>
100#import <WebCore/markup.h>
101#import <WebKitSystemInterface.h>
102#import <bindings/ScriptValue.h>
103#import <runtime/JSLock.h>
104#import <runtime/JSObject.h>
105#import <runtime/JSCJSValue.h>
106#import <wtf/CurrentTime.h>
107
108#if PLATFORM(IOS)
109#import "WebMailDelegate.h"
110#import "WebResource.h"
111#import "WebUIKitDelegate.h"
112#import <WebCore/Document.h>
113#import <WebCore/Editor.h>
114#import <WebCore/EditorClient.h>
115#import <WebCore/FocusController.h>
116#import <WebCore/FrameSelection.h>
117#import <WebCore/HistoryController.h>
118#import <WebCore/NodeTraversal.h>
119#import <WebCore/RenderLayer.h>
120#import <WebCore/SimpleFontData.h>
121#import <WebCore/TextResourceDecoder.h>
122#import <WebCore/WAKScrollView.h>
123#import <WebCore/WAKViewPrivate.h>
124#import <WebCore/WKGraphics.h>
125#import <WebCore/WebCoreThreadRun.h>
126#endif
127
128#if USE(QUICK_LOOK)
129#import <WebCore/QuickLook.h>
130#import <WebCore/WebCoreURLResponseIOS.h>
131#endif
132
133using namespace WebCore;
134using namespace HTMLNames;
135
136using JSC::JSGlobalObject;
137using JSC::JSLock;
138
139/*
140Here is the current behavior matrix for four types of navigations:
141
142Standard Nav:
143
144 Restore form state:   YES
145 Restore scroll and focus state:  YES
146 Cache policy: NSURLRequestUseProtocolCachePolicy
147 Add to back/forward list: YES
148
149Back/Forward:
150
151 Restore form state:   YES
152 Restore scroll and focus state:  YES
153 Cache policy: NSURLRequestReturnCacheDataElseLoad
154 Add to back/forward list: NO
155
156Reload (meaning only the reload button):
157
158 Restore form state:   NO
159 Restore scroll and focus state:  YES
160 Cache policy: NSURLRequestReloadIgnoringCacheData
161 Add to back/forward list: NO
162
163Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
164
165 Restore form state:   NO
166 Restore scroll and focus state:  NO, reset to initial conditions
167 Cache policy: NSURLRequestReloadIgnoringCacheData
168 Add to back/forward list: NO
169*/
170
171NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
172NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
173NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
174
175NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey";
176NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey";
177NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey";
178NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey";
179NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey";
180NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey";
181NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey";
182
183// FIXME: Remove when this key becomes publicly defined
184NSString *NSAccessibilityEnhancedUserInterfaceAttribute = @"AXEnhancedUserInterface";
185
186@implementation WebFramePrivate
187
188- (void)dealloc
189{
190    [webFrameView release];
191
192    [super dealloc];
193}
194
195- (void)finalize
196{
197    [super finalize];
198}
199
200- (void)setWebFrameView:(WebFrameView *)v
201{
202    [v retain];
203    [webFrameView release];
204    webFrameView = v;
205}
206
207@end
208
209EditableLinkBehavior core(WebKitEditableLinkBehavior editableLinkBehavior)
210{
211    switch (editableLinkBehavior) {
212        case WebKitEditableLinkDefaultBehavior:
213            return EditableLinkDefaultBehavior;
214        case WebKitEditableLinkAlwaysLive:
215            return EditableLinkAlwaysLive;
216        case WebKitEditableLinkOnlyLiveWithShiftKey:
217            return EditableLinkOnlyLiveWithShiftKey;
218        case WebKitEditableLinkLiveWhenNotFocused:
219            return EditableLinkLiveWhenNotFocused;
220        case WebKitEditableLinkNeverLive:
221            return EditableLinkNeverLive;
222    }
223    ASSERT_NOT_REACHED();
224    return EditableLinkDefaultBehavior;
225}
226
227TextDirectionSubmenuInclusionBehavior core(WebTextDirectionSubmenuInclusionBehavior behavior)
228{
229    switch (behavior) {
230        case WebTextDirectionSubmenuNeverIncluded:
231            return TextDirectionSubmenuNeverIncluded;
232        case WebTextDirectionSubmenuAutomaticallyIncluded:
233            return TextDirectionSubmenuAutomaticallyIncluded;
234        case WebTextDirectionSubmenuAlwaysIncluded:
235            return TextDirectionSubmenuAlwaysIncluded;
236    }
237    ASSERT_NOT_REACHED();
238    return TextDirectionSubmenuNeverIncluded;
239}
240
241#if PLATFORM(IOS)
242PassOwnPtr<Vector<Vector<String>>> vectorForDictationPhrasesArray(NSArray *dictationPhrases)
243{
244    NSUInteger dictationPhrasesCount = [dictationPhrases count];
245    if (!dictationPhrasesCount)
246        return PassOwnPtr<Vector<Vector<String> > >();
247
248    OwnPtr<Vector<Vector<String> > > dictationPhrasesVector = adoptPtr(new Vector<Vector<String> >(dictationPhrasesCount));
249
250    for (NSUInteger i = 0; i < dictationPhrasesCount; i++) {
251
252        id dictationPhrase = [dictationPhrases objectAtIndex:i];
253        if (![dictationPhrase isKindOfClass:[NSArray class]])
254            continue;
255
256        NSArray *interpretationsArray = (NSArray *)dictationPhrase;
257        Vector<String>& interpretationsVector = dictationPhrasesVector->at(i);
258
259        NSUInteger interpretationsCount = [interpretationsArray count];
260
261        for (NSUInteger j = 0; j < interpretationsCount; j++) {
262
263            id interpretation = [interpretationsArray objectAtIndex:j];
264            if (![interpretation isKindOfClass:[NSString class]])
265                continue;
266
267            interpretationsVector.append(String((NSString *)interpretation));
268        }
269    }
270
271    return dictationPhrasesVector.release();
272}
273#endif
274
275@implementation WebFrame (WebInternal)
276
277Frame* core(WebFrame *frame)
278{
279    return frame ? frame->_private->coreFrame : 0;
280}
281
282WebFrame *kit(Frame* frame)
283{
284    if (!frame)
285        return nil;
286
287    FrameLoaderClient& frameLoaderClient = frame->loader().client();
288    if (frameLoaderClient.isEmptyFrameLoaderClient())
289        return nil;
290
291    return static_cast<WebFrameLoaderClient&>(frameLoaderClient).webFrame();
292}
293
294Page* core(WebView *webView)
295{
296    return [webView page];
297}
298
299WebView *kit(Page* page)
300{
301    if (!page)
302        return nil;
303
304    if (page->chrome().client().isEmptyChromeClient())
305        return nil;
306
307    return static_cast<WebChromeClient&>(page->chrome().client()).webView();
308}
309
310WebView *getWebView(WebFrame *webFrame)
311{
312    Frame* coreFrame = core(webFrame);
313    if (!coreFrame)
314        return nil;
315    return kit(coreFrame->page());
316}
317
318+ (PassRefPtr<Frame>)_createFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
319{
320    WebView *webView = kit(page);
321
322    WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
323    RefPtr<Frame> coreFrame = Frame::create(page, ownerElement, new WebFrameLoaderClient(frame));
324    [frame release];
325    frame->_private->coreFrame = coreFrame.get();
326
327    coreFrame->tree().setName(name);
328    if (ownerElement) {
329        ASSERT(ownerElement->document().frame());
330        ownerElement->document().frame()->tree().appendChild(coreFrame.get());
331    }
332
333    coreFrame->init();
334
335    [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
336
337    return coreFrame.release();
338}
339
340+ (void)_createMainFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView
341{
342    WebView *webView = kit(page);
343
344    WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
345    frame->_private->coreFrame = &page->mainFrame();
346    static_cast<WebFrameLoaderClient&>(page->mainFrame().loader().client()).setWebFrame(frame);
347    [frame release];
348
349    page->mainFrame().tree().setName(name);
350    page->mainFrame().init();
351
352    [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
353}
354
355+ (PassRefPtr<WebCore::Frame>)_createSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(const String&)name frameView:(WebFrameView *)frameView
356{
357    return [self _createFrameWithPage:ownerElement->document().frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
358}
359
360- (BOOL)_isIncludedInWebKitStatistics
361{
362    return _private && _private->includedInWebKitStatistics;
363}
364
365#if PLATFORM(IOS)
366static NSURL *createUniqueWebDataURL();
367
368+ (void)_createMainFrameWithSimpleHTMLDocumentWithPage:(Page*)page frameView:(WebFrameView *)frameView style:(NSString *)style
369{
370    WebView *webView = kit(page);
371
372    WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
373    frame->_private->coreFrame = &page->mainFrame();
374    static_cast<WebFrameLoaderClient&>(page->mainFrame().loader().client()).setWebFrame(frame);
375    [frame release];
376
377    frame->_private->coreFrame->initWithSimpleHTMLDocument(style, createUniqueWebDataURL());
378}
379#endif
380
381- (void)_attachScriptDebugger
382{
383    ScriptController& scriptController = _private->coreFrame->script();
384
385    // Calling ScriptController::globalObject() would create a window shell, and dispatch corresponding callbacks, which may be premature
386    // if the script debugger is attached before a document is created.  These calls use the debuggerWorld(), we will need to pass a world
387    // to be able to debug isolated worlds.
388    if (!scriptController.existingWindowShell(debuggerWorld()))
389        return;
390
391    JSGlobalObject* globalObject = scriptController.globalObject(debuggerWorld());
392    if (!globalObject)
393        return;
394
395    if (_private->scriptDebugger) {
396        ASSERT(_private->scriptDebugger.get() == globalObject->debugger());
397        return;
398    }
399
400    _private->scriptDebugger = std::make_unique<WebScriptDebugger>(globalObject);
401}
402
403- (void)_detachScriptDebugger
404{
405    _private->scriptDebugger = nullptr;
406}
407
408- (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v
409{
410    self = [super init];
411    if (!self)
412        return nil;
413
414    _private = [[WebFramePrivate alloc] init];
415
416    // Set includedInWebKitStatistics before calling WebFrameView _setWebFrame, since
417    // it calls WebFrame _isIncludedInWebKitStatistics.
418    if ((_private->includedInWebKitStatistics = [[v class] shouldIncludeInWebKitStatistics]))
419        ++WebFrameCount;
420
421    if (fv) {
422        [_private setWebFrameView:fv];
423        [fv _setWebFrame:self];
424    }
425
426    _private->shouldCreateRenderers = YES;
427
428    return self;
429}
430
431- (void)_clearCoreFrame
432{
433    _private->coreFrame = 0;
434}
435
436- (void)_updateBackgroundAndUpdatesWhileOffscreen
437{
438    WebView *webView = getWebView(self);
439    BOOL drawsBackground = [webView drawsBackground];
440#if !PLATFORM(IOS)
441    NSColor *backgroundColor = [webView backgroundColor];
442#else
443    CGColorRef backgroundColor = [webView backgroundColor];
444#endif
445
446    Frame* coreFrame = _private->coreFrame;
447    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
448        // Don't call setDrawsBackground:YES here because it may be NO because of a load
449        // in progress; WebFrameLoaderClient keeps it set to NO during the load process.
450        WebFrame *webFrame = kit(frame);
451        if (!drawsBackground)
452            [[[webFrame frameView] _scrollView] setDrawsBackground:NO];
453#if !PLATFORM(IOS)
454        [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor];
455#endif
456
457        if (FrameView* view = frame->view()) {
458            view->setTransparent(!drawsBackground);
459#if !PLATFORM(IOS)
460            Color color = colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
461#else
462            Color color = Color(backgroundColor);
463#endif
464            view->setBaseBackgroundColor(color);
465            view->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]);
466        }
467    }
468}
469
470- (void)_setInternalLoadDelegate:(id)internalLoadDelegate
471{
472    _private->internalLoadDelegate = internalLoadDelegate;
473}
474
475- (id)_internalLoadDelegate
476{
477    return _private->internalLoadDelegate;
478}
479
480- (void)_unmarkAllBadGrammar
481{
482    Frame* coreFrame = _private->coreFrame;
483    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
484        if (Document* document = frame->document())
485            document->markers().removeMarkers(DocumentMarker::Grammar);
486    }
487}
488
489- (void)_unmarkAllMisspellings
490{
491#if !PLATFORM(IOS)
492    Frame* coreFrame = _private->coreFrame;
493    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
494        if (Document* document = frame->document())
495            document->markers().removeMarkers(DocumentMarker::Spelling);
496    }
497#endif
498}
499
500- (BOOL)_hasSelection
501{
502    id documentView = [_private->webFrameView documentView];
503
504    // optimization for common case to avoid creating potentially large selection string
505    if ([documentView isKindOfClass:[WebHTMLView class]])
506        if (Frame* coreFrame = _private->coreFrame)
507            return coreFrame->selection().isRange();
508
509    if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
510        return [[documentView selectedString] length] > 0;
511
512    return NO;
513}
514
515- (void)_clearSelection
516{
517    id documentView = [_private->webFrameView documentView];
518    if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
519        [documentView deselectAll];
520}
521
522#if !ASSERT_DISABLED
523- (BOOL)_atMostOneFrameHasSelection
524{
525    // FIXME: 4186050 is one known case that makes this debug check fail.
526    BOOL found = NO;
527    Frame* coreFrame = _private->coreFrame;
528    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame))
529        if ([kit(frame) _hasSelection]) {
530            if (found)
531                return NO;
532            found = YES;
533        }
534    return YES;
535}
536#endif
537
538- (WebFrame *)_findFrameWithSelection
539{
540    Frame* coreFrame = _private->coreFrame;
541    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
542        WebFrame *webFrame = kit(frame);
543        if ([webFrame _hasSelection])
544            return webFrame;
545    }
546    return nil;
547}
548
549- (void)_clearSelectionInOtherFrames
550{
551    // We rely on WebDocumentSelection protocol implementors to call this method when they become first
552    // responder. It would be nicer to just notice first responder changes here instead, but there's no
553    // notification sent when the first responder changes in general (Radar 2573089).
554    WebFrame *frameWithSelection = [[getWebView(self) mainFrame] _findFrameWithSelection];
555    if (frameWithSelection != self)
556        [frameWithSelection _clearSelection];
557
558    // While we're in the general area of selection and frames, check that there is only one now.
559    ASSERT([[getWebView(self) mainFrame] _atMostOneFrameHasSelection]);
560}
561
562static inline WebDataSource *dataSource(DocumentLoader* loader)
563{
564    return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
565}
566
567- (WebDataSource *)_dataSource
568{
569    return dataSource(_private->coreFrame->loader().documentLoader());
570}
571
572#if PLATFORM(IOS)
573- (BOOL)_isCommitting
574{
575    return _private->isCommitting;
576}
577
578- (void)_setIsCommitting:(BOOL)value
579{
580    _private->isCommitting = value;
581}
582#endif
583
584- (NSArray *)_nodesFromList:(Vector<Node*> *)nodesVector
585{
586    size_t size = nodesVector->size();
587    NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
588    for (size_t i = 0; i < size; ++i)
589        [nodes addObject:kit((*nodesVector)[i])];
590    return nodes;
591}
592
593- (NSString *)_selectedString
594{
595    return _private->coreFrame->displayStringModifiedByEncoding(_private->coreFrame->editor().selectedText());
596}
597
598- (NSString *)_stringForRange:(DOMRange *)range
599{
600    return plainText(core(range), TextIteratorDefaultBehavior, true);
601}
602
603- (BOOL)_shouldFlattenCompositingLayers:(CGContextRef)context
604{
605#if !PLATFORM(IOS)
606    // -currentContextDrawingToScreen returns YES for bitmap contexts.
607    BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
608    if (isPrinting)
609        return YES;
610#endif
611
612    if (!WKCGContextIsBitmapContext(context))
613        return NO;
614
615    // If we're drawing into a bitmap, we might be snapshotting, or drawing into a layer-backed view.
616    id documentView = [_private->webFrameView documentView];
617    if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _web_isDrawingIntoLayer])
618        return NO;
619
620    return [getWebView(self) _includesFlattenedCompositingLayersWhenDrawingToBitmap];
621}
622
623- (void)_drawRect:(NSRect)rect contentsOnly:(BOOL)contentsOnly
624{
625#if !PLATFORM(IOS)
626    ASSERT([[NSGraphicsContext currentContext] isFlipped]);
627
628    CGContextRef ctx = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
629#else
630    CGContextRef ctx = WKGetCurrentGraphicsContext();
631#endif
632    GraphicsContext context(ctx);
633
634#if PLATFORM(IOS)
635    // FIXME: when <rdar://problem/9034977> is fixed there will be no need to do this here.
636    WebCore::Frame *frame = core(self);
637    if (WebCore::Page* page = frame->page())
638        context.setIsAcceleratedContext(page->settings().acceleratedDrawingEnabled());
639#endif
640
641    FrameView* view = _private->coreFrame->view();
642
643    bool shouldFlatten = false;
644    if (Frame* parentFrame = _private->coreFrame->tree().parent()) {
645        // For subframes, we need to inherit the paint behavior from our parent
646        FrameView* parentView = parentFrame ? parentFrame->view() : 0;
647        if (parentView)
648            shouldFlatten = parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
649    } else
650        shouldFlatten = [self _shouldFlattenCompositingLayers:ctx];
651
652    PaintBehavior oldBehavior = PaintBehaviorNormal;
653    if (shouldFlatten) {
654        oldBehavior = view->paintBehavior();
655        view->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
656    }
657
658    if (contentsOnly)
659        view->paintContents(&context, enclosingIntRect(rect));
660    else
661        view->paint(&context, enclosingIntRect(rect));
662
663    if (shouldFlatten)
664        view->setPaintBehavior(oldBehavior);
665}
666
667- (BOOL)_getVisibleRect:(NSRect*)rect
668{
669    ASSERT_ARG(rect, rect);
670    if (RenderWidget* ownerRenderer = _private->coreFrame->ownerRenderer()) {
671        if (ownerRenderer->needsLayout())
672            return NO;
673        *rect = ownerRenderer->pixelSnappedAbsoluteClippedOverflowRect();
674        return YES;
675    }
676
677    return NO;
678}
679
680- (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string
681{
682    return [self _stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
683}
684
685- (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
686{
687    if (!string)
688        return @"";
689
690    ASSERT(_private->coreFrame->document());
691    RetainPtr<WebFrame> protect(self); // Executing arbitrary JavaScript can destroy the frame.
692
693#if PLATFORM(IOS)
694    ASSERT(WebThreadIsLockedOrDisabled());
695    JSC::ExecState* exec = _private->coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec();
696    JSC::JSLockHolder jscLock(exec);
697#endif
698
699    JSC::JSValue result = _private->coreFrame->script().executeScript(string, forceUserGesture).jsValue();
700
701    if (!_private->coreFrame) // In case the script removed our frame from the page.
702        return @"";
703
704    // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
705    // If you don't like it, use -[WebScriptObject evaluateWebScript:] or
706    // JSEvaluateScript instead, since they have less surprising semantics.
707    if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
708        return @"";
709
710#if !PLATFORM(IOS)
711    JSC::ExecState* exec = _private->coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec();
712    JSC::JSLockHolder lock(exec);
713#endif
714    return result.toWTFString(exec);
715}
716
717- (NSRect)_caretRectAtPosition:(const Position&)pos affinity:(NSSelectionAffinity)affinity
718{
719    VisiblePosition visiblePosition(pos, static_cast<EAffinity>(affinity));
720    return visiblePosition.absoluteCaretBounds();
721}
722
723- (NSRect)_firstRectForDOMRange:(DOMRange *)range
724{
725   return _private->coreFrame->editor().firstRectForRange(core(range));
726}
727
728- (void)_scrollDOMRangeToVisible:(DOMRange *)range
729{
730    NSRect rangeRect = [self _firstRectForDOMRange:range];
731    Node *startNode = core([range startContainer]);
732
733    if (startNode && startNode->renderer()) {
734#if !PLATFORM(IOS)
735        startNode->renderer()->scrollRectToVisible(enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
736#else
737        RenderLayer* layer = startNode->renderer()->enclosingLayer();
738        if (layer) {
739            layer->setAdjustForIOSCaretWhenScrolling(true);
740            startNode->renderer()->scrollRectToVisible(enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
741            layer->setAdjustForIOSCaretWhenScrolling(false);
742            _private->coreFrame->selection().setCaretRectNeedsUpdate();
743            _private->coreFrame->selection().updateAppearance();
744        }
745#endif
746    }
747}
748
749#if PLATFORM(IOS)
750- (void)_scrollDOMRangeToVisible:(DOMRange *)range withInset:(CGFloat)inset
751{
752    NSRect rangeRect = NSInsetRect([self _firstRectForDOMRange:range], inset, inset);
753    Node *startNode = core([range startContainer]);
754
755    if (startNode && startNode->renderer()) {
756        RenderLayer* layer = startNode->renderer()->enclosingLayer();
757        if (layer) {
758            layer->setAdjustForIOSCaretWhenScrolling(true);
759            startNode->renderer()->scrollRectToVisible(enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
760            layer->setAdjustForIOSCaretWhenScrolling(false);
761
762            Frame *coreFrame = core(self);
763            if (coreFrame) {
764                FrameSelection& frameSelection = coreFrame->selection();
765                frameSelection.setCaretRectNeedsUpdate();
766                frameSelection.updateAppearance();
767            }
768        }
769    }
770}
771#endif
772
773- (BOOL)_needsLayout
774{
775    return _private->coreFrame->view() ? _private->coreFrame->view()->needsLayout() : false;
776}
777
778#if !PLATFORM(IOS)
779- (DOMRange *)_rangeByAlteringCurrentSelection:(FrameSelection::EAlteration)alteration direction:(SelectionDirection)direction granularity:(TextGranularity)granularity
780{
781    if (_private->coreFrame->selection().isNone())
782        return nil;
783
784    FrameSelection selection;
785    selection.setSelection(_private->coreFrame->selection().selection());
786    selection.modify(alteration, direction, granularity);
787    return kit(selection.toNormalizedRange().get());
788}
789#endif
790
791- (TextGranularity)_selectionGranularity
792{
793    return _private->coreFrame->selection().granularity();
794}
795
796- (NSRange)_convertToNSRange:(Range *)range
797{
798    if (!range)
799        return NSMakeRange(NSNotFound, 0);
800
801    size_t location;
802    size_t length;
803    if (!TextIterator::getLocationAndLengthFromRange(_private->coreFrame->selection().rootEditableElementOrDocumentElement(), range, location, length))
804        return NSMakeRange(NSNotFound, 0);
805
806    return NSMakeRange(location, length);
807}
808
809- (PassRefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
810{
811    if (nsrange.location > INT_MAX)
812        return 0;
813    if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
814        nsrange.length = INT_MAX - nsrange.location;
815
816    // our critical assumption is that we are only called by input methods that
817    // concentrate on a given area containing the selection
818    // We have to do this because of text fields and textareas. The DOM for those is not
819    // directly in the document DOM, so serialization is problematic. Our solution is
820    // to use the root editable element of the selection start as the positional base.
821    // That fits with AppKit's idea of an input context.
822    return TextIterator::rangeFromLocationAndLength(_private->coreFrame->selection().rootEditableElementOrDocumentElement(), nsrange.location, nsrange.length);
823}
824
825- (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange
826{
827    return kit([self _convertToDOMRange:nsrange].get());
828}
829
830- (NSRange)_convertDOMRangeToNSRange:(DOMRange *)range
831{
832    return [self _convertToNSRange:core(range)];
833}
834
835- (DOMRange *)_markDOMRange
836{
837    return kit(_private->coreFrame->editor().mark().toNormalizedRange().get());
838}
839
840// Given proposedRange, returns an extended range that includes adjacent whitespace that should
841// be deleted along with the proposed range in order to preserve proper spacing and punctuation of
842// the text surrounding the deletion.
843- (DOMRange *)_smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
844{
845    Node* startContainer = core([proposedRange startContainer]);
846    Node* endContainer = core([proposedRange endContainer]);
847    if (startContainer == nil || endContainer == nil)
848        return nil;
849
850    ASSERT(&startContainer->document() == &endContainer->document());
851
852    _private->coreFrame->document()->updateLayoutIgnorePendingStylesheets();
853
854    Position start = Position(startContainer, [proposedRange startOffset], Position::PositionIsOffsetInAnchor);
855    Position end = Position(endContainer, [proposedRange endOffset], Position::PositionIsOffsetInAnchor);
856    Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true);
857    if (newStart.isNull())
858        newStart = start;
859    Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true);
860    if (newEnd.isNull())
861        newEnd = end;
862
863    newStart = newStart.parentAnchoredEquivalent();
864    newEnd = newEnd.parentAnchoredEquivalent();
865
866    RefPtr<Range> range = _private->coreFrame->document()->createRange();
867    int exception = 0;
868    range->setStart(newStart.containerNode(), newStart.offsetInContainerNode(), exception);
869    range->setEnd(newStart.containerNode(), newStart.offsetInContainerNode(), exception);
870    return kit(range.get());
871}
872
873- (DOMDocumentFragment *)_documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString
874{
875    Frame* frame = _private->coreFrame;
876    if (!frame)
877        return nil;
878
879    Document* document = frame->document();
880    if (!document)
881        return nil;
882
883    return kit(createFragmentFromMarkup(*document, markupString, baseURLString, DisallowScriptingContent).get());
884}
885
886- (DOMDocumentFragment *)_documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
887{
888    Frame* frame = _private->coreFrame;
889    if (!frame)
890        return nil;
891
892    Document* document = frame->document();
893    if (!document)
894        return nil;
895
896    NSEnumerator *nodeEnum = [nodes objectEnumerator];
897    Vector<Node*> nodesVector;
898    DOMNode *node;
899    while ((node = [nodeEnum nextObject]))
900        nodesVector.append(core(node));
901
902    RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
903
904    for (auto* node : nodesVector) {
905        RefPtr<Element> element = createDefaultParagraphElement(*document);
906        element->appendChild(node);
907        fragment->appendChild(element.release());
908    }
909
910    return kit(fragment.release().get());
911}
912
913- (void)_replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
914{
915    DOMDocumentFragment *fragment = kit(_private->coreFrame->document()->createDocumentFragment().get());
916    [fragment appendChild:node];
917    [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
918}
919
920- (void)_insertParagraphSeparatorInQuotedContent
921{
922    if (_private->coreFrame->selection().isNone())
923        return;
924
925    _private->coreFrame->editor().insertParagraphSeparatorInQuotedContent();
926}
927
928- (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
929{
930    // FIXME: Someone with access to Apple's sources could remove this needless wrapper call.
931    return _private->coreFrame->visiblePositionForPoint(IntPoint(point));
932}
933
934- (DOMRange *)_characterRangeAtPoint:(NSPoint)point
935{
936    return kit(_private->coreFrame->rangeForPoint(IntPoint(point)).get());
937}
938
939- (DOMCSSStyleDeclaration *)_typingStyle
940{
941    if (!_private->coreFrame)
942        return nil;
943    RefPtr<MutableStyleProperties> typingStyle = _private->coreFrame->selection().copyTypingStyle();
944    if (!typingStyle)
945        return nil;
946    return kit(typingStyle->ensureCSSStyleDeclaration());
947}
948
949- (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
950{
951    if (!_private->coreFrame || !style)
952        return;
953    // FIXME: We shouldn't have to create a copy here.
954    Ref<MutableStyleProperties> properties(core(style)->copyProperties());
955    _private->coreFrame->editor().computeAndSetTypingStyle(&properties.get(), undoAction);
956}
957
958#if ENABLE(DRAG_SUPPORT)
959- (void)_dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
960{
961    if (!_private->coreFrame)
962        return;
963    FrameView* view = _private->coreFrame->view();
964    if (!view)
965        return;
966    // FIXME: These are fake modifier keys here, but they should be real ones instead.
967    PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]),
968        LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime());
969    _private->coreFrame->eventHandler().dragSourceEndedAt(event, (DragOperation)operation);
970}
971#endif
972
973- (BOOL)_canProvideDocumentSource
974{
975    Frame* frame = _private->coreFrame;
976    String mimeType = frame->document()->loader()->writer().mimeType();
977    PluginData* pluginData = frame->page() ? &frame->page()->pluginData() : 0;
978
979    if (WebCore::DOMImplementation::isTextMIMEType(mimeType)
980        || Image::supportsType(mimeType)
981        || (pluginData && pluginData->supportsMimeType(mimeType, PluginData::AllPlugins) && frame->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin))
982        || (pluginData && pluginData->supportsMimeType(mimeType, PluginData::OnlyApplicationPlugins)))
983        return NO;
984
985    return YES;
986}
987
988- (BOOL)_canSaveAsWebArchive
989{
990    // Currently, all documents that we can view source for
991    // (HTML and XML documents) can also be saved as web archives
992    return [self _canProvideDocumentSource];
993}
994
995- (void)_commitData:(NSData *)data
996{
997    // FIXME: This really should be a setting.
998    Document* document = _private->coreFrame->document();
999    document->setShouldCreateRenderers(_private->shouldCreateRenderers);
1000
1001    _private->coreFrame->loader().documentLoader()->commitData((const char *)[data bytes], [data length]);
1002}
1003
1004- (BOOL)_contentFilterDidHandleNavigationAction:(const WebCore::ResourceRequest &)request
1005{
1006#if PLATFORM(IOS)
1007    if (ContentFilter *contentFilter = _private->contentFilterForBlockedLoad.get()) {
1008        RetainPtr<WebFrame> retainedMainFrame = [[self webView] mainFrame];
1009        return contentFilter->handleUnblockRequestAndDispatchIfSuccessful(request, [retainedMainFrame] {
1010            WebThreadRun(^ {
1011                [retainedMainFrame reload];
1012            });
1013        });
1014    }
1015#endif
1016
1017    return NO;
1018}
1019
1020@end
1021
1022@implementation WebFrame (WebPrivate)
1023
1024// FIXME: This exists only as a convenience for Safari, consider moving there.
1025- (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
1026{
1027    Frame* coreFrame = _private->coreFrame;
1028    return coreFrame && coreFrame->tree().isDescendantOf(core(ancestor));
1029}
1030
1031- (void)_setShouldCreateRenderers:(BOOL)shouldCreateRenderers
1032{
1033    _private->shouldCreateRenderers = shouldCreateRenderers;
1034}
1035
1036#if !PLATFORM(IOS)
1037- (NSColor *)_bodyBackgroundColor
1038#else
1039- (CGColorRef)_bodyBackgroundColor
1040#endif
1041{
1042    Document* document = _private->coreFrame->document();
1043    if (!document)
1044        return nil;
1045    HTMLElement* body = document->body();
1046    if (!body)
1047        return nil;
1048    RenderObject* bodyRenderer = body->renderer();
1049    if (!bodyRenderer)
1050        return nil;
1051    Color color = bodyRenderer->style().visitedDependentColor(CSSPropertyBackgroundColor);
1052    if (!color.isValid())
1053        return nil;
1054#if !PLATFORM(IOS)
1055    return nsColor(color);
1056#else
1057    return cachedCGColor(color, ColorSpaceDeviceRGB);
1058#endif
1059}
1060
1061- (BOOL)_isFrameSet
1062{
1063    Document* document = _private->coreFrame->document();
1064    return document && document->isFrameSet();
1065}
1066
1067- (BOOL)_firstLayoutDone
1068{
1069    return _private->coreFrame->loader().stateMachine().firstLayoutDone();
1070}
1071
1072- (BOOL)_isVisuallyNonEmpty
1073{
1074    if (FrameView* view = _private->coreFrame->view())
1075        return view->isVisuallyNonEmpty();
1076    return NO;
1077}
1078
1079static WebFrameLoadType toWebFrameLoadType(FrameLoadType frameLoadType)
1080{
1081    switch (frameLoadType) {
1082    case FrameLoadType::Standard:
1083        return WebFrameLoadTypeStandard;
1084    case FrameLoadType::Back:
1085        return WebFrameLoadTypeBack;
1086    case FrameLoadType::Forward:
1087        return WebFrameLoadTypeForward;
1088    case FrameLoadType::IndexedBackForward:
1089        return WebFrameLoadTypeIndexedBackForward;
1090    case FrameLoadType::Reload:
1091        return WebFrameLoadTypeReload;
1092    case FrameLoadType::Same:
1093        return WebFrameLoadTypeSame;
1094    case FrameLoadType::RedirectWithLockedBackForwardList:
1095        return WebFrameLoadTypeInternal;
1096    case FrameLoadType::Replace:
1097        return WebFrameLoadTypeReplace;
1098    case FrameLoadType::ReloadFromOrigin:
1099        return WebFrameLoadTypeReloadFromOrigin;
1100    }
1101}
1102
1103- (WebFrameLoadType)_loadType
1104{
1105    return toWebFrameLoadType(_private->coreFrame->loader().loadType());
1106}
1107
1108#if PLATFORM(IOS)
1109- (BOOL)needsLayout
1110{
1111    // Needed for Mail <rdar://problem/6228038>
1112    return _private->coreFrame ? [self _needsLayout] : NO;
1113}
1114
1115- (void)_setLoadsSynchronously:(BOOL)flag
1116{
1117    _private->coreFrame->loader().setLoadsSynchronously(flag);
1118}
1119
1120- (BOOL)_loadsSynchronously
1121{
1122    return _private->coreFrame->loader().loadsSynchronously();
1123}
1124
1125// FIXME: selection
1126
1127- (NSArray *)_rectsForRange:(DOMRange *)domRange
1128{
1129    Range *range = core(domRange);
1130
1131
1132    Vector<IntRect> intRects;
1133    range->textRects(intRects, NO);
1134    unsigned size = intRects.size();
1135
1136    NSMutableArray *rectArray = [NSMutableArray arrayWithCapacity:size];
1137    for (unsigned i = 0; i < size; i++) {
1138        [rectArray addObject:[NSValue valueWithRect:(CGRect )intRects[i]]];
1139    }
1140
1141    return rectArray;
1142}
1143
1144- (DOMRange *)_selectionRangeForFirstPoint:(CGPoint)first secondPoint:(CGPoint)second
1145{
1146    VisiblePosition firstPos = [self _visiblePositionForPoint:first];
1147    VisiblePosition secondPos = [self _visiblePositionForPoint:second];
1148    VisibleSelection selection(firstPos, secondPos);
1149    DOMRange *range = kit(selection.toNormalizedRange().get());
1150    return range;
1151}
1152
1153- (DOMRange *)_selectionRangeForPoint:(CGPoint)point
1154{
1155    VisiblePosition pos = [self _visiblePositionForPoint:point];
1156    VisibleSelection selection(pos);
1157    DOMRange *range = kit(selection.toNormalizedRange().get());
1158    return range;
1159}
1160
1161#endif // PLATFORM(IOS)
1162
1163- (NSRange)_selectedNSRange
1164{
1165    return [self _convertToNSRange:_private->coreFrame->selection().toNormalizedRange().get()];
1166}
1167
1168- (void)_selectNSRange:(NSRange)range
1169{
1170    RefPtr<Range> domRange = [self _convertToDOMRange:range];
1171    if (domRange)
1172        _private->coreFrame->selection().setSelection(VisibleSelection(domRange.get(), SEL_DEFAULT_AFFINITY));
1173}
1174
1175- (BOOL)_isDisplayingStandaloneImage
1176{
1177    Document* document = _private->coreFrame->document();
1178    return document && document->isImageDocument();
1179}
1180
1181- (unsigned)_pendingFrameUnloadEventCount
1182{
1183    return _private->coreFrame->document()->domWindow()->pendingUnloadEventListeners();
1184}
1185
1186#if ENABLE(NETSCAPE_PLUGIN_API)
1187- (void)_recursive_resumeNullEventsForAllNetscapePlugins
1188{
1189    Frame* coreFrame = core(self);
1190    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
1191        NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
1192        if ([documentView isKindOfClass:[WebHTMLView class]])
1193            [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
1194    }
1195}
1196
1197- (void)_recursive_pauseNullEventsForAllNetscapePlugins
1198{
1199    Frame* coreFrame = core(self);
1200    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
1201        NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
1202        if ([documentView isKindOfClass:[WebHTMLView class]])
1203            [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
1204    }
1205}
1206#endif
1207
1208#if PLATFORM(IOS)
1209- (unsigned)formElementsCharacterCount
1210{
1211    WebCore::Frame *frame = core(self);
1212    return frame->formElementsCharacterCount();
1213}
1214
1215- (void)setTimeoutsPaused:(BOOL)flag
1216{
1217    id documentView = [_private->webFrameView documentView];
1218    if ([documentView isKindOfClass:[WebHTMLView class]]) {
1219        if (Frame* coreFrame = _private->coreFrame)
1220            coreFrame->setTimersPaused(flag);
1221    }
1222}
1223
1224- (void)setPluginsPaused:(BOOL)flag
1225{
1226    WebView *webView = getWebView(self);
1227    if (!webView)
1228        return;
1229
1230    if (flag)
1231        [webView _stopAllPlugIns];
1232    else
1233        [webView _startAllPlugIns];
1234}
1235
1236- (void)prepareForPause
1237{
1238    id documentView = [_private->webFrameView documentView];
1239    if ([documentView isKindOfClass:[WebHTMLView class]]) {
1240        if (Frame* coreFrame = _private->coreFrame)
1241            coreFrame->dispatchPageHideEventBeforePause();
1242    }
1243}
1244
1245- (void)resumeFromPause
1246{
1247    id documentView = [_private->webFrameView documentView];
1248    if ([documentView isKindOfClass:[WebHTMLView class]]) {
1249        if (Frame* coreFrame = _private->coreFrame)
1250            coreFrame->dispatchPageShowEventBeforeResume();
1251    }
1252}
1253
1254- (void)selectNSRange:(NSRange)range
1255{
1256    [self _selectNSRange:range];
1257}
1258
1259- (void)selectWithoutClosingTypingNSRange:(NSRange)range
1260{
1261    RefPtr<Range> domRange = [self _convertToDOMRange:range];
1262    if (domRange) {
1263        const VisibleSelection& newSelection = VisibleSelection(domRange.get(), SEL_DEFAULT_AFFINITY);
1264        _private->coreFrame->selection().setSelection(newSelection, 0);
1265
1266        _private->coreFrame->editor().ensureLastEditCommandHasCurrentSelectionIfOpenForMoreTyping();
1267    }
1268}
1269
1270- (NSRange)selectedNSRange
1271{
1272    return [self _selectedNSRange];
1273}
1274
1275- (void)forceLayoutAdjustingViewSize:(BOOL)adjust
1276{
1277    _private->coreFrame->view()->forceLayout(!adjust);
1278    if (adjust)
1279        _private->coreFrame->view()->adjustViewSize();
1280}
1281
1282- (void)_handleKeyEvent:(WebEvent *)event
1283{
1284    core(self)->eventHandler().keyEvent(event);
1285}
1286
1287- (void)_selectAll
1288{
1289    core(self)->selection().selectAll();
1290}
1291
1292- (void)_setSelectionFromNone
1293{
1294    core(self)->selection().setSelectionFromNone();
1295}
1296
1297- (void)_restoreViewState
1298{
1299    ASSERT(!WebThreadIsEnabled() || WebThreadIsLocked());
1300    _private->coreFrame->loader().client().restoreViewState();
1301}
1302
1303- (void)_saveViewState
1304{
1305    ASSERT(!WebThreadIsEnabled() || WebThreadIsLocked());
1306    FrameLoader& frameLoader = _private->coreFrame->loader();
1307    frameLoader.client().saveViewStateToItem(frameLoader.history().currentItem());
1308}
1309
1310- (void)deviceOrientationChanged
1311{
1312    WebThreadRun(^{
1313        if (WebCore::Frame* frame = core(self))
1314            frame->orientationChanged();
1315    });
1316}
1317
1318- (void)sendOrientationChangeEvent:(int)newOrientation
1319{
1320    [self deviceOrientationChanged];
1321}
1322
1323- (void)setNeedsLayout
1324{
1325    WebCore::Frame *frame = core(self);
1326    if (frame->view())
1327        frame->view()->setNeedsLayout();
1328}
1329
1330- (CGSize)renderedSizeOfNode:(DOMNode *)node constrainedToWidth:(float)width
1331{
1332    Node *n = core(node);
1333    RenderObject *r = n ? n->renderer() : 0;
1334    float w = std::min((float)r->maxPreferredLogicalWidth(), width);
1335    return r && r->isBox() ? CGSizeMake(w, toRenderBox(r)->height()) : CGSizeMake(0,0);
1336}
1337
1338- (DOMNode *)deepestNodeAtViewportLocation:(CGPoint)aViewportLocation
1339{
1340    WebCore::Frame *frame = core(self);
1341    return kit(frame->deepestNodeAtLocation(FloatPoint(aViewportLocation)));
1342}
1343
1344- (DOMNode *)scrollableNodeAtViewportLocation:(CGPoint)aViewportLocation
1345{
1346    WebCore::Frame *frame = core(self);
1347    WebCore::Node *node = frame->nodeRespondingToScrollWheelEvents(FloatPoint(aViewportLocation));
1348    return kit(node);
1349}
1350
1351- (DOMNode *)approximateNodeAtViewportLocation:(CGPoint *)aViewportLocation
1352{
1353    WebCore::Frame *frame = core(self);
1354    FloatPoint viewportLocation(*aViewportLocation);
1355    FloatPoint adjustedLocation;
1356    WebCore::Node *node = frame->nodeRespondingToClickEvents(viewportLocation, adjustedLocation);
1357    *aViewportLocation = adjustedLocation;
1358    return kit(node);
1359}
1360
1361- (CGRect)renderRectForPoint:(CGPoint)point isReplaced:(BOOL *)isReplaced fontSize:(float *)fontSize
1362{
1363    WebCore::Frame *frame = core(self);
1364    bool replaced = false;
1365    CGRect rect = frame->renderRectForPoint(point, &replaced, fontSize);
1366    *isReplaced = replaced;
1367    return rect;
1368}
1369
1370- (void)_setProhibitsScrolling:(BOOL)flag
1371{
1372    WebCore::Frame *frame = core(self);
1373    frame->view()->setProhibitsScrolling(flag);
1374}
1375
1376- (void)revealSelectionAtExtent:(BOOL)revealExtent
1377{
1378    WebCore::Frame *frame = core(self);
1379    RevealExtentOption revealExtentOption = revealExtent ? RevealExtent : DoNotRevealExtent;
1380    frame->selection().revealSelection(ScrollAlignment::alignToEdgeIfNeeded, revealExtentOption);
1381}
1382
1383- (void)resetSelection
1384{
1385    WebCore::Frame *frame = core(self);
1386    frame->selection().setSelection(frame->selection().selection());
1387}
1388
1389- (BOOL)hasEditableSelection
1390{
1391    WebCore::Frame *frame = core(self);
1392    return frame->selection().selection().isContentEditable();
1393}
1394
1395- (int)preferredHeight
1396{
1397    WebCore::Frame *frame = core(self);
1398    return frame->preferredHeight();
1399}
1400
1401- (int)innerLineHeight:(DOMNode *)node
1402{
1403    WebCore::Frame *frame = core(self);
1404    return frame->innerLineHeight(node);
1405}
1406
1407- (void)updateLayout
1408{
1409    WebCore::Frame *frame = core(self);
1410    frame->updateLayout();
1411}
1412
1413- (void)setIsActive:(BOOL)flag
1414{
1415    WebCore::Frame *frame = core(self);
1416    frame->page()->focusController().setActive(flag);
1417}
1418
1419- (void)setSelectionChangeCallbacksDisabled:(BOOL)flag
1420{
1421    WebCore::Frame *frame = core(self);
1422    frame->setSelectionChangeCallbacksDisabled(flag);
1423}
1424
1425- (NSRect)caretRect
1426{
1427    WebCore::Frame *frame = core(self);
1428    return frame->caretRect();
1429}
1430
1431- (NSRect)rectForScrollToVisible
1432{
1433    WebCore::Frame *frame = core(self);
1434    return frame->rectForScrollToVisible();
1435}
1436
1437- (void)setCaretColor:(CGColorRef)color
1438{
1439    Color qColor = color ? Color(color) : Color::black;
1440    WebCore::Frame *frame = core(self);
1441    frame->selection().setCaretColor(qColor);
1442}
1443
1444- (NSView *)documentView
1445{
1446    WebCore::Frame *frame = core(self);
1447    return [[kit(frame) frameView] documentView];
1448}
1449
1450- (int)layoutCount
1451{
1452    WebCore::Frame *frame = core(self);
1453    if (!frame || !frame->view())
1454        return 0;
1455    return frame->view()->layoutCount();
1456}
1457
1458- (BOOL)isTelephoneNumberParsingAllowed
1459{
1460    Document *document = core(self)->document();
1461    return document->isTelephoneNumberParsingAllowed();
1462}
1463
1464- (BOOL)isTelephoneNumberParsingEnabled
1465{
1466    Document *document = core(self)->document();
1467    return document->isTelephoneNumberParsingEnabled();
1468}
1469
1470- (BOOL)mediaDataLoadsAutomatically
1471{
1472    WebCore::Frame *frame = core(self);
1473    if (WebCore::Page* page = frame->page())
1474        return page->settings().mediaDataLoadsAutomatically();
1475
1476    return NO;
1477}
1478
1479- (void)setMediaDataLoadsAutomatically:(BOOL)flag
1480{
1481    WebCore::Frame *frame = core(self);
1482    if (WebCore::Page* page = frame->page())
1483        page->settings().setMediaDataLoadsAutomatically(flag);
1484}
1485
1486- (DOMRange *)selectedDOMRange
1487{
1488    WebCore::Frame *frame = core(self);
1489    RefPtr<WebCore::Range> range = frame->selection().toNormalizedRange();
1490    return kit(range.get());
1491}
1492
1493- (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)affinity closeTyping:(BOOL)closeTyping
1494{
1495    WebCore::Frame *frame = core(self);
1496
1497    // Ensure the view becomes first responder.
1498    // This does not happen automatically on iOS because we don't forward
1499    // all the click events to WebKit.
1500    if (FrameView* frameView = frame->view()) {
1501        if (NSView *documentView = frameView->documentView()) {
1502            Page* page = frame->page();
1503            if (!page)
1504                return;
1505            page->chrome().focusNSView(documentView);
1506        }
1507    }
1508
1509    frame->selection().setSelectedRange(core(range), (EAffinity)affinity, closeTyping);
1510    if (!closeTyping)
1511        frame->editor().ensureLastEditCommandHasCurrentSelectionIfOpenForMoreTyping();
1512}
1513
1514- (NSSelectionAffinity)selectionAffinity
1515{
1516    WebCore::Frame *frame = core(self);
1517    return (NSSelectionAffinity)(frame->selection().selection().affinity());
1518}
1519
1520- (void)expandSelectionToElementContainingCaretSelection
1521{
1522    WebCore::Frame *frame = core(self);
1523    frame->selection().expandSelectionToElementContainingCaretSelection();
1524}
1525
1526- (DOMRange *)elementRangeContainingCaretSelection
1527{
1528    WebCore::Frame *frame = core(self);
1529    RefPtr<WebCore::Range> range = frame->selection().elementRangeContainingCaretSelection();
1530    return kit(range.get());
1531}
1532
1533- (void)expandSelectionToWordContainingCaretSelection
1534{
1535    WebCore::Frame *frame = core(self);
1536    frame->selection().expandSelectionToWordContainingCaretSelection();
1537}
1538
1539- (void)expandSelectionToStartOfWordContainingCaretSelection
1540{
1541    WebCore::Frame *frame = core(self);
1542    frame->selection().expandSelectionToStartOfWordContainingCaretSelection();
1543}
1544
1545- (unichar)characterInRelationToCaretSelection:(int)amount
1546{
1547    WebCore::Frame *frame = core(self);
1548    return frame->selection().characterInRelationToCaretSelection(amount);
1549}
1550
1551- (unichar)characterBeforeCaretSelection
1552{
1553    WebCore::Frame *frame = core(self);
1554    return frame->selection().characterBeforeCaretSelection();
1555}
1556
1557- (unichar)characterAfterCaretSelection
1558{
1559    WebCore::Frame *frame = core(self);
1560    return frame->selection().characterAfterCaretSelection();
1561}
1562
1563- (DOMRange *)wordRangeContainingCaretSelection
1564{
1565    WebCore::Frame *frame = core(self);
1566    RefPtr<WebCore::Range> range = frame->selection().wordRangeContainingCaretSelection();
1567    return kit(range.get());
1568}
1569
1570- (NSString *)wordInRange:(DOMRange *)range
1571{
1572    if (!range)
1573        return nil;
1574    return [self _stringForRange:range];
1575}
1576
1577- (int)wordOffsetInRange:(DOMRange *)range
1578{
1579    WebCore::Frame *frame = core(self);
1580    return frame->selection().wordOffsetInRange(core(range));
1581}
1582
1583- (BOOL)spaceFollowsWordInRange:(DOMRange *)range
1584{
1585    WebCore::Frame *frame = core(self);
1586    return frame->selection().spaceFollowsWordInRange(core(range));
1587}
1588
1589- (NSArray *)wordsInCurrentParagraph
1590{
1591    WebCore::Frame *frame = core(self);
1592    return frame->wordsInCurrentParagraph();
1593}
1594
1595- (BOOL)selectionAtDocumentStart
1596{
1597    WebCore::Frame *frame = core(self);
1598
1599    if (frame->selection().selection().isNone())
1600        return NO;
1601
1602    frame->document()->updateLayout();
1603
1604    return frame->selection().selectionAtDocumentStart();
1605}
1606
1607- (BOOL)selectionAtSentenceStart
1608{
1609    WebCore::Frame *frame = core(self);
1610
1611    if (frame->selection().selection().isNone())
1612        return NO;
1613
1614    frame->document()->updateLayout();
1615
1616    return frame->selection().selectionAtSentenceStart();
1617}
1618
1619- (BOOL)selectionAtWordStart
1620{
1621    WebCore::Frame *frame = core(self);
1622
1623    if (frame->selection().selection().isNone())
1624        return NO;
1625
1626    frame->document()->updateLayout();
1627
1628    return frame->selection().selectionAtWordStart();
1629}
1630
1631- (DOMRange *)rangeByMovingCurrentSelection:(int)amount
1632{
1633    WebCore::Frame *frame = core(self);
1634    RefPtr<WebCore::Range> range = frame->selection().rangeByMovingCurrentSelection(amount);
1635    return kit(range.get());
1636}
1637
1638- (DOMRange *)rangeByExtendingCurrentSelection:(int)amount
1639{
1640    WebCore::Frame *frame = core(self);
1641    RefPtr<WebCore::Range> range = frame->selection().rangeByExtendingCurrentSelection(amount);
1642    return kit(range.get());
1643}
1644
1645- (void)selectNSRange:(NSRange)range onElement:(DOMElement *)element
1646{
1647    WebCore::Frame *frame = core(self);
1648
1649    Document *doc = frame->document();
1650    if (!doc)
1651        return;
1652
1653    Node *node = core(element);
1654    if (!node->inDocument())
1655        return;
1656
1657    frame->selection().selectRangeOnElement(range.location, range.length, node);
1658}
1659
1660- (DOMRange *)markedTextDOMRange
1661{
1662    WebCore::Frame *frame = core(self);
1663    if (!frame)
1664        return nil;
1665
1666    return kit(frame->editor().compositionRange().get());
1667}
1668
1669- (void)setMarkedText:(NSString *)text selectedRange:(NSRange)newSelRange
1670{
1671    WebCore::Frame *frame = core(self);
1672    if (!frame)
1673        return;
1674
1675    Vector<CompositionUnderline> underlines;
1676    frame->page()->chrome().client().suppressFormNotifications();
1677    frame->editor().setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange));
1678    frame->page()->chrome().client().restoreFormNotifications();
1679}
1680
1681- (void)setMarkedText:(NSString *)text forCandidates:(BOOL)forCandidates
1682{
1683    WebCore::Frame *frame = core(self);
1684    if (!frame)
1685        return;
1686
1687    Vector<CompositionUnderline> underlines;
1688    frame->editor().setComposition(text, underlines, 0, [text length]);
1689}
1690
1691- (void)confirmMarkedText:(NSString *)text
1692{
1693    WebCore::Frame *frame = core(self);
1694    if (!frame || !frame->editor().client())
1695        return;
1696
1697    frame->page()->chrome().client().suppressFormNotifications();
1698    if (text)
1699        frame->editor().confirmComposition(text);
1700    else
1701        frame->editor().confirmMarkedText();
1702    frame->page()->chrome().client().restoreFormNotifications();
1703}
1704
1705- (void)setText:(NSString *)text asChildOfElement:(DOMElement *)element
1706{
1707    if (!element)
1708        return;
1709
1710    WebCore::Frame *frame = core(self);
1711    if (!frame || !frame->document())
1712        return;
1713
1714    frame->editor().setTextAsChildOfElement(text, core(element));
1715}
1716
1717- (void)setDictationPhrases:(NSArray *)dictationPhrases metadata:(id)metadata asChildOfElement:(DOMElement *)element
1718{
1719    if (!element)
1720        return;
1721
1722    WebCore::Frame *frame = core(self);
1723    if (!frame)
1724        return;
1725
1726    frame->editor().setDictationPhrasesAsChildOfElement(vectorForDictationPhrasesArray(dictationPhrases), metadata, core(element));
1727}
1728
1729- (NSArray *)interpretationsForCurrentRoot
1730{
1731    return core(self)->interpretationsForCurrentRoot();
1732}
1733
1734// Collects the ranges and metadata for all of the mars voltas in the root editable element.
1735- (void)getDictationResultRanges:(NSArray **)outRanges andMetadatas:(NSArray **)outMetadatas
1736{
1737    ASSERT(outRanges);
1738    if (!outRanges)
1739        return;
1740
1741    // *outRanges should not already point to an array.
1742    ASSERT(!(*outRanges));
1743    *outRanges = nil;
1744
1745    ASSERT(outMetadatas);
1746    if (!outMetadatas)
1747        return;
1748
1749    // *metadata should not already point to an array.
1750    ASSERT(!(*outMetadatas));
1751    *outMetadatas = nil;
1752
1753    NSMutableArray *ranges = [NSMutableArray array];
1754    NSMutableArray *metadatas = [NSMutableArray array];
1755
1756    Frame *frame = core(self);
1757    Document *document = frame->document();
1758
1759    const VisibleSelection& selection = frame->selection().selection();
1760    Element *root = selection.selectionType() == VisibleSelection::NoSelection ? frame->document()->body() : selection.rootEditableElement();
1761
1762    DOMRange *previousDOMRange = nil;
1763    id previousMetadata = nil;
1764
1765    for (Node* node = root; node; node = NodeTraversal::next(node)) {
1766        Vector<DocumentMarker*> markers = document->markers().markersFor(node);
1767        Vector<DocumentMarker*>::const_iterator end = markers.end();
1768        for (Vector<DocumentMarker*>::const_iterator it = markers.begin(); it != end; ++it) {
1769
1770            if ((*it)->type() != DocumentMarker::DictationResult)
1771                continue;
1772
1773            const DocumentMarker* marker = *it;
1774            id metadata = marker->metadata();
1775
1776            // All result markers should have metadata.
1777            ASSERT(metadata);
1778            if (!metadata)
1779                continue;
1780
1781            RefPtr<Range> range = Range::create(*document, node, marker->startOffset(), node, marker->endOffset());
1782            DOMRange *domRange = kit(range.get());
1783
1784            if (metadata != previousMetadata) {
1785                [metadatas addObject:metadata];
1786                [ranges addObject:domRange];
1787                previousMetadata = metadata;
1788                previousDOMRange = domRange;
1789            } else {
1790                // It is possible for a DocumentMarker to be split by editing. Adjacent markers with the
1791                // the same metadata are for the same result. So combine their ranges.
1792                ASSERT(previousDOMRange == [ranges lastObject]);
1793                [previousDOMRange retain];
1794                [ranges removeLastObject];
1795                DOMNode *startContainer = [domRange startContainer];
1796                int startOffset = [domRange startOffset];
1797                [previousDOMRange setEnd:startContainer offset:startOffset];
1798                [ranges addObject:previousDOMRange];
1799                [previousDOMRange release];
1800            }
1801        }
1802    }
1803
1804    *outRanges = ranges;
1805    *outMetadatas = metadatas;
1806
1807    return;
1808}
1809
1810- (id)dictationResultMetadataForRange:(DOMRange *)range
1811{
1812    if (!range)
1813        return nil;
1814
1815    Vector<DocumentMarker*> markers = core(self)->document()->markers().markersInRange(core(range), DocumentMarker::DictationResult);
1816
1817    // UIKit should only ever give us a DOMRange for a phrase with alternatives, which should not be part of more than one result.
1818    ASSERT(markers.size() <= 1);
1819    if (markers.size() == 0)
1820        return nil;
1821
1822    return markers[0]->metadata();
1823}
1824
1825- (void)recursiveSetUpdateAppearanceEnabled:(BOOL)enabled
1826{
1827    WebCore::Frame *frame = core(self);
1828    if (frame)
1829        frame->recursiveSetUpdateAppearanceEnabled(enabled);
1830}
1831
1832// WebCoreFrameBridge methods used by iOS applications and frameworks
1833// FIXME: WebCoreFrameBridge is long gone. Can we remove these methods?
1834
1835+ (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName
1836{
1837    WebCore::TextEncoding encoding(textEncodingName);
1838    if (!encoding.isValid())
1839        encoding = WindowsLatin1Encoding();
1840    return encoding.decode(reinterpret_cast<const char*>([data bytes]), [data length]);
1841}
1842
1843- (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
1844{
1845    return [self _caretRectAtPosition:createLegacyEditingPosition(core(node), offset) affinity:affinity];
1846}
1847
1848- (DOMRange *)characterRangeAtPoint:(NSPoint)point
1849{
1850    return [self _characterRangeAtPoint:point];
1851}
1852
1853- (NSRange)convertDOMRangeToNSRange:(DOMRange *)range
1854{
1855    return [self _convertDOMRangeToNSRange:range];
1856}
1857
1858- (DOMRange *)convertNSRangeToDOMRange:(NSRange)nsrange
1859{
1860    return [self _convertNSRangeToDOMRange:nsrange];
1861}
1862
1863- (NSRect)firstRectForDOMRange:(DOMRange *)range
1864{
1865    return [self _firstRectForDOMRange:range];
1866}
1867
1868- (CTFontRef)fontForSelection:(BOOL *)hasMultipleFonts
1869{
1870    bool multipleFonts = false;
1871    CTFontRef font = nil;
1872    if (_private->coreFrame) {
1873        const SimpleFontData* fd = _private->coreFrame->editor().fontForSelection(multipleFonts);
1874        if (fd)
1875            font = fd->getCTFont();
1876    }
1877
1878    if (hasMultipleFonts)
1879        *hasMultipleFonts = multipleFonts;
1880    return font;
1881}
1882
1883- (void)sendScrollEvent
1884{
1885    ASSERT(WebThreadIsLockedOrDisabled());
1886    _private->coreFrame->eventHandler().sendScrollEvent();
1887}
1888
1889- (void)_userScrolled
1890{
1891    ASSERT(WebThreadIsLockedOrDisabled());
1892    if (FrameView* view = _private->coreFrame->view())
1893        view->setWasScrolledByUser(true);
1894}
1895
1896- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
1897{
1898    return [self _stringByEvaluatingJavaScriptFromString:string forceUserGesture:forceUserGesture];
1899}
1900
1901- (NSString *)stringForRange:(DOMRange *)range
1902{
1903    return [self _stringForRange:range];
1904}
1905
1906//
1907// FIXME: We needed to add this method for iOS due to the opensource version's inclusion of
1908// matchStyle:YES. It seems odd that we should need to explicitly match style, given that the
1909// fragment is being made out of plain text, which shouldn't be carrying any style of its own.
1910// When we paste that it will pick up its style from the surrounding content. What else would
1911// we expect? If we flipped that matchStyle bit to NO, we could probably just get rid
1912// of this method, and call the standard WebKit version.
1913//
1914// There's a second problem here, too, which is that ReplaceSelectionCommand sometimes adds
1915// redundant style.
1916//
1917- (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1918{
1919    RefPtr<Range> range = _private->coreFrame->selection().toNormalizedRange();
1920
1921    DOMDocumentFragment* fragment = range ? kit(createFragmentFromText(*range, text).get()) : nil;
1922    [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
1923}
1924
1925- (void)_replaceSelectionWithWebArchive:(WebArchive *)webArchive selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1926{
1927    NSArray* subresources = [webArchive subresources];
1928    for (WebResource* subresource in subresources) {
1929        if (![[self dataSource] subresourceForURL:[subresource URL]])
1930            [[self dataSource] addSubresource:subresource];
1931    }
1932
1933    DOMDocumentFragment* fragment = [[self dataSource] _documentFragmentWithArchive:webArchive];
1934    [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1935}
1936
1937#endif // PLATFORM(IOS)
1938
1939#if ENABLE(IOS_TEXT_AUTOSIZING)
1940- (void)resetTextAutosizingBeforeLayout
1941{
1942    id documentView = [_private->webFrameView documentView];
1943    if (![documentView isKindOfClass:[WebHTMLView class]])
1944        return;
1945
1946    Frame* coreFrame = core(self);
1947    for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
1948        Document *doc = frame->document();
1949        if (!doc || !doc->renderView())
1950            continue;
1951        doc->renderView()->resetTextAutosizing();
1952    }
1953}
1954
1955- (void)_setVisibleSize:(CGSize)size
1956{
1957    [self _setTextAutosizingWidth:size.width];
1958}
1959
1960- (void)_setTextAutosizingWidth:(CGFloat)width
1961{
1962    WebCore::Frame* frame = core(self);
1963    Page* page = frame->page();
1964    if (!page)
1965        return;
1966
1967    page->setTextAutosizingWidth(width);
1968}
1969#else
1970- (void)resetTextAutosizingBeforeLayout
1971{
1972}
1973
1974- (void)_setVisibleSize:(CGSize)size
1975{
1976}
1977
1978- (void)_setTextAutosizingWidth:(CGFloat)width
1979{
1980}
1981#endif // ENABLE(IOS_TEXT_AUTOSIZING)
1982
1983- (void)_replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
1984{
1985    if (_private->coreFrame->selection().isNone() || !fragment)
1986        return;
1987    _private->coreFrame->editor().replaceSelectionWithFragment(core(fragment), selectReplacement, smartReplace, matchStyle);
1988}
1989
1990#if PLATFORM(IOS)
1991- (void)removeUnchangeableStyles
1992{
1993    _private->coreFrame->editor().removeUnchangeableStyles();
1994}
1995
1996- (BOOL)hasRichlyEditableSelection
1997{
1998    return _private->coreFrame->selection().selection().isContentRichlyEditable();
1999}
2000#endif
2001
2002- (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
2003{
2004    RefPtr<Range> range = _private->coreFrame->selection().toNormalizedRange();
2005
2006    DOMDocumentFragment* fragment = range ? kit(createFragmentFromText(*range, text).get()) : nil;
2007    [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
2008}
2009
2010- (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
2011{
2012    DOMDocumentFragment *fragment = [self _documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
2013    [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
2014}
2015
2016#if !PLATFORM(IOS)
2017// Determines whether whitespace needs to be added around aString to preserve proper spacing and
2018// punctuation when it's inserted into the receiver's text over charRange. Returns by reference
2019// in beforeString and afterString any whitespace that should be added, unless either or both are
2020// nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
2021- (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
2022{
2023    // give back nil pointers in case of early returns
2024    if (beforeString)
2025        *beforeString = nil;
2026    if (afterString)
2027        *afterString = nil;
2028
2029    // inspect destination
2030    Node *startContainer = core([rangeToReplace startContainer]);
2031    Node *endContainer = core([rangeToReplace endContainer]);
2032
2033    Position startPos(startContainer, [rangeToReplace startOffset], Position::PositionIsOffsetInAnchor);
2034    Position endPos(endContainer, [rangeToReplace endOffset], Position::PositionIsOffsetInAnchor);
2035
2036    VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
2037    VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
2038
2039    // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
2040    if (startVisiblePos.isNull() || endVisiblePos.isNull())
2041        return;
2042
2043    bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
2044    if (addLeadingSpace)
2045        if (UChar previousChar = startVisiblePos.previous().characterAfter())
2046            addLeadingSpace = !isCharacterSmartReplaceExempt(previousChar, true);
2047
2048    bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
2049    if (addTrailingSpace)
2050        if (UChar thisChar = endVisiblePos.characterAfter())
2051            addTrailingSpace = !isCharacterSmartReplaceExempt(thisChar, false);
2052
2053    // inspect source
2054    bool hasWhitespaceAtStart = false;
2055    bool hasWhitespaceAtEnd = false;
2056    unsigned pasteLength = [pasteString length];
2057    if (pasteLength > 0) {
2058        NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
2059
2060        if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
2061            hasWhitespaceAtStart = YES;
2062        }
2063        if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
2064            hasWhitespaceAtEnd = YES;
2065        }
2066    }
2067
2068    // issue the verdict
2069    if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
2070        *beforeString = @" ";
2071    if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
2072        *afterString = @" ";
2073}
2074#endif // !PLATFORM(IOS)
2075
2076- (NSMutableDictionary *)_cacheabilityDictionary
2077{
2078    NSMutableDictionary *result = [NSMutableDictionary dictionary];
2079
2080    FrameLoader& frameLoader = _private->coreFrame->loader();
2081    DocumentLoader* documentLoader = frameLoader.documentLoader();
2082    if (documentLoader && !documentLoader->mainDocumentError().isNull())
2083        [result setObject:(NSError *)documentLoader->mainDocumentError() forKey:WebFrameMainDocumentError];
2084
2085    if (frameLoader.subframeLoader().containsPlugins())
2086        [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasPlugins];
2087
2088    if (DOMWindow* domWindow = _private->coreFrame->document()->domWindow()) {
2089        if (domWindow->hasEventListeners(eventNames().unloadEvent))
2090            [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasUnloadListener];
2091        if (domWindow->optionalApplicationCache())
2092            [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesApplicationCache];
2093    }
2094
2095    if (Document* document = _private->coreFrame->document()) {
2096#if ENABLE(SQL_DATABASE)
2097        if (DatabaseManager::manager().hasOpenDatabases(document))
2098            [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesDatabases];
2099#endif
2100        if (!document->canSuspendActiveDOMObjects())
2101            [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameCanSuspendActiveDOMObjects];
2102    }
2103
2104    return result;
2105}
2106
2107- (BOOL)_allowsFollowingLink:(NSURL *)URL
2108{
2109    if (!_private->coreFrame)
2110        return YES;
2111    return _private->coreFrame->document()->securityOrigin()->canDisplay(URL);
2112}
2113
2114- (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string withGlobalObject:(JSObjectRef)globalObjectRef inScriptWorld:(WebScriptWorld *)world
2115{
2116    if (!string)
2117        return @"";
2118
2119    if (!world)
2120        return @"";
2121
2122    // Start off with some guess at a frame and a global object, we'll try to do better...!
2123    JSDOMWindow* anyWorldGlobalObject = _private->coreFrame->script().globalObject(mainThreadNormalWorld());
2124
2125    // The global object is probably a shell object? - if so, we know how to use this!
2126    JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
2127    if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
2128        anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
2129
2130    // Get the frame frome the global object we've settled on.
2131    Frame* frame = anyWorldGlobalObject->impl().frame();
2132    ASSERT(frame->document());
2133    RetainPtr<WebFrame> webFrame(kit(frame)); // Running arbitrary JavaScript can destroy the frame.
2134
2135    JSC::JSValue result = frame->script().executeScriptInWorld(*core(world), string, true).jsValue();
2136
2137    if (!webFrame->_private->coreFrame) // In case the script removed our frame from the page.
2138        return @"";
2139
2140    // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
2141    // If you don't like it, use -[WebScriptObject evaluateWebScript:] or
2142    // JSEvaluateScript instead, since they have less surprising semantics.
2143    if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
2144        return @"";
2145
2146    JSC::ExecState* exec = anyWorldGlobalObject->globalExec();
2147    JSC::JSLockHolder lock(exec);
2148    return result.toWTFString(exec);
2149}
2150
2151- (JSGlobalContextRef)_globalContextForScriptWorld:(WebScriptWorld *)world
2152{
2153    Frame* coreFrame = _private->coreFrame;
2154    if (!coreFrame)
2155        return 0;
2156    DOMWrapperWorld* coreWorld = core(world);
2157    if (!coreWorld)
2158        return 0;
2159    return toGlobalRef(coreFrame->script().globalObject(*coreWorld)->globalExec());
2160}
2161
2162#if JSC_OBJC_API_ENABLED
2163- (JSContext *)_javaScriptContextForScriptWorld:(WebScriptWorld *)world
2164{
2165    JSGlobalContextRef globalContextRef = [self _globalContextForScriptWorld:world];
2166    if (!globalContextRef)
2167        return 0;
2168    return [JSContext contextWithJSGlobalContextRef:globalContextRef];
2169}
2170#endif
2171
2172#if !PLATFORM(IOS)
2173- (void)setAllowsScrollersToOverlapContent:(BOOL)flag
2174{
2175    ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
2176    [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAllowsScrollersToOverlapContent:flag];
2177}
2178
2179- (void)setAlwaysHideHorizontalScroller:(BOOL)flag
2180{
2181    ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
2182    [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideHorizontalScroller:flag];
2183}
2184- (void)setAlwaysHideVerticalScroller:(BOOL)flag
2185{
2186    ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
2187    [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideVerticalScroller:flag];
2188}
2189#endif
2190
2191- (void)setAccessibleName:(NSString *)name
2192{
2193#if HAVE(ACCESSIBILITY)
2194    if (!AXObjectCache::accessibilityEnabled())
2195        return;
2196
2197    if (!_private->coreFrame || !_private->coreFrame->document())
2198        return;
2199
2200    AccessibilityObject* rootObject = _private->coreFrame->document()->axObjectCache()->rootObject();
2201    if (rootObject) {
2202        String strName(name);
2203        rootObject->setAccessibleName(strName);
2204    }
2205#endif
2206}
2207
2208- (BOOL)enhancedAccessibilityEnabled
2209{
2210#if HAVE(ACCESSIBILITY)
2211    return AXObjectCache::accessibilityEnhancedUserInterfaceEnabled();
2212#else
2213    return NO;
2214#endif
2215}
2216
2217- (void)setEnhancedAccessibility:(BOOL)enable
2218{
2219#if HAVE(ACCESSIBILITY)
2220    AXObjectCache::setEnhancedUserInterfaceAccessibility(enable);
2221#endif
2222}
2223
2224- (NSString*)_layerTreeAsText
2225{
2226    Frame* coreFrame = _private->coreFrame;
2227    if (!coreFrame)
2228        return @"";
2229
2230    return coreFrame->layerTreeAsText();
2231}
2232
2233- (id)accessibilityRoot
2234{
2235#if HAVE(ACCESSIBILITY)
2236    if (!AXObjectCache::accessibilityEnabled()) {
2237        AXObjectCache::enableAccessibility();
2238#if !PLATFORM(IOS)
2239        AXObjectCache::setEnhancedUserInterfaceAccessibility([[NSApp accessibilityAttributeValue:NSAccessibilityEnhancedUserInterfaceAttribute] boolValue]);
2240#endif
2241    }
2242
2243    if (!_private->coreFrame)
2244        return nil;
2245
2246    Document* document = _private->coreFrame->document();
2247    if (!document || !document->axObjectCache())
2248        return nil;
2249
2250    AccessibilityObject* rootObject = document->axObjectCache()->rootObjectForFrame(_private->coreFrame);
2251    if (!rootObject)
2252        return nil;
2253
2254    // The root object will be a WebCore scroll view object. In WK1, scroll views are handled
2255    // by the system and the root object should be the web area (instead of the scroll view).
2256    if (rootObject->isAttachment() && rootObject->firstChild())
2257        return rootObject->firstChild()->wrapper();
2258
2259    return rootObject->wrapper();
2260#else
2261    return nil;
2262#endif
2263}
2264
2265- (void)_clearOpener
2266{
2267    Frame* coreFrame = _private->coreFrame;
2268    if (coreFrame)
2269        coreFrame->loader().setOpener(0);
2270}
2271
2272// Used by pagination code called from AppKit when a standalone web page is printed.
2273- (NSArray *)_computePageRectsWithPrintScaleFactor:(float)printScaleFactor pageSize:(NSSize)pageSize
2274{
2275    if (printScaleFactor <= 0) {
2276        LOG_ERROR("printScaleFactor has bad value %.2f", printScaleFactor);
2277        return [NSArray array];
2278    }
2279
2280    if (!_private->coreFrame)
2281        return [NSArray array];
2282    if (!_private->coreFrame->document())
2283        return [NSArray array];
2284    if (!_private->coreFrame->view())
2285        return [NSArray array];
2286    if (!_private->coreFrame->view()->documentView())
2287        return [NSArray array];
2288
2289    RenderView* root = _private->coreFrame->document()->renderView();
2290    if (!root)
2291        return [NSArray array];
2292
2293    const LayoutRect& documentRect = root->documentRect();
2294    float printWidth = root->style().isHorizontalWritingMode() ? static_cast<float>(documentRect.width()) / printScaleFactor : pageSize.width;
2295    float printHeight = root->style().isHorizontalWritingMode() ? pageSize.height : static_cast<float>(documentRect.height()) / printScaleFactor;
2296
2297    PrintContext printContext(_private->coreFrame);
2298    printContext.computePageRectsWithPageSize(FloatSize(printWidth, printHeight), true);
2299    const Vector<IntRect>& pageRects = printContext.pageRects();
2300
2301    size_t size = pageRects.size();
2302    NSMutableArray *pages = [NSMutableArray arrayWithCapacity:size];
2303    for (size_t i = 0; i < size; ++i)
2304        [pages addObject:[NSValue valueWithRect:NSRect(pageRects[i])]];
2305    return pages;
2306}
2307
2308#if PLATFORM(IOS)
2309- (DOMDocumentFragment *)_documentFragmentForText:(NSString *)text
2310{
2311    return kit(createFragmentFromText(*_private->coreFrame->selection().toNormalizedRange().get(), text).get());
2312}
2313
2314- (DOMDocumentFragment *)_documentFragmentForWebArchive:(WebArchive *)webArchive
2315{
2316    return [[self dataSource] _documentFragmentWithArchive:webArchive];
2317}
2318
2319- (DOMDocumentFragment *)_documentFragmentForImageData:(NSData *)data withRelativeURLPart:(NSString *)relativeURLPart andMIMEType:(NSString *)mimeType
2320{
2321    WebResource *resource = [[WebResource alloc] initWithData:data
2322                                                          URL:[NSURL uniqueURLWithRelativePart:relativeURLPart]
2323                                                     MIMEType:mimeType
2324                                             textEncodingName:nil
2325                                                    frameName:nil];
2326    DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2327    [resource release];
2328    return fragment;
2329}
2330
2331- (BOOL)focusedNodeHasContent
2332{
2333    Frame* coreFrame = _private->coreFrame;
2334
2335    Element* root;
2336    const VisibleSelection& selection = coreFrame->selection().selection();
2337    if (selection.isNone() || !selection.isContentEditable())
2338        root = coreFrame->document()->body();
2339    else {
2340        // Can't use the focusedNode here because we want the root of the shadow tree for form elements.
2341        root = selection.rootEditableElement();
2342    }
2343    // Early return to avoid the expense of creating VisiblePositions.
2344    // FIXME: We fail to compute a root for SVG, we have a null check here so that we don't crash.
2345    if (!root || !root->hasChildNodes())
2346        return NO;
2347
2348    VisiblePosition first(createLegacyEditingPosition(root, 0));
2349    VisiblePosition last(createLegacyEditingPosition(root, root->childNodeCount()));
2350    return first != last;
2351}
2352
2353- (void)_dispatchDidReceiveTitle:(NSString *)title
2354{
2355    Frame* coreFrame = _private->coreFrame;
2356    if (!coreFrame)
2357        return;
2358    coreFrame->loader().client().dispatchDidReceiveTitle(StringWithDirection(title, LTR));
2359}
2360#endif // PLATFORM(IOS)
2361
2362- (JSValueRef)jsWrapperForNode:(DOMNode *)node inScriptWorld:(WebScriptWorld *)world
2363{
2364    Frame* coreFrame = _private->coreFrame;
2365    if (!coreFrame)
2366        return 0;
2367
2368    if (!world)
2369        return 0;
2370
2371    JSDOMWindow* globalObject = coreFrame->script().globalObject(*core(world));
2372    JSC::ExecState* exec = globalObject->globalExec();
2373
2374    JSC::JSLockHolder lock(exec);
2375    return toRef(exec, toJS(exec, globalObject, core(node)));
2376}
2377
2378- (NSDictionary *)elementAtPoint:(NSPoint)point
2379{
2380    Frame* coreFrame = _private->coreFrame;
2381    if (!coreFrame)
2382        return nil;
2383    return [[[WebElementDictionary alloc] initWithHitTestResult:coreFrame->eventHandler().hitTestResultAtPoint(IntPoint(point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent)] autorelease];
2384}
2385
2386- (NSURL *)_unreachableURL
2387{
2388    return [[self _dataSource] unreachableURL];
2389}
2390
2391@end
2392
2393@implementation WebFrame
2394
2395- (instancetype)init
2396{
2397    return nil;
2398}
2399
2400// Should be deprecated.
2401- (instancetype)initWithName:(NSString *)name webFrameView:(WebFrameView *)view webView:(WebView *)webView
2402{
2403    return nil;
2404}
2405
2406- (void)dealloc
2407{
2408    if (_private && _private->includedInWebKitStatistics)
2409        --WebFrameCount;
2410
2411    [_private release];
2412
2413    [super dealloc];
2414}
2415
2416- (void)finalize
2417{
2418    if (_private && _private->includedInWebKitStatistics)
2419        --WebFrameCount;
2420
2421    [super finalize];
2422}
2423
2424- (NSString *)name
2425{
2426    Frame* coreFrame = _private->coreFrame;
2427    if (!coreFrame)
2428        return nil;
2429    return coreFrame->tree().uniqueName();
2430}
2431
2432- (WebFrameView *)frameView
2433{
2434    return _private->webFrameView;
2435}
2436
2437- (WebView *)webView
2438{
2439    return getWebView(self);
2440}
2441
2442static bool needsMicrosoftMessengerDOMDocumentWorkaround()
2443{
2444    static bool needsWorkaround = applicationIsMicrosoftMessenger() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] compare:@"7.1" options:NSNumericSearch] == NSOrderedAscending;
2445    return needsWorkaround;
2446}
2447
2448- (DOMDocument *)DOMDocument
2449{
2450    if (needsMicrosoftMessengerDOMDocumentWorkaround() && !pthread_main_np())
2451        return nil;
2452
2453    Frame* coreFrame = _private->coreFrame;
2454    if (!coreFrame)
2455        return nil;
2456
2457    // FIXME: <rdar://problem/5145841> When loading a custom view/representation
2458    // into a web frame, the old document can still be around. This makes sure that
2459    // we'll return nil in those cases.
2460    if (![[self _dataSource] _isDocumentHTML])
2461        return nil;
2462
2463    Document* document = coreFrame->document();
2464
2465    // According to the documentation, we should return nil if the frame doesn't have a document.
2466    // While full-frame images and plugins do have an underlying HTML document, we return nil here to be
2467    // backwards compatible.
2468    if (document && (document->isPluginDocument() || document->isImageDocument()))
2469        return nil;
2470
2471    return kit(coreFrame->document());
2472}
2473
2474- (DOMHTMLElement *)frameElement
2475{
2476    Frame* coreFrame = _private->coreFrame;
2477    if (!coreFrame)
2478        return nil;
2479    return kit(coreFrame->ownerElement());
2480}
2481
2482- (WebDataSource *)provisionalDataSource
2483{
2484    Frame* coreFrame = _private->coreFrame;
2485    return coreFrame ? dataSource(coreFrame->loader().provisionalDocumentLoader()) : nil;
2486}
2487
2488- (WebDataSource *)dataSource
2489{
2490    Frame* coreFrame = _private->coreFrame;
2491    return coreFrame && coreFrame->loader().frameHasLoaded() ? [self _dataSource] : nil;
2492}
2493
2494- (void)loadRequest:(NSURLRequest *)request
2495{
2496    Frame* coreFrame = _private->coreFrame;
2497    if (!coreFrame)
2498        return;
2499
2500    ResourceRequest resourceRequest(request);
2501
2502    // Some users of WebKit API incorrectly use "file path as URL" style requests which are invalid.
2503    // By re-writing those URLs here we technically break the -[WebDataSource initialRequest] API
2504    // but that is necessary to implement this quirk only at the API boundary.
2505    // Note that other users of WebKit API use nil requests or requests with nil URLs or empty URLs, so we
2506    // only implement this workaround when the request had a non-nil or non-empty URL.
2507    if (!resourceRequest.url().isValid() && !resourceRequest.url().isEmpty())
2508        resourceRequest.setURL([NSURL URLWithString:[@"file:" stringByAppendingString:[[request URL] absoluteString]]]);
2509
2510    coreFrame->loader().load(FrameLoadRequest(coreFrame, resourceRequest));
2511}
2512
2513static NSURL *createUniqueWebDataURL()
2514{
2515    CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
2516    NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
2517    CFRelease(UUIDRef);
2518    NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"applewebdata://%@", UUIDString]];
2519    CFRelease(UUIDString);
2520    return URL;
2521}
2522
2523- (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
2524{
2525#if !PLATFORM(IOS)
2526    if (!pthread_main_np())
2527        return [[self _webkit_invokeOnMainThread] _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:unreachableURL];
2528#endif
2529
2530    URL responseURL;
2531    if (!baseURL) {
2532        baseURL = blankURL();
2533        responseURL = createUniqueWebDataURL();
2534    }
2535
2536#if USE(QUICK_LOOK)
2537    if (shouldUseQuickLookForMIMEType(MIMEType)) {
2538        URL qlURL = responseURL;
2539        if (qlURL.isEmpty())
2540            qlURL = [baseURL absoluteURL];
2541        OwnPtr<ResourceRequest> qlRequest(registerQLPreviewConverterIfNeeded((NSURL *)qlURL, MIMEType, data));
2542        if (qlRequest) {
2543            _private->coreFrame->loader().load(FrameLoadRequest(_private->coreFrame, *qlRequest));
2544            return;
2545        }
2546    }
2547#endif // USE(QUICK_LOOK)
2548
2549    ResourceRequest request([baseURL absoluteURL]);
2550
2551#if !PLATFORM(IOS)
2552    // hack because Mail checks for this property to detect data / archive loads
2553    [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest(UpdateHTTPBody)];
2554#endif
2555
2556    SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData(data), MIMEType, encodingName, [unreachableURL absoluteURL], responseURL);
2557
2558    _private->coreFrame->loader().load(FrameLoadRequest(_private->coreFrame, request, substituteData));
2559}
2560
2561
2562- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
2563{
2564    WebCoreThreadViolationCheckRoundTwo();
2565
2566    if (!MIMEType)
2567        MIMEType = @"text/html";
2568    [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:[baseURL _webkit_URLFromURLOrSchemelessFileURL] unreachableURL:nil];
2569}
2570
2571- (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
2572{
2573    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
2574    [self _loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL unreachableURL:unreachableURL];
2575}
2576
2577- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
2578{
2579    WebCoreThreadViolationCheckRoundTwo();
2580
2581    [self _loadHTMLString:string baseURL:[baseURL _webkit_URLFromURLOrSchemelessFileURL] unreachableURL:nil];
2582}
2583
2584- (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
2585{
2586    WebCoreThreadViolationCheckRoundTwo();
2587
2588    [self _loadHTMLString:string baseURL:[baseURL _webkit_URLFromURLOrSchemelessFileURL] unreachableURL:[unreachableURL _webkit_URLFromURLOrSchemelessFileURL]];
2589}
2590
2591- (void)loadArchive:(WebArchive *)archive
2592{
2593    if (LegacyWebArchive* coreArchive = [archive _coreLegacyWebArchive])
2594        _private->coreFrame->loader().loadArchive(coreArchive);
2595}
2596
2597- (void)stopLoading
2598{
2599    if (!_private->coreFrame)
2600        return;
2601    _private->coreFrame->loader().stopForUserCancel();
2602}
2603
2604- (void)reload
2605{
2606    _private->coreFrame->loader().reload(false);
2607}
2608
2609- (void)reloadFromOrigin
2610{
2611    _private->coreFrame->loader().reload(true);
2612}
2613
2614- (WebFrame *)findFrameNamed:(NSString *)name
2615{
2616    Frame* coreFrame = _private->coreFrame;
2617    if (!coreFrame)
2618        return nil;
2619    return kit(coreFrame->tree().find(name));
2620}
2621
2622- (WebFrame *)parentFrame
2623{
2624    Frame* coreFrame = _private->coreFrame;
2625    if (!coreFrame)
2626        return nil;
2627    return [[kit(coreFrame->tree().parent()) retain] autorelease];
2628}
2629
2630- (NSArray *)childFrames
2631{
2632    Frame* coreFrame = _private->coreFrame;
2633    if (!coreFrame)
2634        return [NSArray array];
2635    NSMutableArray *children = [NSMutableArray arrayWithCapacity:coreFrame->tree().childCount()];
2636    for (Frame* child = coreFrame->tree().firstChild(); child; child = child->tree().nextSibling())
2637        [children addObject:kit(child)];
2638    return children;
2639}
2640
2641- (WebScriptObject *)windowObject
2642{
2643    Frame* coreFrame = _private->coreFrame;
2644    if (!coreFrame)
2645        return 0;
2646    return coreFrame->script().windowScriptObject();
2647}
2648
2649- (JSGlobalContextRef)globalContext
2650{
2651    Frame* coreFrame = _private->coreFrame;
2652    if (!coreFrame)
2653        return 0;
2654    return toGlobalRef(coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
2655}
2656
2657#if JSC_OBJC_API_ENABLED
2658- (JSContext *)javaScriptContext
2659{
2660    Frame* coreFrame = _private->coreFrame;
2661    if (!coreFrame)
2662        return 0;
2663    return coreFrame->script().javaScriptContext();
2664}
2665#endif
2666
2667@end
2668