summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/WebFrame.cpp')
-rw-r--r--Source/WebKit2/WebProcess/WebPage/WebFrame.cpp517
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