Remove unnecessary calls to std::move()
[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 "APIArray.h"
30 #include "DownloadManager.h"
31 #include "InjectedBundleHitTestResult.h"
32 #include "InjectedBundleNodeHandle.h"
33 #include "InjectedBundleRangeHandle.h"
34 #include "InjectedBundleScriptWorld.h"
35 #include "PluginView.h"
36 #include "WKAPICast.h"
37 #include "WKBundleAPICast.h"
38 #include "WebChromeClient.h"
39 #include "WebPage.h"
40 #include "WebPageProxyMessages.h"
41 #include "WebProcess.h"
42 #include <JavaScriptCore/APICast.h>
43 #include <JavaScriptCore/JSContextRef.h>
44 #include <JavaScriptCore/JSLock.h>
45 #include <JavaScriptCore/JSValueRef.h>
46 #include <WebCore/ArchiveResource.h>
47 #include <WebCore/CertificateInfo.h>
48 #include <WebCore/Chrome.h>
49 #include <WebCore/DocumentLoader.h>
50 #include <WebCore/EventHandler.h>
51 #include <WebCore/Frame.h>
52 #include <WebCore/FrameView.h>
53 #include <WebCore/HTMLFormElement.h>
54 #include <WebCore/HTMLFrameOwnerElement.h>
55 #include <WebCore/HTMLInputElement.h>
56 #include <WebCore/HTMLNames.h>
57 #include <WebCore/HTMLTextAreaElement.h>
58 #include <WebCore/JSCSSStyleDeclaration.h>
59 #include <WebCore/JSElement.h>
60 #include <WebCore/JSRange.h>
61 #include <WebCore/MainFrame.h>
62 #include <WebCore/NetworkingContext.h>
63 #include <WebCore/NodeTraversal.h>
64 #include <WebCore/Page.h>
65 #include <WebCore/PluginDocument.h>
66 #include <WebCore/RenderTreeAsText.h>
67 #include <WebCore/ResourceBuffer.h>
68 #include <WebCore/ResourceLoader.h>
69 #include <WebCore/ScriptController.h>
70 #include <WebCore/SecurityOrigin.h>
71 #include <WebCore/TextIterator.h>
72 #include <WebCore/TextResourceDecoder.h>
73 #include <wtf/text/StringBuilder.h>
74
75 #if PLATFORM(COCOA)
76 #include <WebCore/LegacyWebArchive.h>
77 #endif
78
79 #if ENABLE(NETWORK_PROCESS)
80 #include "NetworkConnectionToWebProcessMessages.h"
81 #include "NetworkProcessConnection.h"
82 #include "WebCoreArgumentCoders.h"
83 #endif
84
85 #ifndef NDEBUG
86 #include <wtf/RefCountedLeakCounter.h>
87 #endif
88
89 using namespace JSC;
90 using namespace WebCore;
91
92 namespace WebKit {
93
94 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
95
96 static uint64_t generateFrameID()
97 {
98     static uint64_t uniqueFrameID = 1;
99     return uniqueFrameID++;
100 }
101
102 static uint64_t generateListenerID()
103 {
104     static uint64_t uniqueListenerID = 1;
105     return uniqueListenerID++;
106 }
107
108 PassRefPtr<WebFrame> WebFrame::createWithCoreMainFrame(WebPage* page, WebCore::Frame* coreFrame)
109 {
110     RefPtr<WebFrame> frame = create(std::unique_ptr<WebFrameLoaderClient>(static_cast<WebFrameLoaderClient*>(&coreFrame->loader().client())));
111     page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
112
113     frame->m_coreFrame = coreFrame;
114     frame->m_coreFrame->tree().setName(String());
115     frame->m_coreFrame->init();
116     return frame.release();
117 }
118
119 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
120 {
121     RefPtr<WebFrame> frame = create(std::make_unique<WebFrameLoaderClient>());
122     page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()));
123
124     RefPtr<Frame> coreFrame = Frame::create(page->corePage(), ownerElement, frame->m_frameLoaderClient.get());
125     frame->m_coreFrame = coreFrame.get();
126     frame->m_coreFrame->tree().setName(frameName);
127     if (ownerElement) {
128         ASSERT(ownerElement->document().frame());
129         ownerElement->document().frame()->tree().appendChild(coreFrame.release());
130     }
131     frame->m_coreFrame->init();
132     return frame.release();
133 }
134
135 PassRefPtr<WebFrame> WebFrame::create(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
136 {
137     RefPtr<WebFrame> frame = adoptRef(new WebFrame(std::move(frameLoaderClient)));
138
139     // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
140     frame->ref();
141
142     return frame.release();
143 }
144
145 WebFrame::WebFrame(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
146     : m_coreFrame(0)
147     , m_policyListenerID(0)
148     , m_policyFunction(0)
149     , m_policyDownloadID(0)
150     , m_frameLoaderClient(std::move(frameLoaderClient))
151     , m_loadListener(0)
152     , m_frameID(generateFrameID())
153 {
154     m_frameLoaderClient->setWebFrame(this);
155     WebProcess::shared().addWebFrame(m_frameID, this);
156
157 #ifndef NDEBUG
158     webFrameCounter.increment();
159 #endif
160 }
161
162 WebFrame::~WebFrame()
163 {
164     ASSERT(!m_coreFrame);
165
166 #ifndef NDEBUG
167     webFrameCounter.decrement();
168 #endif
169 }
170
171 WebPage* WebFrame::page() const
172
173     if (!m_coreFrame)
174         return 0;
175     
176     if (Page* page = m_coreFrame->page())
177         return WebPage::fromCorePage(page);
178
179     return 0;
180 }
181
182 WebFrame* WebFrame::fromCoreFrame(Frame& frame)
183 {
184     auto* webFrameLoaderClient = toWebFrameLoaderClient(frame.loader().client());
185     if (!webFrameLoaderClient)
186         return nullptr;
187
188     return webFrameLoaderClient->webFrame();
189 }
190
191 void WebFrame::invalidate()
192 {
193     WebProcess::shared().removeWebFrame(m_frameID);
194     m_coreFrame = 0;
195 }
196
197 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
198 {
199     // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
200
201     invalidatePolicyListener();
202
203     m_policyListenerID = generateListenerID();
204     m_policyFunction = policyFunction;
205     return m_policyListenerID;
206 }
207
208 void WebFrame::invalidatePolicyListener()
209 {
210     if (!m_policyListenerID)
211         return;
212
213     m_policyDownloadID = 0;
214     m_policyListenerID = 0;
215     m_policyFunction = 0;
216 }
217
218 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
219 {
220     if (!m_coreFrame)
221         return;
222
223     if (!m_policyListenerID)
224         return;
225
226     if (listenerID != m_policyListenerID)
227         return;
228
229     ASSERT(m_policyFunction);
230
231     FramePolicyFunction function = std::move(m_policyFunction);
232
233     invalidatePolicyListener();
234
235     m_policyDownloadID = downloadID;
236     function(action);
237 }
238
239 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
240 {
241     ASSERT(m_policyDownloadID);
242
243     uint64_t policyDownloadID = m_policyDownloadID;
244     m_policyDownloadID = 0;
245
246 #if ENABLE(NETWORK_PROCESS)
247     if (WebProcess::shared().usesNetworkProcess()) {
248         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(page()->sessionID(), policyDownloadID, request), 0);
249         return;
250     }
251 #endif
252
253     WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
254 }
255
256 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
257 {
258     ASSERT(m_policyDownloadID);
259
260     uint64_t policyDownloadID = m_policyDownloadID;
261     m_policyDownloadID = 0;
262
263     ResourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
264
265 #if ENABLE(NETWORK_PROCESS)
266     if (WebProcess::shared().usesNetworkProcess()) {
267         // Use 0 to indicate that there is no main resource loader.
268         // This can happen if the main resource is in the WebCore memory cache.
269         uint64_t mainResourceLoadIdentifier;
270         if (mainResourceLoader)
271             mainResourceLoadIdentifier = mainResourceLoader->identifier();
272         else
273             mainResourceLoadIdentifier = 0;
274
275         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
276         return;
277     }
278 #endif
279
280     if (!mainResourceLoader) {
281         // The main resource has already been loaded. Start a new download instead.
282         WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
283         return;
284     }
285
286     WebProcess::shared().downloadManager().convertHandleToDownload(policyDownloadID, documentLoader->mainResourceLoader()->handle(), request, response);
287 }
288
289 String WebFrame::source() const 
290 {
291     if (!m_coreFrame)
292         return String();
293     Document* document = m_coreFrame->document();
294     if (!document)
295         return String();
296     TextResourceDecoder* decoder = document->decoder();
297     if (!decoder)
298         return String();
299     DocumentLoader* documentLoader = m_coreFrame->loader().activeDocumentLoader();
300     if (!documentLoader)
301         return String();
302     RefPtr<ResourceBuffer> mainResourceData = documentLoader->mainResourceData();
303     if (!mainResourceData)
304         return String();
305     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
306 }
307
308 String WebFrame::contentsAsString() const 
309 {
310     if (!m_coreFrame)
311         return String();
312
313     if (isFrameSet()) {
314         StringBuilder builder;
315         for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
316             if (!builder.isEmpty())
317                 builder.append(' ');
318
319             WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
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 (!m_coreFrame)
380         return false;
381
382     return m_coreFrame->isMainFrame();
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 WebCore::CertificateInfo WebFrame::certificateInfo() const
406 {
407     if (!m_coreFrame)
408         return CertificateInfo();
409
410     DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
411     if (!documentLoader)
412         return CertificateInfo();
413
414     return CertificateInfo(documentLoader->response());
415 }
416
417 String WebFrame::innerText() const
418 {
419     if (!m_coreFrame)
420         return String();
421
422     if (!m_coreFrame->document()->documentElement())
423         return String();
424
425     return m_coreFrame->document()->documentElement()->innerText();
426 }
427
428 WebFrame* WebFrame::parentFrame() const
429 {
430     if (!m_coreFrame || !m_coreFrame->ownerElement())
431         return 0;
432
433     return WebFrame::fromCoreFrame(*m_coreFrame->ownerElement()->document().frame());
434 }
435
436 PassRefPtr<API::Array> WebFrame::childFrames()
437 {
438     if (!m_coreFrame)
439         return API::Array::create();
440
441     size_t size = m_coreFrame->tree().childCount();
442     if (!size)
443         return API::Array::create();
444
445     Vector<RefPtr<API::Object>> vector;
446     vector.reserveInitialCapacity(size);
447
448     for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
449         WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
450         ASSERT(webFrame);
451         vector.uncheckedAppend(webFrame);
452     }
453
454     return API::Array::create(std::move(vector));
455 }
456
457 String WebFrame::layerTreeAsText() const
458 {
459     if (!m_coreFrame)
460         return "";
461
462     return m_coreFrame->layerTreeAsText(0);
463 }
464
465 unsigned WebFrame::pendingUnloadCount() const
466 {
467     if (!m_coreFrame)
468         return 0;
469
470     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
471 }
472
473 bool WebFrame::allowsFollowingLink(const WebCore::URL& url) const
474 {
475     if (!m_coreFrame)
476         return true;
477         
478     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
479 }
480
481 JSGlobalContextRef WebFrame::jsContext()
482 {
483     return toGlobalRef(m_coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
484 }
485
486 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
487 {
488     return toGlobalRef(m_coreFrame->script().globalObject(world->coreWorld())->globalExec());
489 }
490
491 bool WebFrame::handlesPageScaleGesture() const
492 {
493     if (!m_coreFrame->document()->isPluginDocument())
494         return 0;
495
496     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
497     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
498     return pluginView && pluginView->handlesPageScaleFactor();
499 }
500
501 IntRect WebFrame::contentBounds() const
502 {    
503     if (!m_coreFrame)
504         return IntRect();
505     
506     FrameView* view = m_coreFrame->view();
507     if (!view)
508         return IntRect();
509     
510     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
511 }
512
513 IntRect WebFrame::visibleContentBounds() const
514 {
515     if (!m_coreFrame)
516         return IntRect();
517     
518     FrameView* view = m_coreFrame->view();
519     if (!view)
520         return IntRect();
521     
522     IntRect contentRect = view->visibleContentRectIncludingScrollbars();
523     return IntRect(0, 0, contentRect.width(), contentRect.height());
524 }
525
526 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
527 {
528     if (!m_coreFrame)
529         return IntRect();
530     
531     FrameView* view = m_coreFrame->view();
532     if (!view)
533         return IntRect();
534     
535     IntRect contentRect = view->visibleContentRect();
536     return IntRect(0, 0, contentRect.width(), contentRect.height());
537 }
538
539 IntSize WebFrame::scrollOffset() const
540 {
541     if (!m_coreFrame)
542         return IntSize();
543     
544     FrameView* view = m_coreFrame->view();
545     if (!view)
546         return IntSize();
547
548     return view->scrollOffset();
549 }
550
551 bool WebFrame::hasHorizontalScrollbar() const
552 {
553     if (!m_coreFrame)
554         return false;
555
556     FrameView* view = m_coreFrame->view();
557     if (!view)
558         return false;
559
560     return view->horizontalScrollbar();
561 }
562
563 bool WebFrame::hasVerticalScrollbar() const
564 {
565     if (!m_coreFrame)
566         return false;
567
568     FrameView* view = m_coreFrame->view();
569     if (!view)
570         return false;
571
572     return view->verticalScrollbar();
573 }
574
575 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
576 {
577     if (!m_coreFrame)
578         return 0;
579
580     return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
581 }
582
583 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
584 {
585     if (!m_coreFrame)
586         return false;
587
588     FrameView* view = m_coreFrame->view();
589     if (!view)
590         return false;
591
592     Color bgColor = view->documentBackgroundColor();
593     if (!bgColor.isValid())
594         return false;
595
596     bgColor.getRGBA(*red, *green, *blue, *alpha);
597     return true;
598 }
599
600 bool WebFrame::containsAnyFormElements() const
601 {
602     if (!m_coreFrame)
603         return false;
604     
605     Document* document = m_coreFrame->document();
606     if (!document)
607         return false;
608
609     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
610         if (!node->isElementNode())
611             continue;
612         if (isHTMLFormElement(node))
613             return true;
614     }
615     return false;
616 }
617
618 bool WebFrame::containsAnyFormControls() const
619 {
620     if (!m_coreFrame)
621         return false;
622     
623     Document* document = m_coreFrame->document();
624     if (!document)
625         return false;
626
627     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
628         if (!node->isElementNode())
629             continue;
630         if (isHTMLInputElement(node) || isHTMLSelectElement(node) || isHTMLTextAreaElement(node))
631             return true;
632     }
633     return false;
634 }
635
636 void WebFrame::stopLoading()
637 {
638     if (!m_coreFrame)
639         return;
640
641     m_coreFrame->loader().stopForUserCancel();
642 }
643
644 WebFrame* WebFrame::frameForContext(JSContextRef context)
645 {
646     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
647     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
648     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
649         return 0;
650
651     Frame* frame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl().frame();
652     return WebFrame::fromCoreFrame(*frame);
653 }
654
655 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
656 {
657     if (!m_coreFrame)
658         return 0;
659
660     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
661     ExecState* exec = globalObject->globalExec();
662
663     JSLockHolder lock(exec);
664     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
665 }
666
667 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
668 {
669     if (!m_coreFrame)
670         return 0;
671
672     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
673     ExecState* exec = globalObject->globalExec();
674
675     JSLockHolder lock(exec);
676     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
677 }
678
679 String WebFrame::counterValue(JSObjectRef element)
680 {
681     if (!toJS(element)->inherits(JSElement::info()))
682         return String();
683
684     return counterValueForElement(&jsCast<JSElement*>(toJS(element))->impl());
685 }
686
687 String WebFrame::provisionalURL() const
688 {
689     if (!m_coreFrame)
690         return String();
691
692     DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
693     if (!provisionalDocumentLoader)
694         return String();
695
696     return provisionalDocumentLoader->url().string();
697 }
698
699 String WebFrame::suggestedFilenameForResourceWithURL(const URL& url) const
700 {
701     if (!m_coreFrame)
702         return String();
703
704     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
705     if (!loader)
706         return String();
707
708     // First, try the main resource.
709     if (loader->url() == url)
710         return loader->response().suggestedFilename();
711
712     // Next, try subresources.
713     RefPtr<ArchiveResource> resource = loader->subresource(url);
714     if (resource)
715         return resource->response().suggestedFilename();
716
717     return page()->cachedSuggestedFilenameForURL(url);
718 }
719
720 String WebFrame::mimeTypeForResourceWithURL(const URL& url) const
721 {
722     if (!m_coreFrame)
723         return String();
724
725     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
726     if (!loader)
727         return String();
728
729     // First, try the main resource.
730     if (loader->url() == url)
731         return loader->response().mimeType();
732
733     // Next, try subresources.
734     RefPtr<ArchiveResource> resource = loader->subresource(url);
735     if (resource)
736         return resource->mimeType();
737
738     return page()->cachedResponseMIMETypeForURL(url);
739 }
740
741 void WebFrame::setTextDirection(const String& direction)
742 {
743     if (!m_coreFrame)
744         return;
745
746     if (direction == "auto")
747         m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
748     else if (direction == "ltr")
749         m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
750     else if (direction == "rtl")
751         m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
752 }
753
754 #if PLATFORM(COCOA)
755 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
756 {
757     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), [this, callback, context](Frame& frame) -> bool {
758         if (!callback)
759             return true;
760
761         WebFrame* webFrame = WebFrame::fromCoreFrame(frame);
762         ASSERT(webFrame);
763
764         return callback(toAPI(this), toAPI(webFrame), context);
765     });
766
767     if (!archive)
768         return nullptr;
769
770     return archive->rawDataRepresentation();
771 }
772 #endif
773     
774 } // namespace WebKit