Add WKUIDelegatePrivate equivalent of WKPageUIClient's saveDataToFileInDownloadsFolder
[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 void WebFrame::invalidatePolicyListener()
224 {
225     if (!m_policyListenerID)
226         return;
227
228     m_policyDownloadID = { };
229     m_policyListenerID = 0;
230     m_policyFunction = nullptr;
231 }
232
233 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t navigationID, DownloadID downloadID)
234 {
235     if (!m_coreFrame)
236         return;
237
238     if (!m_policyListenerID)
239         return;
240
241     if (listenerID != m_policyListenerID)
242         return;
243
244     ASSERT(m_policyFunction);
245
246     FramePolicyFunction function = WTFMove(m_policyFunction);
247
248     invalidatePolicyListener();
249
250     m_policyDownloadID = downloadID;
251     if (navigationID) {
252         if (WebDocumentLoader* documentLoader = static_cast<WebDocumentLoader*>(m_coreFrame->loader().policyDocumentLoader()))
253             documentLoader->setNavigationID(navigationID);
254     }
255
256     function(action);
257 }
258
259 void WebFrame::startDownload(const WebCore::ResourceRequest& request, const String& suggestedName)
260 {
261     ASSERT(m_policyDownloadID.downloadID());
262
263     auto policyDownloadID = m_policyDownloadID;
264     m_policyDownloadID = { };
265
266     auto& webProcess = WebProcess::singleton();
267     PAL::SessionID sessionID = page() ? page()->sessionID() : PAL::SessionID::defaultSessionID();
268     webProcess.networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::StartDownload(sessionID, policyDownloadID, request, suggestedName), 0);
269 }
270
271 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, PAL::SessionID sessionID, const ResourceRequest& request, const ResourceResponse& response)
272 {
273     ASSERT(m_policyDownloadID.downloadID());
274
275     auto policyDownloadID = m_policyDownloadID;
276     m_policyDownloadID = { };
277
278     SubresourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
279
280     auto& webProcess = WebProcess::singleton();
281     // Use 0 to indicate that the resource load can't be converted and a new download must be started.
282     // This can happen if there is no loader because the main resource is in the WebCore memory cache,
283     // or because the conversion was attempted when not calling SubresourceLoader::didReceiveResponse().
284     uint64_t mainResourceLoadIdentifier;
285     if (mainResourceLoader)
286         mainResourceLoadIdentifier = mainResourceLoader->identifier();
287     else
288         mainResourceLoadIdentifier = 0;
289
290     webProcess.networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(sessionID, mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
291 }
292
293 String WebFrame::source() const
294 {
295     if (!m_coreFrame)
296         return String();
297     Document* document = m_coreFrame->document();
298     if (!document)
299         return String();
300     TextResourceDecoder* decoder = document->decoder();
301     if (!decoder)
302         return String();
303     DocumentLoader* documentLoader = m_coreFrame->loader().activeDocumentLoader();
304     if (!documentLoader)
305         return String();
306     RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData();
307     if (!mainResourceData)
308         return String();
309     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
310 }
311
312 String WebFrame::contentsAsString() const 
313 {
314     if (!m_coreFrame)
315         return String();
316
317     if (isFrameSet()) {
318         StringBuilder builder;
319         for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
320             if (!builder.isEmpty())
321                 builder.append(' ');
322
323             WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
324             ASSERT(webFrame);
325
326             builder.append(webFrame->contentsAsString());
327         }
328         // FIXME: It may make sense to use toStringPreserveCapacity() here.
329         return builder.toString();
330     }
331
332     Document* document = m_coreFrame->document();
333     if (!document)
334         return String();
335
336     RefPtr<Element> documentElement = document->documentElement();
337     if (!documentElement)
338         return String();
339
340     RefPtr<Range> range = document->createRange();
341
342     if (range->selectNode(*documentElement).hasException())
343         return String();
344
345     return plainText(range.get());
346 }
347
348 String WebFrame::selectionAsString() const 
349 {
350     if (!m_coreFrame)
351         return String();
352
353     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor().selectedText());
354 }
355
356 IntSize WebFrame::size() const
357 {
358     if (!m_coreFrame)
359         return IntSize();
360
361     FrameView* frameView = m_coreFrame->view();
362     if (!frameView)
363         return IntSize();
364
365     return frameView->contentsSize();
366 }
367
368 bool WebFrame::isFrameSet() const
369 {
370     if (!m_coreFrame)
371         return false;
372
373     Document* document = m_coreFrame->document();
374     if (!document)
375         return false;
376     return document->isFrameSet();
377 }
378
379 bool WebFrame::isMainFrame() const
380 {
381     if (!m_coreFrame)
382         return false;
383
384     return m_coreFrame->isMainFrame();
385 }
386
387 String WebFrame::name() const
388 {
389     if (!m_coreFrame)
390         return String();
391
392     return m_coreFrame->tree().uniqueName();
393 }
394
395 URL WebFrame::url() const
396 {
397     if (!m_coreFrame)
398         return { };
399
400     auto* documentLoader = m_coreFrame->loader().documentLoader();
401     if (!documentLoader)
402         return { };
403
404     return documentLoader->url();
405 }
406
407 CertificateInfo WebFrame::certificateInfo() const
408 {
409     if (!m_coreFrame)
410         return { };
411
412     DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
413     if (!documentLoader)
414         return { };
415
416     return valueOrCompute(documentLoader->response().certificateInfo(), [] { return CertificateInfo(); });
417 }
418
419 String WebFrame::innerText() const
420 {
421     if (!m_coreFrame)
422         return String();
423
424     if (!m_coreFrame->document()->documentElement())
425         return String();
426
427     return m_coreFrame->document()->documentElement()->innerText();
428 }
429
430 WebFrame* WebFrame::parentFrame() const
431 {
432     if (!m_coreFrame || !m_coreFrame->ownerElement())
433         return 0;
434
435     return WebFrame::fromCoreFrame(*m_coreFrame->ownerElement()->document().frame());
436 }
437
438 Ref<API::Array> WebFrame::childFrames()
439 {
440     if (!m_coreFrame)
441         return API::Array::create();
442
443     size_t size = m_coreFrame->tree().childCount();
444     if (!size)
445         return API::Array::create();
446
447     Vector<RefPtr<API::Object>> vector;
448     vector.reserveInitialCapacity(size);
449
450     for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
451         WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
452         ASSERT(webFrame);
453         vector.uncheckedAppend(webFrame);
454     }
455
456     return API::Array::create(WTFMove(vector));
457 }
458
459 String WebFrame::layerTreeAsText() const
460 {
461     if (!m_coreFrame)
462         return "";
463
464     return m_coreFrame->layerTreeAsText(0);
465 }
466
467 unsigned WebFrame::pendingUnloadCount() const
468 {
469     if (!m_coreFrame)
470         return 0;
471
472     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
473 }
474
475 bool WebFrame::allowsFollowingLink(const WebCore::URL& url) const
476 {
477     if (!m_coreFrame)
478         return true;
479         
480     return m_coreFrame->document()->securityOrigin().canDisplay(url);
481 }
482
483 JSGlobalContextRef WebFrame::jsContext()
484 {
485     return toGlobalRef(m_coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
486 }
487
488 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
489 {
490     return toGlobalRef(m_coreFrame->script().globalObject(world->coreWorld())->globalExec());
491 }
492
493 bool WebFrame::handlesPageScaleGesture() const
494 {
495     if (!m_coreFrame->document()->isPluginDocument())
496         return 0;
497
498     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
499     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
500     return pluginView && pluginView->handlesPageScaleFactor();
501 }
502
503 bool WebFrame::requiresUnifiedScaleFactor() const
504 {
505     if (!m_coreFrame->document()->isPluginDocument())
506         return 0;
507
508     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
509     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
510     return pluginView && pluginView->requiresUnifiedScaleFactor();
511 }
512
513 void WebFrame::setAccessibleName(const String& accessibleName)
514 {
515     if (!AXObjectCache::accessibilityEnabled())
516         return;
517     
518     if (!m_coreFrame)
519         return;
520
521     auto* document = m_coreFrame->document();
522     if (!document)
523         return;
524     
525     auto* rootObject = document->axObjectCache()->rootObject();
526     if (!rootObject)
527         return;
528
529     rootObject->setAccessibleName(accessibleName);
530 }
531
532 IntRect WebFrame::contentBounds() const
533 {    
534     if (!m_coreFrame)
535         return IntRect();
536     
537     FrameView* view = m_coreFrame->view();
538     if (!view)
539         return IntRect();
540     
541     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
542 }
543
544 IntRect WebFrame::visibleContentBounds() const
545 {
546     if (!m_coreFrame)
547         return IntRect();
548     
549     FrameView* view = m_coreFrame->view();
550     if (!view)
551         return IntRect();
552     
553     IntRect contentRect = view->visibleContentRectIncludingScrollbars();
554     return IntRect(0, 0, contentRect.width(), contentRect.height());
555 }
556
557 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() 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->visibleContentRect();
567     return IntRect(0, 0, contentRect.width(), contentRect.height());
568 }
569
570 IntSize WebFrame::scrollOffset() const
571 {
572     if (!m_coreFrame)
573         return IntSize();
574     
575     FrameView* view = m_coreFrame->view();
576     if (!view)
577         return IntSize();
578
579     return toIntSize(view->scrollPosition());
580 }
581
582 bool WebFrame::hasHorizontalScrollbar() const
583 {
584     if (!m_coreFrame)
585         return false;
586
587     FrameView* view = m_coreFrame->view();
588     if (!view)
589         return false;
590
591     return view->horizontalScrollbar();
592 }
593
594 bool WebFrame::hasVerticalScrollbar() const
595 {
596     if (!m_coreFrame)
597         return false;
598
599     FrameView* view = m_coreFrame->view();
600     if (!view)
601         return false;
602
603     return view->verticalScrollbar();
604 }
605
606 RefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
607 {
608     if (!m_coreFrame)
609         return nullptr;
610
611     return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent));
612 }
613
614 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
615 {
616     if (!m_coreFrame)
617         return false;
618
619     FrameView* view = m_coreFrame->view();
620     if (!view)
621         return false;
622
623     Color bgColor = view->documentBackgroundColor();
624     if (!bgColor.isValid())
625         return false;
626
627     bgColor.getRGBA(*red, *green, *blue, *alpha);
628     return true;
629 }
630
631 bool WebFrame::containsAnyFormElements() const
632 {
633     if (!m_coreFrame)
634         return false;
635     
636     Document* document = m_coreFrame->document();
637     if (!document)
638         return false;
639
640     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(*node)) {
641         if (!is<Element>(*node))
642             continue;
643         if (is<HTMLFormElement>(*node))
644             return true;
645     }
646     return false;
647 }
648
649 bool WebFrame::containsAnyFormControls() const
650 {
651     if (!m_coreFrame)
652         return false;
653     
654     Document* document = m_coreFrame->document();
655     if (!document)
656         return false;
657
658     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(*node)) {
659         if (!is<Element>(*node))
660             continue;
661         if (is<HTMLInputElement>(*node) || is<HTMLSelectElement>(*node) || is<HTMLTextAreaElement>(*node))
662             return true;
663     }
664     return false;
665 }
666
667 void WebFrame::stopLoading()
668 {
669     if (!m_coreFrame)
670         return;
671
672     m_coreFrame->loader().stopForUserCancel();
673 }
674
675 WebFrame* WebFrame::frameForContext(JSContextRef context)
676 {
677
678     JSC::JSGlobalObject* globalObjectObj = toJS(context)->lexicalGlobalObject();
679     JSDOMWindow* window = jsDynamicDowncast<JSDOMWindow*>(globalObjectObj->vm(), globalObjectObj);
680     if (!window)
681         return nullptr;
682     return WebFrame::fromCoreFrame(*(window->wrapped().frame()));
683 }
684
685 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
686 {
687     if (!m_coreFrame)
688         return 0;
689
690     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
691     ExecState* exec = globalObject->globalExec();
692
693     JSLockHolder lock(exec);
694     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
695 }
696
697 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
698 {
699     if (!m_coreFrame)
700         return 0;
701
702     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
703     ExecState* exec = globalObject->globalExec();
704
705     JSLockHolder lock(exec);
706     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
707 }
708
709 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleFileHandle* fileHandle, InjectedBundleScriptWorld* world)
710 {
711     if (!m_coreFrame)
712         return nullptr;
713
714     JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
715     ExecState* exec = globalObject->globalExec();
716
717     JSLockHolder lock(exec);
718     return toRef(exec, toJS(exec, globalObject, fileHandle->coreFile()));
719 }
720
721 String WebFrame::counterValue(JSObjectRef element)
722 {
723     if (!toJS(element)->inherits(*toJS(element)->vm(), JSElement::info()))
724         return String();
725
726     return counterValueForElement(&jsCast<JSElement*>(toJS(element))->wrapped());
727 }
728
729 String WebFrame::provisionalURL() const
730 {
731     if (!m_coreFrame)
732         return String();
733
734     DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
735     if (!provisionalDocumentLoader)
736         return String();
737
738     return provisionalDocumentLoader->url().string();
739 }
740
741 String WebFrame::suggestedFilenameForResourceWithURL(const URL& url) const
742 {
743     if (!m_coreFrame)
744         return String();
745
746     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
747     if (!loader)
748         return String();
749
750     // First, try the main resource.
751     if (loader->url() == url)
752         return loader->response().suggestedFilename();
753
754     // Next, try subresources.
755     RefPtr<ArchiveResource> resource = loader->subresource(url);
756     if (resource)
757         return resource->response().suggestedFilename();
758
759     return page()->cachedSuggestedFilenameForURL(url);
760 }
761
762 String WebFrame::mimeTypeForResourceWithURL(const URL& url) const
763 {
764     if (!m_coreFrame)
765         return String();
766
767     DocumentLoader* loader = m_coreFrame->loader().documentLoader();
768     if (!loader)
769         return String();
770
771     // First, try the main resource.
772     if (loader->url() == url)
773         return loader->response().mimeType();
774
775     // Next, try subresources.
776     RefPtr<ArchiveResource> resource = loader->subresource(url);
777     if (resource)
778         return resource->mimeType();
779
780     return page()->cachedResponseMIMETypeForURL(url);
781 }
782
783 void WebFrame::setTextDirection(const String& direction)
784 {
785     if (!m_coreFrame)
786         return;
787
788     if (direction == "auto")
789         m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
790     else if (direction == "ltr")
791         m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
792     else if (direction == "rtl")
793         m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
794 }
795
796 void WebFrame::documentLoaderDetached(uint64_t navigationID)
797 {
798     page()->send(Messages::WebPageProxy::DidDestroyNavigation(navigationID));
799 }
800
801 #if PLATFORM(COCOA)
802 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
803 {
804     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(*coreFrame()->document(), [this, callback, context](Frame& frame) -> bool {
805         if (!callback)
806             return true;
807
808         WebFrame* webFrame = WebFrame::fromCoreFrame(frame);
809         ASSERT(webFrame);
810
811         return callback(toAPI(this), toAPI(webFrame), context);
812     });
813
814     if (!archive)
815         return nullptr;
816
817     return archive->rawDataRepresentation();
818 }
819 #endif
820
821 RefPtr<ShareableBitmap> WebFrame::createSelectionSnapshot() const
822 {
823     std::unique_ptr<ImageBuffer> snapshot = snapshotSelection(*coreFrame(), WebCore::SnapshotOptionsForceBlackText);
824     if (!snapshot)
825         return nullptr;
826
827     auto sharedSnapshot = ShareableBitmap::createShareable(snapshot->internalSize(), { });
828     if (!sharedSnapshot)
829         return nullptr;
830
831     // FIXME: We should consider providing a way to use subpixel antialiasing for the snapshot
832     // if we're compositing this image onto a solid color (e.g. the modern find indicator style).
833     auto graphicsContext = sharedSnapshot->createGraphicsContext();
834     float deviceScaleFactor = coreFrame()->page()->deviceScaleFactor();
835     graphicsContext->scale(deviceScaleFactor);
836     graphicsContext->drawConsumingImageBuffer(WTFMove(snapshot), FloatPoint());
837
838     return sharedSnapshot;
839 }
840     
841 } // namespace WebKit