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