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