• Home
  • History
  • Annotate
  • 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 "web/WebPagePopupImpl.h"
33 
34 #include "core/dom/ContextFeatures.h"
35 #include "core/frame/FrameView.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/Settings.h"
38 #include "core/loader/EmptyClients.h"
39 #include "core/loader/FrameLoadRequest.h"
40 #include "core/page/Chrome.h"
41 #include "core/page/DOMWindowPagePopup.h"
42 #include "core/page/EventHandler.h"
43 #include "core/page/FocusController.h"
44 #include "core/page/Page.h"
45 #include "core/page/PagePopupClient.h"
46 #include "platform/TraceEvent.h"
47 #include "platform/heap/Handle.h"
48 #include "public/platform/WebCompositeAndReadbackAsyncCallback.h"
49 #include "public/platform/WebCursorInfo.h"
50 #include "public/web/WebAXObject.h"
51 #include "public/web/WebFrameClient.h"
52 #include "public/web/WebViewClient.h"
53 #include "public/web/WebWidgetClient.h"
54 #include "web/WebInputEventConversion.h"
55 #include "web/WebLocalFrameImpl.h"
56 #include "web/WebSettingsImpl.h"
57 #include "web/WebViewImpl.h"
58 
59 namespace blink {
60 
61 class PagePopupChromeClient : public EmptyChromeClient {
62     WTF_MAKE_NONCOPYABLE(PagePopupChromeClient);
63     WTF_MAKE_FAST_ALLOCATED;
64 
65 public:
PagePopupChromeClient(WebPagePopupImpl * popup)66     explicit PagePopupChromeClient(WebPagePopupImpl* popup)
67         : m_popup(popup)
68     {
69         ASSERT(m_popup->widgetClient());
70     }
71 
72 private:
closeWindowSoon()73     virtual void closeWindowSoon() OVERRIDE
74     {
75         m_popup->closePopup();
76     }
77 
windowRect()78     virtual FloatRect windowRect() OVERRIDE
79     {
80         return FloatRect(m_popup->m_windowRectInScreen.x, m_popup->m_windowRectInScreen.y, m_popup->m_windowRectInScreen.width, m_popup->m_windowRectInScreen.height);
81     }
82 
setWindowRect(const FloatRect & rect)83     virtual void setWindowRect(const FloatRect& rect) OVERRIDE
84     {
85         m_popup->m_windowRectInScreen = IntRect(rect);
86         m_popup->widgetClient()->setWindowRect(m_popup->m_windowRectInScreen);
87     }
88 
rootViewToScreen(const IntRect & rect) const89     virtual IntRect rootViewToScreen(const IntRect& rect) const OVERRIDE
90     {
91         IntRect rectInScreen(rect);
92         rectInScreen.move(m_popup->m_windowRectInScreen.x, m_popup->m_windowRectInScreen.y);
93         return rectInScreen;
94     }
95 
addMessageToConsole(LocalFrame *,MessageSource,MessageLevel,const String & message,unsigned lineNumber,const String &,const String &)96     virtual void addMessageToConsole(LocalFrame*, MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String&, const String&) OVERRIDE
97     {
98 #ifndef NDEBUG
99         fprintf(stderr, "CONSOLE MESSSAGE:%u: %s\n", lineNumber, message.utf8().data());
100 #endif
101     }
102 
invalidateContentsAndRootView(const IntRect & paintRect)103     virtual void invalidateContentsAndRootView(const IntRect& paintRect) OVERRIDE
104     {
105         if (paintRect.isEmpty())
106             return;
107         m_popup->widgetClient()->didInvalidateRect(paintRect);
108     }
109 
invalidateContentsForSlowScroll(const IntRect & updateRect)110     virtual void invalidateContentsForSlowScroll(const IntRect& updateRect) OVERRIDE
111     {
112         invalidateContentsAndRootView(updateRect);
113     }
114 
scheduleAnimation()115     virtual void scheduleAnimation() OVERRIDE
116     {
117         if (m_popup->isAcceleratedCompositingActive()) {
118             ASSERT(m_popup->m_layerTreeView);
119             m_popup->m_layerTreeView->setNeedsAnimate();
120             return;
121         }
122         m_popup->widgetClient()->scheduleAnimation();
123     }
124 
screenInfo() const125     virtual WebScreenInfo screenInfo() const OVERRIDE
126     {
127         return m_popup->m_webView->client() ? m_popup->m_webView->client()->screenInfo() : WebScreenInfo();
128     }
129 
webView() const130     virtual void* webView() const OVERRIDE
131     {
132         return m_popup->m_webView;
133     }
134 
minimumWindowSize() const135     virtual FloatSize minimumWindowSize() const OVERRIDE
136     {
137         return FloatSize(0, 0);
138     }
139 
setCursor(const Cursor & cursor)140     virtual void setCursor(const Cursor& cursor) OVERRIDE
141     {
142         if (m_popup->m_webView->client())
143             m_popup->m_webView->client()->didChangeCursor(WebCursorInfo(cursor));
144     }
145 
needTouchEvents(bool needsTouchEvents)146     virtual void needTouchEvents(bool needsTouchEvents) OVERRIDE
147     {
148         m_popup->widgetClient()->hasTouchEventHandlers(needsTouchEvents);
149     }
150 
graphicsLayerFactory() const151     virtual GraphicsLayerFactory* graphicsLayerFactory() const OVERRIDE
152     {
153         return m_popup->m_webView->graphicsLayerFactory();
154     }
155 
attachRootGraphicsLayer(GraphicsLayer * graphicsLayer)156     virtual void attachRootGraphicsLayer(GraphicsLayer* graphicsLayer) OVERRIDE
157     {
158         m_popup->setRootGraphicsLayer(graphicsLayer);
159     }
160 
postAccessibilityNotification(AXObject * obj,AXObjectCache::AXNotification notification)161     virtual void postAccessibilityNotification(AXObject* obj, AXObjectCache::AXNotification notification) OVERRIDE
162     {
163         WebLocalFrameImpl* frame = WebLocalFrameImpl::fromFrame(m_popup->m_popupClient->ownerElement().document().frame());
164         if (obj && frame && frame->client())
165             frame->client()->postAccessibilityEvent(WebAXObject(obj), static_cast<WebAXEvent>(notification));
166 
167         // FIXME: Delete these lines once Chromium only uses the frame client interface, above.
168         if (obj && m_popup->m_webView->client())
169             m_popup->m_webView->client()->postAccessibilityEvent(WebAXObject(obj), static_cast<WebAXEvent>(notification));
170     }
171 
172     WebPagePopupImpl* m_popup;
173 };
174 
175 class PagePopupFeaturesClient : public ContextFeaturesClient {
176     virtual bool isEnabled(Document*, ContextFeatures::FeatureType, bool) OVERRIDE;
177 };
178 
isEnabled(Document *,ContextFeatures::FeatureType type,bool defaultValue)179 bool PagePopupFeaturesClient::isEnabled(Document*, ContextFeatures::FeatureType type, bool defaultValue)
180 {
181     if (type == ContextFeatures::PagePopup)
182         return true;
183     return defaultValue;
184 }
185 
186 // WebPagePopupImpl ----------------------------------------------------------------
187 
WebPagePopupImpl(WebWidgetClient * client)188 WebPagePopupImpl::WebPagePopupImpl(WebWidgetClient* client)
189     : m_widgetClient(client)
190     , m_closing(false)
191     , m_layerTreeView(0)
192     , m_rootLayer(0)
193     , m_rootGraphicsLayer(0)
194     , m_isAcceleratedCompositingActive(false)
195 {
196     ASSERT(client);
197 }
198 
~WebPagePopupImpl()199 WebPagePopupImpl::~WebPagePopupImpl()
200 {
201     ASSERT(!m_page);
202 }
203 
initialize(WebViewImpl * webView,PagePopupClient * popupClient,const IntRect &)204 bool WebPagePopupImpl::initialize(WebViewImpl* webView, PagePopupClient* popupClient, const IntRect&)
205 {
206     ASSERT(webView);
207     ASSERT(popupClient);
208     m_webView = webView;
209     m_popupClient = popupClient;
210 
211     resize(m_popupClient->contentSize());
212 
213     if (!m_widgetClient || !initializePage())
214         return false;
215     m_widgetClient->show(WebNavigationPolicy());
216     setFocus(true);
217 
218     return true;
219 }
220 
initializePage()221 bool WebPagePopupImpl::initializePage()
222 {
223     Page::PageClients pageClients;
224     fillWithEmptyClients(pageClients);
225     m_chromeClient = adoptPtr(new PagePopupChromeClient(this));
226     pageClients.chromeClient = m_chromeClient.get();
227 
228     m_page = adoptPtrWillBeNoop(new Page(pageClients));
229     m_page->settings().setScriptEnabled(true);
230     m_page->settings().setAllowScriptsToCloseWindows(true);
231     m_page->setDeviceScaleFactor(m_webView->deviceScaleFactor());
232     m_page->settings().setDeviceSupportsTouch(m_webView->page()->settings().deviceSupportsTouch());
233     // FIXME: Should we support enabling a11y while a popup is shown?
234     m_page->settings().setAccessibilityEnabled(m_webView->page()->settings().accessibilityEnabled());
235 
236     provideContextFeaturesTo(*m_page, adoptPtr(new PagePopupFeaturesClient()));
237     static FrameLoaderClient* emptyFrameLoaderClient = new EmptyFrameLoaderClient();
238     RefPtrWillBeRawPtr<LocalFrame> frame = LocalFrame::create(emptyFrameLoaderClient, &m_page->frameHost(), 0);
239     frame->setPagePopupOwner(m_popupClient->ownerElement());
240     frame->setView(FrameView::create(frame.get()));
241     frame->init();
242     frame->view()->resize(m_popupClient->contentSize());
243     frame->view()->setTransparent(false);
244     if (AXObjectCache* cache = m_popupClient->ownerElement().document().existingAXObjectCache())
245         cache->childrenChanged(&m_popupClient->ownerElement());
246 
247     ASSERT(frame->domWindow());
248     DOMWindowPagePopup::install(*frame->domWindow(), m_popupClient);
249     ASSERT(m_popupClient->ownerElement().document().existingAXObjectCache() == frame->document()->existingAXObjectCache());
250 
251     RefPtr<SharedBuffer> data = SharedBuffer::create();
252     m_popupClient->writeDocument(data.get());
253     frame->loader().load(FrameLoadRequest(0, blankURL(), SubstituteData(data, "text/html", "UTF-8", KURL(), ForceSynchronousLoad)));
254     return true;
255 }
256 
destroyPage()257 void WebPagePopupImpl::destroyPage()
258 {
259     if (!m_page)
260         return;
261 
262     m_page->willBeDestroyed();
263     m_page.clear();
264 }
265 
rootAXObject()266 AXObject* WebPagePopupImpl::rootAXObject()
267 {
268     if (!m_page || !m_page->mainFrame())
269         return 0;
270     Document* document = toLocalFrame(m_page->mainFrame())->document();
271     if (!document)
272         return 0;
273     AXObjectCache* cache = document->axObjectCache();
274     ASSERT(cache);
275     return cache->getOrCreate(document->view());
276 }
277 
setRootGraphicsLayer(GraphicsLayer * layer)278 void WebPagePopupImpl::setRootGraphicsLayer(GraphicsLayer* layer)
279 {
280     m_rootGraphicsLayer = layer;
281     m_rootLayer = layer ? layer->platformLayer() : 0;
282 
283     setIsAcceleratedCompositingActive(layer);
284     if (m_layerTreeView) {
285         if (m_rootLayer) {
286             m_layerTreeView->setRootLayer(*m_rootLayer);
287         } else {
288             m_layerTreeView->clearRootLayer();
289         }
290     }
291 }
292 
setIsAcceleratedCompositingActive(bool enter)293 void WebPagePopupImpl::setIsAcceleratedCompositingActive(bool enter)
294 {
295     if (m_isAcceleratedCompositingActive == enter)
296         return;
297 
298     if (!enter) {
299         m_isAcceleratedCompositingActive = false;
300     } else if (m_layerTreeView) {
301         m_isAcceleratedCompositingActive = true;
302     } else {
303         TRACE_EVENT0("blink", "WebPagePopupImpl::setIsAcceleratedCompositingActive(true)");
304 
305         m_widgetClient->initializeLayerTreeView();
306         m_layerTreeView = m_widgetClient->layerTreeView();
307         if (m_layerTreeView) {
308             m_layerTreeView->setVisible(true);
309             m_isAcceleratedCompositingActive = true;
310             m_layerTreeView->setDeviceScaleFactor(m_widgetClient->deviceScaleFactor());
311         } else {
312             m_isAcceleratedCompositingActive = false;
313         }
314     }
315 }
316 
size()317 WebSize WebPagePopupImpl::size()
318 {
319     return m_popupClient->contentSize();
320 }
321 
beginFrame(const WebBeginFrameArgs & frameTime)322 void WebPagePopupImpl::beginFrame(const WebBeginFrameArgs& frameTime)
323 {
324     // FIXME: This should use frameTime.lastFrameTimeMonotonic but doing so
325     // breaks tests.
326     PageWidgetDelegate::animate(m_page.get(), monotonicallyIncreasingTime());
327 }
328 
willCloseLayerTreeView()329 void WebPagePopupImpl::willCloseLayerTreeView()
330 {
331     setIsAcceleratedCompositingActive(false);
332     m_layerTreeView = 0;
333 }
334 
layout()335 void WebPagePopupImpl::layout()
336 {
337     PageWidgetDelegate::layout(m_page.get());
338 }
339 
paint(WebCanvas * canvas,const WebRect & rect)340 void WebPagePopupImpl::paint(WebCanvas* canvas, const WebRect& rect)
341 {
342     if (!m_closing)
343         PageWidgetDelegate::paint(m_page.get(), 0, canvas, rect, PageWidgetDelegate::Opaque);
344 }
345 
resize(const WebSize & newSize)346 void WebPagePopupImpl::resize(const WebSize& newSize)
347 {
348     m_windowRectInScreen = WebRect(m_windowRectInScreen.x, m_windowRectInScreen.y, newSize.width, newSize.height);
349     m_widgetClient->setWindowRect(m_windowRectInScreen);
350 
351     if (m_page)
352         toLocalFrame(m_page->mainFrame())->view()->resize(newSize);
353     m_widgetClient->didInvalidateRect(WebRect(0, 0, newSize.width, newSize.height));
354 }
355 
handleKeyEvent(const WebKeyboardEvent &)356 bool WebPagePopupImpl::handleKeyEvent(const WebKeyboardEvent&)
357 {
358     // The main WebView receives key events and forward them to this via handleKeyEvent().
359     ASSERT_NOT_REACHED();
360     return false;
361 }
362 
handleCharEvent(const WebKeyboardEvent &)363 bool WebPagePopupImpl::handleCharEvent(const WebKeyboardEvent&)
364 {
365     // The main WebView receives key events and forward them to this via handleKeyEvent().
366     ASSERT_NOT_REACHED();
367     return false;
368 }
369 
handleGestureEvent(const WebGestureEvent & event)370 bool WebPagePopupImpl::handleGestureEvent(const WebGestureEvent& event)
371 {
372     if (m_closing || !m_page || !m_page->mainFrame() || !toLocalFrame(m_page->mainFrame())->view())
373         return false;
374     LocalFrame& frame = *toLocalFrame(m_page->mainFrame());
375     return frame.eventHandler().handleGestureEvent(PlatformGestureEventBuilder(frame.view(), event));
376 }
377 
handleInputEvent(const WebInputEvent & event)378 bool WebPagePopupImpl::handleInputEvent(const WebInputEvent& event)
379 {
380     if (m_closing)
381         return false;
382     return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, event);
383 }
384 
handleKeyEvent(const PlatformKeyboardEvent & event)385 bool WebPagePopupImpl::handleKeyEvent(const PlatformKeyboardEvent& event)
386 {
387     if (m_closing || !m_page->mainFrame() || !toLocalFrame(m_page->mainFrame())->view())
388         return false;
389     return toLocalFrame(m_page->mainFrame())->eventHandler().keyEvent(event);
390 }
391 
setFocus(bool enable)392 void WebPagePopupImpl::setFocus(bool enable)
393 {
394     if (!m_page)
395         return;
396     m_page->focusController().setFocused(enable);
397     if (enable)
398         m_page->focusController().setActive(true);
399 }
400 
close()401 void WebPagePopupImpl::close()
402 {
403     m_closing = true;
404     destroyPage(); // In case closePopup() was not called.
405     m_widgetClient = 0;
406     deref();
407 }
408 
closePopup()409 void WebPagePopupImpl::closePopup()
410 {
411     if (m_page) {
412         toLocalFrame(m_page->mainFrame())->loader().stopAllLoaders();
413         ASSERT(m_page->mainFrame()->domWindow());
414         DOMWindowPagePopup::uninstall(*m_page->mainFrame()->domWindow());
415     }
416     m_closing = true;
417 
418     destroyPage();
419 
420     // m_widgetClient might be 0 because this widget might be already closed.
421     if (m_widgetClient) {
422         // closeWidgetSoon() will call this->close() later.
423         m_widgetClient->closeWidgetSoon();
424     }
425 
426     m_popupClient->didClosePopup();
427 }
428 
compositeAndReadbackAsync(WebCompositeAndReadbackAsyncCallback * callback)429 void WebPagePopupImpl::compositeAndReadbackAsync(WebCompositeAndReadbackAsyncCallback* callback)
430 {
431     ASSERT(isAcceleratedCompositingActive());
432     m_layerTreeView->compositeAndReadbackAsync(callback);
433 }
434 
positionRelativeToOwner()435 WebPoint WebPagePopupImpl::positionRelativeToOwner()
436 {
437     WebRect windowRect = m_webView->client()->rootWindowRect();
438     return WebPoint(m_windowRectInScreen.x - windowRect.x, m_windowRectInScreen.y - windowRect.y);
439 }
440 
441 // WebPagePopup ----------------------------------------------------------------
442 
create(WebWidgetClient * client)443 WebPagePopup* WebPagePopup::create(WebWidgetClient* client)
444 {
445     if (!client)
446         CRASH();
447     // A WebPagePopupImpl instance usually has two references.
448     //  - One owned by the instance itself. It represents the visible widget.
449     //  - One owned by a WebViewImpl. It's released when the WebViewImpl ask the
450     //    WebPagePopupImpl to close.
451     // We need them because the closing operation is asynchronous and the widget
452     // can be closed while the WebViewImpl is unaware of it.
453     return adoptRef(new WebPagePopupImpl(client)).leakRef();
454 }
455 
456 } // namespace blink
457