50933e69c9bedbd6c3eebeee03a6aaedf4464eef
[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 "DOMDocumentInternal.h"
33 #import "DOMElementInternal.h"
34 #import "DOMHTMLElementInternal.h"
35 #import "DOMNodeInternal.h"
36 #import "DOMRangeInternal.h"
37 #import "WebBackForwardList.h"
38 #import "WebChromeClient.h"
39 #import "WebScriptDebugger.h"
40 #import "WebDataSourceInternal.h"
41 #import "WebDocumentInternal.h"
42 #import "WebDocumentLoaderMac.h"
43 #import "WebFrameBridge.h"
44 #import "WebFrameLoadDelegate.h"
45 #import "WebFrameLoaderClient.h"
46 #import "WebFrameViewInternal.h"
47 #import "WebHTMLViewInternal.h"
48 #import "WebHistoryItem.h"
49 #import "WebHistoryItemInternal.h"
50 #import "WebHistoryItemPrivate.h"
51 #import "WebKitLogging.h"
52 #import "WebKitStatisticsPrivate.h"
53 #import "WebNSURLExtras.h"
54 #import "WebNSURLRequestExtras.h"
55 #import "WebNetscapePluginEmbeddedView.h"
56 #import "WebNullPluginView.h"
57 #import "WebPlugin.h"
58 #import "WebPluginController.h"
59 #import "WebPreferencesPrivate.h"
60 #import "WebViewInternal.h"
61 #import <WebCore/Chrome.h>
62 #import <WebCore/ColorMac.h>
63 #import <WebCore/Document.h>
64 #import <WebCore/Event.h>
65 #import <WebCore/FrameLoader.h>
66 #import <WebCore/Frame.h>
67 #import <WebCore/FrameTree.h>
68 #import <WebCore/HistoryItem.h>
69 #import <WebCore/HTMLFormElement.h>
70 #import <WebCore/HTMLFrameOwnerElement.h>
71 #import <WebCore/Page.h>
72 #import <WebCore/SelectionController.h>
73 #import <WebCore/SharedBuffer.h>
74 #import <WebCore/FormState.h>
75 #import <WebCore/ResourceRequest.h>
76 #import <WebCore/kjs_binding.h>
77 #import <WebCore/kjs_proxy.h>
78 #import <WebKit/DOMDocument.h>
79 #import <WebKit/DOMElement.h>
80 #import <WebKit/DOMHTMLElement.h>
81 #import <WebKit/DOMNode.h>
82 #import <WebKit/DOMRange.h>
83 #import <JavaScriptCore/APICast.h>
84
85 using namespace WebCore;
86
87 /*
88 Here is the current behavior matrix for four types of navigations:
89
90 Standard Nav:
91
92  Restore form state:   YES
93  Restore scroll and focus state:  YES
94  Cache policy: NSURLRequestUseProtocolCachePolicy
95  Add to back/forward list: YES
96  
97 Back/Forward:
98
99  Restore form state:   YES
100  Restore scroll and focus state:  YES
101  Cache policy: NSURLRequestReturnCacheDataElseLoad
102  Add to back/forward list: NO
103
104 Reload (meaning only the reload button):
105
106  Restore form state:   NO
107  Restore scroll and focus state:  YES
108  Cache policy: NSURLRequestReloadIgnoringCacheData
109  Add to back/forward list: NO
110
111 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
112
113  Restore form state:   NO
114  Restore scroll and focus state:  NO, reset to initial conditions
115  Cache policy: NSURLRequestReloadIgnoringCacheData
116  Add to back/forward list: NO
117 */
118
119 using namespace WebCore;
120
121 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
122 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
123 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
124
125 @interface WebFrame (ForwardDecls)
126 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL;
127 - (WebHistoryItem *)_createItem:(BOOL)useOriginal;
128 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
129 @end
130
131 @interface NSView (WebFramePluginHosting)
132 - (void)setWebFrame:(WebFrame *)webFrame;
133 @end
134
135 @implementation WebFramePrivate
136
137 - (void)dealloc
138 {
139     [bridge release];
140     [webFrameView release];
141
142     delete scriptDebugger;
143
144     [super dealloc];
145 }
146
147 - (void)finalize
148 {
149     delete scriptDebugger;
150
151     [super finalize];
152 }
153
154 - (void)setWebFrameView:(WebFrameView *)v 
155
156     [v retain];
157     [webFrameView release];
158     webFrameView = v;
159 }
160
161 @end
162
163 CSSStyleDeclaration* core(DOMCSSStyleDeclaration *declaration)
164 {
165     return [declaration _CSSStyleDeclaration];
166 }
167
168 DOMCSSStyleDeclaration *kit(WebCore::CSSStyleDeclaration* declaration)
169 {
170     return [DOMCSSStyleDeclaration _wrapCSSStyleDeclaration:declaration];
171 }
172
173 Element* core(DOMElement *element)
174 {
175     return [element _element];
176 }
177
178 DOMElement *kit(Element* element)
179 {
180     return [DOMElement _wrapElement:element];
181 }
182
183 Node* core(DOMNode *node)
184 {
185     return [node _node];
186 }
187
188 DOMNode *kit(Node* node)
189 {
190     return [DOMNode _wrapNode:node];
191 }
192
193 DOMNode *kit(PassRefPtr<Node> node)
194 {
195     return [DOMNode _wrapNode:node.get()];
196 }
197
198 Document* core(DOMDocument *document)
199 {
200     return [document _document];
201 }
202
203 DOMDocument *kit(Document* document)
204 {
205     return [DOMDocument _wrapDocument:document];
206 }
207
208 HTMLElement* core(DOMHTMLElement *element)
209 {
210     return [element _HTMLElement];
211 }
212
213 DOMHTMLElement *kit(HTMLElement *element)
214 {
215     return [DOMHTMLElement _wrapHTMLElement:element];
216 }
217
218 Range* core(DOMRange *range)
219 {
220     return [range _range];
221 }
222
223 DOMRange *kit(Range* range)
224 {
225     return [DOMRange _wrapRange:range];
226 }
227
228 EditableLinkBehavior core(WebKitEditableLinkBehavior editableLinkBehavior)
229 {
230     switch (editableLinkBehavior) {
231         case WebKitEditableLinkDefaultBehavior:
232             return EditableLinkDefaultBehavior;
233         case WebKitEditableLinkAlwaysLive:
234             return EditableLinkAlwaysLive;
235         case WebKitEditableLinkOnlyLiveWithShiftKey:
236             return EditableLinkOnlyLiveWithShiftKey;
237         case WebKitEditableLinkLiveWhenNotFocused:
238             return EditableLinkLiveWhenNotFocused;
239         case WebKitEditableLinkNeverLive:
240             return EditableLinkNeverLive;
241     }
242     ASSERT_NOT_REACHED();
243     return EditableLinkDefaultBehavior;
244 }
245
246 @implementation WebFrame (WebInternal)
247
248 Frame* core(WebFrame *frame)
249 {
250     if (!frame)
251         return 0;
252     
253     if (!frame->_private->bridge)
254         return 0;
255
256     return frame->_private->bridge->m_frame;
257 }
258
259 WebFrame *kit(Frame* frame)
260 {
261     return frame ? static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame() : nil;
262 }
263
264 Page* core(WebView *webView)
265 {
266     return [webView page];
267 }
268
269 WebView *kit(Page* page)
270 {
271     return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : nil;
272 }
273
274 WebView *getWebView(WebFrame *webFrame)
275 {
276     Frame* coreFrame = core(webFrame);
277     if (!coreFrame)
278         return nil;
279     return kit(coreFrame->page());
280 }
281
282 + (PassRefPtr<Frame>)_createFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
283 {
284     ++WebBridgeCount;
285
286     WebView *webView = kit(page);
287
288     WebFrameBridge *bridge = [[WebFrameBridge alloc] init];
289     WebFrame *frame = [[self alloc] _initWithWebFrameView:frameView webView:webView bridge:bridge];
290     RefPtr<Frame> coreFrame = new Frame(page, ownerElement, new WebFrameLoaderClient(frame));
291     [frame release];
292     [bridge setWebCoreFrame:coreFrame.get()];
293     [bridge release];
294
295     coreFrame->tree()->setName(name);
296     coreFrame->init();
297
298     [webView _setZoomMultiplier:[webView _realZoomMultiplier] isTextOnly:[webView _realZoomMultiplierIsTextOnly]];
299
300     return coreFrame.release();
301 }
302
303 + (void)_createMainFrameWithPage:(Page*)page frameName:(const String&)name frameView:(WebFrameView *)frameView
304 {
305     [self _createFrameWithPage:page frameName:name frameView:frameView ownerElement:0];
306 }
307
308 + (PassRefPtr<WebCore::Frame>)_createSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(const String&)name frameView:(WebFrameView *)frameView
309 {
310     return [self _createFrameWithPage:ownerElement->document()->frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
311 }
312
313 /*
314     In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.  
315     The item that was the target of the user's navigation is designated as the "targetItem".  
316     When this method is called with doClip=YES we're able to create the whole tree except for the target's children, 
317     which will be loaded in the future.  That part of the tree will be filled out as the child loads are committed.
318 */
319
320 + (CFAbsoluteTime)_timeOfLastCompletedLoad
321 {
322     return FrameLoader::timeOfLastCompletedLoad() - kCFAbsoluteTimeIntervalSince1970;
323 }
324
325 - (WebFrameBridge *)_bridge
326 {
327     return _private->bridge;
328 }
329
330 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
331 {
332     ASSERT(childFrame);
333     HistoryItem* parentItem = core(self)->loader()->currentHistoryItem();
334     FrameLoadType loadType = [self _frameLoader]->loadType();
335     FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory;
336
337     // If we're moving in the backforward list, we might want to replace the content
338     // of this child frame with whatever was there at that point.
339     // Reload will maintain the frame contents, LoadSame will not.
340     if (parentItem && parentItem->children().size() &&
341         (isBackForwardLoadType(loadType)
342          || loadType == FrameLoadTypeReload
343          || loadType == FrameLoadTypeReloadAllowingStaleData))
344     {
345         HistoryItem* childItem = parentItem->childItemWithName([childFrame name]);
346         if (childItem) {
347             // Use the original URL to ensure we get all the side-effects, such as
348             // onLoad handlers, of any redirects that happened. An example of where
349             // this is needed is Radar 3213556.
350             URL = [NSURL _web_URLWithDataAsString:childItem->originalURLString()];
351             // These behaviors implied by these loadTypes should apply to the child frames
352             childLoadType = loadType;
353
354             if (isBackForwardLoadType(loadType))
355                 // For back/forward, remember this item so we can traverse any child items as child frames load
356                 core(childFrame)->loader()->setProvisionalHistoryItem(childItem);
357             else
358                 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
359                 core(childFrame)->loader()->setCurrentHistoryItem(childItem);
360         }
361     }
362
363     WebArchive *archive = [[self _dataSource] _popSubframeArchiveWithName:[childFrame name]];
364     if (archive)
365         [childFrame loadArchive:archive];
366     else
367         [childFrame _frameLoader]->load([URL absoluteURL], referrer, childLoadType,
368                                         String(), 0, 0);
369 }
370
371
372 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
373 {
374     Frame* coreFrame = core(self);
375     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
376         [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow];
377 }
378
379 - (void)_viewDidMoveToHostWindow
380 {
381     Frame* coreFrame = core(self);
382     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
383         [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow];
384 }
385
386 - (void)_addChild:(WebFrame *)child
387 {
388     core(self)->tree()->appendChild(adoptRef(core(child)));
389     if ([child _dataSource])
390         [[child _dataSource] _documentLoader]->setOverrideEncoding([[self _dataSource] _documentLoader]->overrideEncoding());  
391 }
392
393 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
394 {
395     return core(self)->loader()->numPendingOrLoadingRequests(recurse);
396 }
397
398 - (void)_attachScriptDebugger
399 {
400     if (_private->scriptDebugger)
401         return;
402
403     KJS::JSGlobalObject* globalObject = core(self)->scriptProxy()->globalObject();
404     if (!globalObject)
405         return;
406
407     _private->scriptDebugger = new WebScriptDebugger(globalObject);
408 }
409
410 - (void)_detachScriptDebugger
411 {
412     if (!_private->scriptDebugger)
413         return;
414
415     delete _private->scriptDebugger;
416     _private->scriptDebugger = 0;
417 }
418
419 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
420 {
421     self = [super init];
422     if (!self)
423         return nil;
424
425     _private = [[WebFramePrivate alloc] init];
426     _private->bridge = [bridge retain];
427     [bridge setWebFrame:self];
428
429     if (fv) {
430         [_private setWebFrameView:fv];
431         [fv _setWebFrame:self];
432     }
433
434     ++WebFrameCount;
435
436     return self;
437 }
438
439 - (NSArray *)_documentViews
440 {
441     NSMutableArray *result = [NSMutableArray array];
442     Frame* coreFrame = core(self);
443     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
444         id docView = [[kit(frame) frameView] documentView];
445         if (docView)
446             [result addObject:docView];
447     }
448     return result;
449 }
450
451 - (void)_updateBackground
452 {
453     BOOL drawsBackground = [getWebView(self) drawsBackground];
454     NSColor *backgroundColor = [getWebView(self) backgroundColor];
455
456     Frame* coreFrame = core(self);
457     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
458         WebFrame *webFrame = kit(frame);
459         WebFrameBridge *bridge = [webFrame _bridge];
460         // Never call setDrawsBackground:YES here on the scroll view or the background color will
461         // flash between pages loads. setDrawsBackground:YES will be called in _frameLoadCompleted.
462         if (!drawsBackground)
463             [[[webFrame frameView] _scrollView] setDrawsBackground:NO];
464         [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor];
465         id documentView = [[webFrame frameView] documentView];
466         if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
467             [documentView setDrawsBackground:drawsBackground];
468         if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
469             [documentView setBackgroundColor:backgroundColor];
470         [bridge setDrawsBackground:drawsBackground];
471         [bridge setBaseBackgroundColor:backgroundColor];
472     }
473 }
474
475 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
476 {
477     _private->internalLoadDelegate = internalLoadDelegate;
478 }
479
480 - (id)_internalLoadDelegate
481 {
482     return _private->internalLoadDelegate;
483 }
484
485 #ifndef BUILDING_ON_TIGER
486 - (void)_unmarkAllBadGrammar
487 {
488     Frame* coreFrame = core(self);
489     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
490         Document *doc = frame->document();
491         if (!doc)
492             return;
493
494         doc->removeMarkers(DocumentMarker::Grammar);
495     }
496 }
497 #endif
498
499 - (void)_unmarkAllMisspellings
500 {
501     Frame* coreFrame = core(self);
502     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
503         Document *doc = frame->document();
504         if (!doc)
505             return;
506
507         doc->removeMarkers(DocumentMarker::Spelling);
508     }
509 }
510
511 - (BOOL)_hasSelection
512 {
513     id documentView = [_private->webFrameView documentView];    
514
515     // optimization for common case to avoid creating potentially large selection string
516     if ([documentView isKindOfClass:[WebHTMLView class]])
517         if (Frame* coreFrame = core(self))
518             return coreFrame->selectionController()->isRange();
519
520     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
521         return [[documentView selectedString] length] > 0;
522     
523     return NO;
524 }
525
526 - (void)_clearSelection
527 {
528     id documentView = [_private->webFrameView documentView];    
529     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
530         [documentView deselectAll];
531 }
532
533 #if !ASSERT_DISABLED
534 - (BOOL)_atMostOneFrameHasSelection
535 {
536     // FIXME: 4186050 is one known case that makes this debug check fail.
537     BOOL found = NO;
538     Frame* coreFrame = core(self);
539     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
540         if ([kit(frame) _hasSelection]) {
541             if (found)
542                 return NO;
543             found = YES;
544         }
545     return YES;
546 }
547 #endif
548
549 - (WebFrame *)_findFrameWithSelection
550 {
551     Frame* coreFrame = core(self);
552     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame))
553         if ([kit(frame) _hasSelection])
554             return kit(frame);
555     return nil;
556 }
557
558 - (void)_clearSelectionInOtherFrames
559 {
560     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
561     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
562     // notification sent when the first responder changes in general (Radar 2573089).
563     WebFrame *frameWithSelection = [[getWebView(self) mainFrame] _findFrameWithSelection];
564     if (frameWithSelection != self)
565         [frameWithSelection _clearSelection];
566
567     // While we're in the general area of selection and frames, check that there is only one now.
568     ASSERT([[getWebView(self) mainFrame] _atMostOneFrameHasSelection]);
569 }
570
571 - (BOOL)_isMainFrame
572 {
573    Frame* coreFrame = core(self);
574    if (!coreFrame)
575        return NO;
576    return coreFrame == coreFrame->page()->mainFrame() ;
577 }
578
579 - (FrameLoader*)_frameLoader
580 {
581     Frame* frame = core(self);
582     return frame ? frame->loader() : 0;
583 }
584
585 static inline WebDataSource *dataSource(DocumentLoader* loader)
586 {
587     return loader ? static_cast<WebDocumentLoaderMac*>(loader)->dataSource() : nil;
588 }
589
590 - (WebDataSource *)_dataSourceForDocumentLoader:(DocumentLoader*)loader
591 {
592     return dataSource(loader);
593 }
594
595 - (void)_addDocumentLoader:(DocumentLoader*)loader toUnarchiveState:(WebArchive *)archive
596 {
597     [dataSource(loader) _addToUnarchiveState:archive];
598 }
599
600 - (WebDataSource *)_dataSource
601 {
602     FrameLoader* frameLoader = [self _frameLoader];
603
604     if (!frameLoader)
605         return nil;
606
607     return dataSource(frameLoader->documentLoader());
608 }
609
610 #if ENABLE(NETSCAPE_PLUGIN_API)
611 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
612 {
613     Frame* coreFrame = core(self);
614     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
615         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
616         if ([documentView isKindOfClass:[WebHTMLView class]])
617             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
618     }
619 }
620
621 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
622 {
623     Frame* coreFrame = core(self);
624     for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) {
625         NSView <WebDocumentView> *documentView = [[kit(frame) frameView] documentView];
626         if ([documentView isKindOfClass:[WebHTMLView class]])
627             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
628     }
629 }
630 #endif
631
632 @end
633
634 @implementation WebFrame (WebPrivate)
635
636 // FIXME: Yhis exists only as a convenience for Safari, consider moving there.
637 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
638 {
639     Frame* coreFrame = core(self);
640     return coreFrame && coreFrame->tree()->isDescendantOf(core(ancestor));
641 }
642
643 - (void)_setShouldCreateRenderers:(BOOL)frame
644 {
645     [_private->bridge setShouldCreateRenderers:frame];
646 }
647
648 - (NSColor *)_bodyBackgroundColor
649 {
650     Document* document = core(self)->document();
651     if (!document)
652         return nil;
653     HTMLElement* body = document->body();
654     if (!body)
655         return nil;
656     RenderObject* bodyRenderer = body->renderer();
657     if (!bodyRenderer)
658         return nil;
659     Color color = bodyRenderer->style()->backgroundColor();
660     if (!color.isValid())
661         return nil;
662     return nsColor(color);
663 }
664
665 - (BOOL)_isFrameSet
666 {
667     return core(self)->isFrameSet();
668 }
669
670 - (BOOL)_firstLayoutDone
671 {
672     return [self _frameLoader]->firstLayoutDone();
673 }
674
675 - (WebFrameLoadType)_loadType
676 {
677     return (WebFrameLoadType)[self _frameLoader]->loadType();
678 }
679
680 - (NSRange)_selectedNSRange
681 {
682     return [_private->bridge selectedNSRange];
683 }
684
685 - (void)_selectNSRange:(NSRange)range
686 {
687     [_private->bridge selectNSRange:range];
688 }
689
690 - (BOOL)_isDisplayingStandaloneImage
691 {
692     Document* document = core(self)->document();
693     return document && document->isImageDocument();
694 }
695
696 @end
697
698 @implementation WebFrame
699
700 - (id)init
701 {
702     return nil;
703 }
704
705 // Should be deprecated.
706 - (id)initWithName:(NSString *)name webFrameView:(WebFrameView *)view webView:(WebView *)webView
707 {
708     return nil;
709 }
710
711 - (void)dealloc
712 {
713     [_private->bridge setWebFrame:nil];
714     [_private release];
715     --WebFrameCount;
716     [super dealloc];
717 }
718
719 - (void)finalize
720 {
721     [_private->bridge setWebFrame:nil];
722     --WebFrameCount;
723     [super finalize];
724 }
725
726 - (NSString *)name
727 {
728     Frame* coreFrame = core(self);
729     if (!coreFrame)
730         return nil;
731     return coreFrame->tree()->name();
732 }
733
734 - (WebFrameView *)frameView
735 {
736     return _private->webFrameView;
737 }
738
739 - (WebView *)webView
740 {
741     return getWebView(self);
742 }
743
744 - (DOMDocument *)DOMDocument
745 {
746     Frame* coreFrame = core(self);
747     if (!coreFrame)
748         return nil;
749     
750     // FIXME: <rdar://problem/5145841> When loading a custom view/representation 
751     // into a web frame, the old document can still be around. This makes sure that
752     // we'll return nil in those cases.
753     if (![[self _dataSource] _isDocumentHTML]) 
754         return nil; 
755
756     Document* document = coreFrame->document();
757     
758     // According to the documentation, we should return nil if the frame doesn't have a document.
759     // While full-frame images and plugins do have an underlying HTML document, we return nil here to be
760     // backwards compatible.
761     if (document && (document->isPluginDocument() || document->isImageDocument()))
762         return nil;
763     
764     return kit(coreFrame->document());
765 }
766
767 - (DOMHTMLElement *)frameElement
768 {
769     Frame* coreFrame = core(self);
770     if (!coreFrame)
771         return nil;
772     return kit(coreFrame->ownerElement());
773 }
774
775 - (WebDataSource *)provisionalDataSource
776 {
777     FrameLoader* frameLoader = [self _frameLoader];
778     return frameLoader ? dataSource(frameLoader->provisionalDocumentLoader()) : nil;
779 }
780
781 - (WebDataSource *)dataSource
782 {
783     FrameLoader* loader = [self _frameLoader];
784     if (!loader || !loader->frameHasLoaded())
785         return nil;
786
787     return [self _dataSource];
788 }
789
790 - (void)loadRequest:(NSURLRequest *)request
791 {
792     [self _frameLoader]->load(request);
793 }
794
795 static NSURL *createUniqueWebDataURL()
796 {
797     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
798     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
799     CFRelease(UUIDRef);
800     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"applewebdata://%@", UUIDString]];
801     CFRelease(UUIDString);
802     return URL;
803 }
804
805 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
806 {
807     KURL responseURL;
808     if (!baseURL) {
809         baseURL = blankURL();
810         responseURL = createUniqueWebDataURL();
811     }
812     
813     ResourceRequest request([baseURL absoluteURL]);
814
815     // hack because Mail checks for this property to detect data / archive loads
816     [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest()];
817
818     SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData(data), MIMEType, encodingName, [unreachableURL absoluteURL], responseURL);
819
820     [self _frameLoader]->load(request, substituteData);
821 }
822
823
824 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
825 {
826     if (!MIMEType)
827         MIMEType = @"text/html";
828     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:nil];
829 }
830
831 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL
832 {
833     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
834     [self _loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL unreachableURL:unreachableURL];
835 }
836
837 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
838 {
839     [self _loadHTMLString:string baseURL:baseURL unreachableURL:nil];
840 }
841
842 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
843 {
844     [self _loadHTMLString:string baseURL:baseURL unreachableURL:unreachableURL];
845 }
846
847 - (void)loadArchive:(WebArchive *)archive
848 {
849     WebResource *mainResource = [archive mainResource];
850     if (mainResource) {
851         SubstituteData substituteData(WebCore::SharedBuffer::wrapNSData([mainResource data]), [mainResource MIMEType], [mainResource textEncodingName], KURL());
852         ResourceRequest request([mainResource URL]);
853
854         // hack because Mail checks for this property to detect data / archive loads
855         [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)request.nsURLRequest()];
856
857         RefPtr<DocumentLoader> documentLoader = core(self)->loader()->client()->createDocumentLoader(request, substituteData);
858
859         [dataSource(documentLoader.get()) _addToUnarchiveState:archive];
860
861         [self _frameLoader]->load(documentLoader.get());
862     }
863 }
864
865 - (void)stopLoading
866 {
867     if (FrameLoader* frameLoader = [self _frameLoader])
868         frameLoader->stopForUserCancel();
869 }
870
871 - (void)reload
872 {
873     [self _frameLoader]->reload();
874 }
875
876 - (WebFrame *)findFrameNamed:(NSString *)name
877 {
878     Frame* coreFrame = core(self);
879     if (!coreFrame)
880         return nil;
881     return kit(coreFrame->tree()->find(name));
882 }
883
884 - (WebFrame *)parentFrame
885 {
886     Frame* coreFrame = core(self);
887     if (!coreFrame)
888         return nil;
889     return [[kit(coreFrame->tree()->parent()) retain] autorelease];
890 }
891
892 - (NSArray *)childFrames
893 {
894     Frame* coreFrame = core(self);
895     if (!coreFrame)
896         return [NSArray array];
897     NSMutableArray *children = [NSMutableArray arrayWithCapacity:coreFrame->tree()->childCount()];
898     for (Frame* child = coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling())
899         [children addObject:kit(child)];
900     return children;
901 }
902
903 - (WebScriptObject *)windowObject
904 {
905     Frame* coreFrame = core(self);
906     if (!coreFrame)
907         return 0;
908     return coreFrame->windowScriptObject();
909 }
910
911 - (JSGlobalContextRef)globalContext
912 {
913     Frame* coreFrame = core(self);
914     if (!coreFrame)
915         return 0;
916     return toGlobalRef(coreFrame->scriptProxy()->globalObject()->globalExec());
917 }
918
919 @end