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