diff options
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/WebFrame.cpp')
-rw-r--r-- | Source/WebKit2/WebProcess/WebPage/WebFrame.cpp | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp b/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp new file mode 100644 index 0000000..c5f117e --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "WebFrame.h" + +#include "DownloadManager.h" +#include "InjectedBundleNodeHandle.h" +#include "InjectedBundleRangeHandle.h" +#include "InjectedBundleScriptWorld.h" +#include "WebChromeClient.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include "WebProcess.h" +#include <JavaScriptCore/APICast.h> +#include <JavaScriptCore/JSLock.h> +#include <JavaScriptCore/JSValueRef.h> +#include <WebCore/AnimationController.h> +#include <WebCore/CSSComputedStyleDeclaration.h> +#include <WebCore/Chrome.h> +#include <WebCore/DocumentLoader.h> +#include <WebCore/Frame.h> +#include <WebCore/FrameView.h> +#include <WebCore/HTMLFrameOwnerElement.h> +#include <WebCore/JSCSSStyleDeclaration.h> +#include <WebCore/JSElement.h> +#include <WebCore/JSRange.h> +#include <WebCore/Page.h> +#include <WebCore/RenderTreeAsText.h> +#include <WebCore/TextIterator.h> +#include <WebCore/TextResourceDecoder.h> +#include <wtf/text/StringBuilder.h> + +#ifndef NDEBUG +#include <wtf/RefCountedLeakCounter.h> +#endif + +using namespace JSC; +using namespace WebCore; + +namespace WebKit { + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter webFrameCounter("WebFrame"); +#endif + +static uint64_t generateFrameID() +{ + static uint64_t uniqueFrameID = 1; + return uniqueFrameID++; +} + +static uint64_t generateListenerID() +{ + static uint64_t uniqueListenerID = 1; + return uniqueListenerID++; +} + +PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page) +{ + RefPtr<WebFrame> frame = create(); + + page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID())); + + frame->init(page, String(), 0); + + return frame.release(); +} + +PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement) +{ + RefPtr<WebFrame> frame = create(); + + WebFrame* parentFrame = static_cast<WebFrameLoaderClient*>(ownerElement->document()->frame()->loader()->client())->webFrame(); + page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID(), parentFrame->frameID())); + + frame->init(page, frameName, ownerElement); + + return frame.release(); +} + +PassRefPtr<WebFrame> WebFrame::create() +{ + RefPtr<WebFrame> frame = adoptRef(new WebFrame); + + // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed(). + frame->ref(); + + return frame.release(); +} + +WebFrame::WebFrame() + : m_coreFrame(0) + , m_policyListenerID(0) + , m_policyFunction(0) + , m_policyDownloadID(0) + , m_frameLoaderClient(this) + , m_loadListener(0) + , m_frameID(generateFrameID()) +{ + WebProcess::shared().addWebFrame(m_frameID, this); + +#ifndef NDEBUG + webFrameCounter.increment(); +#endif +} + +WebFrame::~WebFrame() +{ + ASSERT(!m_coreFrame); + +#ifndef NDEBUG + webFrameCounter.decrement(); +#endif +} + +void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement) +{ + RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient); + m_coreFrame = frame.get(); + + frame->tree()->setName(frameName); + + if (ownerElement) { + ASSERT(ownerElement->document()->frame()); + ownerElement->document()->frame()->tree()->appendChild(frame); + } + + frame->init(); +} + +WebPage* WebFrame::page() const +{ + if (!m_coreFrame) + return 0; + + if (WebCore::Page* page = m_coreFrame->page()) + return static_cast<WebChromeClient*>(page->chrome()->client())->page(); + + return 0; +} + +void WebFrame::invalidate() +{ + WebProcess::shared().removeWebFrame(m_frameID); + m_coreFrame = 0; +} + +uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction) +{ + // FIXME: <rdar://5634381> We need to support multiple active policy listeners. + + invalidatePolicyListener(); + + m_policyListenerID = generateListenerID(); + m_policyFunction = policyFunction; + return m_policyListenerID; +} + +void WebFrame::invalidatePolicyListener() +{ + if (!m_policyListenerID) + return; + + m_policyDownloadID = 0; + m_policyListenerID = 0; + m_policyFunction = 0; +} + +void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID) +{ + if (!m_coreFrame) + return; + + if (!m_policyListenerID) + return; + + if (listenerID != m_policyListenerID) + return; + + ASSERT(m_policyFunction); + + FramePolicyFunction function = m_policyFunction; + + invalidatePolicyListener(); + + m_policyDownloadID = downloadID; + + (m_coreFrame->loader()->policyChecker()->*function)(action); +} + +void WebFrame::startDownload(const WebCore::ResourceRequest& request) +{ + ASSERT(m_policyDownloadID); + + DownloadManager::shared().startDownload(m_policyDownloadID, page(), request); + + m_policyDownloadID = 0; +} + +void WebFrame::convertHandleToDownload(ResourceHandle* handle, const ResourceRequest& request, const ResourceRequest& initialRequest, const ResourceResponse& response) +{ + ASSERT(m_policyDownloadID); + + DownloadManager::shared().convertHandleToDownload(m_policyDownloadID, page(), handle, request, initialRequest, response); + m_policyDownloadID = 0; +} + +String WebFrame::source() const +{ + if (!m_coreFrame) + return String(); + Document* document = m_coreFrame->document(); + if (!document) + return String(); + TextResourceDecoder* decoder = document->decoder(); + if (!decoder) + return String(); + DocumentLoader* documentLoader = m_coreFrame->loader()->activeDocumentLoader(); + if (!documentLoader) + return String(); + RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData(); + if (!mainResourceData) + return String(); + return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size()); +} + +String WebFrame::contentsAsString() const +{ + if (!m_coreFrame) + return String(); + + if (isFrameSet()) { + StringBuilder builder; + for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { + if (!builder.isEmpty()) + builder.append(' '); + builder.append(static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame()->contentsAsString()); + } + // FIXME: It may make sense to use toStringPreserveCapacity() here. + return builder.toString(); + } + + Document* document = m_coreFrame->document(); + if (!document) + return String(); + + RefPtr<Element> documentElement = document->documentElement(); + if (!documentElement) + return String(); + + RefPtr<Range> range = document->createRange(); + + ExceptionCode ec = 0; + range->selectNode(documentElement.get(), ec); + if (ec) + return String(); + + return plainText(range.get()); +} + +String WebFrame::selectionAsString() const +{ + if (!m_coreFrame) + return String(); + + return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText()); +} + +IntSize WebFrame::size() const +{ + if (!m_coreFrame) + return IntSize(); + + FrameView* frameView = m_coreFrame->view(); + if (!frameView) + return IntSize(); + + return frameView->contentsSize(); +} + +bool WebFrame::isFrameSet() const +{ + if (!m_coreFrame) + return false; + + Document* document = m_coreFrame->document(); + if (!document) + return false; + return document->isFrameSet(); +} + +bool WebFrame::isMainFrame() const +{ + if (WebPage* p = page()) + return p->mainFrame() == this; + + return false; +} + +String WebFrame::name() const +{ + if (!m_coreFrame) + return String(); + + return m_coreFrame->tree()->uniqueName(); +} + +String WebFrame::url() const +{ + if (!m_coreFrame) + return String(); + + return m_coreFrame->loader()->url().string(); +} + +String WebFrame::innerText() const +{ + if (!m_coreFrame) + return String(); + + if (!m_coreFrame->document()->documentElement()) + return String(); + + return m_coreFrame->document()->documentElement()->innerText(); +} + +PassRefPtr<ImmutableArray> WebFrame::childFrames() +{ + if (!m_coreFrame) + return ImmutableArray::create(); + + size_t size = m_coreFrame->tree()->childCount(); + if (!size) + return ImmutableArray::create(); + + Vector<RefPtr<APIObject> > vector; + vector.reserveInitialCapacity(size); + + for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { + WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame(); + vector.uncheckedAppend(webFrame); + } + + return ImmutableArray::adopt(vector); +} + +unsigned WebFrame::numberOfActiveAnimations() const +{ + if (!m_coreFrame) + return 0; + + AnimationController* controller = m_coreFrame->animation(); + if (!controller) + return 0; + + return controller->numberOfActiveAnimations(); +} + +bool WebFrame::pauseAnimationOnElementWithId(const String& animationName, const String& elementID, double time) +{ + if (!m_coreFrame) + return false; + + AnimationController* controller = m_coreFrame->animation(); + if (!controller) + return false; + + if (!m_coreFrame->document()) + return false; + + Node* coreNode = m_coreFrame->document()->getElementById(elementID); + if (!coreNode || !coreNode->renderer()) + return false; + + return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time); +} + +void WebFrame::suspendAnimations() +{ + if (!m_coreFrame) + return; + + AnimationController* controller = m_coreFrame->animation(); + if (!controller) + return; + + controller->suspendAnimations(); +} + +void WebFrame::resumeAnimations() +{ + if (!m_coreFrame) + return; + + AnimationController* controller = m_coreFrame->animation(); + if (!controller) + return; + + controller->resumeAnimations(); +} + +String WebFrame::layerTreeAsText() const +{ + if (!m_coreFrame) + return ""; + + return m_coreFrame->layerTreeAsText(); +} + +unsigned WebFrame::pendingUnloadCount() const +{ + if (!m_coreFrame) + return 0; + + return m_coreFrame->domWindow()->pendingUnloadEventListeners(); +} + +bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const +{ + if (!m_coreFrame) + return true; + + return m_coreFrame->document()->securityOrigin()->canDisplay(url); +} + +JSGlobalContextRef WebFrame::jsContext() +{ + return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()); +} + +JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world) +{ + return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec()); +} + +JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world) +{ + JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld()); + ExecState* exec = globalObject->globalExec(); + + JSLock lock(SilenceAssertionsOnly); + return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode())); +} + +JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world) +{ + JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld()); + ExecState* exec = globalObject->globalExec(); + + JSLock lock(SilenceAssertionsOnly); + return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange())); +} + +JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element) +{ + if (!m_coreFrame) + return 0; + + JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld()); + ExecState* exec = globalObject->globalExec(); + + if (!toJS(element)->inherits(&JSElement::s_info)) + return JSValueMakeUndefined(toRef(exec)); + + RefPtr<CSSComputedStyleDeclaration> style = computedStyle(static_cast<JSElement*>(toJS(element))->impl(), true); + + JSLock lock(SilenceAssertionsOnly); + return toRef(exec, toJS(exec, globalObject, style.get())); +} + +String WebFrame::counterValue(JSObjectRef element) +{ + if (!toJS(element)->inherits(&JSElement::s_info)) + return String(); + + return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl()); +} + +String WebFrame::markerText(JSObjectRef element) +{ + if (!toJS(element)->inherits(&JSElement::s_info)) + return String(); + + return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl()); +} + +String WebFrame::provisionalURL() const +{ + if (!m_coreFrame) + return String(); + + return m_coreFrame->loader()->provisionalDocumentLoader()->url().string(); +} + +} // namespace WebKit |