2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
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 "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"
45 #include "WebPageProxyMessages.h"
46 #include "WebProcess.h"
47 #include <JavaScriptCore/APICast.h>
48 #include <JavaScriptCore/JSContextRef.h>
49 #include <JavaScriptCore/JSLock.h>
50 #include <JavaScriptCore/JSValueRef.h>
51 #include <WebCore/ArchiveResource.h>
52 #include <WebCore/CertificateInfo.h>
53 #include <WebCore/Chrome.h>
54 #include <WebCore/DocumentLoader.h>
55 #include <WebCore/EventHandler.h>
56 #include <WebCore/File.h>
57 #include <WebCore/Frame.h>
58 #include <WebCore/FrameSnapshotting.h>
59 #include <WebCore/FrameView.h>
60 #include <WebCore/HTMLFormElement.h>
61 #include <WebCore/HTMLFrameOwnerElement.h>
62 #include <WebCore/HTMLInputElement.h>
63 #include <WebCore/HTMLNames.h>
64 #include <WebCore/HTMLTextAreaElement.h>
65 #include <WebCore/ImageBuffer.h>
66 #include <WebCore/JSCSSStyleDeclaration.h>
67 #include <WebCore/JSElement.h>
68 #include <WebCore/JSFile.h>
69 #include <WebCore/JSRange.h>
70 #include <WebCore/MainFrame.h>
71 #include <WebCore/NetworkingContext.h>
72 #include <WebCore/NodeTraversal.h>
73 #include <WebCore/Page.h>
74 #include <WebCore/PluginDocument.h>
75 #include <WebCore/RenderTreeAsText.h>
76 #include <WebCore/ScriptController.h>
77 #include <WebCore/SecurityOrigin.h>
78 #include <WebCore/SubresourceLoader.h>
79 #include <WebCore/TextIterator.h>
80 #include <WebCore/TextResourceDecoder.h>
81 #include <wtf/text/StringBuilder.h>
84 #include <WebCore/LegacyWebArchive.h>
88 #include <wtf/RefCountedLeakCounter.h>
92 using namespace WebCore;
96 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
98 static uint64_t generateFrameID()
100 static uint64_t uniqueFrameID = 1;
101 return uniqueFrameID++;
104 static uint64_t generateListenerID()
106 static uint64_t uniqueListenerID = 1;
107 return uniqueListenerID++;
110 PassRefPtr<WebFrame> WebFrame::createWithCoreMainFrame(WebPage* page, WebCore::Frame* coreFrame)
112 RefPtr<WebFrame> frame = create(std::unique_ptr<WebFrameLoaderClient>(static_cast<WebFrameLoaderClient*>(&coreFrame->loader().client())));
113 page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()), page->pageID(), IPC::DispatchMessageEvenWhenWaitingForSyncReply);
115 frame->m_coreFrame = coreFrame;
116 frame->m_coreFrame->tree().setName(String());
117 frame->m_coreFrame->init();
118 return frame.release();
121 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
123 RefPtr<WebFrame> frame = create(std::make_unique<WebFrameLoaderClient>());
124 page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()), page->pageID(), IPC::DispatchMessageEvenWhenWaitingForSyncReply);
126 Ref<WebCore::Frame> coreFrame = Frame::create(page->corePage(), ownerElement, frame->m_frameLoaderClient.get());
127 frame->m_coreFrame = coreFrame.ptr();
128 frame->m_coreFrame->tree().setName(frameName);
130 ASSERT(ownerElement->document().frame());
131 ownerElement->document().frame()->tree().appendChild(WTF::move(coreFrame));
133 frame->m_coreFrame->init();
134 return frame.release();
137 PassRefPtr<WebFrame> WebFrame::create(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
139 RefPtr<WebFrame> frame = adoptRef(new WebFrame(WTF::move(frameLoaderClient)));
141 // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
144 return frame.release();
147 WebFrame::WebFrame(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
149 , m_policyListenerID(0)
150 , m_policyFunction(0)
151 , m_policyDownloadID(0)
152 , m_frameLoaderClient(WTF::move(frameLoaderClient))
154 , m_frameID(generateFrameID())
156 , m_firstLayerTreeTransactionIDAfterDidCommitLoad(0)
159 m_frameLoaderClient->setWebFrame(this);
160 WebProcess::singleton().addWebFrame(m_frameID, this);
163 webFrameCounter.increment();
167 WebFrame::~WebFrame()
169 ASSERT(!m_coreFrame);
172 webFrameCounter.decrement();
176 WebPage* WebFrame::page() const
181 if (Page* page = m_coreFrame->page())
182 return WebPage::fromCorePage(page);
187 WebFrame* WebFrame::fromCoreFrame(Frame& frame)
189 auto* webFrameLoaderClient = toWebFrameLoaderClient(frame.loader().client());
190 if (!webFrameLoaderClient)
193 return webFrameLoaderClient->webFrame();
196 void WebFrame::invalidate()
198 WebProcess::singleton().removeWebFrame(m_frameID);
202 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
204 // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
206 invalidatePolicyListener();
208 m_policyListenerID = generateListenerID();
209 m_policyFunction = policyFunction;
210 return m_policyListenerID;
213 void WebFrame::invalidatePolicyListener()
215 if (!m_policyListenerID)
218 m_policyDownloadID = 0;
219 m_policyListenerID = 0;
220 m_policyFunction = 0;
223 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t navigationID, uint64_t downloadID)
228 if (!m_policyListenerID)
231 if (listenerID != m_policyListenerID)
234 ASSERT(m_policyFunction);
236 FramePolicyFunction function = WTF::move(m_policyFunction);
238 invalidatePolicyListener();
240 m_policyDownloadID = downloadID;
242 if (WebDocumentLoader* documentLoader = static_cast<WebDocumentLoader*>(m_coreFrame->loader().policyDocumentLoader()))
243 documentLoader->setNavigationID(navigationID);
249 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
251 ASSERT(m_policyDownloadID);
253 uint64_t policyDownloadID = m_policyDownloadID;
254 m_policyDownloadID = 0;
256 auto& webProcess = WebProcess::singleton();
257 SessionID sessionID = page() ? page()->sessionID() : SessionID::defaultSessionID();
258 webProcess.networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(sessionID, policyDownloadID, request), 0);
261 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, SessionID sessionID, const ResourceRequest& request, const ResourceResponse& response)
263 ASSERT(m_policyDownloadID);
265 uint64_t policyDownloadID = m_policyDownloadID;
266 m_policyDownloadID = 0;
268 SubresourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
270 auto& webProcess = WebProcess::singleton();
271 // Use 0 to indicate that the resource load can't be converted and a new download must be started.
272 // This can happen if there is no loader because the main resource is in the WebCore memory cache,
273 // or because the conversion was attempted when not calling SubresourceLoader::didReceiveResponse().
274 uint64_t mainResourceLoadIdentifier;
275 if (mainResourceLoader)
276 mainResourceLoadIdentifier = mainResourceLoader->identifier();
278 mainResourceLoadIdentifier = 0;
280 webProcess.networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(sessionID, mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
283 String WebFrame::source() const
287 Document* document = m_coreFrame->document();
290 TextResourceDecoder* decoder = document->decoder();
293 DocumentLoader* documentLoader = m_coreFrame->loader().activeDocumentLoader();
296 RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData();
297 if (!mainResourceData)
299 return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
302 String WebFrame::contentsAsString() const
308 StringBuilder builder;
309 for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
310 if (!builder.isEmpty())
313 WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
316 builder.append(webFrame->contentsAsString());
318 // FIXME: It may make sense to use toStringPreserveCapacity() here.
319 return builder.toString();
322 Document* document = m_coreFrame->document();
326 RefPtr<Element> documentElement = document->documentElement();
327 if (!documentElement)
330 RefPtr<Range> range = document->createRange();
332 ExceptionCode ec = 0;
333 range->selectNode(documentElement.get(), ec);
337 return plainText(range.get());
340 String WebFrame::selectionAsString() const
345 return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor().selectedText());
348 IntSize WebFrame::size() const
353 FrameView* frameView = m_coreFrame->view();
357 return frameView->contentsSize();
360 bool WebFrame::isFrameSet() const
365 Document* document = m_coreFrame->document();
368 return document->isFrameSet();
371 bool WebFrame::isMainFrame() const
376 return m_coreFrame->isMainFrame();
379 String WebFrame::name() const
384 return m_coreFrame->tree().uniqueName();
387 String WebFrame::url() const
392 DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
396 return documentLoader->url().string();
399 WebCore::CertificateInfo WebFrame::certificateInfo() const
402 return CertificateInfo();
404 DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
406 return CertificateInfo();
408 return documentLoader->response().certificateInfo();
411 String WebFrame::innerText() const
416 if (!m_coreFrame->document()->documentElement())
419 return m_coreFrame->document()->documentElement()->innerText();
422 WebFrame* WebFrame::parentFrame() const
424 if (!m_coreFrame || !m_coreFrame->ownerElement())
427 return WebFrame::fromCoreFrame(*m_coreFrame->ownerElement()->document().frame());
430 Ref<API::Array> WebFrame::childFrames()
433 return API::Array::create();
435 size_t size = m_coreFrame->tree().childCount();
437 return API::Array::create();
439 Vector<RefPtr<API::Object>> vector;
440 vector.reserveInitialCapacity(size);
442 for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
443 WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
445 vector.uncheckedAppend(webFrame);
448 return API::Array::create(WTF::move(vector));
451 String WebFrame::layerTreeAsText() const
456 return m_coreFrame->layerTreeAsText(0);
459 unsigned WebFrame::pendingUnloadCount() const
464 return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
467 bool WebFrame::allowsFollowingLink(const WebCore::URL& url) const
472 return m_coreFrame->document()->securityOrigin()->canDisplay(url);
475 JSGlobalContextRef WebFrame::jsContext()
477 return toGlobalRef(m_coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
480 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
482 return toGlobalRef(m_coreFrame->script().globalObject(world->coreWorld())->globalExec());
485 bool WebFrame::handlesPageScaleGesture() const
487 if (!m_coreFrame->document()->isPluginDocument())
490 PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
491 PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
492 return pluginView && pluginView->handlesPageScaleFactor();
495 bool WebFrame::requiresUnifiedScaleFactor() const
497 if (!m_coreFrame->document()->isPluginDocument())
500 PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
501 PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
502 return pluginView && pluginView->requiresUnifiedScaleFactor();
505 void WebFrame::setAccessibleName(const String& accessibleName)
507 if (!AXObjectCache::accessibilityEnabled())
513 auto* document = m_coreFrame->document();
517 auto* rootObject = document->axObjectCache()->rootObject();
521 rootObject->setAccessibleName(accessibleName);
524 IntRect WebFrame::contentBounds() const
529 FrameView* view = m_coreFrame->view();
533 return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
536 IntRect WebFrame::visibleContentBounds() const
541 FrameView* view = m_coreFrame->view();
545 IntRect contentRect = view->visibleContentRectIncludingScrollbars();
546 return IntRect(0, 0, contentRect.width(), contentRect.height());
549 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
554 FrameView* view = m_coreFrame->view();
558 IntRect contentRect = view->visibleContentRect();
559 return IntRect(0, 0, contentRect.width(), contentRect.height());
562 IntSize WebFrame::scrollOffset() const
567 FrameView* view = m_coreFrame->view();
571 return view->scrollOffset();
574 bool WebFrame::hasHorizontalScrollbar() const
579 FrameView* view = m_coreFrame->view();
583 return view->horizontalScrollbar();
586 bool WebFrame::hasVerticalScrollbar() const
591 FrameView* view = m_coreFrame->view();
595 return view->verticalScrollbar();
598 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
603 return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
606 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
611 FrameView* view = m_coreFrame->view();
615 Color bgColor = view->documentBackgroundColor();
616 if (!bgColor.isValid())
619 bgColor.getRGBA(*red, *green, *blue, *alpha);
623 bool WebFrame::containsAnyFormElements() const
628 Document* document = m_coreFrame->document();
632 for (Node* node = document->documentElement(); node; node = NodeTraversal::next(*node)) {
633 if (!is<Element>(*node))
635 if (is<HTMLFormElement>(*node))
641 bool WebFrame::containsAnyFormControls() const
646 Document* document = m_coreFrame->document();
650 for (Node* node = document->documentElement(); node; node = NodeTraversal::next(*node)) {
651 if (!is<Element>(*node))
653 if (is<HTMLInputElement>(*node) || is<HTMLSelectElement>(*node) || is<HTMLTextAreaElement>(*node))
659 void WebFrame::stopLoading()
664 m_coreFrame->loader().stopForUserCancel();
667 WebFrame* WebFrame::frameForContext(JSContextRef context)
669 JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
670 JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
671 if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
674 Frame* frame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->wrapped().frame();
675 return WebFrame::fromCoreFrame(*frame);
678 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
683 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
684 ExecState* exec = globalObject->globalExec();
686 JSLockHolder lock(exec);
687 return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
690 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
695 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
696 ExecState* exec = globalObject->globalExec();
698 JSLockHolder lock(exec);
699 return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
702 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleFileHandle* fileHandle, InjectedBundleScriptWorld* world)
707 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
708 ExecState* exec = globalObject->globalExec();
710 JSLockHolder lock(exec);
711 return toRef(exec, toJS(exec, globalObject, fileHandle->coreFile()));
714 String WebFrame::counterValue(JSObjectRef element)
716 if (!toJS(element)->inherits(JSElement::info()))
719 return counterValueForElement(&jsCast<JSElement*>(toJS(element))->wrapped());
722 String WebFrame::provisionalURL() const
727 DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
728 if (!provisionalDocumentLoader)
731 return provisionalDocumentLoader->url().string();
734 String WebFrame::suggestedFilenameForResourceWithURL(const URL& url) const
739 DocumentLoader* loader = m_coreFrame->loader().documentLoader();
743 // First, try the main resource.
744 if (loader->url() == url)
745 return loader->response().suggestedFilename();
747 // Next, try subresources.
748 RefPtr<ArchiveResource> resource = loader->subresource(url);
750 return resource->response().suggestedFilename();
752 return page()->cachedSuggestedFilenameForURL(url);
755 String WebFrame::mimeTypeForResourceWithURL(const URL& url) const
760 DocumentLoader* loader = m_coreFrame->loader().documentLoader();
764 // First, try the main resource.
765 if (loader->url() == url)
766 return loader->response().mimeType();
768 // Next, try subresources.
769 RefPtr<ArchiveResource> resource = loader->subresource(url);
771 return resource->mimeType();
773 return page()->cachedResponseMIMETypeForURL(url);
776 void WebFrame::setTextDirection(const String& direction)
781 if (direction == "auto")
782 m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
783 else if (direction == "ltr")
784 m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
785 else if (direction == "rtl")
786 m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
789 void WebFrame::documentLoaderDetached(uint64_t navigationID)
791 page()->send(Messages::WebPageProxy::DidDestroyNavigation(navigationID));
795 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
797 RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), [this, callback, context](Frame& frame) -> bool {
801 WebFrame* webFrame = WebFrame::fromCoreFrame(frame);
804 return callback(toAPI(this), toAPI(webFrame), context);
810 return archive->rawDataRepresentation();
814 PassRefPtr<ShareableBitmap> WebFrame::createSelectionSnapshot() const
816 std::unique_ptr<ImageBuffer> snapshot = snapshotSelection(*coreFrame(), WebCore::SnapshotOptionsForceBlackText);
820 RefPtr<ShareableBitmap> sharedSnapshot = ShareableBitmap::createShareable(snapshot->internalSize(), ShareableBitmap::SupportsAlpha);
824 // FIXME: We should consider providing a way to use subpixel antialiasing for the snapshot
825 // if we're compositing this image onto a solid color (e.g. the modern find indicator style).
826 auto graphicsContext = sharedSnapshot->createGraphicsContext();
827 float deviceScaleFactor = coreFrame()->page()->deviceScaleFactor();
828 graphicsContext->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
829 graphicsContext->drawConsumingImageBuffer(WTF::move(snapshot), FloatPoint());
831 return sharedSnapshot.release();
834 } // namespace WebKit