ecbda3798ca8e09a4d7dcdf345745ba09776157e
[WebKit-https.git] / Source / WebKit / chromium / src / WebPagePopupImpl.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 "WebPagePopupImpl.h"
33
34 #include "Chrome.h"
35 #include "ContextFeatures.h"
36 #include "DOMWindowPagePopup.h"
37 #include "DocumentLoader.h"
38 #include "EmptyClients.h"
39 #include "FocusController.h"
40 #include "FrameView.h"
41 #include "Page.h"
42 #include "PagePopupClient.h"
43 #include "PageWidgetDelegate.h"
44 #include "Settings.h"
45 #include "WebCursorInfo.h"
46 #include "WebInputEventConversion.h"
47 #include "WebPagePopup.h"
48 #include "WebSettingsImpl.h"
49 #include "WebViewClient.h"
50 #include "WebViewImpl.h"
51 #include "WebWidgetClient.h"
52
53 using namespace WebCore;
54 using namespace std;
55
56 namespace WebKit {
57
58 #if ENABLE(PAGE_POPUP)
59
60 class PagePopupChromeClient : public EmptyChromeClient, public WebCore::PageClientChromium {
61     WTF_MAKE_NONCOPYABLE(PagePopupChromeClient);
62     WTF_MAKE_FAST_ALLOCATED;
63
64 public:
65     explicit PagePopupChromeClient(WebPagePopupImpl* popup)
66         : m_popup(popup)
67     {
68         ASSERT(m_popup->widgetClient());
69     }
70
71 private:
72     virtual void closeWindowSoon() OVERRIDE
73     {
74         m_popup->closePopup();
75     }
76
77     virtual FloatRect windowRect() OVERRIDE
78     {
79         return FloatRect(m_popup->m_windowRectInScreen.x, m_popup->m_windowRectInScreen.y, m_popup->m_windowRectInScreen.width, m_popup->m_windowRectInScreen.height);
80     }
81
82     virtual void setWindowRect(const FloatRect& rect) OVERRIDE
83     {
84         m_popup->m_windowRectInScreen = IntRect(rect);
85         m_popup->widgetClient()->setWindowRect(m_popup->m_windowRectInScreen);
86     }
87
88     virtual void addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String&) OVERRIDE
89     {
90 #ifndef NDEBUG
91         fprintf(stderr, "CONSOLE MESSSAGE:%u: %s\n", lineNumber, message.utf8().data());
92 #else
93         UNUSED_PARAM(message);
94         UNUSED_PARAM(lineNumber);
95 #endif
96     }
97
98     virtual void invalidateContentsAndRootView(const IntRect& paintRect, bool) OVERRIDE
99     {
100         if (paintRect.isEmpty())
101             return;
102         m_popup->widgetClient()->didInvalidateRect(paintRect);
103     }
104
105     virtual void scroll(const IntSize& scrollDelta, const IntRect& scrollRect, const IntRect& clipRect) OVERRIDE
106     {
107         m_popup->widgetClient()->didScrollRect(scrollDelta.width(), scrollDelta.height(), intersection(scrollRect, clipRect));
108     }
109
110     virtual void invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) OVERRIDE
111     {
112         invalidateContentsAndRootView(updateRect, immediate);
113     }
114
115     virtual void scheduleAnimation() OVERRIDE
116     {
117         m_popup->widgetClient()->scheduleAnimation();
118     }
119
120     virtual void* webView() const OVERRIDE
121     {
122         return m_popup->m_webView;
123     }
124
125     virtual FloatSize minimumWindowSize() const OVERRIDE
126     {
127         return FloatSize(0, 0);
128     }
129
130     virtual PlatformPageClient platformPageClient() const OVERRIDE
131     {
132         return PlatformPageClient(this);
133     }
134
135     virtual void setCursor(const WebCore::Cursor& cursor) OVERRIDE
136     {
137         if (m_popup->m_webView->client())
138             m_popup->m_webView->client()->didChangeCursor(WebCursorInfo(cursor));
139     }
140
141     // PageClientChromium methods:
142     virtual WebKit::WebScreenInfo screenInfo() OVERRIDE
143     {
144         return m_popup->m_webView->client()->screenInfo();
145     }
146
147     WebPagePopupImpl* m_popup;
148 };
149
150 class PagePopupFeaturesClient : public ContextFeaturesClient {
151     virtual bool isEnabled(Document*, ContextFeatures::FeatureType, bool) OVERRIDE;
152 };
153
154 bool PagePopupFeaturesClient::isEnabled(Document*, ContextFeatures::FeatureType type, bool defaultValue)
155 {
156     if (type == ContextFeatures::PagePopup)
157         return true;
158     return defaultValue;
159 }
160
161 // WebPagePopupImpl ----------------------------------------------------------------
162
163 WebPagePopupImpl::WebPagePopupImpl(WebWidgetClient* client)
164     : m_widgetClient(client)
165     , m_closing(false)
166 {
167     ASSERT(client);
168 }
169
170 WebPagePopupImpl::~WebPagePopupImpl()
171 {
172     ASSERT(!m_page);
173 }
174
175 bool WebPagePopupImpl::initialize(WebViewImpl* webView, PagePopupClient* popupClient, const IntRect&)
176 {
177     ASSERT(webView);
178     ASSERT(popupClient);
179     m_webView = webView;
180     m_popupClient = popupClient;
181
182     resize(m_popupClient->contentSize());
183
184     if (!initializePage())
185         return false;
186     m_widgetClient->show(WebNavigationPolicy());
187     setFocus(true);
188
189     return true;
190 }
191
192 bool WebPagePopupImpl::initializePage()
193 {
194     Page::PageClients pageClients;
195     fillWithEmptyClients(pageClients);
196     m_chromeClient = adoptPtr(new PagePopupChromeClient(this));
197     pageClients.chromeClient = m_chromeClient.get();
198
199     m_page = adoptPtr(new Page(pageClients));
200     m_page->settings()->setScriptEnabled(true);
201     m_page->settings()->setAllowScriptsToCloseWindows(true);
202     m_page->setDeviceScaleFactor(m_webView->deviceScaleFactor());
203     m_page->settings()->setDeviceSupportsTouch(m_webView->page()->settings()->deviceSupportsTouch());
204
205     unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout;
206     m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones));
207
208     static ContextFeaturesClient* pagePopupFeaturesClient =  new PagePopupFeaturesClient();
209     provideContextFeaturesTo(m_page.get(), pagePopupFeaturesClient);
210     static FrameLoaderClient* emptyFrameLoaderClient =  new EmptyFrameLoaderClient();
211     RefPtr<Frame> frame = Frame::create(m_page.get(), 0, emptyFrameLoaderClient);
212     frame->setView(FrameView::create(frame.get()));
213     frame->init();
214     frame->view()->resize(m_popupClient->contentSize());
215     frame->view()->setTransparent(false);
216
217     DOMWindowPagePopup::install(frame->document()->domWindow(), m_popupClient);
218
219     DocumentWriter* writer = frame->loader()->activeDocumentLoader()->writer();
220     writer->setMIMEType("text/html");
221     writer->setEncoding("UTF-8", false);
222     writer->begin();
223     m_popupClient->writeDocument(*writer);
224     writer->end();
225     return true;
226 }
227
228 void WebPagePopupImpl::destoryPage()
229 {
230     if (!m_page)
231         return;
232
233     if (m_page->mainFrame())
234         m_page->mainFrame()->loader()->frameDetached();
235
236     m_page.clear();
237 }
238
239 WebSize WebPagePopupImpl::size()
240 {
241     return m_popupClient->contentSize();
242 }
243
244 void WebPagePopupImpl::animate(double)
245 {
246     PageWidgetDelegate::animate(m_page.get(), monotonicallyIncreasingTime());
247 }
248
249 void WebPagePopupImpl::setCompositorSurfaceReady()
250 {
251 }
252
253 void WebPagePopupImpl::composite(bool)
254 {
255 }
256
257 void WebPagePopupImpl::layout()
258 {
259     PageWidgetDelegate::layout(m_page.get());
260 }
261
262 void WebPagePopupImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions)
263 {
264     if (!m_closing)
265         PageWidgetDelegate::paint(m_page.get(), 0, canvas, rect, PageWidgetDelegate::Opaque, m_webView->settingsImpl()->applyDeviceScaleFactorInCompositor());
266 }
267
268 void WebPagePopupImpl::resize(const WebSize& newSize)
269 {
270     m_windowRectInScreen = WebRect(m_windowRectInScreen.x, m_windowRectInScreen.y, newSize.width, newSize.height);
271     m_widgetClient->setWindowRect(m_windowRectInScreen);
272
273     if (m_page)
274         m_page->mainFrame()->view()->resize(newSize);
275     m_widgetClient->didInvalidateRect(WebRect(0, 0, newSize.width, newSize.height));
276 }
277
278 bool WebPagePopupImpl::handleKeyEvent(const WebKeyboardEvent&)
279 {
280     // The main WebView receives key events and forward them to this via handleKeyEvent().
281     ASSERT_NOT_REACHED();
282     return false;
283 }
284
285 bool WebPagePopupImpl::handleCharEvent(const WebKeyboardEvent&)
286 {
287     // The main WebView receives key events and forward them to this via handleKeyEvent().
288     ASSERT_NOT_REACHED();
289     return false;
290 }
291
292 #if ENABLE(GESTURE_EVENTS)
293 bool WebPagePopupImpl::handleGestureEvent(const WebGestureEvent& event)
294 {
295     if (m_closing || !m_page || !m_page->mainFrame() || !m_page->mainFrame()->view())
296         return false;
297     Frame& frame = *m_page->mainFrame();
298     return frame.eventHandler()->handleGestureEvent(PlatformGestureEventBuilder(frame.view(), event));
299 }
300 #endif
301
302 bool WebPagePopupImpl::handleInputEvent(const WebInputEvent& event)
303 {
304     if (m_closing)
305         return false;
306     return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, event);
307 }
308
309 bool WebPagePopupImpl::handleKeyEvent(const PlatformKeyboardEvent& event)
310 {
311     if (m_closing || !m_page->mainFrame() || !m_page->mainFrame()->view())
312         return false;
313     return m_page->mainFrame()->eventHandler()->keyEvent(event);
314 }
315
316 void WebPagePopupImpl::setFocus(bool enable)
317 {
318     if (!m_page)
319         return;
320     m_page->focusController()->setFocused(enable);
321     if (enable)
322         m_page->focusController()->setActive(true);
323 }
324
325 void WebPagePopupImpl::close()
326 {
327     m_closing = true;
328     destoryPage(); // In case closePopup() was not called.
329     m_widgetClient = 0;
330     deref();
331 }
332
333 void WebPagePopupImpl::closePopup()
334 {
335     if (m_page) {
336         m_page->setGroupName(String());
337         m_page->mainFrame()->loader()->stopAllLoaders();
338         m_page->mainFrame()->loader()->stopLoading(UnloadEventPolicyNone);
339         DOMWindowPagePopup::uninstall(m_page->mainFrame()->document()->domWindow());
340     }
341     m_closing = true;
342
343     destoryPage();
344
345     // m_widgetClient might be 0 because this widget might be already closed.
346     if (m_widgetClient) {
347         // closeWidgetSoon() will call this->close() later.
348         m_widgetClient->closeWidgetSoon();
349     }
350
351     m_popupClient->didClosePopup();
352 }
353
354 #endif // ENABLE(PAGE_POPUP)
355
356 // WebPagePopup ----------------------------------------------------------------
357
358 WebPagePopup* WebPagePopup::create(WebWidgetClient* client)
359 {
360 #if ENABLE(PAGE_POPUP)
361     if (!client)
362         CRASH();
363     // A WebPagePopupImpl instance usually has two references.
364     //  - One owned by the instance itself. It represents the visible widget.
365     //  - One owned by a WebViewImpl. It's released when the WebViewImpl ask the
366     //    WebPagePopupImpl to close.
367     // We need them because the closing operation is asynchronous and the widget
368     // can be closed while the WebViewImpl is unaware of it.
369     return adoptRef(new WebPagePopupImpl(client)).leakRef();
370 #else
371     UNUSED_PARAM(client);
372     return 0;
373 #endif
374 }
375
376 } // namespace WebKit