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