2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "web/WebPagePopupImpl.h"
34 #include "core/dom/ContextFeatures.h"
35 #include "core/frame/FrameHost.h"
36 #include "core/frame/FrameView.h"
37 #include "core/frame/LocalFrame.h"
38 #include "core/frame/Settings.h"
39 #include "core/frame/VisualViewport.h"
40 #include "core/input/EventHandler.h"
41 #include "core/layout/LayoutView.h"
42 #include "core/loader/EmptyClients.h"
43 #include "core/loader/FrameLoadRequest.h"
44 #include "core/page/DOMWindowPagePopup.h"
45 #include "core/page/FocusController.h"
46 #include "core/page/Page.h"
47 #include "core/page/PagePopupClient.h"
48 #include "modules/accessibility/AXObject.h"
49 #include "modules/accessibility/AXObjectCacheImpl.h"
50 #include "platform/EventDispatchForbiddenScope.h"
51 #include "platform/LayoutTestSupport.h"
52 #include "platform/ScriptForbiddenScope.h"
53 #include "platform/TraceEvent.h"
54 #include "platform/heap/Handle.h"
55 #include "public/platform/WebCompositeAndReadbackAsyncCallback.h"
56 #include "public/platform/WebCursorInfo.h"
57 #include "public/web/WebAXObject.h"
58 #include "public/web/WebFrameClient.h"
59 #include "public/web/WebViewClient.h"
60 #include "public/web/WebWidgetClient.h"
61 #include "web/WebInputEventConversion.h"
62 #include "web/WebLocalFrameImpl.h"
63 #include "web/WebSettingsImpl.h"
64 #include "web/WebViewImpl.h"
68 class PagePopupChromeClient final
: public EmptyChromeClient
{
70 static PassOwnPtrWillBeRawPtr
<PagePopupChromeClient
> create(WebPagePopupImpl
* popup
)
72 return adoptPtrWillBeNoop(new PagePopupChromeClient(popup
));
75 void setWindowRect(const IntRect
& rect
) override
77 m_popup
->m_windowRectInScreen
= rect
;
78 m_popup
->widgetClient()->setWindowRect(m_popup
->m_windowRectInScreen
);
82 explicit PagePopupChromeClient(WebPagePopupImpl
* popup
)
85 ASSERT(m_popup
->widgetClient());
88 void closeWindowSoon() override
90 m_popup
->closePopup();
93 IntRect
windowRect() override
95 return IntRect(m_popup
->m_windowRectInScreen
.x
, m_popup
->m_windowRectInScreen
.y
, m_popup
->m_windowRectInScreen
.width
, m_popup
->m_windowRectInScreen
.height
);
98 IntRect
viewportToScreen(const IntRect
& rect
) const override
100 IntRect
rectInScreen(rect
);
101 rectInScreen
.move(m_popup
->m_windowRectInScreen
.x
, m_popup
->m_windowRectInScreen
.y
);
105 void addMessageToConsole(LocalFrame
*, MessageSource
, MessageLevel
, const String
& message
, unsigned lineNumber
, const String
&, const String
&) override
108 fprintf(stderr
, "CONSOLE MESSSAGE:%u: %s\n", lineNumber
, message
.utf8().data());
112 void invalidateRect(const IntRect
& paintRect
) override
114 if (!paintRect
.isEmpty())
115 m_popup
->widgetClient()->didInvalidateRect(paintRect
);
118 void scheduleAnimation() override
120 // Calling scheduleAnimation on m_webView so WebTestProxy will call beginFrame.
121 if (LayoutTestSupport::isRunningLayoutTest())
122 m_popup
->m_webView
->scheduleAnimation();
124 if (m_popup
->isAcceleratedCompositingActive()) {
125 ASSERT(m_popup
->m_layerTreeView
);
126 m_popup
->m_layerTreeView
->setNeedsCompositorUpdate();
129 m_popup
->m_widgetClient
->scheduleAnimation();
132 WebScreenInfo
screenInfo() const override
134 return m_popup
->m_webView
->client() ? m_popup
->m_webView
->client()->screenInfo() : WebScreenInfo();
137 void* webView() const override
139 return m_popup
->m_webView
;
142 IntSize
minimumWindowSize() const override
144 return IntSize(0, 0);
147 void setCursor(const Cursor
& cursor
) override
149 if (m_popup
->m_webView
->client())
150 m_popup
->m_webView
->client()->didChangeCursor(WebCursorInfo(cursor
));
153 void needTouchEvents(bool needsTouchEvents
) override
155 m_popup
->widgetClient()->hasTouchEventHandlers(needsTouchEvents
);
158 GraphicsLayerFactory
* graphicsLayerFactory() const override
160 return m_popup
->m_webView
->graphicsLayerFactory();
163 void attachRootGraphicsLayer(GraphicsLayer
* graphicsLayer
, LocalFrame
* localRoot
) override
165 m_popup
->setRootGraphicsLayer(graphicsLayer
);
168 void postAccessibilityNotification(AXObject
* obj
, AXObjectCache::AXNotification notification
) override
170 WebLocalFrameImpl
* frame
= WebLocalFrameImpl::fromFrame(m_popup
->m_popupClient
->ownerElement().document().frame());
171 if (obj
&& frame
&& frame
->client())
172 frame
->client()->postAccessibilityEvent(WebAXObject(obj
), static_cast<WebAXEvent
>(notification
));
175 void setToolTip(const String
& tooltipText
, TextDirection dir
) override
177 if (m_popup
->widgetClient())
178 m_popup
->widgetClient()->setToolTipText(tooltipText
, toWebTextDirection(dir
));
181 WebPagePopupImpl
* m_popup
;
184 class PagePopupFeaturesClient
: public ContextFeaturesClient
{
185 bool isEnabled(Document
*, ContextFeatures::FeatureType
, bool) override
;
188 bool PagePopupFeaturesClient::isEnabled(Document
*, ContextFeatures::FeatureType type
, bool defaultValue
)
190 if (type
== ContextFeatures::PagePopup
)
195 // WebPagePopupImpl ----------------------------------------------------------------
197 WebPagePopupImpl::WebPagePopupImpl(WebWidgetClient
* client
)
198 : m_widgetClient(client
)
202 , m_rootGraphicsLayer(0)
203 , m_isAcceleratedCompositingActive(false)
208 WebPagePopupImpl::~WebPagePopupImpl()
213 bool WebPagePopupImpl::initialize(WebViewImpl
* webView
, PagePopupClient
* popupClient
)
218 m_popupClient
= popupClient
;
220 resize(m_popupClient
->contentSize());
222 if (!m_widgetClient
|| !initializePage())
224 m_widgetClient
->show(WebNavigationPolicy());
230 bool WebPagePopupImpl::initializePage()
232 Page::PageClients pageClients
;
233 fillWithEmptyClients(pageClients
);
234 m_chromeClient
= PagePopupChromeClient::create(this);
235 pageClients
.chromeClient
= m_chromeClient
.get();
237 m_page
= adoptPtrWillBeNoop(new Page(pageClients
));
238 m_page
->settings().setScriptEnabled(true);
239 m_page
->settings().setAllowScriptsToCloseWindows(true);
240 m_page
->setDeviceScaleFactor(m_webView
->deviceScaleFactor());
241 m_page
->settings().setDeviceSupportsTouch(m_webView
->page()->settings().deviceSupportsTouch());
242 // FIXME: Should we support enabling a11y while a popup is shown?
243 m_page
->settings().setAccessibilityEnabled(m_webView
->page()->settings().accessibilityEnabled());
244 m_page
->settings().setScrollAnimatorEnabled(m_webView
->page()->settings().scrollAnimatorEnabled());
246 provideContextFeaturesTo(*m_page
, adoptPtr(new PagePopupFeaturesClient()));
247 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent
<FrameLoaderClient
>, emptyFrameLoaderClient
, (EmptyFrameLoaderClient::create()));
248 RefPtrWillBeRawPtr
<LocalFrame
> frame
= LocalFrame::create(emptyFrameLoaderClient
.get(), &m_page
->frameHost(), 0);
249 frame
->setPagePopupOwner(m_popupClient
->ownerElement());
250 frame
->setView(FrameView::create(frame
.get()));
252 frame
->view()->resize(m_popupClient
->contentSize());
253 frame
->view()->setTransparent(false);
254 if (AXObjectCache
* cache
= m_popupClient
->ownerElement().document().existingAXObjectCache())
255 cache
->childrenChanged(&m_popupClient
->ownerElement());
257 ASSERT(frame
->localDOMWindow());
258 DOMWindowPagePopup::install(*frame
->localDOMWindow(), *this, m_popupClient
);
259 ASSERT(m_popupClient
->ownerElement().document().existingAXObjectCache() == frame
->document()->existingAXObjectCache());
261 RefPtr
<SharedBuffer
> data
= SharedBuffer::create();
262 m_popupClient
->writeDocument(data
.get());
263 frame
->loader().load(FrameLoadRequest(0, blankURL(), SubstituteData(data
, "text/html", "UTF-8", KURL(), ForceSynchronousLoad
)));
268 void WebPagePopupImpl::postMessage(const String
& message
)
272 ScriptForbiddenScope::AllowUserAgentScript allowScript
;
273 if (LocalDOMWindow
* window
= toLocalFrame(m_page
->mainFrame())->localDOMWindow())
274 window
->dispatchEvent(MessageEvent::create(message
));
277 void WebPagePopupImpl::destroyPage()
282 m_page
->willBeDestroyed();
286 AXObject
* WebPagePopupImpl::rootAXObject()
288 if (!m_page
|| !m_page
->mainFrame())
290 Document
* document
= toLocalFrame(m_page
->mainFrame())->document();
293 AXObjectCache
* cache
= document
->axObjectCache();
295 return toAXObjectCacheImpl(cache
)->getOrCreate(document
->layoutView());
298 void WebPagePopupImpl::setWindowRect(const IntRect
& rect
)
300 m_chromeClient
->setWindowRect(rect
);
303 void WebPagePopupImpl::setRootGraphicsLayer(GraphicsLayer
* layer
)
305 m_rootGraphicsLayer
= layer
;
306 m_rootLayer
= layer
? layer
->platformLayer() : 0;
308 setIsAcceleratedCompositingActive(layer
);
309 if (m_layerTreeView
) {
311 m_layerTreeView
->setRootLayer(*m_rootLayer
);
313 m_layerTreeView
->clearRootLayer();
318 void WebPagePopupImpl::setIsAcceleratedCompositingActive(bool enter
)
320 if (m_isAcceleratedCompositingActive
== enter
)
324 m_isAcceleratedCompositingActive
= false;
325 } else if (m_layerTreeView
) {
326 m_isAcceleratedCompositingActive
= true;
328 TRACE_EVENT0("blink", "WebPagePopupImpl::setIsAcceleratedCompositingActive(true)");
330 m_widgetClient
->initializeLayerTreeView();
331 m_layerTreeView
= m_widgetClient
->layerTreeView();
332 if (m_layerTreeView
) {
333 m_layerTreeView
->setVisible(true);
334 m_isAcceleratedCompositingActive
= true;
335 m_layerTreeView
->setDeviceScaleFactor(m_widgetClient
->deviceScaleFactor());
337 m_isAcceleratedCompositingActive
= false;
342 WebSize
WebPagePopupImpl::size()
344 return m_popupClient
->contentSize();
347 void WebPagePopupImpl::beginFrame(const WebBeginFrameArgs
& frameTime
)
351 // FIXME: This should use frameTime.lastFrameTimeMonotonic but doing so
353 PageWidgetDelegate::animate(*m_page
, monotonicallyIncreasingTime(), *m_page
->deprecatedLocalMainFrame());
356 void WebPagePopupImpl::willCloseLayerTreeView()
358 setIsAcceleratedCompositingActive(false);
362 void WebPagePopupImpl::layout()
366 PageWidgetDelegate::layout(*m_page
, *m_page
->deprecatedLocalMainFrame());
369 void WebPagePopupImpl::paint(WebCanvas
* canvas
, const WebRect
& rect
)
372 PageWidgetDelegate::paint(*m_page
, canvas
, rect
, *m_page
->deprecatedLocalMainFrame());
375 void WebPagePopupImpl::resize(const WebSize
& newSize
)
377 m_windowRectInScreen
= WebRect(m_windowRectInScreen
.x
, m_windowRectInScreen
.y
, newSize
.width
, newSize
.height
);
378 m_widgetClient
->setWindowRect(m_windowRectInScreen
);
381 toLocalFrame(m_page
->mainFrame())->view()->resize(newSize
);
382 m_page
->frameHost().visualViewport().setSize(newSize
);
385 m_widgetClient
->didInvalidateRect(WebRect(0, 0, newSize
.width
, newSize
.height
));
388 bool WebPagePopupImpl::handleKeyEvent(const WebKeyboardEvent
& event
)
390 return handleKeyEvent(PlatformKeyboardEventBuilder(event
));
393 bool WebPagePopupImpl::handleCharEvent(const WebKeyboardEvent
& event
)
395 return handleKeyEvent(PlatformKeyboardEventBuilder(event
));
398 bool WebPagePopupImpl::handleGestureEvent(const WebGestureEvent
& event
)
400 if (m_closing
|| !m_page
|| !m_page
->mainFrame() || !toLocalFrame(m_page
->mainFrame())->view())
402 if (event
.type
== WebInputEvent::GestureTap
&& !isGestureEventInWindow(event
)) {
406 LocalFrame
& frame
= *toLocalFrame(m_page
->mainFrame());
407 return frame
.eventHandler().handleGestureEvent(PlatformGestureEventBuilder(frame
.view(), event
));
410 void WebPagePopupImpl::handleMouseDown(LocalFrame
& mainFrame
, const WebMouseEvent
& event
)
412 if (isMouseEventInWindow(event
))
413 PageWidgetEventHandler::handleMouseDown(mainFrame
, event
);
418 bool WebPagePopupImpl::handleMouseWheel(LocalFrame
& mainFrame
, const WebMouseWheelEvent
& event
)
420 if (isMouseEventInWindow(event
))
421 return PageWidgetEventHandler::handleMouseWheel(mainFrame
, event
);
426 bool WebPagePopupImpl::isMouseEventInWindow(const WebMouseEvent
& event
)
428 return IntRect(0, 0, m_windowRectInScreen
.width
, m_windowRectInScreen
.height
).contains(IntPoint(event
.x
, event
.y
));
431 bool WebPagePopupImpl::isGestureEventInWindow(const WebGestureEvent
& event
)
433 return IntRect(0, 0, m_windowRectInScreen
.width
, m_windowRectInScreen
.height
).contains(IntPoint(event
.x
, event
.y
));
436 bool WebPagePopupImpl::handleInputEvent(const WebInputEvent
& event
)
440 return PageWidgetDelegate::handleInputEvent(*this, event
, m_page
->deprecatedLocalMainFrame());
443 bool WebPagePopupImpl::handleKeyEvent(const PlatformKeyboardEvent
& event
)
445 if (m_closing
|| !m_page
->mainFrame() || !toLocalFrame(m_page
->mainFrame())->view())
447 return toLocalFrame(m_page
->mainFrame())->eventHandler().keyEvent(event
);
450 void WebPagePopupImpl::setFocus(bool enable
)
454 m_page
->focusController().setFocused(enable
);
456 m_page
->focusController().setActive(true);
459 void WebPagePopupImpl::close()
462 destroyPage(); // In case closePopup() was not called.
467 void WebPagePopupImpl::closePopup()
469 // This function can be called in EventDispatchForbiddenScope for the main
470 // document, and the following operations dispatch some events. It's safe
471 // because web authors can't listen the events.
472 EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents
;
475 toLocalFrame(m_page
->mainFrame())->loader().stopAllLoaders();
476 ASSERT(m_page
->deprecatedLocalMainFrame()->localDOMWindow());
477 DOMWindowPagePopup::uninstall(*m_page
->deprecatedLocalMainFrame()->localDOMWindow());
483 // m_widgetClient might be 0 because this widget might be already closed.
484 if (m_widgetClient
) {
485 // closeWidgetSoon() will call this->close() later.
486 m_widgetClient
->closeWidgetSoon();
489 m_popupClient
->didClosePopup();
492 LocalDOMWindow
* WebPagePopupImpl::window()
494 return m_page
->deprecatedLocalMainFrame()->localDOMWindow();
497 void WebPagePopupImpl::layoutAndPaintAsync(WebLayoutAndPaintAsyncCallback
* callback
)
499 m_layerTreeView
->layoutAndPaintAsync(callback
);
502 void WebPagePopupImpl::compositeAndReadbackAsync(WebCompositeAndReadbackAsyncCallback
* callback
)
504 ASSERT(isAcceleratedCompositingActive());
505 m_layerTreeView
->compositeAndReadbackAsync(callback
);
508 WebPoint
WebPagePopupImpl::positionRelativeToOwner()
510 WebRect windowRect
= m_webView
->client()->rootWindowRect();
511 return WebPoint(m_windowRectInScreen
.x
- windowRect
.x
, m_windowRectInScreen
.y
- windowRect
.y
);
514 void WebPagePopupImpl::cancel()
517 m_popupClient
->closePopup();
520 // WebPagePopup ----------------------------------------------------------------
522 WebPagePopup
* WebPagePopup::create(WebWidgetClient
* client
)
526 // A WebPagePopupImpl instance usually has two references.
527 // - One owned by the instance itself. It represents the visible widget.
528 // - One owned by a WebViewImpl. It's released when the WebViewImpl ask the
529 // WebPagePopupImpl to close.
530 // We need them because the closing operation is asynchronous and the widget
531 // can be closed while the WebViewImpl is unaware of it.
532 return adoptRef(new WebPagePopupImpl(client
)).leakRef();