• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "WebHelperPluginImpl.h"
33 
34 #include "PageWidgetDelegate.h"
35 #include "WebDocument.h"
36 #include "WebFrameClient.h"
37 #include "WebFrameImpl.h"
38 #include "WebPlugin.h"
39 #include "WebPluginContainerImpl.h"
40 #include "WebViewClient.h"
41 #include "WebViewImpl.h"
42 #include "WebWidgetClient.h"
43 #include "core/dom/NodeList.h"
44 #include "core/html/HTMLPlugInElement.h"
45 #include "core/loader/DocumentLoader.h"
46 #include "core/loader/EmptyClients.h"
47 #include "core/page/FocusController.h"
48 #include "core/frame/FrameView.h"
49 #include "core/page/Page.h"
50 #include "core/frame/Settings.h"
51 
52 using namespace WebCore;
53 
54 namespace blink {
55 
56 #define addLiteral(literal, writer)    writer->addData(literal, sizeof(literal) - 1)
57 
addString(const String & str,DocumentWriter * writer)58 static inline void addString(const String& str, DocumentWriter* writer)
59 {
60     CString str8 = str.utf8();
61     writer->addData(str8.data(), str8.length());
62 }
63 
writeDocument(const String & pluginType,const WebDocument & hostDocument,WebCore::DocumentLoader * loader)64 static void writeDocument(const String& pluginType, const WebDocument& hostDocument, WebCore::DocumentLoader* loader)
65 {
66     // Give the new document the same URL as the hose document so that content
67     // settings and other decisions can be made based on the correct origin.
68     const WebURL& url = hostDocument.url();
69 
70     DocumentWriter* writer = loader->beginWriting("text/html", "UTF-8", url);
71 
72     addLiteral("<!DOCTYPE html><head><meta charset='UTF-8'></head><body>\n", writer);
73     String objectTag = "<object type=\"" + pluginType + "\"></object>";
74     addString(objectTag, writer);
75     addLiteral("</body>\n", writer);
76 
77     loader->endWriting(writer);
78 }
79 
80 class HelperPluginChromeClient : public EmptyChromeClient {
81     WTF_MAKE_NONCOPYABLE(HelperPluginChromeClient);
82     WTF_MAKE_FAST_ALLOCATED;
83 
84 public:
HelperPluginChromeClient(WebHelperPluginImpl * widget)85     explicit HelperPluginChromeClient(WebHelperPluginImpl* widget)
86         : m_widget(widget)
87     {
88         ASSERT(m_widget->m_widgetClient);
89     }
90 
91 private:
closeWindowSoon()92     virtual void closeWindowSoon() OVERRIDE
93     {
94         // This should never be called since the only way to close the
95         // invisible page is via closeHelperPlugin().
96         ASSERT_NOT_REACHED();
97         m_widget->closeHelperPlugin();
98     }
99 
webView() const100     virtual void* webView() const OVERRIDE
101     {
102         return m_widget->m_webView;
103     }
104 
105     WebHelperPluginImpl* m_widget;
106 };
107 
108 // HelperPluginFrameClient acts as a filter to only forward messages onto the
109 // main render frame that WebHelperPlugin actually needs. This prevents
110 // having the WebHelperPlugin's frame accidentally signaling events on the
111 // client that are meant only for WebFrames which are part of the main DOM.
112 class HelperPluginFrameClient : public WebFrameClient {
113 public:
HelperPluginFrameClient(WebFrameClient * hostWebFrameClient)114     HelperPluginFrameClient(WebFrameClient* hostWebFrameClient)
115         : m_hostWebFrameClient(hostWebFrameClient)
116     {
117     }
118 
~HelperPluginFrameClient()119     virtual ~HelperPluginFrameClient()
120     {
121     }
122 
createPlugin(blink::WebFrame * frame,const WebPluginParams & params)123     virtual WebPlugin* createPlugin(blink::WebFrame* frame, const WebPluginParams& params)
124     {
125         return m_hostWebFrameClient->createPlugin(frame, params);
126     }
127 
128 private:
129     WebFrameClient* m_hostWebFrameClient;
130 };
131 
132 
133 // WebHelperPluginImpl ----------------------------------------------------------------
134 
WebHelperPluginImpl(WebWidgetClient * client)135 WebHelperPluginImpl::WebHelperPluginImpl(WebWidgetClient* client)
136     : m_widgetClient(client)
137     , m_webView(0)
138     , m_mainFrame(0)
139 {
140     ASSERT(client);
141 }
142 
~WebHelperPluginImpl()143 WebHelperPluginImpl::~WebHelperPluginImpl()
144 {
145     ASSERT(!m_page);
146 }
147 
initialize(const String & pluginType,const WebDocument & hostDocument,WebViewImpl * webView)148 bool WebHelperPluginImpl::initialize(const String& pluginType, const WebDocument& hostDocument, WebViewImpl* webView)
149 {
150     ASSERT(webView);
151     m_webView = webView;
152 
153     return initializePage(pluginType, hostDocument);
154 }
155 
closeHelperPlugin()156 void WebHelperPluginImpl::closeHelperPlugin()
157 {
158     if (m_page) {
159         m_page->clearPageGroup();
160         m_page->mainFrame()->loader().stopAllLoaders();
161     }
162 
163     // We must destroy the page now in case the host page is being destroyed, in
164     // which case some of the objects the page depends on may have been
165     // destroyed by the time this->close() is called asynchronously.
166     destroyPage();
167 
168     // m_widgetClient might be 0 because this widget might be already closed.
169     if (m_widgetClient) {
170         // closeWidgetSoon() will call this->close() later.
171         m_widgetClient->closeWidgetSoon();
172     }
173     m_mainFrame->close();
174 }
175 
initializeFrame(WebFrameClient * client)176 void WebHelperPluginImpl::initializeFrame(WebFrameClient* client)
177 {
178     ASSERT(m_page);
179     ASSERT(!m_frameClient);
180     m_frameClient = adoptPtr(new HelperPluginFrameClient(client));
181     m_mainFrame = WebFrameImpl::create(m_frameClient.get());
182     m_mainFrame->initializeAsMainFrame(m_page.get());
183 }
184 
185 // Returns a pointer to the WebPlugin by finding the single <object> tag in the page.
getPlugin()186 WebPlugin* WebHelperPluginImpl::getPlugin()
187 {
188     ASSERT(m_page);
189 
190     RefPtr<NodeList> objectElements = m_page->mainFrame()->document()->getElementsByTagName(WebCore::HTMLNames::objectTag.localName());
191     ASSERT(objectElements && objectElements->length() == 1);
192     if (!objectElements || objectElements->length() < 1)
193         return 0;
194     Node* node = objectElements->item(0);
195     ASSERT(node->hasTagName(WebCore::HTMLNames::objectTag));
196     WebCore::Widget* widget = toHTMLPlugInElement(node)->pluginWidget();
197     if (!widget)
198         return 0;
199     WebPlugin* plugin = toPluginContainerImpl(widget)->plugin();
200     ASSERT(plugin);
201     // If the plugin is a placeholder, it is not useful to the caller, and it
202     // could be replaced at any time. Therefore, do not return it.
203     if (plugin->isPlaceholder())
204         return 0;
205 
206     // The plugin was instantiated and will outlive this object.
207     return plugin;
208 }
209 
initializePage(const String & pluginType,const WebDocument & hostDocument)210 bool WebHelperPluginImpl::initializePage(const String& pluginType, const WebDocument& hostDocument)
211 {
212     Page::PageClients pageClients;
213     fillWithEmptyClients(pageClients);
214     m_chromeClient = adoptPtr(new HelperPluginChromeClient(this));
215     pageClients.chromeClient = m_chromeClient.get();
216 
217     m_page = adoptPtr(new Page(pageClients));
218     ASSERT(!m_page->settings().isScriptEnabled());
219     m_page->settings().setPluginsEnabled(true);
220 
221     m_webView->client()->initializeHelperPluginWebFrame(this);
222 
223     // The page's main frame was set in initializeFrame() as a result of the above call.
224     Frame* frame = m_page->mainFrame();
225     ASSERT(frame);
226     frame->loader().forceSandboxFlags(SandboxAll & ~SandboxPlugins);
227     frame->setView(FrameView::create(frame));
228     // No need to set a size or make it not transparent.
229 
230     writeDocument(pluginType, hostDocument, frame->loader().activeDocumentLoader());
231 
232     return true;
233 }
234 
destroyPage()235 void WebHelperPluginImpl::destroyPage()
236 {
237     if (!m_page)
238         return;
239 
240     if (m_page->mainFrame())
241         m_page->mainFrame()->loader().frameDetached();
242 
243     m_page.clear();
244 }
245 
layout()246 void WebHelperPluginImpl::layout()
247 {
248     PageWidgetDelegate::layout(m_page.get());
249 }
250 
setFocus(bool)251 void WebHelperPluginImpl::setFocus(bool)
252 {
253     ASSERT_NOT_REACHED();
254 }
255 
close()256 void WebHelperPluginImpl::close()
257 {
258     ASSERT(!m_page); // Should only be called via closePopup().
259     m_widgetClient = 0;
260     deref();
261 }
262 
263 // WebHelperPlugin ----------------------------------------------------------------
264 
create(WebWidgetClient * client)265 WebHelperPlugin* WebHelperPlugin::create(WebWidgetClient* client)
266 {
267     RELEASE_ASSERT(client);
268     // A WebHelperPluginImpl instance usually has two references.
269     //  - One owned by the instance itself. It represents the visible widget.
270     //  - One owned by the hosting element. It's released when the hosting
271     //    element asks the WebHelperPluginImpl to close.
272     // We need them because the closing operation is asynchronous and the widget
273     // can be closed while the hosting element is unaware of it.
274     return adoptRef(new WebHelperPluginImpl(client)).leakRef();
275 }
276 
277 } // namespace blink
278