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 "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