<https://webkit.org/b/119859> Frame::loader() should return a reference
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / WebFrame.cpp
1 /*
2  * Copyright (C) 2010 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebFrame.h"
28
29 #include "DownloadManager.h"
30 #include "InjectedBundleHitTestResult.h"
31 #include "InjectedBundleNodeHandle.h"
32 #include "InjectedBundleRangeHandle.h"
33 #include "InjectedBundleScriptWorld.h"
34 #include "PluginView.h"
35 #include "WKAPICast.h"
36 #include "WKBundleAPICast.h"
37 #include "WebChromeClient.h"
38 #include "WebPage.h"
39 #include "WebPageProxyMessages.h"
40 #include "WebProcess.h"
41 #include <JavaScriptCore/APICast.h>
42 #include <JavaScriptCore/JSContextRef.h>
43 #include <JavaScriptCore/JSLock.h>
44 #include <JavaScriptCore/JSValueRef.h>
45 #include <WebCore/ArchiveResource.h>
46 #include <WebCore/Chrome.h>
47 #include <WebCore/DocumentLoader.h>
48 #include <WebCore/EventHandler.h>
49 #include <WebCore/Frame.h>
50 #include <WebCore/FrameView.h>
51 #include <WebCore/HTMLFormElement.h>
52 #include <WebCore/HTMLFrameOwnerElement.h>
53 #include <WebCore/HTMLInputElement.h>
54 #include <WebCore/HTMLNames.h>
55 #include <WebCore/HTMLTextAreaElement.h>
56 #include <WebCore/JSCSSStyleDeclaration.h>
57 #include <WebCore/JSElement.h>
58 #include <WebCore/JSRange.h>
59 #include <WebCore/NetworkingContext.h>
60 #include <WebCore/NodeTraversal.h>
61 #include <WebCore/Page.h>
62 #include <WebCore/PluginDocument.h>
63 #include <WebCore/RenderTreeAsText.h>
64 #include <WebCore/ResourceBuffer.h>
65 #include <WebCore/ResourceLoader.h>
66 #include <WebCore/ScriptController.h>
67 #include <WebCore/SecurityOrigin.h>
68 #include <WebCore/TextIterator.h>
69 #include <WebCore/TextResourceDecoder.h>
70 #include <wtf/text/StringBuilder.h>
71
72 #if PLATFORM(MAC)
73 #include <WebCore/LegacyWebArchive.h>
74 #endif
75
76 #if ENABLE(NETWORK_PROCESS)
77 #include "NetworkConnectionToWebProcessMessages.h"
78 #include "NetworkProcessConnection.h"
79 #include "WebCoreArgumentCoders.h"
80 #endif
81
82 #ifndef NDEBUG
83 #include <wtf/RefCountedLeakCounter.h>
84 #endif
85
86 using namespace JSC;
87 using namespace WebCore;
88
89 namespace WebKit {
90
91 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
92
93 static uint64_t generateFrameID()
94 {
95     static uint64_t uniqueFrameID = 1;
96     return uniqueFrameID++;
97 }
98
99 static uint64_t generateListenerID()
100 {
101     static uint64_t uniqueListenerID = 1;
102     return uniqueListenerID++;
103 }
104
105 PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page)
106 {
107     RefPtr<WebFrame> frame = create();
108
109     page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
110
111     frame->init(page, String(), 0);
112
113     return frame.release();
114 }
115
116 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
117 {
118     RefPtr<WebFrame> frame = create();
119
120     page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()));
121
122     frame->init(page, frameName, ownerElement);
123
124     return frame.release();
125 }
126
127 PassRefPtr<WebFrame> WebFrame::create()
128 {
129     RefPtr<WebFrame> frame = adoptRef(new WebFrame);
130
131     // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
132     frame->ref();
133
134     return frame.release();
135 }
136
137 WebFrame::WebFrame()
138     : m_coreFrame(0)
139     , m_policyListenerID(0)
140     , m_policyFunction(0)
141     , m_policyDownloadID(0)
142     , m_frameLoaderClient(this)
143     , m_loadListener(0)
144     , m_frameID(generateFrameID())
145 {
146     WebProcess::shared().addWebFrame(m_frameID, this);
147
148 #ifndef NDEBUG
149     webFrameCounter.increment();
150 #endif
151 }
152
153 WebFrame::~WebFrame()
154 {
155     ASSERT(!m_coreFrame);
156
157 #ifndef NDEBUG
158     webFrameCounter.decrement();
159 #endif
160 }
161
162 void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
163 {
164     RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
165     m_coreFrame = frame.get();
166
167     frame->tree()->setName(frameName);
168
169     if (ownerElement) {
170         ASSERT(ownerElement->document()->frame());
171         ownerElement->document()->frame()->tree()->appendChild(frame);
172     }
173
174     frame->init();
175 }
176
177 WebPage* WebFrame::page() const
178
179     if (!m_coreFrame)
180         return 0;
181     
182     if (Page* page = m_coreFrame->page())
183         return WebPage::fromCorePage(page);
184
185     return 0;
186 }
187
188 void WebFrame::invalidate()
189 {
190     WebProcess::shared().removeWebFrame(m_frameID);
191     m_coreFrame = 0;
192 }
193
194 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
195 {
196     // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
197
198     invalidatePolicyListener();
199
200     m_policyListenerID = generateListenerID();
201     m_policyFunction = policyFunction;
202     return m_policyListenerID;
203 }
204
205 void WebFrame::invalidatePolicyListener()
206 {
207     if (!m_policyListenerID)
208         return;
209
210     m_policyDownloadID = 0;
211     m_policyListenerID = 0;
212     m_policyFunction = 0;
213 }
214
215 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
216 {
217     if (!m_coreFrame)
218         return;
219
220     if (!m_policyListenerID)
221         return;
222
223     if (listenerID != m_policyListenerID)
224         return;
225
226     ASSERT(m_policyFunction);
227
228     FramePolicyFunction function = m_policyFunction;
229
230     invalidatePolicyListener();
231
232     m_policyDownloadID = downloadID;
233
234     (m_coreFrame->loader().policyChecker()->*function)(action);
235 }
236
237 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
238 {
239     ASSERT(m_policyDownloadID);
240
241     uint64_t policyDownloadID = m_policyDownloadID;
242     m_policyDownloadID = 0;
243
244 #if ENABLE(NETWORK_PROCESS)
245     if (WebProcess::shared().usesNetworkProcess()) {
246         bool privateBrowsingEnabled = m_coreFrame->loader().networkingContext()->storageSession().isPrivateBrowsingSession();
247         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(privateBrowsingEnabled, policyDownloadID, request), 0);
248         return;
249     }
250 #endif
251
252     WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
253 }
254
255 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
256 {
257     ASSERT(m_policyDownloadID);
258
259     uint64_t policyDownloadID = m_policyDownloadID;
260     m_policyDownloadID = 0;
261
262     ResourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
263
264 #if ENABLE(NETWORK_PROCESS)
265     if (WebProcess::shared().usesNetworkProcess()) {
266         // Use 0 to indicate that there is no main resource loader.
267         // This can happen if the main resource is in the WebCore memory cache.
268         uint64_t mainResourceLoadIdentifier;
269         if (mainResourceLoader)
270             mainResourceLoadIdentifier = mainResourceLoader->identifier();
271         else
272             mainResourceLoadIdentifier = 0;
273
274         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
275         return;
276     }
277 #endif
278
279     if (!mainResourceLoader) {
280         // The main resource has already been loaded. Start a new download instead.
281         WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
282         return;
283     }
284
285     WebProcess::shared().downloadManager().convertHandleToDownload(policyDownloadID, documentLoader->mainResourceLoader()->handle(), request, response);
286 }
287
288 String WebFrame::source() const 
289 {
290     if (!m_coreFrame)
291         return String();
292     Document* document = m_coreFrame->document();
293     if (!document)
294         return String();
295     TextResourceDecoder* decoder = document->decoder();
296     if (!decoder)
297         return String();
298     DocumentLoader* documentLoader = m_coreFrame->loader().activeDocumentLoader();
299     if (!documentLoader)
300         return String();
301     RefPtr<ResourceBuffer> mainResourceData = documentLoader->mainResourceData();
302     if (!mainResourceData)
303         return String();
304     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
305 }
306
307 String WebFrame::contentsAsString() const 
308 {
309     if (!m_coreFrame)
310         return String();
311
312     if (isFrameSet()) {
313         StringBuilder builder;
314         for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
315             if (!builder.isEmpty())
316                 builder.append(' ');
317
318             WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(child->loader().client());
319             WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
320             ASSERT(webFrame);
321
322             builder.append(webFrame->contentsAsString());
323         }
324         // FIXME: It may make sense to use toStringPreserveCapacity() here.
325         return builder.toString();
326     }
327
328     Document* document = m_coreFrame->document();
329     if (!document)
330         return String();
331
332     RefPtr<Element> documentElement = document->documentElement();
333     if (!documentElement)
334         return String();
335
336     RefPtr<Range> range = document->createRange();
337
338     ExceptionCode ec = 0;
339     range->selectNode(documentElement.get(), ec);
340     if (ec)
341         return String();
342
343     return plainText(range.get());
344 }
345
346 String WebFrame::selectionAsString() const 
347 {
348     if (!m_coreFrame)
349         return String();
350
351     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor().selectedText());
352 }
353
354 IntSize WebFrame::size() const
355 {
356     if (!m_coreFrame)
357         return IntSize();
358
359     FrameView* frameView = m_coreFrame->view();
360     if (!frameView)
361         return IntSize();
362
363     return frameView->contentsSize();
364 }
365
366 bool WebFrame::isFrameSet() const
367 {
368     if (!m_coreFrame)
369         return false;
370
371     Document* document = m_coreFrame->document();
372     if (!document)
373         return false;
374     return document->isFrameSet();
375 }
376
377 bool WebFrame::isMainFrame() const
378 {
379     if (WebPage* p = page())
380         return p->mainWebFrame() == this;
381
382     return false;
383 }
384
385 String WebFrame::name() const
386 {
387     if (!m_coreFrame)
388         return String();
389
390     return m_coreFrame->tree()->uniqueName();
391 }
392
393 String WebFrame::url() const
394 {
395     if (!m_coreFrame)
396         return String();
397
398     DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
399     if (!documentLoader)
400         return String();
401
402     return documentLoader->url().string();
403 }
404
405 String WebFrame::innerText() const
406 {
407     if (!m_coreFrame)
408         return String();
409
410     if (!m_coreFrame->document()->documentElement())
411         return String();
412
413     return m_coreFrame->document()->documentElement()->innerText();
414 }
415
416 WebFrame* WebFrame::parentFrame() const
417 {
418     if (!m_coreFrame || !m_coreFrame->ownerElement() || !m_coreFrame->ownerElement()->document())
419         return 0;
420
421     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(m_coreFrame->ownerElement()->document()->frame()->loader().client());
422     return webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
423 }
424
425 PassRefPtr<ImmutableArray> WebFrame::childFrames()
426 {
427     if (!m_coreFrame)
428         return ImmutableArray::create();
429
430     size_t size = m_coreFrame->tree()->childCount();
431     if (!size)
432         return ImmutableArray::create();
433
434     Vector<RefPtr<APIObject>> vector;
435     vector.reserveInitialCapacity(size);
436
437     for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
438         WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(child->loader().client());
439         WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
440         ASSERT(webFrame);
441         vector.uncheckedAppend(webFrame);
442     }
443
444     return ImmutableArray::adopt(vector);
445 }
446
447 String WebFrame::layerTreeAsText() const
448 {
449     if (!m_coreFrame)
450         return "";
451
452     return m_coreFrame->layerTreeAsText(0);
453 }
454
455 unsigned WebFrame::pendingUnloadCount() const
456 {
457     if (!m_coreFrame)
458         return 0;
459
460     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
461 }
462
463 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
464 {
465     if (!m_coreFrame)
466         return true;
467         
468     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
469 }
470
471 JSGlobalContextRef WebFrame::jsContext()
472 {
473     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
474 }
475
476 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
477 {
478     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
479 }
480
481 bool WebFrame::handlesPageScaleGesture() const
482 {
483     if (!m_coreFrame->document()->isPluginDocument())
484         return 0;
485
486     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
487     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
488     return pluginView && pluginView->handlesPageScaleFactor();
489 }
490
491 IntRect WebFrame::contentBounds() const
492 {    
493     if (!m_coreFrame)
494         return IntRect();
495     
496     FrameView* view = m_coreFrame->view();
497     if (!view)
498         return IntRect();
499     
500     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
501 }
502
503 IntRect WebFrame::visibleContentBounds() const
504 {
505     if (!m_coreFrame)
506         return IntRect();
507     
508     FrameView* view = m_coreFrame->view();
509     if (!view)
510         return IntRect();
511     
512     IntRect contentRect = view->visibleContentRect(ScrollableArea::IncludeScrollbars);
513     return IntRect(0, 0, contentRect.width(), contentRect.height());
514 }
515
516 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
517 {
518     if (!m_coreFrame)
519         return IntRect();
520     
521     FrameView* view = m_coreFrame->view();
522     if (!view)
523         return IntRect();
524     
525     IntRect contentRect = view->visibleContentRect();
526     return IntRect(0, 0, contentRect.width(), contentRect.height());
527 }
528
529 IntSize WebFrame::scrollOffset() const
530 {
531     if (!m_coreFrame)
532         return IntSize();
533     
534     FrameView* view = m_coreFrame->view();
535     if (!view)
536         return IntSize();
537
538     return view->scrollOffset();
539 }
540
541 bool WebFrame::hasHorizontalScrollbar() const
542 {
543     if (!m_coreFrame)
544         return false;
545
546     FrameView* view = m_coreFrame->view();
547     if (!view)
548         return false;
549
550     return view->horizontalScrollbar();
551 }
552
553 bool WebFrame::hasVerticalScrollbar() const
554 {
555     if (!m_coreFrame)
556         return false;
557
558     FrameView* view = m_coreFrame->view();
559     if (!view)
560         return false;
561
562     return view->verticalScrollbar();
563 }
564
565 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
566 {
567     if (!m_coreFrame)
568         return 0;
569
570     return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler()->hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
571 }
572
573 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
574 {
575     if (!m_coreFrame)
576         return false;
577
578     FrameView* view = m_coreFrame->view();
579     if (!view)
580         return false;
581
582     Color bgColor = view->documentBackgroundColor();
583     if (!bgColor.isValid())
584         return false;
585
586     bgColor.getRGBA(*red, *green, *blue, *alpha);
587     return true;
588 }
589
590 bool WebFrame::containsAnyFormElements() const
591 {
592     if (!m_coreFrame)
593         return false;
594     
595     Document* document = m_coreFrame->document();
596     if (!document)
597         return false;
598
599     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
600         if (!node->isElementNode())
601             continue;
602         if (isHTMLFormElement(node))
603             return true;
604     }
605     return false;
606 }
607
608 bool WebFrame::containsAnyFormControls() const
609 {
610     if (!m_coreFrame)
611         return false;
612     
613     Document* document = m_coreFrame->document();
614     if (!document)
615         return false;
616
617     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
618         if (!node->isElementNode())
619             continue;
620         if (isHTMLInputElement(node) || toElement(node)->hasTagName(HTMLNames::selectTag) || isHTMLTextAreaElement(node))
621             return true;
622     }
623     return false;
624 }
625
626 void WebFrame::stopLoading()
627 {
628     if (!m_coreFrame)
629         return;
630
631     m_coreFrame->loader().stopForUserCancel();
632 }
633
634 WebFrame* WebFrame::frameForContext(JSContextRef context)
635 {
636     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
637     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
638     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
639         return 0;
640
641     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
642
643     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(coreFrame->loader().client());
644     return webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
645 }
646
647 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
648 {
649     if (!m_coreFrame)
650         return 0;
651
652     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
653     ExecState* exec = globalObject->globalExec();
654
655     JSLockHolder lock(exec);
656     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
657 }
658
659 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
660 {
661     if (!m_coreFrame)
662         return 0;
663
664     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
665     ExecState* exec = globalObject->globalExec();
666
667     JSLockHolder lock(exec);
668     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
669 }
670
671 String WebFrame::counterValue(JSObjectRef element)
672 {
673     if (!toJS(element)->inherits(JSElement::info()))
674         return String();
675
676     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
677 }
678
679 String WebFrame::provisionalURL() const
680 {
681     if (!m_coreFrame)
682         return String();
683
684     DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
685     if (!provisionalDocumentLoader)
686         return String();
687
688     return provisionalDocumentLoader->url().string();
689 }
690
691 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
692 {
693     if (!m_coreFrame)
694         return String();
695
696     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
697     if (!loader)
698         return String();
699
700     // First, try the main resource.
701     if (loader->url() == url)
702         return loader->response().suggestedFilename();
703
704     // Next, try subresources.
705     RefPtr<ArchiveResource> resource = loader->subresource(url);
706     if (resource)
707         return resource->response().suggestedFilename();
708
709     return page()->cachedSuggestedFilenameForURL(url);
710 }
711
712 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
713 {
714     if (!m_coreFrame)
715         return String();
716
717     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
718     if (!loader)
719         return String();
720
721     // First, try the main resource.
722     if (loader->url() == url)
723         return loader->response().mimeType();
724
725     // Next, try subresources.
726     RefPtr<ArchiveResource> resource = loader->subresource(url);
727     if (resource)
728         return resource->mimeType();
729
730     return page()->cachedResponseMIMETypeForURL(url);
731 }
732
733 void WebFrame::setTextDirection(const String& direction)
734 {
735     if (!m_coreFrame)
736         return;
737
738     if (direction == "auto")
739         m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
740     else if (direction == "ltr")
741         m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
742     else if (direction == "rtl")
743         m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
744 }
745
746 #if PLATFORM(MAC)
747
748 class WebFrameFilter : public FrameFilter {
749 public:
750     WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
751         
752 private:
753     virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
754
755     WebFrame* m_topLevelWebFrame;
756     WebFrame::FrameFilterFunction m_callback;
757     void* m_context;
758 };
759
760 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
761     : m_topLevelWebFrame(topLevelWebFrame)
762     , m_callback(callback)
763     , m_context(context)
764 {
765 }
766
767 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
768 {
769     if (!m_callback)
770         return true;
771
772     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frame->loader().client());
773     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
774     ASSERT(webFrame);
775
776     return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
777 }
778
779 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
780 {
781     WebFrameFilter filter(this, callback, context);
782
783     if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
784         return archive->rawDataRepresentation();
785     
786     return 0;
787 }
788 #endif
789     
790 } // namespace WebKit