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