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