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 "public/platform/WebCursorInfo.h" 48#include "public/web/WebViewClient.h" 49#include "public/web/WebWidgetClient.h" 50#include "web/WebInputEventConversion.h" 51#include "web/WebSettingsImpl.h" 52#include "web/WebViewImpl.h" 53 54using namespace WebCore; 55 56namespace blink { 57 58class PagePopupChromeClient : public EmptyChromeClient { 59 WTF_MAKE_NONCOPYABLE(PagePopupChromeClient); 60 WTF_MAKE_FAST_ALLOCATED; 61 62public: 63 explicit PagePopupChromeClient(WebPagePopupImpl* popup) 64 : m_popup(popup) 65 { 66 ASSERT(m_popup->widgetClient()); 67 } 68 69private: 70 virtual void closeWindowSoon() OVERRIDE 71 { 72 m_popup->closePopup(); 73 } 74 75 virtual FloatRect windowRect() OVERRIDE 76 { 77 return FloatRect(m_popup->m_windowRectInScreen.x, m_popup->m_windowRectInScreen.y, m_popup->m_windowRectInScreen.width, m_popup->m_windowRectInScreen.height); 78 } 79 80 virtual void setWindowRect(const FloatRect& rect) OVERRIDE 81 { 82 m_popup->m_windowRectInScreen = IntRect(rect); 83 m_popup->widgetClient()->setWindowRect(m_popup->m_windowRectInScreen); 84 } 85 86 virtual void addMessageToConsole(LocalFrame*, MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String&, const String&) OVERRIDE 87 { 88#ifndef NDEBUG 89 fprintf(stderr, "CONSOLE MESSSAGE:%u: %s\n", lineNumber, message.utf8().data()); 90#endif 91 } 92 93 virtual void invalidateContentsAndRootView(const IntRect& paintRect) OVERRIDE 94 { 95 if (paintRect.isEmpty()) 96 return; 97 m_popup->widgetClient()->didInvalidateRect(paintRect); 98 } 99 100 virtual void scroll(const IntSize& scrollDelta, const IntRect& scrollRect, const IntRect& clipRect) OVERRIDE 101 { 102 m_popup->widgetClient()->didScrollRect(scrollDelta.width(), scrollDelta.height(), intersection(scrollRect, clipRect)); 103 } 104 105 virtual void invalidateContentsForSlowScroll(const IntRect& updateRect) OVERRIDE 106 { 107 invalidateContentsAndRootView(updateRect); 108 } 109 110 virtual void scheduleAnimation() OVERRIDE 111 { 112 if (m_popup->isAcceleratedCompositingActive()) { 113 ASSERT(m_popup->m_layerTreeView); 114 m_popup->m_layerTreeView->setNeedsAnimate(); 115 return; 116 } 117 m_popup->widgetClient()->scheduleAnimation(); 118 } 119 120 virtual WebScreenInfo screenInfo() const OVERRIDE 121 { 122 return m_popup->m_webView->client() ? m_popup->m_webView->client()->screenInfo() : WebScreenInfo(); 123 } 124 125 virtual void* webView() const OVERRIDE 126 { 127 return m_popup->m_webView; 128 } 129 130 virtual FloatSize minimumWindowSize() const OVERRIDE 131 { 132 return FloatSize(0, 0); 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 virtual void needTouchEvents(bool needsTouchEvents) OVERRIDE 142 { 143 m_popup->widgetClient()->hasTouchEventHandlers(needsTouchEvents); 144 } 145 146 virtual GraphicsLayerFactory* graphicsLayerFactory() const OVERRIDE 147 { 148 return m_popup->m_webView->graphicsLayerFactory(); 149 } 150 151 virtual void attachRootGraphicsLayer(GraphicsLayer* graphicsLayer) OVERRIDE 152 { 153 m_popup->setRootGraphicsLayer(graphicsLayer); 154 } 155 156 WebPagePopupImpl* m_popup; 157}; 158 159class PagePopupFeaturesClient : public ContextFeaturesClient { 160 virtual bool isEnabled(Document*, ContextFeatures::FeatureType, bool) OVERRIDE; 161}; 162 163bool PagePopupFeaturesClient::isEnabled(Document*, ContextFeatures::FeatureType type, bool defaultValue) 164{ 165 if (type == ContextFeatures::PagePopup) 166 return true; 167 return defaultValue; 168} 169 170// WebPagePopupImpl ---------------------------------------------------------------- 171 172WebPagePopupImpl::WebPagePopupImpl(WebWidgetClient* client) 173 : m_widgetClient(client) 174 , m_closing(false) 175 , m_layerTreeView(0) 176 , m_rootLayer(0) 177 , m_rootGraphicsLayer(0) 178 , m_isAcceleratedCompositingActive(false) 179{ 180 ASSERT(client); 181} 182 183WebPagePopupImpl::~WebPagePopupImpl() 184{ 185 ASSERT(!m_page); 186} 187 188bool WebPagePopupImpl::initialize(WebViewImpl* webView, PagePopupClient* popupClient, const IntRect&) 189{ 190 ASSERT(webView); 191 ASSERT(popupClient); 192 m_webView = webView; 193 m_popupClient = popupClient; 194 195 resize(m_popupClient->contentSize()); 196 197 if (!initializePage()) 198 return false; 199 m_widgetClient->show(WebNavigationPolicy()); 200 setFocus(true); 201 202 return true; 203} 204 205bool WebPagePopupImpl::initializePage() 206{ 207 Page::PageClients pageClients; 208 fillWithEmptyClients(pageClients); 209 m_chromeClient = adoptPtr(new PagePopupChromeClient(this)); 210 pageClients.chromeClient = m_chromeClient.get(); 211 212 m_page = adoptPtrWillBeNoop(new Page(pageClients)); 213 m_page->settings().setScriptEnabled(true); 214 m_page->settings().setAllowScriptsToCloseWindows(true); 215 m_page->setDeviceScaleFactor(m_webView->deviceScaleFactor()); 216 m_page->settings().setDeviceSupportsTouch(m_webView->page()->settings().deviceSupportsTouch()); 217 218 provideContextFeaturesTo(*m_page, adoptPtr(new PagePopupFeaturesClient())); 219 static FrameLoaderClient* emptyFrameLoaderClient = new EmptyFrameLoaderClient(); 220 RefPtr<LocalFrame> frame = LocalFrame::create(emptyFrameLoaderClient, &m_page->frameHost(), 0); 221 frame->setView(FrameView::create(frame.get())); 222 frame->init(); 223 frame->view()->resize(m_popupClient->contentSize()); 224 frame->view()->setTransparent(false); 225 226 ASSERT(frame->domWindow()); 227 DOMWindowPagePopup::install(*frame->domWindow(), m_popupClient); 228 229 RefPtr<SharedBuffer> data = SharedBuffer::create(); 230 m_popupClient->writeDocument(data.get()); 231 frame->loader().load(FrameLoadRequest(0, blankURL(), SubstituteData(data, "text/html", "UTF-8", KURL(), ForceSynchronousLoad))); 232 return true; 233} 234 235void WebPagePopupImpl::destroyPage() 236{ 237 if (!m_page) 238 return; 239 240 m_page->willBeDestroyed(); 241 m_page.clear(); 242} 243 244void WebPagePopupImpl::setRootGraphicsLayer(GraphicsLayer* layer) 245{ 246 m_rootGraphicsLayer = layer; 247 m_rootLayer = layer ? layer->platformLayer() : 0; 248 249 setIsAcceleratedCompositingActive(layer); 250 if (m_layerTreeView) { 251 if (m_rootLayer) { 252 m_layerTreeView->setRootLayer(*m_rootLayer); 253 } else { 254 m_layerTreeView->clearRootLayer(); 255 } 256 } 257} 258 259void WebPagePopupImpl::setIsAcceleratedCompositingActive(bool enter) 260{ 261 if (m_isAcceleratedCompositingActive == enter) 262 return; 263 264 if (!enter) { 265 m_isAcceleratedCompositingActive = false; 266 } else if (m_layerTreeView) { 267 m_isAcceleratedCompositingActive = true; 268 } else { 269 TRACE_EVENT0("webkit", "WebPagePopupImpl::setIsAcceleratedCompositingActive(true)"); 270 271 m_widgetClient->initializeLayerTreeView(); 272 m_layerTreeView = m_widgetClient->layerTreeView(); 273 if (m_layerTreeView) { 274 m_layerTreeView->setVisible(true); 275 m_isAcceleratedCompositingActive = true; 276 m_layerTreeView->setDeviceScaleFactor(m_widgetClient->deviceScaleFactor()); 277 } else { 278 m_isAcceleratedCompositingActive = false; 279 } 280 } 281} 282 283WebSize WebPagePopupImpl::size() 284{ 285 return m_popupClient->contentSize(); 286} 287 288void WebPagePopupImpl::animate(double) 289{ 290 PageWidgetDelegate::animate(m_page.get(), monotonicallyIncreasingTime()); 291} 292 293void WebPagePopupImpl::willCloseLayerTreeView() 294{ 295 setIsAcceleratedCompositingActive(false); 296 m_layerTreeView = 0; 297} 298 299void WebPagePopupImpl::layout() 300{ 301 PageWidgetDelegate::layout(m_page.get()); 302} 303 304void WebPagePopupImpl::paint(WebCanvas* canvas, const WebRect& rect) 305{ 306 if (!m_closing) 307 PageWidgetDelegate::paint(m_page.get(), 0, canvas, rect, PageWidgetDelegate::Opaque); 308} 309 310void WebPagePopupImpl::resize(const WebSize& newSize) 311{ 312 m_windowRectInScreen = WebRect(m_windowRectInScreen.x, m_windowRectInScreen.y, newSize.width, newSize.height); 313 m_widgetClient->setWindowRect(m_windowRectInScreen); 314 315 if (m_page) 316 toLocalFrame(m_page->mainFrame())->view()->resize(newSize); 317 m_widgetClient->didInvalidateRect(WebRect(0, 0, newSize.width, newSize.height)); 318} 319 320bool WebPagePopupImpl::handleKeyEvent(const WebKeyboardEvent&) 321{ 322 // The main WebView receives key events and forward them to this via handleKeyEvent(). 323 ASSERT_NOT_REACHED(); 324 return false; 325} 326 327bool WebPagePopupImpl::handleCharEvent(const WebKeyboardEvent&) 328{ 329 // The main WebView receives key events and forward them to this via handleKeyEvent(). 330 ASSERT_NOT_REACHED(); 331 return false; 332} 333 334bool WebPagePopupImpl::handleGestureEvent(const WebGestureEvent& event) 335{ 336 if (m_closing || !m_page || !m_page->mainFrame() || !toLocalFrame(m_page->mainFrame())->view()) 337 return false; 338 LocalFrame& frame = *toLocalFrame(m_page->mainFrame()); 339 return frame.eventHandler().handleGestureEvent(PlatformGestureEventBuilder(frame.view(), event)); 340} 341 342bool WebPagePopupImpl::handleInputEvent(const WebInputEvent& event) 343{ 344 if (m_closing) 345 return false; 346 return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, event); 347} 348 349bool WebPagePopupImpl::handleKeyEvent(const PlatformKeyboardEvent& event) 350{ 351 if (m_closing || !m_page->mainFrame() || !toLocalFrame(m_page->mainFrame())->view()) 352 return false; 353 return toLocalFrame(m_page->mainFrame())->eventHandler().keyEvent(event); 354} 355 356void WebPagePopupImpl::setFocus(bool enable) 357{ 358 if (!m_page) 359 return; 360 m_page->focusController().setFocused(enable); 361 if (enable) 362 m_page->focusController().setActive(true); 363} 364 365void WebPagePopupImpl::close() 366{ 367 m_closing = true; 368 destroyPage(); // In case closePopup() was not called. 369 m_widgetClient = 0; 370 deref(); 371} 372 373void WebPagePopupImpl::closePopup() 374{ 375 if (m_page) { 376 toLocalFrame(m_page->mainFrame())->loader().stopAllLoaders(); 377 ASSERT(m_page->mainFrame()->domWindow()); 378 DOMWindowPagePopup::uninstall(*m_page->mainFrame()->domWindow()); 379 } 380 m_closing = true; 381 382 destroyPage(); 383 384 // m_widgetClient might be 0 because this widget might be already closed. 385 if (m_widgetClient) { 386 // closeWidgetSoon() will call this->close() later. 387 m_widgetClient->closeWidgetSoon(); 388 } 389 390 m_popupClient->didClosePopup(); 391} 392 393// WebPagePopup ---------------------------------------------------------------- 394 395WebPagePopup* WebPagePopup::create(WebWidgetClient* client) 396{ 397 if (!client) 398 CRASH(); 399 // A WebPagePopupImpl instance usually has two references. 400 // - One owned by the instance itself. It represents the visible widget. 401 // - One owned by a WebViewImpl. It's released when the WebViewImpl ask the 402 // WebPagePopupImpl to close. 403 // We need them because the closing operation is asynchronous and the widget 404 // can be closed while the WebViewImpl is unaware of it. 405 return adoptRef(new WebPagePopupImpl(client)).leakRef(); 406} 407 408} // namespace blink 409