Get rid of more uses of OwnPtr and PassOwnPtr
[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::createWithCoreMainFrame(WebPage* page, WebCore::Frame* coreFrame)
106 {
107     RefPtr<WebFrame> frame = create(std::unique_ptr<WebFrameLoaderClient>(static_cast<WebFrameLoaderClient*>(&coreFrame->loader().client())));
108     page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
109
110     frame->m_coreFrame = coreFrame;
111     frame->m_coreFrame->tree().setName(String());
112     frame->m_coreFrame->init();
113     return frame.release();
114 }
115
116 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
117 {
118     RefPtr<WebFrame> frame = create(std::make_unique<WebFrameLoaderClient>());
119     page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()));
120
121     RefPtr<Frame> coreFrame = Frame::create(page->corePage(), ownerElement, frame->m_frameLoaderClient.get());
122     frame->m_coreFrame = coreFrame.get();
123     frame->m_coreFrame->tree().setName(frameName);
124     if (ownerElement) {
125         ASSERT(ownerElement->document().frame());
126         ownerElement->document().frame()->tree().appendChild(coreFrame.release());
127     }
128     frame->m_coreFrame->init();
129     return frame.release();
130 }
131
132 PassRefPtr<WebFrame> WebFrame::create(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
133 {
134     RefPtr<WebFrame> frame = adoptRef(new WebFrame(std::move(frameLoaderClient)));
135
136     // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
137     frame->ref();
138
139     return frame.release();
140 }
141
142 WebFrame::WebFrame(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
143     : m_coreFrame(0)
144     , m_policyListenerID(0)
145     , m_policyFunction(0)
146     , m_policyDownloadID(0)
147     , m_frameLoaderClient(std::move(frameLoaderClient))
148     , m_loadListener(0)
149     , m_frameID(generateFrameID())
150 {
151     m_frameLoaderClient->setWebFrame(this);
152     WebProcess::shared().addWebFrame(m_frameID, this);
153
154 #ifndef NDEBUG
155     webFrameCounter.increment();
156 #endif
157 }
158
159 WebFrame::~WebFrame()
160 {
161     ASSERT(!m_coreFrame);
162
163 #ifndef NDEBUG
164     webFrameCounter.decrement();
165 #endif
166 }
167
168 WebPage* WebFrame::page() const
169
170     if (!m_coreFrame)
171         return 0;
172     
173     if (Page* page = m_coreFrame->page())
174         return WebPage::fromCorePage(page);
175
176     return 0;
177 }
178
179 void WebFrame::invalidate()
180 {
181     WebProcess::shared().removeWebFrame(m_frameID);
182     m_coreFrame = 0;
183 }
184
185 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
186 {
187     // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
188
189     invalidatePolicyListener();
190
191     m_policyListenerID = generateListenerID();
192     m_policyFunction = policyFunction;
193     return m_policyListenerID;
194 }
195
196 void WebFrame::invalidatePolicyListener()
197 {
198     if (!m_policyListenerID)
199         return;
200
201     m_policyDownloadID = 0;
202     m_policyListenerID = 0;
203     m_policyFunction = 0;
204 }
205
206 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
207 {
208     if (!m_coreFrame)
209         return;
210
211     if (!m_policyListenerID)
212         return;
213
214     if (listenerID != m_policyListenerID)
215         return;
216
217     ASSERT(m_policyFunction);
218
219     FramePolicyFunction function = m_policyFunction;
220
221     invalidatePolicyListener();
222
223     m_policyDownloadID = downloadID;
224
225     (m_coreFrame->loader().policyChecker().*function)(action);
226 }
227
228 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
229 {
230     ASSERT(m_policyDownloadID);
231
232     uint64_t policyDownloadID = m_policyDownloadID;
233     m_policyDownloadID = 0;
234
235 #if ENABLE(NETWORK_PROCESS)
236     if (WebProcess::shared().usesNetworkProcess()) {
237         bool privateBrowsingEnabled = m_coreFrame->loader().networkingContext()->storageSession().isPrivateBrowsingSession();
238         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(privateBrowsingEnabled, policyDownloadID, request), 0);
239         return;
240     }
241 #endif
242
243     WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
244 }
245
246 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
247 {
248     ASSERT(m_policyDownloadID);
249
250     uint64_t policyDownloadID = m_policyDownloadID;
251     m_policyDownloadID = 0;
252
253     ResourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
254
255 #if ENABLE(NETWORK_PROCESS)
256     if (WebProcess::shared().usesNetworkProcess()) {
257         // Use 0 to indicate that there is no main resource loader.
258         // This can happen if the main resource is in the WebCore memory cache.
259         uint64_t mainResourceLoadIdentifier;
260         if (mainResourceLoader)
261             mainResourceLoadIdentifier = mainResourceLoader->identifier();
262         else
263             mainResourceLoadIdentifier = 0;
264
265         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
266         return;
267     }
268 #endif
269
270     if (!mainResourceLoader) {
271         // The main resource has already been loaded. Start a new download instead.
272         WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
273         return;
274     }
275
276     WebProcess::shared().downloadManager().convertHandleToDownload(policyDownloadID, documentLoader->mainResourceLoader()->handle(), request, response);
277 }
278
279 String WebFrame::source() const 
280 {
281     if (!m_coreFrame)
282         return String();
283     Document* document = m_coreFrame->document();
284     if (!document)
285         return String();
286     TextResourceDecoder* decoder = document->decoder();
287     if (!decoder)
288         return String();
289     DocumentLoader* documentLoader = m_coreFrame->loader().activeDocumentLoader();
290     if (!documentLoader)
291         return String();
292     RefPtr<ResourceBuffer> mainResourceData = documentLoader->mainResourceData();
293     if (!mainResourceData)
294         return String();
295     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
296 }
297
298 String WebFrame::contentsAsString() const 
299 {
300     if (!m_coreFrame)
301         return String();
302
303     if (isFrameSet()) {
304         StringBuilder builder;
305         for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
306             if (!builder.isEmpty())
307                 builder.append(' ');
308
309             WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(child->loader().client());
310             WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
311             ASSERT(webFrame);
312
313             builder.append(webFrame->contentsAsString());
314         }
315         // FIXME: It may make sense to use toStringPreserveCapacity() here.
316         return builder.toString();
317     }
318
319     Document* document = m_coreFrame->document();
320     if (!document)
321         return String();
322
323     RefPtr<Element> documentElement = document->documentElement();
324     if (!documentElement)
325         return String();
326
327     RefPtr<Range> range = document->createRange();
328
329     ExceptionCode ec = 0;
330     range->selectNode(documentElement.get(), ec);
331     if (ec)
332         return String();
333
334     return plainText(range.get());
335 }
336
337 String WebFrame::selectionAsString() const 
338 {
339     if (!m_coreFrame)
340         return String();
341
342     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor().selectedText());
343 }
344
345 IntSize WebFrame::size() const
346 {
347     if (!m_coreFrame)
348         return IntSize();
349
350     FrameView* frameView = m_coreFrame->view();
351     if (!frameView)
352         return IntSize();
353
354     return frameView->contentsSize();
355 }
356
357 bool WebFrame::isFrameSet() const
358 {
359     if (!m_coreFrame)
360         return false;
361
362     Document* document = m_coreFrame->document();
363     if (!document)
364         return false;
365     return document->isFrameSet();
366 }
367
368 bool WebFrame::isMainFrame() const
369 {
370     if (WebPage* p = page())
371         return p->mainWebFrame() == this;
372
373     return false;
374 }
375
376 String WebFrame::name() const
377 {
378     if (!m_coreFrame)
379         return String();
380
381     return m_coreFrame->tree().uniqueName();
382 }
383
384 String WebFrame::url() const
385 {
386     if (!m_coreFrame)
387         return String();
388
389     DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
390     if (!documentLoader)
391         return String();
392
393     return documentLoader->url().string();
394 }
395
396 String WebFrame::innerText() const
397 {
398     if (!m_coreFrame)
399         return String();
400
401     if (!m_coreFrame->document()->documentElement())
402         return String();
403
404     return m_coreFrame->document()->documentElement()->innerText();
405 }
406
407 WebFrame* WebFrame::parentFrame() const
408 {
409     if (!m_coreFrame || !m_coreFrame->ownerElement())
410         return 0;
411
412     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(m_coreFrame->ownerElement()->document().frame()->loader().client());
413     return webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
414 }
415
416 PassRefPtr<ImmutableArray> WebFrame::childFrames()
417 {
418     if (!m_coreFrame)
419         return ImmutableArray::create();
420
421     size_t size = m_coreFrame->tree().childCount();
422     if (!size)
423         return ImmutableArray::create();
424
425     Vector<RefPtr<APIObject>> vector;
426     vector.reserveInitialCapacity(size);
427
428     for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
429         WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(child->loader().client());
430         WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
431         ASSERT(webFrame);
432         vector.uncheckedAppend(webFrame);
433     }
434
435     return ImmutableArray::adopt(vector);
436 }
437
438 String WebFrame::layerTreeAsText() const
439 {
440     if (!m_coreFrame)
441         return "";
442
443     return m_coreFrame->layerTreeAsText(0);
444 }
445
446 unsigned WebFrame::pendingUnloadCount() const
447 {
448     if (!m_coreFrame)
449         return 0;
450
451     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
452 }
453
454 bool WebFrame::allowsFollowingLink(const WebCore::URL& url) const
455 {
456     if (!m_coreFrame)
457         return true;
458         
459     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
460 }
461
462 JSGlobalContextRef WebFrame::jsContext()
463 {
464     return toGlobalRef(m_coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
465 }
466
467 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
468 {
469     return toGlobalRef(m_coreFrame->script().globalObject(world->coreWorld())->globalExec());
470 }
471
472 bool WebFrame::handlesPageScaleGesture() const
473 {
474     if (!m_coreFrame->document()->isPluginDocument())
475         return 0;
476
477     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
478     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
479     return pluginView && pluginView->handlesPageScaleFactor();
480 }
481
482 IntRect WebFrame::contentBounds() const
483 {    
484     if (!m_coreFrame)
485         return IntRect();
486     
487     FrameView* view = m_coreFrame->view();
488     if (!view)
489         return IntRect();
490     
491     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
492 }
493
494 IntRect WebFrame::visibleContentBounds() const
495 {
496     if (!m_coreFrame)
497         return IntRect();
498     
499     FrameView* view = m_coreFrame->view();
500     if (!view)
501         return IntRect();
502     
503     IntRect contentRect = view->visibleContentRect(ScrollableArea::IncludeScrollbars);
504     return IntRect(0, 0, contentRect.width(), contentRect.height());
505 }
506
507 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
508 {
509     if (!m_coreFrame)
510         return IntRect();
511     
512     FrameView* view = m_coreFrame->view();
513     if (!view)
514         return IntRect();
515     
516     IntRect contentRect = view->visibleContentRect();
517     return IntRect(0, 0, contentRect.width(), contentRect.height());
518 }
519
520 IntSize WebFrame::scrollOffset() const
521 {
522     if (!m_coreFrame)
523         return IntSize();
524     
525     FrameView* view = m_coreFrame->view();
526     if (!view)
527         return IntSize();
528
529     return view->scrollOffset();
530 }
531
532 bool WebFrame::hasHorizontalScrollbar() const
533 {
534     if (!m_coreFrame)
535         return false;
536
537     FrameView* view = m_coreFrame->view();
538     if (!view)
539         return false;
540
541     return view->horizontalScrollbar();
542 }
543
544 bool WebFrame::hasVerticalScrollbar() const
545 {
546     if (!m_coreFrame)
547         return false;
548
549     FrameView* view = m_coreFrame->view();
550     if (!view)
551         return false;
552
553     return view->verticalScrollbar();
554 }
555
556 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
557 {
558     if (!m_coreFrame)
559         return 0;
560
561     return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
562 }
563
564 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
565 {
566     if (!m_coreFrame)
567         return false;
568
569     FrameView* view = m_coreFrame->view();
570     if (!view)
571         return false;
572
573     Color bgColor = view->documentBackgroundColor();
574     if (!bgColor.isValid())
575         return false;
576
577     bgColor.getRGBA(*red, *green, *blue, *alpha);
578     return true;
579 }
580
581 bool WebFrame::containsAnyFormElements() const
582 {
583     if (!m_coreFrame)
584         return false;
585     
586     Document* document = m_coreFrame->document();
587     if (!document)
588         return false;
589
590     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
591         if (!node->isElementNode())
592             continue;
593         if (isHTMLFormElement(node))
594             return true;
595     }
596     return false;
597 }
598
599 bool WebFrame::containsAnyFormControls() const
600 {
601     if (!m_coreFrame)
602         return false;
603     
604     Document* document = m_coreFrame->document();
605     if (!document)
606         return false;
607
608     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
609         if (!node->isElementNode())
610             continue;
611         if (isHTMLInputElement(node) || isHTMLSelectElement(node) || isHTMLTextAreaElement(node))
612             return true;
613     }
614     return false;
615 }
616
617 void WebFrame::stopLoading()
618 {
619     if (!m_coreFrame)
620         return;
621
622     m_coreFrame->loader().stopForUserCancel();
623 }
624
625 WebFrame* WebFrame::frameForContext(JSContextRef context)
626 {
627     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
628     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
629     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
630         return 0;
631
632     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
633
634     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(coreFrame->loader().client());
635     return webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
636 }
637
638 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
639 {
640     if (!m_coreFrame)
641         return 0;
642
643     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
644     ExecState* exec = globalObject->globalExec();
645
646     JSLockHolder lock(exec);
647     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
648 }
649
650 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
651 {
652     if (!m_coreFrame)
653         return 0;
654
655     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
656     ExecState* exec = globalObject->globalExec();
657
658     JSLockHolder lock(exec);
659     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
660 }
661
662 String WebFrame::counterValue(JSObjectRef element)
663 {
664     if (!toJS(element)->inherits(JSElement::info()))
665         return String();
666
667     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
668 }
669
670 String WebFrame::provisionalURL() const
671 {
672     if (!m_coreFrame)
673         return String();
674
675     DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
676     if (!provisionalDocumentLoader)
677         return String();
678
679     return provisionalDocumentLoader->url().string();
680 }
681
682 String WebFrame::suggestedFilenameForResourceWithURL(const URL& url) const
683 {
684     if (!m_coreFrame)
685         return String();
686
687     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
688     if (!loader)
689         return String();
690
691     // First, try the main resource.
692     if (loader->url() == url)
693         return loader->response().suggestedFilename();
694
695     // Next, try subresources.
696     RefPtr<ArchiveResource> resource = loader->subresource(url);
697     if (resource)
698         return resource->response().suggestedFilename();
699
700     return page()->cachedSuggestedFilenameForURL(url);
701 }
702
703 String WebFrame::mimeTypeForResourceWithURL(const URL& url) const
704 {
705     if (!m_coreFrame)
706         return String();
707
708     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
709     if (!loader)
710         return String();
711
712     // First, try the main resource.
713     if (loader->url() == url)
714         return loader->response().mimeType();
715
716     // Next, try subresources.
717     RefPtr<ArchiveResource> resource = loader->subresource(url);
718     if (resource)
719         return resource->mimeType();
720
721     return page()->cachedResponseMIMETypeForURL(url);
722 }
723
724 void WebFrame::setTextDirection(const String& direction)
725 {
726     if (!m_coreFrame)
727         return;
728
729     if (direction == "auto")
730         m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
731     else if (direction == "ltr")
732         m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
733     else if (direction == "rtl")
734         m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
735 }
736
737 #if PLATFORM(MAC)
738
739 class WebFrameFilter : public FrameFilter {
740 public:
741     WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
742         
743 private:
744     virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
745
746     WebFrame* m_topLevelWebFrame;
747     WebFrame::FrameFilterFunction m_callback;
748     void* m_context;
749 };
750
751 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
752     : m_topLevelWebFrame(topLevelWebFrame)
753     , m_callback(callback)
754     , m_context(context)
755 {
756 }
757
758 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
759 {
760     if (!m_callback)
761         return true;
762
763     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frame->loader().client());
764     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
765     ASSERT(webFrame);
766
767     return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
768 }
769
770 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
771 {
772     WebFrameFilter filter(this, callback, context);
773
774     if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
775         return archive->rawDataRepresentation();
776     
777     return 0;
778 }
779 #endif
780     
781 } // namespace WebKit