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