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