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