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