b242f8ff15f89ab2865439ecdb86ecc6296bc69d
[WebKit-https.git] / Source / WebKit / chromium / src / WebHelperPluginImpl.cpp
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 "DocumentLoader.h"
35 #include "EmptyClients.h"
36 #include "FocusController.h"
37 #include "FrameView.h"
38 #include "HTMLPlugInElement.h"
39 #include "NodeList.h"
40 #include "Page.h"
41 #include "PageWidgetDelegate.h"
42 #include "Settings.h"
43 #include "WebFrameImpl.h"
44 #include "WebPlugin.h"
45 #include "WebPluginContainerImpl.h"
46 #include "WebViewClient.h"
47 #include "WebViewImpl.h"
48 #include "WebWidgetClient.h"
49
50 using namespace WebCore;
51
52 namespace WebKit {
53
54 #define addLiteral(literal, writer)    writer.addData(literal, sizeof(literal) - 1)
55
56 static inline void addString(const String& str, DocumentWriter& writer)
57 {
58     CString str8 = str.utf8();
59     writer.addData(str8.data(), str8.length());
60 }
61
62 void writeDocument(WebCore::DocumentWriter& writer, const String& pluginType)
63 {
64     writer.setMIMEType("text/html");
65     writer.setEncoding("UTF-8", false);
66     writer.begin();
67
68     addLiteral("<!DOCTYPE html><head><meta charset='UTF-8'></head><body>\n", writer);
69     String objectTag = "<object type=\"" + pluginType + "\"></object>";
70     addString(objectTag, writer);
71     addLiteral("</body>\n", writer);
72
73     writer.end();
74 }
75
76 class HelperPluginChromeClient : public EmptyChromeClient {
77     WTF_MAKE_NONCOPYABLE(HelperPluginChromeClient);
78     WTF_MAKE_FAST_ALLOCATED;
79
80 public:
81     explicit HelperPluginChromeClient(WebHelperPluginImpl* widget)
82         : m_widget(widget)
83     {
84         ASSERT(m_widget->m_widgetClient);
85     }
86
87 private:
88     virtual void closeWindowSoon() OVERRIDE
89     {
90         // This should never be called since the only way to close the
91         // invisible page is via closeHelperPlugin().
92         ASSERT_NOT_REACHED(); 
93         m_widget->closeHelperPlugin();
94     }
95
96     virtual void* webView() const OVERRIDE
97     {
98         return m_widget->m_webView;
99     }
100
101     WebHelperPluginImpl* m_widget;
102 };
103
104 // WebHelperPluginImpl ----------------------------------------------------------------
105
106 WebHelperPluginImpl::WebHelperPluginImpl(WebWidgetClient* client)
107     : m_widgetClient(client)
108     , m_webView(0)
109 {
110     ASSERT(client);
111 }
112
113 WebHelperPluginImpl::~WebHelperPluginImpl()
114 {
115     ASSERT(!m_page);
116 }
117
118 bool WebHelperPluginImpl::initialize(WebViewImpl* webView, const String& pluginType)
119 {
120     ASSERT(webView);
121     m_webView = webView;
122
123     return initializePage(webView, pluginType);
124 }
125
126 void WebHelperPluginImpl::closeHelperPlugin()
127 {
128     if (m_page) {
129         m_page->setGroupName(String());
130         m_page->mainFrame()->loader()->stopAllLoaders();
131         m_page->mainFrame()->loader()->stopLoading(UnloadEventPolicyNone);
132     }
133
134     // We must destroy the page now in case the host page is being destroyed, in
135     // which case some of the objects the page depends on may have been
136     // destroyed by the time this->close() is called asynchronously.
137     destoryPage();
138
139     // m_widgetClient might be 0 because this widget might be already closed.
140     if (m_widgetClient) {
141         // closeWidgetSoon() will call this->close() later.
142         m_widgetClient->closeWidgetSoon();
143     }
144 }
145
146 void WebHelperPluginImpl::initializeFrame(WebFrameClient* client)
147 {
148     ASSERT(m_page);
149     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client);
150     frame->initializeAsMainFrame(m_page.get());
151 }
152
153 // Returns a pointer to the WebPlugin by finding the single <object> tag in the page.
154 WebPlugin* WebHelperPluginImpl::getPlugin()
155 {
156     ASSERT(m_page);
157
158     RefPtr<NodeList> objectElements = m_page->mainFrame()->document()->getElementsByTagName(WebCore::HTMLNames::objectTag.localName());
159     ASSERT(objectElements && objectElements->length() == 1);
160     if (!objectElements || objectElements->length() < 1)
161         return 0;
162     Node* node = objectElements->item(0);
163     ASSERT(node->hasTagName(WebCore::HTMLNames::objectTag));
164     WebCore::Widget* widget = static_cast<HTMLPlugInElement*>(node)->pluginWidget();
165     if (!widget)
166         return 0;
167     WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(widget)->plugin();
168     ASSERT(plugin);
169     // If the plugin is a placeholder, it is not useful to the caller, and it
170     // could be replaced at any time. Therefore, do not return it.
171     if (plugin->isPlaceholder())
172         return 0;
173
174     // The plugin was instantiated and will outlive this object.
175     return plugin;
176 }
177
178 bool WebHelperPluginImpl::initializePage(WebKit::WebViewImpl* webView, const String& pluginType)
179 {
180     Page::PageClients pageClients;
181     fillWithEmptyClients(pageClients);
182     m_chromeClient = adoptPtr(new HelperPluginChromeClient(this));
183     pageClients.chromeClient = m_chromeClient.get();
184
185     m_page = adoptPtr(new Page(pageClients));
186     // Scripting must be enabled in ScriptController::windowScriptNPObject().
187     m_page->settings()->setScriptEnabled(true);
188     m_page->settings()->setPluginsEnabled(true);
189
190     unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout;
191     m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones));
192
193     webView->client()->initializeHelperPluginWebFrame(this);
194
195     // The page's main frame was set in initializeFrame() as a result of the above call.
196     Frame* frame = m_page->mainFrame();
197     ASSERT(frame);
198     frame->setView(FrameView::create(frame));
199     // No need to set a size or make it not transparent.
200
201     DocumentWriter* writer = frame->loader()->activeDocumentLoader()->writer();
202     writeDocument(*writer, pluginType);
203
204     return true;
205 }
206
207 void WebHelperPluginImpl::destoryPage()
208 {
209     if (!m_page)
210         return;
211
212     if (m_page->mainFrame())
213         m_page->mainFrame()->loader()->frameDetached();
214
215     m_page.clear();
216 }
217
218 void WebHelperPluginImpl::setCompositorSurfaceReady()
219 {
220 }
221
222 void WebHelperPluginImpl::composite(bool)
223 {
224 }
225
226 void WebHelperPluginImpl::layout()
227 {
228     PageWidgetDelegate::layout(m_page.get());
229 }
230
231 void WebHelperPluginImpl::setFocus(bool)
232 {
233     ASSERT_NOT_REACHED();
234 }
235
236 void WebHelperPluginImpl::close()
237 {
238     ASSERT(!m_page); // Should only be called via closePopup().
239     m_widgetClient = 0;
240     deref();
241 }
242
243 // WebHelperPlugin ----------------------------------------------------------------
244
245 WebHelperPlugin* WebHelperPlugin::create(WebWidgetClient* client)
246 {
247     if (!client)
248         CRASH();
249     // A WebHelperPluginImpl instance usually has two references.
250     //  - One owned by the instance itself. It represents the visible widget.
251     //  - One owned by the hosting element. It's released when the hosting
252     //    element asks the WebHelperPluginImpl to close.
253     // We need them because the closing operation is asynchronous and the widget
254     // can be closed while the hosting element is unaware of it.
255     return adoptRef(new WebHelperPluginImpl(client)).leakRef();
256 }
257
258 } // namespace WebKit