summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp b/chromium/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp
new file mode 100644
index 00000000000..570d4b31050
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "config.h"
+#include "WebHelperPluginImpl.h"
+
+#include "PageWidgetDelegate.h"
+#include "WebDocument.h"
+#include "WebFrameImpl.h"
+#include "WebPlugin.h"
+#include "WebPluginContainerImpl.h"
+#include "WebViewClient.h"
+#include "WebViewImpl.h"
+#include "WebWidgetClient.h"
+#include "core/dom/NodeList.h"
+#include "core/html/HTMLPlugInElement.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/EmptyClients.h"
+#include "core/page/FocusController.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+#define addLiteral(literal, writer) writer->addData(literal, sizeof(literal) - 1)
+
+static inline void addString(const String& str, DocumentWriter* writer)
+{
+ CString str8 = str.utf8();
+ writer->addData(str8.data(), str8.length());
+}
+
+static void writeDocument(const String& pluginType, const WebDocument& hostDocument, WebCore::DocumentLoader* loader)
+{
+ // Give the new document the same URL as the hose document so that content
+ // settings and other decisions can be made based on the correct origin.
+ const WebURL& url = hostDocument.url();
+
+ DocumentWriter* writer = loader->beginWriting("text/html", "UTF-8", url);
+
+ addLiteral("<!DOCTYPE html><head><meta charset='UTF-8'></head><body>\n", writer);
+ String objectTag = "<object type=\"" + pluginType + "\"></object>";
+ addString(objectTag, writer);
+ addLiteral("</body>\n", writer);
+
+ loader->endWriting(writer);
+}
+
+class HelperPluginChromeClient : public EmptyChromeClient {
+ WTF_MAKE_NONCOPYABLE(HelperPluginChromeClient);
+ WTF_MAKE_FAST_ALLOCATED;
+
+public:
+ explicit HelperPluginChromeClient(WebHelperPluginImpl* widget)
+ : m_widget(widget)
+ {
+ ASSERT(m_widget->m_widgetClient);
+ }
+
+private:
+ virtual void closeWindowSoon() OVERRIDE
+ {
+ // This should never be called since the only way to close the
+ // invisible page is via closeHelperPlugin().
+ ASSERT_NOT_REACHED();
+ m_widget->closeHelperPlugin();
+ }
+
+ virtual void* webView() const OVERRIDE
+ {
+ return m_widget->m_webView;
+ }
+
+ WebHelperPluginImpl* m_widget;
+};
+
+// WebHelperPluginImpl ----------------------------------------------------------------
+
+WebHelperPluginImpl::WebHelperPluginImpl(WebWidgetClient* client)
+ : m_widgetClient(client)
+ , m_webView(0)
+{
+ ASSERT(client);
+}
+
+WebHelperPluginImpl::~WebHelperPluginImpl()
+{
+ ASSERT(!m_page);
+}
+
+bool WebHelperPluginImpl::initialize(const String& pluginType, const WebDocument& hostDocument, WebViewImpl* webView)
+{
+ ASSERT(webView);
+ m_webView = webView;
+
+ return initializePage(pluginType, hostDocument);
+}
+
+void WebHelperPluginImpl::closeHelperPlugin()
+{
+ if (m_page) {
+ m_page->clearPageGroup();
+ m_page->mainFrame()->loader()->stopAllLoaders();
+ m_page->mainFrame()->loader()->stopLoading();
+ }
+
+ // We must destroy the page now in case the host page is being destroyed, in
+ // which case some of the objects the page depends on may have been
+ // destroyed by the time this->close() is called asynchronously.
+ destroyPage();
+
+ // m_widgetClient might be 0 because this widget might be already closed.
+ if (m_widgetClient) {
+ // closeWidgetSoon() will call this->close() later.
+ m_widgetClient->closeWidgetSoon();
+ }
+}
+
+void WebHelperPluginImpl::initializeFrame(WebFrameClient* client)
+{
+ ASSERT(m_page);
+ RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client);
+ frame->initializeAsMainFrame(m_page.get());
+}
+
+// Returns a pointer to the WebPlugin by finding the single <object> tag in the page.
+WebPlugin* WebHelperPluginImpl::getPlugin()
+{
+ ASSERT(m_page);
+
+ RefPtr<NodeList> objectElements = m_page->mainFrame()->document()->getElementsByTagName(WebCore::HTMLNames::objectTag.localName());
+ ASSERT(objectElements && objectElements->length() == 1);
+ if (!objectElements || objectElements->length() < 1)
+ return 0;
+ Node* node = objectElements->item(0);
+ ASSERT(node->hasTagName(WebCore::HTMLNames::objectTag));
+ WebCore::Widget* widget = toHTMLPlugInElement(node)->pluginWidget();
+ if (!widget)
+ return 0;
+ WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(widget)->plugin();
+ ASSERT(plugin);
+ // If the plugin is a placeholder, it is not useful to the caller, and it
+ // could be replaced at any time. Therefore, do not return it.
+ if (plugin->isPlaceholder())
+ return 0;
+
+ // The plugin was instantiated and will outlive this object.
+ return plugin;
+}
+
+bool WebHelperPluginImpl::initializePage(const String& pluginType, const WebDocument& hostDocument)
+{
+ Page::PageClients pageClients;
+ fillWithEmptyClients(pageClients);
+ m_chromeClient = adoptPtr(new HelperPluginChromeClient(this));
+ pageClients.chromeClient = m_chromeClient.get();
+
+ m_page = adoptPtr(new Page(pageClients));
+ ASSERT(!m_page->settings()->isScriptEnabled());
+ m_page->settings()->setPluginsEnabled(true);
+
+ unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout;
+ m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones));
+
+ m_webView->client()->initializeHelperPluginWebFrame(this);
+
+ // The page's main frame was set in initializeFrame() as a result of the above call.
+ Frame* frame = m_page->mainFrame();
+ ASSERT(frame);
+ frame->loader()->forceSandboxFlags(SandboxAll & ~SandboxPlugins);
+ frame->setView(FrameView::create(frame));
+ // No need to set a size or make it not transparent.
+
+ writeDocument(pluginType, hostDocument, frame->loader()->activeDocumentLoader());
+
+ return true;
+}
+
+void WebHelperPluginImpl::destroyPage()
+{
+ if (!m_page)
+ return;
+
+ if (m_page->mainFrame())
+ m_page->mainFrame()->loader()->frameDetached();
+
+ m_page.clear();
+}
+
+void WebHelperPluginImpl::layout()
+{
+ PageWidgetDelegate::layout(m_page.get());
+}
+
+void WebHelperPluginImpl::setFocus(bool)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void WebHelperPluginImpl::close()
+{
+ ASSERT(!m_page); // Should only be called via closePopup().
+ m_widgetClient = 0;
+ deref();
+}
+
+// WebHelperPlugin ----------------------------------------------------------------
+
+WebHelperPlugin* WebHelperPlugin::create(WebWidgetClient* client)
+{
+ if (!client)
+ CRASH();
+ // A WebHelperPluginImpl instance usually has two references.
+ // - One owned by the instance itself. It represents the visible widget.
+ // - One owned by the hosting element. It's released when the hosting
+ // element asks the WebHelperPluginImpl to close.
+ // We need them because the closing operation is asynchronous and the widget
+ // can be closed while the hosting element is unaware of it.
+ return adoptRef(new WebHelperPluginImpl(client)).leakRef();
+}
+
+} // namespace WebKit