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