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