Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (C) 2009 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/WebPopupMenuImpl.h"
     33 
     34 #include "core/frame/FrameView.h"
     35 #include "platform/Cursor.h"
     36 #include "platform/NotImplemented.h"
     37 #include "platform/PlatformGestureEvent.h"
     38 #include "platform/PlatformKeyboardEvent.h"
     39 #include "platform/PlatformMouseEvent.h"
     40 #include "platform/PlatformWheelEvent.h"
     41 #include "platform/geometry/IntRect.h"
     42 #include "platform/graphics/GraphicsContext.h"
     43 #include "platform/graphics/skia/SkiaUtils.h"
     44 #include "platform/scroll/FramelessScrollView.h"
     45 #include "public/platform/Platform.h"
     46 #include "public/platform/WebCompositorSupport.h"
     47 #include "public/platform/WebContentLayer.h"
     48 #include "public/platform/WebFloatRect.h"
     49 #include "public/platform/WebLayerTreeView.h"
     50 #include "public/platform/WebRect.h"
     51 #include "public/web/WebInputEvent.h"
     52 #include "public/web/WebRange.h"
     53 #include "public/web/WebViewClient.h"
     54 #include "public/web/WebWidgetClient.h"
     55 #include "web/PopupContainer.h"
     56 #include "web/PopupMenuChromium.h"
     57 #include "web/WebInputEventConversion.h"
     58 #include <skia/ext/platform_canvas.h>
     59 
     60 using namespace WebCore;
     61 
     62 namespace blink {
     63 
     64 // WebPopupMenu ---------------------------------------------------------------
     65 
     66 WebPopupMenu* WebPopupMenu::create(WebWidgetClient* client)
     67 {
     68     // Pass the WebPopupMenuImpl's self-reference to the caller.
     69     return adoptRef(new WebPopupMenuImpl(client)).leakRef();
     70 }
     71 
     72 // WebWidget ------------------------------------------------------------------
     73 
     74 WebPopupMenuImpl::WebPopupMenuImpl(WebWidgetClient* client)
     75     : m_client(client)
     76     , m_layerTreeView(0)
     77     // Set to impossible point so we always get the first mouse position.
     78     , m_lastMousePosition(WebPoint(-1, -1))
     79     , m_widget(0)
     80 {
     81 }
     82 
     83 WebPopupMenuImpl::~WebPopupMenuImpl()
     84 {
     85     if (m_widget)
     86         m_widget->setClient(0);
     87 }
     88 
     89 void WebPopupMenuImpl::willCloseLayerTreeView()
     90 {
     91     m_layerTreeView = 0;
     92 }
     93 
     94 void WebPopupMenuImpl::initialize(FramelessScrollView* widget, const WebRect& bounds)
     95 {
     96     m_widget = widget;
     97     m_widget->setClient(this);
     98 
     99     if (!m_client)
    100         return;
    101     m_client->setWindowRect(bounds);
    102     m_client->show(WebNavigationPolicy()); // Policy is ignored.
    103 
    104     m_client->initializeLayerTreeView();
    105     m_layerTreeView = m_client->layerTreeView();
    106     if (m_layerTreeView) {
    107         m_layerTreeView->setVisible(true);
    108         m_layerTreeView->setDeviceScaleFactor(m_client->deviceScaleFactor());
    109         m_rootLayer = adoptPtr(Platform::current()->compositorSupport()->createContentLayer(this));
    110         m_rootLayer->layer()->setBounds(m_size);
    111         m_layerTreeView->setRootLayer(*m_rootLayer->layer());
    112     }
    113 }
    114 
    115 void WebPopupMenuImpl::handleMouseMove(const WebMouseEvent& event)
    116 {
    117     // Don't send mouse move messages if the mouse hasn't moved.
    118     if (event.x != m_lastMousePosition.x || event.y != m_lastMousePosition.y) {
    119         m_lastMousePosition = WebPoint(event.x, event.y);
    120         m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event));
    121 
    122         // We cannot call setToolTipText() in PopupContainer, because PopupContainer is in WebCore, and we cannot refer to WebKit from Webcore.
    123         PopupContainer* container = static_cast<PopupContainer*>(m_widget);
    124         client()->setToolTipText(container->getSelectedItemToolTip(), container->menuStyle().textDirection() == WebCore::RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight);
    125     }
    126 }
    127 
    128 void WebPopupMenuImpl::handleMouseLeave(const WebMouseEvent& event)
    129 {
    130     m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event));
    131 }
    132 
    133 void WebPopupMenuImpl::handleMouseDown(const WebMouseEvent& event)
    134 {
    135     m_widget->handleMouseDownEvent(PlatformMouseEventBuilder(m_widget, event));
    136 }
    137 
    138 void WebPopupMenuImpl::handleMouseUp(const WebMouseEvent& event)
    139 {
    140     mouseCaptureLost();
    141     m_widget->handleMouseReleaseEvent(PlatformMouseEventBuilder(m_widget, event));
    142 }
    143 
    144 void WebPopupMenuImpl::handleMouseWheel(const WebMouseWheelEvent& event)
    145 {
    146     m_widget->handleWheelEvent(PlatformWheelEventBuilder(m_widget, event));
    147 }
    148 
    149 bool WebPopupMenuImpl::handleGestureEvent(const WebGestureEvent& event)
    150 {
    151     return m_widget->handleGestureEvent(PlatformGestureEventBuilder(m_widget, event));
    152 }
    153 
    154 bool WebPopupMenuImpl::handleTouchEvent(const WebTouchEvent& event)
    155 {
    156 
    157     PlatformTouchEventBuilder touchEventBuilder(m_widget, event);
    158     bool defaultPrevented(m_widget->handleTouchEvent(touchEventBuilder));
    159     return defaultPrevented;
    160 }
    161 
    162 bool WebPopupMenuImpl::handleKeyEvent(const WebKeyboardEvent& event)
    163 {
    164     return m_widget->handleKeyEvent(PlatformKeyboardEventBuilder(event));
    165 }
    166 
    167 // WebWidget -------------------------------------------------------------------
    168 
    169 void WebPopupMenuImpl::close()
    170 {
    171     if (m_widget)
    172         m_widget->hide();
    173 
    174     m_client = 0;
    175 
    176     deref(); // Balances ref() from WebPopupMenu::create.
    177 }
    178 
    179 void WebPopupMenuImpl::willStartLiveResize()
    180 {
    181 }
    182 
    183 void WebPopupMenuImpl::resize(const WebSize& newSize)
    184 {
    185     if (m_size == newSize)
    186         return;
    187     m_size = newSize;
    188 
    189     if (m_widget) {
    190         IntRect newGeometry(0, 0, m_size.width, m_size.height);
    191         m_widget->setFrameRect(newGeometry);
    192     }
    193 
    194     if (m_client) {
    195         WebRect damagedRect(0, 0, m_size.width, m_size.height);
    196         m_client->didInvalidateRect(damagedRect);
    197     }
    198 
    199     if (m_rootLayer)
    200         m_rootLayer->layer()->setBounds(newSize);
    201 }
    202 
    203 void WebPopupMenuImpl::willEndLiveResize()
    204 {
    205 }
    206 
    207 void WebPopupMenuImpl::animate(double)
    208 {
    209 }
    210 
    211 void WebPopupMenuImpl::layout()
    212 {
    213 }
    214 
    215 void WebPopupMenuImpl::paintContents(WebCanvas* canvas, const WebRect& rect, bool, WebFloatRect&,
    216     WebContentLayerClient::GraphicsContextStatus contextStatus)
    217 {
    218     if (!m_widget)
    219         return;
    220 
    221     if (!rect.isEmpty()) {
    222         GraphicsContext context(canvas,
    223             contextStatus == WebContentLayerClient::GraphicsContextEnabled ? GraphicsContext::NothingDisabled : GraphicsContext::FullyDisabled);
    224         m_widget->paint(&context, rect);
    225     }
    226 }
    227 
    228 void WebPopupMenuImpl::paint(WebCanvas* canvas, const WebRect& rect)
    229 {
    230     if (!m_widget)
    231         return;
    232 
    233     if (!rect.isEmpty()) {
    234         GraphicsContext context(canvas);
    235         context.applyDeviceScaleFactor(m_client->deviceScaleFactor());
    236         m_widget->paint(&context, rect);
    237     }
    238 }
    239 
    240 void WebPopupMenuImpl::themeChanged()
    241 {
    242     notImplemented();
    243 }
    244 
    245 bool WebPopupMenuImpl::handleInputEvent(const WebInputEvent& inputEvent)
    246 {
    247     if (!m_widget)
    248         return false;
    249 
    250     // FIXME: WebKit seems to always return false on mouse events methods. For
    251     // now we'll assume it has processed them (as we are only interested in
    252     // whether keyboard events are processed).
    253     switch (inputEvent.type) {
    254     case WebInputEvent::MouseMove:
    255         handleMouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
    256         return true;
    257 
    258     case WebInputEvent::MouseLeave:
    259         handleMouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
    260         return true;
    261 
    262     case WebInputEvent::MouseWheel:
    263         handleMouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
    264         return true;
    265 
    266     case WebInputEvent::MouseDown:
    267         handleMouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
    268         return true;
    269 
    270     case WebInputEvent::MouseUp:
    271         handleMouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
    272         return true;
    273 
    274     // In Windows, RawKeyDown only has information about the physical key, but
    275     // for "selection", we need the information about the character the key
    276     // translated into. For English, the physical key value and the character
    277     // value are the same, hence, "selection" works for English. But for other
    278     // languages, such as Hebrew, the character value is different from the
    279     // physical key value. Thus, without accepting Char event type which
    280     // contains the key's character value, the "selection" won't work for
    281     // non-English languages, such as Hebrew.
    282     case WebInputEvent::RawKeyDown:
    283     case WebInputEvent::KeyDown:
    284     case WebInputEvent::KeyUp:
    285     case WebInputEvent::Char:
    286         return handleKeyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
    287 
    288     case WebInputEvent::TouchStart:
    289     case WebInputEvent::TouchMove:
    290     case WebInputEvent::TouchEnd:
    291     case WebInputEvent::TouchCancel:
    292         return handleTouchEvent(*static_cast<const WebTouchEvent*>(&inputEvent));
    293 
    294     case WebInputEvent::GestureScrollBegin:
    295     case WebInputEvent::GestureScrollEnd:
    296     case WebInputEvent::GestureScrollUpdate:
    297     case WebInputEvent::GestureScrollUpdateWithoutPropagation:
    298     case WebInputEvent::GestureFlingStart:
    299     case WebInputEvent::GestureFlingCancel:
    300     case WebInputEvent::GestureTap:
    301     case WebInputEvent::GestureTapUnconfirmed:
    302     case WebInputEvent::GestureTapDown:
    303     case WebInputEvent::GestureShowPress:
    304     case WebInputEvent::GestureTapCancel:
    305     case WebInputEvent::GestureDoubleTap:
    306     case WebInputEvent::GestureTwoFingerTap:
    307     case WebInputEvent::GestureLongPress:
    308     case WebInputEvent::GestureLongTap:
    309     case WebInputEvent::GesturePinchBegin:
    310     case WebInputEvent::GesturePinchEnd:
    311     case WebInputEvent::GesturePinchUpdate:
    312         return handleGestureEvent(*static_cast<const WebGestureEvent*>(&inputEvent));
    313 
    314     case WebInputEvent::Undefined:
    315     case WebInputEvent::MouseEnter:
    316     case WebInputEvent::ContextMenu:
    317         return false;
    318     }
    319     return false;
    320 }
    321 
    322 void WebPopupMenuImpl::mouseCaptureLost()
    323 {
    324 }
    325 
    326 void WebPopupMenuImpl::setFocus(bool)
    327 {
    328 }
    329 
    330 bool WebPopupMenuImpl::setComposition(const WebString&, const WebVector<WebCompositionUnderline>&, int, int)
    331 {
    332     return false;
    333 }
    334 
    335 bool WebPopupMenuImpl::confirmComposition()
    336 {
    337     return false;
    338 }
    339 
    340 bool WebPopupMenuImpl::confirmComposition(ConfirmCompositionBehavior)
    341 {
    342     return false;
    343 }
    344 
    345 bool WebPopupMenuImpl::confirmComposition(const WebString&)
    346 {
    347     return false;
    348 }
    349 
    350 bool WebPopupMenuImpl::compositionRange(size_t* location, size_t* length)
    351 {
    352     *location = 0;
    353     *length = 0;
    354     return false;
    355 }
    356 
    357 bool WebPopupMenuImpl::caretOrSelectionRange(size_t* location, size_t* length)
    358 {
    359     *location = 0;
    360     *length = 0;
    361     return false;
    362 }
    363 
    364 void WebPopupMenuImpl::setTextDirection(WebTextDirection)
    365 {
    366 }
    367 
    368 
    369 //-----------------------------------------------------------------------------
    370 // WebCore::HostWindow
    371 
    372 void WebPopupMenuImpl::invalidateContentsAndRootView(const IntRect& paintRect)
    373 {
    374     if (paintRect.isEmpty())
    375         return;
    376     if (m_client)
    377         m_client->didInvalidateRect(paintRect);
    378     if (m_rootLayer)
    379         m_rootLayer->layer()->invalidateRect(FloatRect(paintRect));
    380 }
    381 
    382 void WebPopupMenuImpl::invalidateContentsForSlowScroll(const IntRect& updateRect)
    383 {
    384     invalidateContentsAndRootView(updateRect);
    385 }
    386 
    387 void WebPopupMenuImpl::scheduleAnimation()
    388 {
    389 }
    390 
    391 void WebPopupMenuImpl::scroll(const IntSize& scrollDelta, const IntRect& scrollRect, const IntRect& clipRect)
    392 {
    393     if (m_client) {
    394         int dx = scrollDelta.width();
    395         int dy = scrollDelta.height();
    396         m_client->didScrollRect(dx, dy, clipRect);
    397     }
    398     if (m_rootLayer)
    399         m_rootLayer->layer()->invalidateRect(FloatRect(clipRect));
    400 }
    401 
    402 IntRect WebPopupMenuImpl::rootViewToScreen(const IntRect& rect) const
    403 {
    404     notImplemented();
    405     return IntRect();
    406 }
    407 
    408 WebScreenInfo WebPopupMenuImpl::screenInfo() const
    409 {
    410     return WebScreenInfo();
    411 }
    412 
    413 //-----------------------------------------------------------------------------
    414 // WebCore::FramelessScrollViewClient
    415 
    416 void WebPopupMenuImpl::popupClosed(FramelessScrollView* widget)
    417 {
    418     ASSERT(widget == m_widget);
    419     if (m_widget) {
    420         m_widget->setClient(0);
    421         m_widget = 0;
    422     }
    423     if (m_client)
    424         m_client->closeWidgetSoon();
    425 }
    426 
    427 } // namespace blink
    428