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 "WebInputEventConversion.h" 35 #include "WebSettingsImpl.h" 36 #include "WebViewClient.h" 37 #include "WebViewImpl.h" 38 #include "WebWidgetClient.h" 39 #include "core/dom/ContextFeatures.h" 40 #include "core/loader/DocumentLoader.h" 41 #include "core/loader/EmptyClients.h" 42 #include "core/page/Chrome.h" 43 #include "core/page/DOMWindowPagePopup.h" 44 #include "core/page/EventHandler.h" 45 #include "core/page/FocusController.h" 46 #include "core/frame/Frame.h" 47 #include "core/frame/FrameView.h" 48 #include "core/page/Page.h" 49 #include "core/page/PagePopupClient.h" 50 #include "core/frame/Settings.h" 51 #include "public/platform/WebCursorInfo.h" 52 53 using namespace WebCore; 54 using namespace std; 55 56 namespace blink { 57 58 class PagePopupChromeClient : public EmptyChromeClient { 59 WTF_MAKE_NONCOPYABLE(PagePopupChromeClient); 60 WTF_MAKE_FAST_ALLOCATED; 61 62 public: 63 explicit PagePopupChromeClient(WebPagePopupImpl* popup) 64 : m_popup(popup) 65 { 66 ASSERT(m_popup->widgetClient()); 67 } 68 69 private: 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(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 m_popup->widgetClient()->scheduleAnimation(); 113 } 114 115 virtual WebScreenInfo screenInfo() const OVERRIDE 116 { 117 return m_popup->m_webView->client() ? m_popup->m_webView->client()->screenInfo() : WebScreenInfo(); 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 void setCursor(const WebCore::Cursor& cursor) OVERRIDE 131 { 132 if (m_popup->m_webView->client()) 133 m_popup->m_webView->client()->didChangeCursor(WebCursorInfo(cursor)); 134 } 135 136 virtual void needTouchEvents(bool needsTouchEvents) OVERRIDE 137 { 138 m_popup->widgetClient()->hasTouchEventHandlers(needsTouchEvents); 139 } 140 141 WebPagePopupImpl* m_popup; 142 }; 143 144 class PagePopupFeaturesClient : public ContextFeaturesClient { 145 virtual bool isEnabled(Document*, ContextFeatures::FeatureType, bool) OVERRIDE; 146 }; 147 148 bool PagePopupFeaturesClient::isEnabled(Document*, ContextFeatures::FeatureType type, bool defaultValue) 149 { 150 if (type == ContextFeatures::PagePopup) 151 return true; 152 return defaultValue; 153 } 154 155 // WebPagePopupImpl ---------------------------------------------------------------- 156 157 WebPagePopupImpl::WebPagePopupImpl(WebWidgetClient* client) 158 : m_widgetClient(client) 159 , m_closing(false) 160 { 161 ASSERT(client); 162 } 163 164 WebPagePopupImpl::~WebPagePopupImpl() 165 { 166 ASSERT(!m_page); 167 } 168 169 bool WebPagePopupImpl::initialize(WebViewImpl* webView, PagePopupClient* popupClient, const IntRect&) 170 { 171 ASSERT(webView); 172 ASSERT(popupClient); 173 m_webView = webView; 174 m_popupClient = popupClient; 175 176 resize(m_popupClient->contentSize()); 177 178 if (!initializePage()) 179 return false; 180 m_widgetClient->show(WebNavigationPolicy()); 181 setFocus(true); 182 183 return true; 184 } 185 186 bool WebPagePopupImpl::initializePage() 187 { 188 Page::PageClients pageClients; 189 fillWithEmptyClients(pageClients); 190 m_chromeClient = adoptPtr(new PagePopupChromeClient(this)); 191 pageClients.chromeClient = m_chromeClient.get(); 192 193 m_page = adoptPtr(new Page(pageClients)); 194 m_page->settings().setScriptEnabled(true); 195 m_page->settings().setAllowScriptsToCloseWindows(true); 196 m_page->setDeviceScaleFactor(m_webView->deviceScaleFactor()); 197 m_page->settings().setDeviceSupportsTouch(m_webView->page()->settings().deviceSupportsTouch()); 198 199 static ContextFeaturesClient* pagePopupFeaturesClient = new PagePopupFeaturesClient(); 200 provideContextFeaturesTo(m_page.get(), pagePopupFeaturesClient); 201 static FrameLoaderClient* emptyFrameLoaderClient = new EmptyFrameLoaderClient(); 202 RefPtr<Frame> frame = Frame::create(FrameInit::create(0, m_page.get(), emptyFrameLoaderClient)); 203 frame->setView(FrameView::create(frame.get())); 204 frame->init(); 205 frame->view()->resize(m_popupClient->contentSize()); 206 frame->view()->setTransparent(false); 207 208 DOMWindowPagePopup::install(frame->domWindow(), m_popupClient); 209 210 DocumentWriter* writer = frame->loader().activeDocumentLoader()->beginWriting("text/html", "UTF-8"); 211 m_popupClient->writeDocument(*writer); 212 frame->loader().activeDocumentLoader()->endWriting(writer); 213 return true; 214 } 215 216 void WebPagePopupImpl::destroyPage() 217 { 218 if (!m_page) 219 return; 220 221 if (m_page->mainFrame()) 222 m_page->mainFrame()->loader().frameDetached(); 223 224 m_page.clear(); 225 } 226 227 WebSize WebPagePopupImpl::size() 228 { 229 return m_popupClient->contentSize(); 230 } 231 232 void WebPagePopupImpl::animate(double) 233 { 234 PageWidgetDelegate::animate(m_page.get(), monotonicallyIncreasingTime()); 235 } 236 237 void WebPagePopupImpl::layout() 238 { 239 PageWidgetDelegate::layout(m_page.get()); 240 } 241 242 void WebPagePopupImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions) 243 { 244 if (!m_closing) 245 PageWidgetDelegate::paint(m_page.get(), 0, canvas, rect, PageWidgetDelegate::Opaque); 246 } 247 248 void WebPagePopupImpl::resize(const WebSize& newSize) 249 { 250 m_windowRectInScreen = WebRect(m_windowRectInScreen.x, m_windowRectInScreen.y, newSize.width, newSize.height); 251 m_widgetClient->setWindowRect(m_windowRectInScreen); 252 253 if (m_page) 254 m_page->mainFrame()->view()->resize(newSize); 255 m_widgetClient->didInvalidateRect(WebRect(0, 0, newSize.width, newSize.height)); 256 } 257 258 bool WebPagePopupImpl::handleKeyEvent(const WebKeyboardEvent&) 259 { 260 // The main WebView receives key events and forward them to this via handleKeyEvent(). 261 ASSERT_NOT_REACHED(); 262 return false; 263 } 264 265 bool WebPagePopupImpl::handleCharEvent(const WebKeyboardEvent&) 266 { 267 // The main WebView receives key events and forward them to this via handleKeyEvent(). 268 ASSERT_NOT_REACHED(); 269 return false; 270 } 271 272 bool WebPagePopupImpl::handleGestureEvent(const WebGestureEvent& event) 273 { 274 if (m_closing || !m_page || !m_page->mainFrame() || !m_page->mainFrame()->view()) 275 return false; 276 Frame& frame = *m_page->mainFrame(); 277 return frame.eventHandler().handleGestureEvent(PlatformGestureEventBuilder(frame.view(), event)); 278 } 279 280 bool WebPagePopupImpl::handleInputEvent(const WebInputEvent& event) 281 { 282 if (m_closing) 283 return false; 284 return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, event); 285 } 286 287 bool WebPagePopupImpl::handleKeyEvent(const PlatformKeyboardEvent& event) 288 { 289 if (m_closing || !m_page->mainFrame() || !m_page->mainFrame()->view()) 290 return false; 291 return m_page->mainFrame()->eventHandler().keyEvent(event); 292 } 293 294 void WebPagePopupImpl::setFocus(bool enable) 295 { 296 if (!m_page) 297 return; 298 m_page->focusController().setFocused(enable); 299 if (enable) 300 m_page->focusController().setActive(true); 301 } 302 303 void WebPagePopupImpl::close() 304 { 305 m_closing = true; 306 destroyPage(); // In case closePopup() was not called. 307 m_widgetClient = 0; 308 deref(); 309 } 310 311 void WebPagePopupImpl::closePopup() 312 { 313 if (m_page) { 314 m_page->clearPageGroup(); 315 m_page->mainFrame()->loader().stopAllLoaders(); 316 DOMWindowPagePopup::uninstall(m_page->mainFrame()->domWindow()); 317 } 318 m_closing = true; 319 320 destroyPage(); 321 322 // m_widgetClient might be 0 because this widget might be already closed. 323 if (m_widgetClient) { 324 // closeWidgetSoon() will call this->close() later. 325 m_widgetClient->closeWidgetSoon(); 326 } 327 328 m_popupClient->didClosePopup(); 329 } 330 331 // WebPagePopup ---------------------------------------------------------------- 332 333 WebPagePopup* WebPagePopup::create(WebWidgetClient* client) 334 { 335 if (!client) 336 CRASH(); 337 // A WebPagePopupImpl instance usually has two references. 338 // - One owned by the instance itself. It represents the visible widget. 339 // - One owned by a WebViewImpl. It's released when the WebViewImpl ask the 340 // WebPagePopupImpl to close. 341 // We need them because the closing operation is asynchronous and the widget 342 // can be closed while the WebViewImpl is unaware of it. 343 return adoptRef(new WebPagePopupImpl(client)).leakRef(); 344 } 345 346 } // namespace blink 347