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