Home | History | Annotate | Download | only in web
      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 
     54 using namespace WebCore;
     55 using namespace std;
     56 
     57 namespace WebKit {
     58 
     59 class PagePopupChromeClient : public EmptyChromeClient {
     60     WTF_MAKE_NONCOPYABLE(PagePopupChromeClient);
     61     WTF_MAKE_FAST_ALLOCATED;
     62 
     63 public:
     64     explicit PagePopupChromeClient(WebPagePopupImpl* popup)
     65         : m_popup(popup)
     66     {
     67         ASSERT(m_popup->widgetClient());
     68     }
     69 
     70 private:
     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 
    148 class PagePopupFeaturesClient : public ContextFeaturesClient {
    149     virtual bool isEnabled(Document*, ContextFeatures::FeatureType, bool) OVERRIDE;
    150 };
    151 
    152 bool 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 
    161 WebPagePopupImpl::WebPagePopupImpl(WebWidgetClient* client)
    162     : m_widgetClient(client)
    163     , m_closing(false)
    164 {
    165     ASSERT(client);
    166 }
    167 
    168 WebPagePopupImpl::~WebPagePopupImpl()
    169 {
    170     ASSERT(!m_page);
    171 }
    172 
    173 bool 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 
    190 bool 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 
    223 void 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 
    234 WebSize WebPagePopupImpl::size()
    235 {
    236     return m_popupClient->contentSize();
    237 }
    238 
    239 void WebPagePopupImpl::animate(double)
    240 {
    241     PageWidgetDelegate::animate(m_page.get(), monotonicallyIncreasingTime());
    242 }
    243 
    244 void WebPagePopupImpl::layout()
    245 {
    246     PageWidgetDelegate::layout(m_page.get());
    247 }
    248 
    249 void 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 
    255 void 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 
    265 bool 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 
    272 bool 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 
    279 bool 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 
    287 bool WebPagePopupImpl::handleInputEvent(const WebInputEvent& event)
    288 {
    289     if (m_closing)
    290         return false;
    291     return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, event);
    292 }
    293 
    294 bool 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 
    301 void 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 
    310 void WebPagePopupImpl::close()
    311 {
    312     m_closing = true;
    313     destroyPage(); // In case closePopup() was not called.
    314     m_widgetClient = 0;
    315     deref();
    316 }
    317 
    318 void 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 
    341 WebPagePopup* 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