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