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