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