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()));
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()));
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 if (!m_coreFrame)
524 return nullptr;
525
526 return toGlobalRef(m_coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
527}
528
529JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
530{
531 if (!m_coreFrame)
532 return nullptr;
533
534 return toGlobalRef(m_coreFrame->script().globalObject(world->coreWorld())->globalExec());
535}
536
537bool WebFrame::handlesPageScaleGesture() const
538{
539 auto* pluginView = WebPage::pluginViewForFrame(m_coreFrame);
540 return pluginView && pluginView->handlesPageScaleFactor();
541}
542
543bool WebFrame::requiresUnifiedScaleFactor() const
544{
545 auto* pluginView = WebPage::pluginViewForFrame(m_coreFrame);
546 return pluginView && pluginView->requiresUnifiedScaleFactor();
547}
548
549void WebFrame::setAccessibleName(const String& accessibleName)
550{
551 if (!AXObjectCache::accessibilityEnabled())
552 return;
553
554 if (!m_coreFrame)
555 return;
556
557 auto* document = m_coreFrame->document();
558 if (!document)
559 return;
560
561 auto* rootObject = document->axObjectCache()->rootObject();
562 if (!rootObject)
563 return;
564
565 rootObject->setAccessibleName(accessibleName);
566}
567
568IntRect WebFrame::contentBounds() const
569{
570 if (!m_coreFrame)
571 return IntRect();
572
573 FrameView* view = m_coreFrame->view();
574 if (!view)
575 return IntRect();
576
577 return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
578}
579
580IntRect WebFrame::visibleContentBounds() const
581{
582 if (!m_coreFrame)
583 return IntRect();
584
585 FrameView* view = m_coreFrame->view();
586 if (!view)
587 return IntRect();
588
589 IntRect contentRect = view->visibleContentRectIncludingScrollbars();
590 return IntRect(0, 0, contentRect.width(), contentRect.height());
591}
592
593IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
594{
595 if (!m_coreFrame)
596 return IntRect();
597
598 FrameView* view = m_coreFrame->view();
599 if (!view)
600 return IntRect();
601
602 IntRect contentRect = view->visibleContentRect();
603 return IntRect(0, 0, contentRect.width(), contentRect.height());
604}
605
606IntSize WebFrame::scrollOffset() const
607{
608 if (!m_coreFrame)
609 return IntSize();
610
611 FrameView* view = m_coreFrame->view();
612 if (!view)
613 return IntSize();
614
615 return toIntSize(view->scrollPosition());
616}
617
618bool WebFrame::hasHorizontalScrollbar() const
619{
620 if (!m_coreFrame)
621 return false;
622
623 FrameView* view = m_coreFrame->view();
624 if (!view)
625 return false;
626
627 return view->horizontalScrollbar();
628}
629
630bool WebFrame::hasVerticalScrollbar() const
631{
632 if (!m_coreFrame)
633 return false;
634
635 FrameView* view = m_coreFrame->view();
636 if (!view)
637 return false;
638
639 return view->verticalScrollbar();
640}
641
642RefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
643{
644 if (!m_coreFrame)
645 return nullptr;
646
647 return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent));
648}
649
650bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
651{
652 if (!m_coreFrame)
653 return false;
654
655 FrameView* view = m_coreFrame->view();
656 if (!view)
657 return false;
658
659 Color bgColor = view->documentBackgroundColor();
660 if (!bgColor.isValid())
661 return false;
662
663 bgColor.getRGBA(*red, *green, *blue, *alpha);
664 return true;
665}
666
667bool WebFrame::containsAnyFormElements() const
668{
669 if (!m_coreFrame)
670 return false;
671
672 Document* document = m_coreFrame->document();
673 if (!document)
674 return false;
675
676 for (Node* node = document->documentElement(); node; node = NodeTraversal::next(*node)) {
677 if (!is<Element>(*node))
678 continue;
679 if (is<HTMLFormElement>(*node))
680 return true;
681 }
682 return false;
683}
684
685bool WebFrame::containsAnyFormControls() const
686{
687 if (!m_coreFrame)
688 return false;
689
690 Document* document = m_coreFrame->document();
691 if (!document)
692 return false;
693
694 for (Node* node = document->documentElement(); node; node = NodeTraversal::next(*node)) {
695 if (!is<Element>(*node))
696 continue;
697 if (is<HTMLInputElement>(*node) || is<HTMLSelectElement>(*node) || is<HTMLTextAreaElement>(*node))
698 return true;
699 }
700 return false;
701}
702
703void WebFrame::stopLoading()
704{
705 if (!m_coreFrame)
706 return;
707
708 m_coreFrame->loader().stopForUserCancel();
709}
710
711WebFrame* WebFrame::frameForContext(JSContextRef context)
712{
713
714 JSC::JSGlobalObject* globalObjectObj = toJS(context)->lexicalGlobalObject();
715 JSDOMWindow* window = jsDynamicCast<JSDOMWindow*>(globalObjectObj->vm(), globalObjectObj);
716 if (!window)
717 return nullptr;
718 return WebFrame::fromCoreFrame(*(window->wrapped().frame()));
719}
720
721JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
722{
723 if (!m_coreFrame)
724 return 0;
725
726 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
727 ExecState* exec = globalObject->globalExec();
728
729 JSLockHolder lock(exec);
730 return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
731}
732
733JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
734{
735 if (!m_coreFrame)
736 return 0;
737
738 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
739 ExecState* exec = globalObject->globalExec();
740
741 JSLockHolder lock(exec);
742 return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
743}
744
745String WebFrame::counterValue(JSObjectRef element)
746{
747 if (!toJS(element)->inherits<JSElement>(*toJS(element)->vm()))
748 return String();
749
750 return counterValueForElement(&jsCast<JSElement*>(toJS(element))->wrapped());
751}
752
753String WebFrame::provisionalURL() const
754{
755 if (!m_coreFrame)
756 return String();
757
758 DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
759 if (!provisionalDocumentLoader)
760 return String();
761
762 return provisionalDocumentLoader->url().string();
763}
764
765String WebFrame::suggestedFilenameForResourceWithURL(const URL& url) const
766{
767 if (!m_coreFrame)
768 return String();
769
770 DocumentLoader* loader = m_coreFrame->loader().documentLoader();
771 if (!loader)
772 return String();
773
774 // First, try the main resource.
775 if (loader->url() == url)
776 return loader->response().suggestedFilename();
777
778 // Next, try subresources.
779 RefPtr<ArchiveResource> resource = loader->subresource(url);
780 if (resource)
781 return resource->response().suggestedFilename();
782
783 return String();
784}
785
786String WebFrame::mimeTypeForResourceWithURL(const URL& url) const
787{
788 if (!m_coreFrame)
789 return String();
790
791 DocumentLoader* loader = m_coreFrame->loader().documentLoader();
792 if (!loader)
793 return String();
794
795 // First, try the main resource.
796 if (loader->url() == url)
797 return loader->response().mimeType();
798
799 // Next, try subresources.
800 RefPtr<ArchiveResource> resource = loader->subresource(url);
801 if (resource)
802 return resource->mimeType();
803
804 return String();
805}
806
807void WebFrame::setTextDirection(const String& direction)
808{
809 if (!m_coreFrame)
810 return;
811
812 if (direction == "auto")
813 m_coreFrame->editor().setBaseWritingDirection(WritingDirection::Natural);
814 else if (direction == "ltr")
815 m_coreFrame->editor().setBaseWritingDirection(WritingDirection::LeftToRight);
816 else if (direction == "rtl")
817 m_coreFrame->editor().setBaseWritingDirection(WritingDirection::RightToLeft);
818}
819
820void WebFrame::documentLoaderDetached(uint64_t navigationID)
821{
822 if (auto* page = this->page())
823 page->send(Messages::WebPageProxy::DidDestroyNavigation(navigationID));
824}
825
826#if PLATFORM(COCOA)
827RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
828{
829 auto archive = LegacyWebArchive::create(*coreFrame()->document(), [this, callback, context](Frame& frame) -> bool {
830 if (!callback)
831 return true;
832
833 WebFrame* webFrame = WebFrame::fromCoreFrame(frame);
834 ASSERT(webFrame);
835
836 return callback(toAPI(this), toAPI(webFrame), context);
837 });
838
839 if (!archive)
840 return nullptr;
841
842 return archive->rawDataRepresentation();
843}
844#endif
845
846RefPtr<ShareableBitmap> WebFrame::createSelectionSnapshot() const
847{
848 std::unique_ptr<ImageBuffer> snapshot = snapshotSelection(*coreFrame(), WebCore::SnapshotOptionsForceBlackText);
849 if (!snapshot)
850 return nullptr;
851
852 auto sharedSnapshot = ShareableBitmap::createShareable(snapshot->internalSize(), { });
853 if (!sharedSnapshot)
854 return nullptr;
855
856 // FIXME: We should consider providing a way to use subpixel antialiasing for the snapshot
857 // if we're compositing this image onto a solid color (e.g. the modern find indicator style).
858 auto graphicsContext = sharedSnapshot->createGraphicsContext();
859 float deviceScaleFactor = coreFrame()->page()->deviceScaleFactor();
860 graphicsContext->scale(deviceScaleFactor);
861 graphicsContext->drawConsumingImageBuffer(WTFMove(snapshot), FloatPoint());
862
863 return sharedSnapshot;
864}
865
866} // namespace WebKit
867