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