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 "InjectedBundleHitTestResult.h"
32 #include "InjectedBundleNodeHandle.h"
33 #include "InjectedBundleRangeHandle.h"
34 #include "InjectedBundleScriptWorld.h"
35 #include "PluginView.h"
36 #include "WKAPICast.h"
37 #include "WKBundleAPICast.h"
38 #include "WebChromeClient.h"
39 #include "WebDocumentLoader.h"
41 #include "WebPageProxyMessages.h"
42 #include "WebProcess.h"
43 #include <JavaScriptCore/APICast.h>
44 #include <JavaScriptCore/JSContextRef.h>
45 #include <JavaScriptCore/JSLock.h>
46 #include <JavaScriptCore/JSValueRef.h>
47 #include <WebCore/ArchiveResource.h>
48 #include <WebCore/CertificateInfo.h>
49 #include <WebCore/Chrome.h>
50 #include <WebCore/DocumentLoader.h>
51 #include <WebCore/EventHandler.h>
52 #include <WebCore/Frame.h>
53 #include <WebCore/FrameView.h>
54 #include <WebCore/HTMLFormElement.h>
55 #include <WebCore/HTMLFrameOwnerElement.h>
56 #include <WebCore/HTMLInputElement.h>
57 #include <WebCore/HTMLNames.h>
58 #include <WebCore/HTMLTextAreaElement.h>
59 #include <WebCore/JSCSSStyleDeclaration.h>
60 #include <WebCore/JSElement.h>
61 #include <WebCore/JSRange.h>
62 #include <WebCore/MainFrame.h>
63 #include <WebCore/NetworkingContext.h>
64 #include <WebCore/NodeTraversal.h>
65 #include <WebCore/Page.h>
66 #include <WebCore/PluginDocument.h>
67 #include <WebCore/RenderTreeAsText.h>
68 #include <WebCore/ResourceLoader.h>
69 #include <WebCore/ScriptController.h>
70 #include <WebCore/SecurityOrigin.h>
71 #include <WebCore/TextIterator.h>
72 #include <WebCore/TextResourceDecoder.h>
73 #include <wtf/text/StringBuilder.h>
76 #include <WebCore/LegacyWebArchive.h>
79 #if ENABLE(NETWORK_PROCESS)
80 #include "NetworkConnectionToWebProcessMessages.h"
81 #include "NetworkProcessConnection.h"
82 #include "WebCoreArgumentCoders.h"
86 #include <wtf/RefCountedLeakCounter.h>
90 using namespace WebCore;
94 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
96 static uint64_t generateFrameID()
98 static uint64_t uniqueFrameID = 1;
99 return uniqueFrameID++;
102 static uint64_t generateListenerID()
104 static uint64_t uniqueListenerID = 1;
105 return uniqueListenerID++;
108 PassRefPtr<WebFrame> WebFrame::createWithCoreMainFrame(WebPage* page, WebCore::Frame* coreFrame)
110 RefPtr<WebFrame> frame = create(std::unique_ptr<WebFrameLoaderClient>(static_cast<WebFrameLoaderClient*>(&coreFrame->loader().client())));
111 page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()), page->pageID(), IPC::DispatchMessageEvenWhenWaitingForSyncReply);
113 frame->m_coreFrame = coreFrame;
114 frame->m_coreFrame->tree().setName(String());
115 frame->m_coreFrame->init();
116 return frame.release();
119 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
121 RefPtr<WebFrame> frame = create(std::make_unique<WebFrameLoaderClient>());
122 page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()), page->pageID(), IPC::DispatchMessageEvenWhenWaitingForSyncReply);
124 RefPtr<Frame> coreFrame = Frame::create(page->corePage(), ownerElement, frame->m_frameLoaderClient.get());
125 frame->m_coreFrame = coreFrame.get();
126 frame->m_coreFrame->tree().setName(frameName);
128 ASSERT(ownerElement->document().frame());
129 ownerElement->document().frame()->tree().appendChild(coreFrame.release());
131 frame->m_coreFrame->init();
132 return frame.release();
135 PassRefPtr<WebFrame> WebFrame::create(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
137 RefPtr<WebFrame> frame = adoptRef(new WebFrame(WTF::move(frameLoaderClient)));
139 // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
142 return frame.release();
145 WebFrame::WebFrame(std::unique_ptr<WebFrameLoaderClient> frameLoaderClient)
147 , m_policyListenerID(0)
148 , m_policyFunction(0)
149 , m_policyDownloadID(0)
150 , m_frameLoaderClient(WTF::move(frameLoaderClient))
152 , m_frameID(generateFrameID())
154 m_frameLoaderClient->setWebFrame(this);
155 WebProcess::shared().addWebFrame(m_frameID, this);
158 webFrameCounter.increment();
162 WebFrame::~WebFrame()
164 ASSERT(!m_coreFrame);
167 webFrameCounter.decrement();
171 WebPage* WebFrame::page() const
176 if (Page* page = m_coreFrame->page())
177 return WebPage::fromCorePage(page);
182 WebFrame* WebFrame::fromCoreFrame(Frame& frame)
184 auto* webFrameLoaderClient = toWebFrameLoaderClient(frame.loader().client());
185 if (!webFrameLoaderClient)
188 return webFrameLoaderClient->webFrame();
191 void WebFrame::invalidate()
193 WebProcess::shared().removeWebFrame(m_frameID);
197 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
199 // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
201 invalidatePolicyListener();
203 m_policyListenerID = generateListenerID();
204 m_policyFunction = policyFunction;
205 return m_policyListenerID;
208 void WebFrame::invalidatePolicyListener()
210 if (!m_policyListenerID)
213 m_policyDownloadID = 0;
214 m_policyListenerID = 0;
215 m_policyFunction = 0;
218 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t navigationID, uint64_t downloadID)
223 if (!m_policyListenerID)
226 if (listenerID != m_policyListenerID)
229 ASSERT(m_policyFunction);
231 FramePolicyFunction function = WTF::move(m_policyFunction);
233 invalidatePolicyListener();
235 m_policyDownloadID = downloadID;
237 if (WebDocumentLoader* documentLoader = static_cast<WebDocumentLoader*>(m_coreFrame->loader().policyDocumentLoader()))
238 documentLoader->setNavigationID(navigationID);
244 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
246 ASSERT(m_policyDownloadID);
248 uint64_t policyDownloadID = m_policyDownloadID;
249 m_policyDownloadID = 0;
251 #if ENABLE(NETWORK_PROCESS)
252 if (WebProcess::shared().usesNetworkProcess()) {
253 WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(page()->sessionID(), policyDownloadID, request), 0);
258 WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
261 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
263 ASSERT(m_policyDownloadID);
265 uint64_t policyDownloadID = m_policyDownloadID;
266 m_policyDownloadID = 0;
268 ResourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
270 #if ENABLE(NETWORK_PROCESS)
271 if (WebProcess::shared().usesNetworkProcess()) {
272 // Use 0 to indicate that there is no main resource loader.
273 // This can happen if the main resource is in the WebCore memory cache.
274 uint64_t mainResourceLoadIdentifier;
275 if (mainResourceLoader)
276 mainResourceLoadIdentifier = mainResourceLoader->identifier();
278 mainResourceLoadIdentifier = 0;
280 WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
285 if (!mainResourceLoader) {
286 // The main resource has already been loaded. Start a new download instead.
287 WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
291 WebProcess::shared().downloadManager().convertHandleToDownload(policyDownloadID, documentLoader->mainResourceLoader()->handle(), request, response);
294 String WebFrame::source() const
298 Document* document = m_coreFrame->document();
301 TextResourceDecoder* decoder = document->decoder();
304 DocumentLoader* documentLoader = m_coreFrame->loader().activeDocumentLoader();
307 RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData();
308 if (!mainResourceData)
310 return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
313 String WebFrame::contentsAsString() const
319 StringBuilder builder;
320 for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
321 if (!builder.isEmpty())
324 WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
327 builder.append(webFrame->contentsAsString());
329 // FIXME: It may make sense to use toStringPreserveCapacity() here.
330 return builder.toString();
333 Document* document = m_coreFrame->document();
337 RefPtr<Element> documentElement = document->documentElement();
338 if (!documentElement)
341 RefPtr<Range> range = document->createRange();
343 ExceptionCode ec = 0;
344 range->selectNode(documentElement.get(), ec);
348 return plainText(range.get());
351 String WebFrame::selectionAsString() const
356 return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor().selectedText());
359 IntSize WebFrame::size() const
364 FrameView* frameView = m_coreFrame->view();
368 return frameView->contentsSize();
371 bool WebFrame::isFrameSet() const
376 Document* document = m_coreFrame->document();
379 return document->isFrameSet();
382 bool WebFrame::isMainFrame() const
387 return m_coreFrame->isMainFrame();
390 String WebFrame::name() const
395 return m_coreFrame->tree().uniqueName();
398 String WebFrame::url() const
403 DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
407 return documentLoader->url().string();
410 WebCore::CertificateInfo WebFrame::certificateInfo() const
413 return CertificateInfo();
415 DocumentLoader* documentLoader = m_coreFrame->loader().documentLoader();
417 return CertificateInfo();
419 return documentLoader->response().certificateInfo();
422 String WebFrame::innerText() const
427 if (!m_coreFrame->document()->documentElement())
430 return m_coreFrame->document()->documentElement()->innerText();
433 WebFrame* WebFrame::parentFrame() const
435 if (!m_coreFrame || !m_coreFrame->ownerElement())
438 return WebFrame::fromCoreFrame(*m_coreFrame->ownerElement()->document().frame());
441 PassRefPtr<API::Array> WebFrame::childFrames()
444 return API::Array::create();
446 size_t size = m_coreFrame->tree().childCount();
448 return API::Array::create();
450 Vector<RefPtr<API::Object>> vector;
451 vector.reserveInitialCapacity(size);
453 for (Frame* child = m_coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
454 WebFrame* webFrame = WebFrame::fromCoreFrame(*child);
456 vector.uncheckedAppend(webFrame);
459 return API::Array::create(WTF::move(vector));
462 String WebFrame::layerTreeAsText() const
467 return m_coreFrame->layerTreeAsText(0);
470 unsigned WebFrame::pendingUnloadCount() const
475 return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
478 bool WebFrame::allowsFollowingLink(const WebCore::URL& url) const
483 return m_coreFrame->document()->securityOrigin()->canDisplay(url);
486 JSGlobalContextRef WebFrame::jsContext()
488 return toGlobalRef(m_coreFrame->script().globalObject(mainThreadNormalWorld())->globalExec());
491 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
493 return toGlobalRef(m_coreFrame->script().globalObject(world->coreWorld())->globalExec());
496 bool WebFrame::handlesPageScaleGesture() const
498 if (!m_coreFrame->document()->isPluginDocument())
501 PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
502 PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
503 return pluginView && pluginView->handlesPageScaleFactor();
506 IntRect WebFrame::contentBounds() const
511 FrameView* view = m_coreFrame->view();
515 return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
518 IntRect WebFrame::visibleContentBounds() const
523 FrameView* view = m_coreFrame->view();
527 IntRect contentRect = view->visibleContentRectIncludingScrollbars();
528 return IntRect(0, 0, contentRect.width(), contentRect.height());
531 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
536 FrameView* view = m_coreFrame->view();
540 IntRect contentRect = view->visibleContentRect();
541 return IntRect(0, 0, contentRect.width(), contentRect.height());
544 IntSize WebFrame::scrollOffset() const
549 FrameView* view = m_coreFrame->view();
553 return view->scrollOffset();
556 bool WebFrame::hasHorizontalScrollbar() const
561 FrameView* view = m_coreFrame->view();
565 return view->horizontalScrollbar();
568 bool WebFrame::hasVerticalScrollbar() const
573 FrameView* view = m_coreFrame->view();
577 return view->verticalScrollbar();
580 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
585 return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
588 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
593 FrameView* view = m_coreFrame->view();
597 Color bgColor = view->documentBackgroundColor();
598 if (!bgColor.isValid())
601 bgColor.getRGBA(*red, *green, *blue, *alpha);
605 bool WebFrame::containsAnyFormElements() const
610 Document* document = m_coreFrame->document();
614 for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
615 if (!is<Element>(*node))
617 if (is<HTMLFormElement>(*node))
623 bool WebFrame::containsAnyFormControls() 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<HTMLInputElement>(*node) || is<HTMLSelectElement>(*node) || is<HTMLTextAreaElement>(*node))
641 void WebFrame::stopLoading()
646 m_coreFrame->loader().stopForUserCancel();
649 WebFrame* WebFrame::frameForContext(JSContextRef context)
651 JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
652 JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
653 if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
656 Frame* frame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl().frame();
657 return WebFrame::fromCoreFrame(*frame);
660 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
665 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
666 ExecState* exec = globalObject->globalExec();
668 JSLockHolder lock(exec);
669 return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
672 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
677 JSDOMWindow* globalObject = m_coreFrame->script().globalObject(world->coreWorld());
678 ExecState* exec = globalObject->globalExec();
680 JSLockHolder lock(exec);
681 return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
684 String WebFrame::counterValue(JSObjectRef element)
686 if (!toJS(element)->inherits(JSElement::info()))
689 return counterValueForElement(&jsCast<JSElement*>(toJS(element))->impl());
692 String WebFrame::provisionalURL() const
697 DocumentLoader* provisionalDocumentLoader = m_coreFrame->loader().provisionalDocumentLoader();
698 if (!provisionalDocumentLoader)
701 return provisionalDocumentLoader->url().string();
704 String WebFrame::suggestedFilenameForResourceWithURL(const URL& url) const
709 DocumentLoader* loader = m_coreFrame->loader().documentLoader();
713 // First, try the main resource.
714 if (loader->url() == url)
715 return loader->response().suggestedFilename();
717 // Next, try subresources.
718 RefPtr<ArchiveResource> resource = loader->subresource(url);
720 return resource->response().suggestedFilename();
722 return page()->cachedSuggestedFilenameForURL(url);
725 String WebFrame::mimeTypeForResourceWithURL(const URL& url) const
730 DocumentLoader* loader = m_coreFrame->loader().documentLoader();
734 // First, try the main resource.
735 if (loader->url() == url)
736 return loader->response().mimeType();
738 // Next, try subresources.
739 RefPtr<ArchiveResource> resource = loader->subresource(url);
741 return resource->mimeType();
743 return page()->cachedResponseMIMETypeForURL(url);
746 void WebFrame::setTextDirection(const String& direction)
751 if (direction == "auto")
752 m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
753 else if (direction == "ltr")
754 m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
755 else if (direction == "rtl")
756 m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
759 void WebFrame::documentLoaderDetached(uint64_t navigationID)
761 page()->send(Messages::WebPageProxy::DidDestroyNavigation(navigationID));
765 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
767 RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), [this, callback, context](Frame& frame) -> bool {
771 WebFrame* webFrame = WebFrame::fromCoreFrame(frame);
774 return callback(toAPI(this), toAPI(webFrame), context);
780 return archive->rawDataRepresentation();
784 } // namespace WebKit