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