fae7facfffe46415f1a64eb784e4e39748c0f64a
[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 using namespace WebCore;
109 using namespace HTMLNames;
110
111 using JSC::JSGlobalObject;
112 using JSC::JSLock;
113
114 /*
115 Here is the current behavior matrix for four types of navigations:
116
117 Standard Nav:
118
119  Restore form state:   YES
120  Restore scroll and focus state:  YES
121  Cache policy: NSURLRequestUseProtocolCachePolicy
122  Add to back/forward list: YES
123  
124 Back/Forward:
125
126  Restore form state:   YES
127  Restore scroll and focus state:  YES
128  Cache policy: NSURLRequestReturnCacheDataElseLoad
129  Add to back/forward list: NO
130
131 Reload (meaning only the reload button):
132
133  Restore form state:   NO
134  Restore scroll and focus state:  YES
135  Cache policy: NSURLRequestReloadIgnoringCacheData
136  Add to back/forward list: NO
137
138 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
139
140  Restore form state:   NO
141  Restore scroll and focus state:  NO, reset to initial conditions
142  Cache policy: NSURLRequestReloadIgnoringCacheData
143  Add to back/forward list: NO
144 */
145
146 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
147 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
148 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
149
150 NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey";
151 NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey";
152 NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey";
153 NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey";
154 NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey";
155 NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey";
156 NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey";
157
158 // FIXME: Remove when this key becomes publicly defined
159 NSString *NSAccessibilityEnhancedUserInterfaceAttribute = @"AXEnhancedUserInterface";
160
161 @implementation WebFramePrivate
162
163 - (void)dealloc
164 {
165     [webFrameView release];
166
167     [super dealloc];
168 }
169
170 - (void)finalize
171 {
172     [super finalize];
173 }
174
175 - (void)setWebFrameView:(WebFrameView *)v 
176
177     [v retain];
178     [webFrameView release];
179     webFrameView = v;
180 }
181
182 @end
183
184 EditableLinkBehavior core(WebKitEditableLinkBehavior editableLinkBehavior)
185 {
186     switch (editableLinkBehavior) {
187         case WebKitEditableLinkDefaultBehavior:
188             return EditableLinkDefaultBehavior;
189         case WebKitEditableLinkAlwaysLive:
190             return EditableLinkAlwaysLive;
191         case WebKitEditableLinkOnlyLiveWithShiftKey:
192             return EditableLinkOnlyLiveWithShiftKey;
193         case WebKitEditableLinkLiveWhenNotFocused:
194             return EditableLinkLiveWhenNotFocused;
195         case WebKitEditableLinkNeverLive:
196             return EditableLinkNeverLive;
197     }
198     ASSERT_NOT_REACHED();
199     return EditableLinkDefaultBehavior;
200 }
201
202 TextDirectionSubmenuInclusionBehavior core(WebTextDirectionSubmenuInclusionBehavior behavior)
203 {
204     switch (behavior) {
205         case WebTextDirectionSubmenuNeverIncluded:
206             return TextDirectionSubmenuNeverIncluded;
207         case WebTextDirectionSubmenuAutomaticallyIncluded:
208             return TextDirectionSubmenuAutomaticallyIncluded;
209         case WebTextDirectionSubmenuAlwaysIncluded:
210             return TextDirectionSubmenuAlwaysIncluded;
211     }
212     ASSERT_NOT_REACHED();
213     return TextDirectionSubmenuNeverIncluded;
214 }
215
216 @implementation WebFrame (WebInternal)
217
218 Frame* core(WebFrame *frame)
219 {
220     return frame ? frame->_private->coreFrame : 0;
221 }
222
223 WebFrame *kit(Frame* frame)
224 {
225     if (!frame)
226         return nil;
227
228     FrameLoaderClient& frameLoaderClient = frame->loader().client();
229     if (frameLoaderClient.isEmptyFrameLoaderClient())
230         return nil;
231
232     return static_cast<WebFrameLoaderClient&>(frameLoaderClient).webFrame();
233 }
234
235 Page* core(WebView *webView)
236 {
237     return [webView page];
238 }
239
240 WebView *kit(Page* page)
241 {
242     if (!page)
243         return nil;
244
245     if (page->chrome().client().isEmptyChromeClient())
246         return nil;
247
248     return static_cast<WebChromeClient&>(page->chrome().client()).webView();
249 }
250
251 WebView *getWebView(WebFrame *webFrame)
252 {
253     Frame* coreFrame = core(webFrame);
254     if (!coreFrame)
255         return nil;
256     return kit(coreFrame->page());
257 }
258
259 + (PassRefPtr<Frame>)_createFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
260 {
261     WebView *webView = kit(page);
262
263     WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
264     RefPtr<Frame> coreFrame = Frame::create(page, ownerElement, new WebFrameLoaderClient(frame));
265     [frame release];
266     frame->_private->coreFrame = coreFrame.get();
267
268     coreFrame->tree().setName(name);
269     if (ownerElement) {
270         ASSERT(ownerElement->document().frame());
271         ownerElement->document().frame()->tree().appendChild(coreFrame.get());
272     }
273
274     coreFrame->init();
275
276     [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
277
278     return coreFrame.release();
279 }
280
281 + (void)_createMainFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView
282 {
283     WebView *webView = kit(page);
284
285     WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView];
286     frame->_private->coreFrame = &page->mainFrame();
287     static_cast<WebFrameLoaderClient&>(page->mainFrame().loader().client()).setWebFrame(frame);
288     [frame release];
289
290     page->mainFrame().tree().setName(name);
291     page->mainFrame().init();
292
293     [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
294 }
295
296 + (PassRefPtr<WebCore::Frame>)_createSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(const String&)name frameView:(WebFrameView *)frameView
297 {
298     return [self _createFrameWithPage:ownerElement->document().frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
299 }
300
301 - (BOOL)_isIncludedInWebKitStatistics
302 {
303     return _private && _private->includedInWebKitStatistics;
304 }
305
306 - (void)_attachScriptDebugger
307 {
308     ScriptController& scriptController = _private->coreFrame->script();
309
310     // Calling ScriptController::globalObject() would create a window shell, and dispatch corresponding callbacks, which may be premature
311     // if the script debugger is attached before a document is created.  These calls use the debuggerWorld(), we will need to pass a world
312     // to be able to debug isolated worlds.
313     if (!scriptController.existingWindowShell(debuggerWorld()))
314         return;
315
316     JSGlobalObject* globalObject = scriptController.globalObject(debuggerWorld());
317     if (!globalObject)
318         return;
319
320     if (_private->scriptDebugger) {
321         ASSERT(_private->scriptDebugger.get() == globalObject->debugger());
322         return;
323     }
324
325     _private->scriptDebugger = std::make_unique<WebScriptDebugger>(globalObject);
326 }
327
328 - (void)_detachScriptDebugger
329 {
330     _private->scriptDebugger = nullptr;
331 }
332
333 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v
334 {
335     self = [super init];
336     if (!self)
337         return nil;
338
339     _private = [[WebFramePrivate alloc] init];
340
341     // Set includedInWebKitStatistics before calling WebFrameView _setWebFrame, since
342     // it calls WebFrame _isIncludedInWebKitStatistics.
343     if ((_private->includedInWebKitStatistics = [[v class] shouldIncludeInWebKitStatistics]))
344         ++WebFrameCount;
345
346     if (fv) {
347         [_private setWebFrameView:fv];
348         [fv _setWebFrame:self];
349     }
350
351     _private->shouldCreateRenderers = YES;
352
353     return self;
354 }
355
356 - (void)_clearCoreFrame
357 {
358     _private->coreFrame = 0;
359 }
360
361 - (void)_updateBackgroundAndUpdatesWhileOffscreen
362 {
363     WebView *webView = getWebView(self);
364     BOOL drawsBackground = [webView drawsBackground];
365     NSColor *backgroundColor = [webView backgroundColor];
366
367     Frame* coreFrame = _private->coreFrame;
368     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
369         // Don't call setDrawsBackground:YES here because it may be NO because of a load
370         // in progress; WebFrameLoaderClient keeps it set to NO during the load process.
371         WebFrame *webFrame = kit(frame);
372         if (!drawsBackground)
373             [[[webFrame frameView] _scrollView] setDrawsBackground:NO];
374         [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor];
375
376         if (FrameView* view = frame->view()) {
377             view->setTransparent(!drawsBackground);
378             view->setBaseBackgroundColor(colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
379             view->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]);
380         }
381     }
382 }
383
384 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
385 {
386     _private->internalLoadDelegate = internalLoadDelegate;
387 }
388
389 - (id)_internalLoadDelegate
390 {
391     return _private->internalLoadDelegate;
392 }
393
394 - (void)_unmarkAllBadGrammar
395 {
396     Frame* coreFrame = _private->coreFrame;
397     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
398         if (Document* document = frame->document())
399             document->markers().removeMarkers(DocumentMarker::Grammar);
400     }
401 }
402
403 - (void)_unmarkAllMisspellings
404 {
405     Frame* coreFrame = _private->coreFrame;
406     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
407         if (Document* document = frame->document())
408             document->markers().removeMarkers(DocumentMarker::Spelling);
409     }
410 }
411
412 - (BOOL)_hasSelection
413 {
414     id documentView = [_private->webFrameView documentView];    
415
416     // optimization for common case to avoid creating potentially large selection string
417     if ([documentView isKindOfClass:[WebHTMLView class]])
418         if (Frame* coreFrame = _private->coreFrame)
419             return coreFrame->selection().isRange();
420
421     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
422         return [[documentView selectedString] length] > 0;
423     
424     return NO;
425 }
426
427 - (void)_clearSelection
428 {
429     id documentView = [_private->webFrameView documentView];    
430     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
431         [documentView deselectAll];
432 }
433
434 #if !ASSERT_DISABLED
435 - (BOOL)_atMostOneFrameHasSelection
436 {
437     // FIXME: 4186050 is one known case that makes this debug check fail.
438     BOOL found = NO;
439     Frame* coreFrame = _private->coreFrame;
440     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame))
441         if ([kit(frame) _hasSelection]) {
442             if (found)
443                 return NO;
444             found = YES;
445         }
446     return YES;
447 }
448 #endif
449
450 - (WebFrame *)_findFrameWithSelection
451 {
452     Frame* coreFrame = _private->coreFrame;
453     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
454         WebFrame *webFrame = kit(frame);
455         if ([webFrame _hasSelection])
456             return webFrame;
457     }
458     return nil;
459 }
460
461 - (void)_clearSelectionInOtherFrames
462 {
463     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
464     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
465     // notification sent when the first responder changes in general (Radar 2573089).
466     WebFrame *frameWithSelection = [[getWebView(self) mainFrame] _findFrameWithSelection];
467     if (frameWithSelection != self)
468         [frameWithSelection _clearSelection];
469
470     // While we're in the general area of selection and frames, check that there is only one now.
471     ASSERT([[getWebView(self) mainFrame] _atMostOneFrameHasSelection]);
472 }
473
474 static inline WebDataSource *dataSource(DocumentLoader* loader)
475 {
476     return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
477 }
478
479 - (WebDataSource *)_dataSource
480 {
481     return dataSource(_private->coreFrame->loader().documentLoader());
482 }
483
484 - (NSArray *)_nodesFromList:(Vector<Node*> *)nodesVector
485 {
486     size_t size = nodesVector->size();
487     NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
488     for (size_t i = 0; i < size; ++i)
489         [nodes addObject:kit((*nodesVector)[i])];
490     return nodes;
491 }
492
493 - (NSString *)_selectedString
494 {
495     return _private->coreFrame->displayStringModifiedByEncoding(_private->coreFrame->editor().selectedText());
496 }
497
498 - (NSString *)_stringForRange:(DOMRange *)range
499 {
500     return plainText(core(range), TextIteratorDefaultBehavior, true);
501 }
502
503 - (BOOL)_shouldFlattenCompositingLayers:(CGContextRef)context
504 {
505     // -currentContextDrawingToScreen returns YES for bitmap contexts.
506     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
507     if (isPrinting)
508         return YES;
509
510     if (!WKCGContextIsBitmapContext(context))
511         return NO;
512
513     // If we're drawing into a bitmap, we might be snapshotting, or drawing into a layer-backed view.
514     id documentView = [_private->webFrameView documentView];
515     if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _web_isDrawingIntoLayer])
516         return NO;
517
518     return [getWebView(self) _includesFlattenedCompositingLayersWhenDrawingToBitmap];
519 }
520
521 - (void)_drawRect:(NSRect)rect contentsOnly:(BOOL)contentsOnly
522 {
523     ASSERT([[NSGraphicsContext currentContext] isFlipped]);
524
525     CGContextRef ctx = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
526     GraphicsContext context(ctx);
527
528     FrameView* view = _private->coreFrame->view();
529     
530     bool shouldFlatten = false;
531     if (Frame* parentFrame = _private->coreFrame->tree().parent()) {
532         // For subframes, we need to inherit the paint behavior from our parent
533         FrameView* parentView = parentFrame ? parentFrame->view() : 0;
534         if (parentView)
535             shouldFlatten = parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
536     } else
537         shouldFlatten = [self _shouldFlattenCompositingLayers:ctx];
538
539     PaintBehavior oldBehavior = PaintBehaviorNormal;
540     if (shouldFlatten) {
541         oldBehavior = view->paintBehavior();
542         view->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
543     }
544     
545     if (contentsOnly)
546         view->paintContents(&context, enclosingIntRect(rect));
547     else
548         view->paint(&context, enclosingIntRect(rect));
549
550     if (shouldFlatten)
551         view->setPaintBehavior(oldBehavior);
552 }
553
554 - (BOOL)_getVisibleRect:(NSRect*)rect
555 {
556     ASSERT_ARG(rect, rect);
557     if (RenderWidget* ownerRenderer = _private->coreFrame->ownerRenderer()) {
558         if (ownerRenderer->needsLayout())
559             return NO;
560         *rect = ownerRenderer->pixelSnappedAbsoluteClippedOverflowRect();
561         return YES;
562     }
563
564     return NO;
565 }
566
567 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string
568 {
569     return [self _stringByEvaluatingJavaScriptFromString:string forceUserGesture:true];
570 }
571
572 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture
573 {
574     if (!string)
575         return @"";
576
577     ASSERT(_private->coreFrame->document());
578     RetainPtr<WebFrame> protect(self); // Executing arbitrary JavaScript can destroy the frame.
579     
580     JSC::JSValue result = _private->coreFrame->script().executeScript(string, forceUserGesture).jsValue();
581
582     if (!_private->coreFrame) // In case the script removed our frame from the page.
583         return @"";
584
585     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
586     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
587     // JSEvaluateScript instead, since they have less surprising semantics.
588     if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
589         return @"";
590
591     JSC::ExecState* exec = _private->coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec();
592     JSC::JSLockHolder lock(exec);
593     return result.toWTFString(exec);
594 }
595
596 - (NSRect)_caretRectAtPosition:(const Position&)pos affinity:(NSSelectionAffinity)affinity
597 {
598     VisiblePosition visiblePosition(pos, static_cast<EAffinity>(affinity));
599     return visiblePosition.absoluteCaretBounds();
600 }
601
602 - (NSRect)_firstRectForDOMRange:(DOMRange *)range
603 {
604    return _private->coreFrame->editor().firstRectForRange(core(range));
605 }
606
607 - (void)_scrollDOMRangeToVisible:(DOMRange *)range
608 {
609     NSRect rangeRect = [self _firstRectForDOMRange:range];    
610     Node *startNode = core([range startContainer]);
611         
612     if (startNode && startNode->renderer())
613         startNode->renderer()->scrollRectToVisible(enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
614 }
615
616 - (BOOL)_needsLayout
617 {
618     return _private->coreFrame->view() ? _private->coreFrame->view()->needsLayout() : false;
619 }
620
621 - (DOMRange *)_rangeByAlteringCurrentSelection:(FrameSelection::EAlteration)alteration direction:(SelectionDirection)direction granularity:(TextGranularity)granularity
622 {
623     if (_private->coreFrame->selection().isNone())
624         return nil;
625
626     FrameSelection selection;
627     selection.setSelection(_private->coreFrame->selection().selection());
628     selection.modify(alteration, direction, granularity);
629     return kit(selection.toNormalizedRange().get());
630 }
631
632 - (TextGranularity)_selectionGranularity
633 {
634     return _private->coreFrame->selection().granularity();
635 }
636
637 - (NSRange)_convertToNSRange:(Range *)range
638 {
639     if (!range)
640         return NSMakeRange(NSNotFound, 0);
641
642     size_t location;
643     size_t length;
644     if (!TextIterator::getLocationAndLengthFromRange(_private->coreFrame->selection().rootEditableElementOrDocumentElement(), range, location, length))
645         return NSMakeRange(NSNotFound, 0);
646
647     return NSMakeRange(location, length);
648 }
649
650 - (PassRefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
651 {
652     if (nsrange.location > INT_MAX)
653         return 0;
654     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
655         nsrange.length = INT_MAX - nsrange.location;
656
657     // our critical assumption is that we are only called by input methods that
658     // concentrate on a given area containing the selection
659     // We have to do this because of text fields and textareas. The DOM for those is not
660     // directly in the document DOM, so serialization is problematic. Our solution is
661     // to use the root editable element of the selection start as the positional base.
662     // That fits with AppKit's idea of an input context.
663     return TextIterator::rangeFromLocationAndLength(_private->coreFrame->selection().rootEditableElementOrDocumentElement(), nsrange.location, nsrange.length);
664 }
665
666 - (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange
667 {
668     return kit([self _convertToDOMRange:nsrange].get());
669 }
670
671 - (NSRange)_convertDOMRangeToNSRange:(DOMRange *)range
672 {
673     return [self _convertToNSRange:core(range)];
674 }
675
676 - (DOMRange *)_markDOMRange
677 {
678     return kit(_private->coreFrame->editor().mark().toNormalizedRange().get());
679 }
680
681 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
682 // be deleted along with the proposed range in order to preserve proper spacing and punctuation of
683 // the text surrounding the deletion.
684 - (DOMRange *)_smartDeleteRangeForProposedRange:(DOMRange *)proposedRange
685 {
686     Node* startContainer = core([proposedRange startContainer]);
687     Node* endContainer = core([proposedRange endContainer]);
688     if (startContainer == nil || endContainer == nil)
689         return nil;
690
691     ASSERT(&startContainer->document() == &endContainer->document());
692     
693     _private->coreFrame->document()->updateLayoutIgnorePendingStylesheets();
694
695     Position start = Position(startContainer, [proposedRange startOffset], Position::PositionIsOffsetInAnchor);
696     Position end = Position(endContainer, [proposedRange endOffset], Position::PositionIsOffsetInAnchor);
697     Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true);
698     if (newStart.isNull())
699         newStart = start;
700     Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true);
701     if (newEnd.isNull())
702         newEnd = end;
703
704     newStart = newStart.parentAnchoredEquivalent();
705     newEnd = newEnd.parentAnchoredEquivalent();
706
707     RefPtr<Range> range = _private->coreFrame->document()->createRange();
708     int exception = 0;
709     range->setStart(newStart.containerNode(), newStart.offsetInContainerNode(), exception);
710     range->setEnd(newStart.containerNode(), newStart.offsetInContainerNode(), exception);
711     return kit(range.get());
712 }
713
714 - (DOMDocumentFragment *)_documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString 
715 {
716     Frame* frame = _private->coreFrame;
717     if (!frame)
718         return nil;
719
720     Document* document = frame->document();
721     if (!document)
722         return nil;
723
724     return kit(createFragmentFromMarkup(*document, markupString, baseURLString, DisallowScriptingContent).get());
725 }
726
727 - (DOMDocumentFragment *)_documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
728 {
729     Frame* frame = _private->coreFrame;
730     if (!frame)
731         return nil;
732
733     Document* document = frame->document();
734     if (!document)
735         return nil;
736
737     NSEnumerator *nodeEnum = [nodes objectEnumerator];
738     Vector<Node*> nodesVector;
739     DOMNode *node;
740     while ((node = [nodeEnum nextObject]))
741         nodesVector.append(core(node));
742
743     RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
744
745     for (auto node : nodesVector) {
746         RefPtr<Element> element = createDefaultParagraphElement(*document);
747         element->appendChild(node, ASSERT_NO_EXCEPTION);
748         fragment->appendChild(element.release(), ASSERT_NO_EXCEPTION);
749     }
750
751     return kit(fragment.release().get());
752 }
753
754 - (void)_replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
755 {
756     DOMDocumentFragment *fragment = kit(_private->coreFrame->document()->createDocumentFragment().get());
757     [fragment appendChild:node];
758     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle];
759 }
760
761 - (void)_insertParagraphSeparatorInQuotedContent
762 {
763     if (_private->coreFrame->selection().isNone())
764         return;
765
766     _private->coreFrame->editor().insertParagraphSeparatorInQuotedContent();
767 }
768
769 - (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
770 {
771     // FIXME: Someone with access to Apple's sources could remove this needless wrapper call.
772     return _private->coreFrame->visiblePositionForPoint(IntPoint(point));
773 }
774
775 - (DOMRange *)_characterRangeAtPoint:(NSPoint)point
776 {
777     return kit(_private->coreFrame->rangeForPoint(IntPoint(point)).get());
778 }
779
780 - (DOMCSSStyleDeclaration *)_typingStyle
781 {
782     if (!_private->coreFrame)
783         return nil;
784     RefPtr<MutableStyleProperties> typingStyle = _private->coreFrame->selection().copyTypingStyle();
785     if (!typingStyle)
786         return nil;
787     return kit(typingStyle->ensureCSSStyleDeclaration());
788 }
789
790 - (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction
791 {
792     if (!_private->coreFrame || !style)
793         return;
794     // FIXME: We shouldn't have to create a copy here.
795     Ref<MutableStyleProperties> properties(core(style)->copyProperties());
796     _private->coreFrame->editor().computeAndSetTypingStyle(&properties.get(), undoAction);
797 }
798
799 #if ENABLE(DRAG_SUPPORT)
800 - (void)_dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation
801 {
802     if (!_private->coreFrame)
803         return;
804     FrameView* view = _private->coreFrame->view();
805     if (!view)
806         return;
807     // FIXME: These are fake modifier keys here, but they should be real ones instead.
808     PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]),
809         LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime());
810     _private->coreFrame->eventHandler().dragSourceEndedAt(event, (DragOperation)operation);
811 }
812 #endif
813
814 - (BOOL)_canProvideDocumentSource
815 {
816     Frame* frame = _private->coreFrame;
817     String mimeType = frame->document()->loader()->writer().mimeType();
818     PluginData* pluginData = frame->page() ? &frame->page()->pluginData() : 0;
819
820     if (WebCore::DOMImplementation::isTextMIMEType(mimeType)
821         || Image::supportsType(mimeType)
822         || (pluginData && pluginData->supportsMimeType(mimeType, PluginData::AllPlugins) && frame->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin))
823         || (pluginData && pluginData->supportsMimeType(mimeType, PluginData::OnlyApplicationPlugins)))
824         return NO;
825
826     return YES;
827 }
828
829 - (BOOL)_canSaveAsWebArchive
830 {
831     // Currently, all documents that we can view source for
832     // (HTML and XML documents) can also be saved as web archives
833     return [self _canProvideDocumentSource];
834 }
835
836 - (void)_commitData:(NSData *)data
837 {
838     // FIXME: This really should be a setting.
839     Document* document = _private->coreFrame->document();
840     document->setShouldCreateRenderers(_private->shouldCreateRenderers);
841
842     _private->coreFrame->loader().documentLoader()->commitData((const char *)[data bytes], [data length]);
843 }
844
845 @end
846
847 @implementation WebFrame (WebPrivate)
848
849 // FIXME: This exists only as a convenience for Safari, consider moving there.
850 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
851 {
852     Frame* coreFrame = _private->coreFrame;
853     return coreFrame && coreFrame->tree().isDescendantOf(core(ancestor));
854 }
855
856 - (void)_setShouldCreateRenderers:(BOOL)shouldCreateRenderers
857 {
858     _private->shouldCreateRenderers = shouldCreateRenderers;
859 }
860
861 - (NSColor *)_bodyBackgroundColor
862 {
863     Document* document = _private->coreFrame->document();
864     if (!document)
865         return nil;
866     HTMLElement* body = document->body();
867     if (!body)
868         return nil;
869     RenderObject* bodyRenderer = body->renderer();
870     if (!bodyRenderer)
871         return nil;
872     Color color = bodyRenderer->style().visitedDependentColor(CSSPropertyBackgroundColor);
873     if (!color.isValid())
874         return nil;
875     return nsColor(color);
876 }
877
878 - (BOOL)_isFrameSet
879 {
880     Document* document = _private->coreFrame->document();
881     return document && document->isFrameSet();
882 }
883
884 - (BOOL)_firstLayoutDone
885 {
886     return _private->coreFrame->loader().stateMachine()->firstLayoutDone();
887 }
888
889 - (BOOL)_isVisuallyNonEmpty
890 {
891     if (FrameView* view = _private->coreFrame->view())
892         return view->isVisuallyNonEmpty();
893     return NO;
894 }
895
896 - (WebFrameLoadType)_loadType
897 {
898     return (WebFrameLoadType)_private->coreFrame->loader().loadType();
899 }
900
901 - (NSRange)_selectedNSRange
902 {
903     return [self _convertToNSRange:_private->coreFrame->selection().toNormalizedRange().get()];
904 }
905
906 - (void)_selectNSRange:(NSRange)range
907 {
908     RefPtr<Range> domRange = [self _convertToDOMRange:range];
909     if (domRange)
910         _private->coreFrame->selection().setSelection(VisibleSelection(domRange.get(), SEL_DEFAULT_AFFINITY));
911 }
912
913 - (BOOL)_isDisplayingStandaloneImage
914 {
915     Document* document = _private->coreFrame->document();
916     return document && document->isImageDocument();
917 }
918
919 - (unsigned)_pendingFrameUnloadEventCount
920 {
921     return _private->coreFrame->document()->domWindow()->pendingUnloadEventListeners();
922 }
923
924 #if ENABLE(NETSCAPE_PLUGIN_API)
925 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
926 {
927     Frame* coreFrame = core(self);
928     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
929         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
930         if ([documentView isKindOfClass:[WebHTMLView class]])
931             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
932     }
933 }
934
935 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
936 {
937     Frame* coreFrame = core(self);
938     for (Frame* frame = coreFrame; frame; frame = frame->tree().traverseNext(coreFrame)) {
939         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
940         if ([documentView isKindOfClass:[WebHTMLView class]])
941             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
942     }
943 }
944 #endif
945
946 #if ENABLE(IOS_TEXT_AUTOSIZING)
947 - (void)resetTextAutosizingBeforeLayout
948 {
949     id documentView = [_private->webFrameView documentView];    
950     if (![documentView isKindOfClass:[WebHTMLView class]])
951         return;
952     
953     Frame* coreFrame = core(self);
954     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
955         Document *doc = frame->document();
956         if (!doc || !doc->renderer())
957             continue;
958         doc->renderer()->resetTextAutosizing();
959     }
960 }
961
962 - (void)_setVisibleSize:(CGSize)size
963 {
964     [self _setTextAutosizingWidth:size.width];
965 }
966
967 - (void)_setTextAutosizingWidth:(CGFloat)width
968 {
969     WebCore::Frame *frame = core(self);
970     frame->setTextAutosizingWidth(width);
971 }
972 #else
973 - (void)resetTextAutosizingBeforeLayout
974 {
975 }
976
977 - (void)_setVisibleSize:(CGSize)size
978 {
979 }
980
981 - (void)_setTextAutosizingWidth:(CGFloat)width
982 {
983 }
984 #endif // ENABLE(IOS_TEXT_AUTOSIZING)
985
986 - (void)_replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
987 {
988     if (_private->coreFrame->selection().isNone() || !fragment)
989         return;
990     _private->coreFrame->editor().replaceSelectionWithFragment(core(fragment), selectReplacement, smartReplace, matchStyle);
991 }
992
993 - (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
994 {
995     RefPtr<Range> range = _private->coreFrame->selection().toNormalizedRange();
996     
997     DOMDocumentFragment* fragment = range ? kit(createFragmentFromText(*range, text).get()) : nil;
998     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
999 }
1000
1001 - (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
1002 {
1003     DOMDocumentFragment *fragment = [self _documentFragmentWithMarkupString:markupString baseURLString:baseURLString];
1004     [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO];
1005 }
1006
1007 // Determines whether whitespace needs to be added around aString to preserve proper spacing and
1008 // punctuation when it's inserted into the receiver's text over charRange. Returns by reference
1009 // in beforeString and afterString any whitespace that should be added, unless either or both are
1010 // nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled.
1011 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1012 {
1013     // give back nil pointers in case of early returns
1014     if (beforeString)
1015         *beforeString = nil;
1016     if (afterString)
1017         *afterString = nil;
1018         
1019     // inspect destination
1020     Node *startContainer = core([rangeToReplace startContainer]);
1021     Node *endContainer = core([rangeToReplace endContainer]);
1022
1023     Position startPos(startContainer, [rangeToReplace startOffset], Position::PositionIsOffsetInAnchor);
1024     Position endPos(endContainer, [rangeToReplace endOffset], Position::PositionIsOffsetInAnchor);
1025
1026     VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
1027     VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
1028     
1029     // this check also ensures startContainer, startPos, endContainer, and endPos are non-null
1030     if (startVisiblePos.isNull() || endVisiblePos.isNull())
1031         return;
1032
1033     bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos);
1034     if (addLeadingSpace)
1035         if (UChar previousChar = startVisiblePos.previous().characterAfter())
1036             addLeadingSpace = !isCharacterSmartReplaceExempt(previousChar, true);
1037     
1038     bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos);
1039     if (addTrailingSpace)
1040         if (UChar thisChar = endVisiblePos.characterAfter())
1041             addTrailingSpace = !isCharacterSmartReplaceExempt(thisChar, false);
1042     
1043     // inspect source
1044     bool hasWhitespaceAtStart = false;
1045     bool hasWhitespaceAtEnd = false;
1046     unsigned pasteLength = [pasteString length];
1047     if (pasteLength > 0) {
1048         NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
1049         
1050         if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) {
1051             hasWhitespaceAtStart = YES;
1052         }
1053         if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) {
1054             hasWhitespaceAtEnd = YES;
1055         }
1056     }
1057     
1058     // issue the verdict
1059     if (beforeString && addLeadingSpace && !hasWhitespaceAtStart)
1060         *beforeString = @" ";
1061     if (afterString && addTrailingSpace && !hasWhitespaceAtEnd)
1062         *afterString = @" ";
1063 }
1064
1065 - (NSMutableDictionary *)_cacheabilityDictionary
1066 {
1067     NSMutableDictionary *result = [NSMutableDictionary dictionary];
1068     
1069     FrameLoader& frameLoader = _private->coreFrame->loader();
1070     DocumentLoader* documentLoader = frameLoader.documentLoader();
1071     if (documentLoader && !documentLoader->mainDocumentError().isNull())
1072         [result setObject:(NSError *)documentLoader->mainDocumentError() forKey:WebFrameMainDocumentError];
1073         
1074     if (frameLoader.subframeLoader().containsPlugins())
1075         [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasPlugins];
1076     
1077     if (DOMWindow* domWindow = _private->coreFrame->document()->domWindow()) {
1078         if (domWindow->hasEventListeners(eventNames().unloadEvent))
1079             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasUnloadListener];
1080         if (domWindow->optionalApplicationCache())
1081             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesApplicationCache];
1082     }
1083     
1084     if (Document* document = _private->coreFrame->document()) {
1085 #if ENABLE(SQL_DATABASE)
1086         if (DatabaseManager::manager().hasOpenDatabases(document))
1087             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesDatabases];
1088 #endif
1089         if (!document->canSuspendActiveDOMObjects())
1090             [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameCanSuspendActiveDOMObjects];
1091     }
1092     
1093     return result;
1094 }
1095
1096 - (BOOL)_allowsFollowingLink:(NSURL *)URL
1097 {
1098     if (!_private->coreFrame)
1099         return YES;
1100     return _private->coreFrame->document()->securityOrigin()->canDisplay(URL);
1101 }
1102
1103 - (NSString *)_stringByEvaluatingJavaScriptFromString:(NSString *)string withGlobalObject:(JSObjectRef)globalObjectRef inScriptWorld:(WebScriptWorld *)world
1104 {
1105     if (!string)
1106         return @"";
1107
1108     if (!world)
1109         return @"";
1110
1111     // Start off with some guess at a frame and a global object, we'll try to do better...!
1112     JSDOMWindow* anyWorldGlobalObject = _private->coreFrame->script().globalObject(mainThreadNormalWorld());
1113
1114     // The global object is probably a shell object? - if so, we know how to use this!
1115     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
1116     if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
1117         anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
1118
1119     // Get the frame frome the global object we've settled on.
1120     Frame* frame = anyWorldGlobalObject->impl().frame();
1121     ASSERT(frame->document());
1122     RetainPtr<WebFrame> webFrame(kit(frame)); // Running arbitrary JavaScript can destroy the frame.
1123
1124     JSC::JSValue result = frame->script().executeScriptInWorld(*core(world), string, true).jsValue();
1125
1126     if (!webFrame->_private->coreFrame) // In case the script removed our frame from the page.
1127         return @"";
1128
1129     // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
1130     // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
1131     // JSEvaluateScript instead, since they have less surprising semantics.
1132     if (!result || (!result.isBoolean() && !result.isString() && !result.isNumber()))
1133         return @"";
1134
1135     JSC::ExecState* exec = anyWorldGlobalObject->globalExec();
1136     JSC::JSLockHolder lock(exec);
1137     return result.toWTFString(exec);
1138 }
1139
1140 - (JSGlobalContextRef)_globalContextForScriptWorld:(WebScriptWorld *)world
1141 {
1142     Frame* coreFrame = _private->coreFrame;
1143     if (!coreFrame)
1144         return 0;
1145     DOMWrapperWorld* coreWorld = core(world);
1146     if (!coreWorld)
1147         return 0;
1148     return toGlobalRef(coreFrame->script().globalObject(*coreWorld)->globalExec());
1149 }
1150
1151 #if JSC_OBJC_API_ENABLED
1152 - (JSContext *)_javaScriptContextForScriptWorld:(WebScriptWorld *)world
1153 {
1154     JSGlobalContextRef globalContextRef = [self _globalContextForScriptWorld:world];
1155     if (!globalContextRef)
1156         return 0;
1157     return [JSContext contextWithJSGlobalContextRef:globalContextRef];
1158 }
1159 #endif
1160
1161 - (void)setAllowsScrollersToOverlapContent:(BOOL)flag
1162 {
1163     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1164     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAllowsScrollersToOverlapContent:flag];
1165 }
1166
1167 - (void)setAlwaysHideHorizontalScroller:(BOOL)flag
1168 {
1169     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1170     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideHorizontalScroller:flag];
1171 }
1172 - (void)setAlwaysHideVerticalScroller:(BOOL)flag
1173 {
1174     ASSERT([[[self frameView] _scrollView] isKindOfClass:[WebDynamicScrollBarsView class]]);
1175     [(WebDynamicScrollBarsView *)[[self frameView] _scrollView] setAlwaysHideVerticalScroller:flag];
1176 }
1177
1178 - (void)setAccessibleName:(NSString *)name
1179 {
1180 #if HAVE(ACCESSIBILITY)
1181     if (!AXObjectCache::accessibilityEnabled())
1182         return;
1183     
1184     if (!_private->coreFrame || !_private->coreFrame->document())
1185         return;
1186     
1187     AccessibilityObject* rootObject = _private->coreFrame->document()->axObjectCache()->rootObject();
1188     if (rootObject) {
1189         String strName(name);
1190         rootObject->setAccessibleName(strName);
1191     }
1192 #endif
1193 }
1194
1195 - (NSString*)_layerTreeAsText
1196 {
1197     Frame* coreFrame = _private->coreFrame;
1198     if (!coreFrame)
1199         return @"";
1200
1201     return coreFrame->layerTreeAsText();
1202 }
1203
1204 - (id)accessibilityRoot
1205 {
1206 #if HAVE(ACCESSIBILITY)
1207     if (!AXObjectCache::accessibilityEnabled()) {
1208         AXObjectCache::enableAccessibility();
1209         AXObjectCache::setEnhancedUserInterfaceAccessibility([[NSApp accessibilityAttributeValue:NSAccessibilityEnhancedUserInterfaceAttribute] boolValue]);
1210     }
1211     
1212     if (!_private->coreFrame)
1213         return nil;
1214     
1215     Document* document = _private->coreFrame->document();
1216     if (!document || !document->axObjectCache())
1217         return nil;
1218     
1219     AccessibilityObject* rootObject = document->axObjectCache()->rootObjectForFrame(_private->coreFrame);
1220     if (!rootObject)
1221         return nil;
1222     
1223     // The root object will be a WebCore scroll view object. In WK1, scroll views are handled
1224     // by the system and the root object should be the web area (instead of the scroll view).
1225     if (rootObject->isAttachment() && rootObject->firstChild())
1226         return rootObject->firstChild()->wrapper();
1227     
1228     return rootObject->wrapper();
1229 #else
1230     return nil;
1231 #endif
1232 }
1233
1234 - (void)_clearOpener
1235 {
1236     Frame* coreFrame = _private->coreFrame;
1237     if (coreFrame)
1238         coreFrame->loader().setOpener(0);
1239 }
1240
1241 // Used by pagination code called from AppKit when a standalone web page is printed.
1242 - (NSArray *)_computePageRectsWithPrintScaleFactor:(float)printScaleFactor pageSize:(NSSize)pageSize
1243 {
1244     if (printScaleFactor <= 0) {
1245         LOG_ERROR("printScaleFactor has bad value %.2f", printScaleFactor);
1246         return [NSArray array];
1247     }
1248
1249     if (!_private->coreFrame)
1250         return [NSArray array];
1251     if (!_private->coreFrame->document())
1252         return [NSArray array];
1253     if (!_private->coreFrame->view())
1254         return [NSArray array];
1255     if (!_private->coreFrame->view()->documentView())
1256         return [NSArray array];
1257
1258     RenderView* root = _private->coreFrame->document()->renderView();
1259     if (!root)
1260         return [NSArray array];
1261
1262     const LayoutRect& documentRect = root->documentRect();
1263     float printWidth = root->style().isHorizontalWritingMode() ? static_cast<float>(documentRect.width()) / printScaleFactor : pageSize.width;
1264     float printHeight = root->style().isHorizontalWritingMode() ? pageSize.height : static_cast<float>(documentRect.height()) / printScaleFactor;
1265
1266     PrintContext printContext(_private->coreFrame);
1267     printContext.computePageRectsWithPageSize(FloatSize(printWidth, printHeight), true);
1268     const Vector<IntRect>& pageRects = printContext.pageRects();
1269
1270     size_t size = pageRects.size();
1271     NSMutableArray *pages = [NSMutableArray arrayWithCapacity:size];
1272     for (size_t i = 0; i < size; ++i)
1273         [pages addObject:[NSValue valueWithRect:NSRect(pageRects[i])]];
1274     return pages;
1275 }
1276
1277 - (JSValueRef)jsWrapperForNode:(DOMNode *)node inScriptWorld:(WebScriptWorld *)world
1278 {
1279     Frame* coreFrame = _private->coreFrame;
1280     if (!coreFrame)
1281         return 0;
1282
1283     if (!world)
1284         return 0;
1285
1286     JSDOMWindow* globalObject = coreFrame->script().globalObject(*core(world));
1287     JSC::ExecState* exec = globalObject->globalExec();
1288
1289     JSC::JSLockHolder lock(exec);
1290     return toRef(exec, toJS(exec, globalObject, core(node)));
1291 }
1292
1293 - (NSDictionary *)elementAtPoint:(NSPoint)point
1294 {
1295     Frame* coreFrame = _private->coreFrame;
1296     if (!coreFrame)
1297         return nil;
1298     return [[[WebElementDictionary alloc] initWithHitTestResult:coreFrame->eventHandler().hitTestResultAtPoint(IntPoint(point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent)] autorelease];
1299 }
1300
1301 - (NSURL *)_unreachableURL
1302 {
1303     return [[self _dataSource] unreachableURL];
1304 }
1305
1306 @end
1307
1308 @implementation WebFrame
1309
1310 - (instancetype)init
1311 {
1312     return nil;
1313 }
1314
1315 // Should be deprecated.
1316 - (instancetype)initWithName:(NSString *)name webFrameView:(WebFrameView *)view webView:(WebView *)webView
1317 {
1318     return nil;
1319 }
1320
1321 - (void)dealloc
1322 {
1323     if (_private && _private->includedInWebKitStatistics)
1324         --WebFrameCount;
1325
1326     [_private release];
1327
1328     [super dealloc];
1329 }
1330
1331 - (void)finalize
1332 {
1333     if (_private && _private->includedInWebKitStatistics)
1334         --WebFrameCount;
1335
1336     [super finalize];
1337 }
1338
1339 - (NSString *)name
1340 {
1341     Frame* coreFrame = _private->coreFrame;
1342     if (!coreFrame)
1343         return nil;
1344     return coreFrame->tree().uniqueName();
1345 }
1346
1347 - (WebFrameView *)frameView
1348 {
1349     return _private->webFrameView;
1350 }
1351
1352 - (WebView *)webView
1353 {
1354     return getWebView(self);
1355 }
1356
1357 static bool needsMicrosoftMessengerDOMDocumentWorkaround()
1358 {
1359     static bool needsWorkaround = applicationIsMicrosoftMessenger() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] compare:@"7.1" options:NSNumericSearch] == NSOrderedAscending;
1360     return needsWorkaround;
1361 }
1362
1363 - (DOMDocument *)DOMDocument
1364 {
1365     if (needsMicrosoftMessengerDOMDocumentWorkaround() && !pthread_main_np())
1366         return nil;
1367
1368     Frame* coreFrame = _private->coreFrame;
1369     if (!coreFrame)
1370         return nil;
1371     
1372     // FIXME: <rdar://problem/5145841> When loading a custom view/representation 
1373     // into a web frame, the old document can still be around. This makes sure that
1374     // we'll return nil in those cases.
1375     if (![[self _dataSource] _isDocumentHTML]) 
1376         return nil; 
1377
1378     Document* document = coreFrame->document();
1379     
1380     // According to the documentation, we should return nil if the frame doesn't have a document.
1381     // While full-frame images and plugins do have an underlying HTML document, we return nil here to be
1382     // backwards compatible.
1383     if (document && (document->isPluginDocument() || document->isImageDocument()))
1384         return nil;
1385     
1386     return kit(coreFrame->document());
1387 }
1388
1389 - (DOMHTMLElement *)frameElement
1390 {
1391     Frame* coreFrame = _private->coreFrame;
1392     if (!coreFrame)
1393         return nil;
1394     return kit(coreFrame->ownerElement());
1395 }
1396
1397 - (WebDataSource *)provisionalDataSource
1398 {
1399     Frame* coreFrame = _private->coreFrame;
1400     return coreFrame ? dataSource(coreFrame->loader().provisionalDocumentLoader()) : nil;
1401 }
1402
1403 - (WebDataSource *)dataSource
1404 {
1405     Frame* coreFrame = _private->coreFrame;
1406     return coreFrame && coreFrame->loader().frameHasLoaded() ? [self _dataSource] : nil;
1407 }
1408
1409 - (void)loadRequest:(NSURLRequest *)request
1410 {
1411     Frame* coreFrame = _private->coreFrame;
1412     if (!coreFrame)
1413         return;
1414
1415     ResourceRequest resourceRequest(request);
1416     
1417     // Some users of WebKit API incorrectly use "file path as URL" style requests which are invalid.
1418     // By re-writing those URLs here we technically break the -[WebDataSource initialRequest] API
1419     // but that is necessary to implement this quirk only at the API boundary.
1420     // Note that other users of WebKit API use nil requests or requests with nil URLs or empty URLs, so we
1421     // only implement this workaround when the request had a non-nil or non-empty URL.
1422     if (!resourceRequest.url().isValid() && !resourceRequest.url().isEmpty())
1423         resourceRequest.setURL([NSURL URLWithString:[@"file:" stringByAppendingString:[[request URL] absoluteString]]]);
1424
1425     coreFrame->loader().load(FrameLoadRequest(coreFrame, resourceRequest));
1426 }
1427
1428 static NSURL *createUniqueWebDataURL()
1429 {
1430     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
1431     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
1432     CFRelease(UUIDRef);
1433     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"applewebdata://%@", UUIDString]];
1434     CFRelease(UUIDString);
1435     return URL;
1436 }
1437
1438 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
1439 {
1440     if (!pthread_main_np())
1441         return [[self _webkit_invokeOnMainThread] _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:unreachableURL];
1442     
1443     URL responseURL;
1444     if (!baseURL) {
1445         baseURL = blankURL();
1446         responseURL = createUniqueWebDataURL();
1447     }
1448     
1449     ResourceRequest request([baseURL absoluteURL]);
1450
1451     // hack because Mail checks for this property to detect data / archive loads
1452     [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest(UpdateHTTPBody)];
1453
1454     SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData(data), MIMEType, encodingName, [unreachableURL absoluteURL], responseURL);
1455
1456     _private->coreFrame->loader().load(FrameLoadRequest(_private->coreFrame, request, substituteData));
1457 }
1458
1459
1460 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
1461 {
1462     WebCoreThreadViolationCheckRoundTwo();
1463     
1464     if (!MIMEType)
1465         MIMEType = @"text/html";
1466     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:[baseURL _webkit_URLFromURLOrSchemelessFileURL] unreachableURL:nil];
1467 }
1468
1469 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
1470 {
1471     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
1472     [self _loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL unreachableURL:unreachableURL];
1473 }
1474
1475 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
1476 {
1477     WebCoreThreadViolationCheckRoundTwo();
1478
1479     [self _loadHTMLString:string baseURL:[baseURL _webkit_URLFromURLOrSchemelessFileURL] unreachableURL:nil];
1480 }
1481
1482 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
1483 {
1484     WebCoreThreadViolationCheckRoundTwo();
1485
1486     [self _loadHTMLString:string baseURL:[baseURL _webkit_URLFromURLOrSchemelessFileURL] unreachableURL:[unreachableURL _webkit_URLFromURLOrSchemelessFileURL]];
1487 }
1488
1489 - (void)loadArchive:(WebArchive *)archive
1490 {
1491     if (LegacyWebArchive* coreArchive = [archive _coreLegacyWebArchive])
1492         _private->coreFrame->loader().loadArchive(coreArchive);
1493 }
1494
1495 - (void)stopLoading
1496 {
1497     if (!_private->coreFrame)
1498         return;
1499     _private->coreFrame->loader().stopForUserCancel();
1500 }
1501
1502 - (void)reload
1503 {
1504     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_RELOAD_FROM_ORIGIN) && applicationIsSafari())
1505         _private->coreFrame->loader().reload(GetCurrentKeyModifiers() & shiftKey);
1506     else
1507         _private->coreFrame->loader().reload(false);
1508 }
1509
1510 - (void)reloadFromOrigin
1511 {
1512     _private->coreFrame->loader().reload(true);
1513 }
1514
1515 - (WebFrame *)findFrameNamed:(NSString *)name
1516 {
1517     Frame* coreFrame = _private->coreFrame;
1518     if (!coreFrame)
1519         return nil;
1520     return kit(coreFrame->tree().find(name));
1521 }
1522
1523 - (WebFrame *)parentFrame
1524 {
1525     Frame* coreFrame = _private->coreFrame;
1526     if (!coreFrame)
1527         return nil;
1528     return [[kit(coreFrame->tree().parent()) retain] autorelease];
1529 }
1530
1531 - (NSArray *)childFrames
1532 {
1533     Frame* coreFrame = _private->coreFrame;
1534     if (!coreFrame)
1535         return [NSArray array];
1536     NSMutableArray *children = [NSMutableArray arrayWithCapacity:coreFrame->tree().childCount()];
1537     for (Frame* child = coreFrame->tree().firstChild(); child; child = child->tree().nextSibling())
1538         [children addObject:kit(child)];
1539     return children;
1540 }
1541
1542 - (WebScriptObject *)windowObject
1543 {
1544     Frame* coreFrame = _private->coreFrame;
1545     if (!coreFrame)
1546         return 0;
1547     return coreFrame->script().windowScriptObject();
1548 }
1549
1550 - (JSGlobalContextRef)globalContext
1551 {
1552     Frame* coreFrame = _private->coreFrame;
1553     if (!coreFrame)
1554         return 0;
1555     return toGlobalRef(coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
1556 }
1557
1558 #if JSC_OBJC_API_ENABLED
1559 - (JSContext *)javaScriptContext
1560 {
1561     Frame* coreFrame = _private->coreFrame;
1562     if (!coreFrame)
1563         return 0;
1564     return coreFrame->script().javaScriptContext();
1565 }
1566 #endif
1567
1568 @end