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