/* * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "WebPopupMenuImpl.h" #include "PopupContainer.h" #include "PopupMenuChromium.h" #include "WebInputEvent.h" #include "WebInputEventConversion.h" #include "WebRange.h" #include "WebViewClient.h" #include "WebWidgetClient.h" #include "core/frame/FrameView.h" #include "platform/Cursor.h" #include "platform/NotImplemented.h" #include "platform/PlatformGestureEvent.h" #include "platform/PlatformKeyboardEvent.h" #include "platform/PlatformMouseEvent.h" #include "platform/PlatformWheelEvent.h" #include "platform/geometry/IntRect.h" #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/skia/SkiaUtils.h" #include "platform/scroll/FramelessScrollView.h" #include "public/platform/WebRect.h" #include using namespace WebCore; namespace blink { // WebPopupMenu --------------------------------------------------------------- WebPopupMenu* WebPopupMenu::create(WebWidgetClient* client) { // Pass the WebPopupMenuImpl's self-reference to the caller. return adoptRef(new WebPopupMenuImpl(client)).leakRef(); } // WebWidget ------------------------------------------------------------------ WebPopupMenuImpl::WebPopupMenuImpl(WebWidgetClient* client) : m_client(client) , m_widget(0) { // Set to impossible point so we always get the first mouse position. m_lastMousePosition = WebPoint(-1, -1); } WebPopupMenuImpl::~WebPopupMenuImpl() { if (m_widget) m_widget->setClient(0); } void WebPopupMenuImpl::initialize(FramelessScrollView* widget, const WebRect& bounds) { m_widget = widget; m_widget->setClient(this); if (m_client) { m_client->setWindowRect(bounds); m_client->show(WebNavigationPolicy()); // Policy is ignored. } } void WebPopupMenuImpl::handleMouseMove(const WebMouseEvent& event) { // Don't send mouse move messages if the mouse hasn't moved. if (event.x != m_lastMousePosition.x || event.y != m_lastMousePosition.y) { m_lastMousePosition = WebPoint(event.x, event.y); m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event)); // We cannot call setToolTipText() in PopupContainer, because PopupContainer is in WebCore, and we cannot refer to WebKit from Webcore. WebCore::PopupContainer* container = static_cast(m_widget); client()->setToolTipText(container->getSelectedItemToolTip(), container->menuStyle().textDirection() == WebCore::RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight); } } void WebPopupMenuImpl::handleMouseLeave(const WebMouseEvent& event) { m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event)); } void WebPopupMenuImpl::handleMouseDown(const WebMouseEvent& event) { m_widget->handleMouseDownEvent(PlatformMouseEventBuilder(m_widget, event)); } void WebPopupMenuImpl::handleMouseUp(const WebMouseEvent& event) { mouseCaptureLost(); m_widget->handleMouseReleaseEvent(PlatformMouseEventBuilder(m_widget, event)); } void WebPopupMenuImpl::handleMouseWheel(const WebMouseWheelEvent& event) { m_widget->handleWheelEvent(PlatformWheelEventBuilder(m_widget, event)); } bool WebPopupMenuImpl::handleGestureEvent(const WebGestureEvent& event) { return m_widget->handleGestureEvent(PlatformGestureEventBuilder(m_widget, event)); } bool WebPopupMenuImpl::handleTouchEvent(const WebTouchEvent& event) { PlatformTouchEventBuilder touchEventBuilder(m_widget, event); bool defaultPrevented(m_widget->handleTouchEvent(touchEventBuilder)); return defaultPrevented; } bool WebPopupMenuImpl::handleKeyEvent(const WebKeyboardEvent& event) { return m_widget->handleKeyEvent(PlatformKeyboardEventBuilder(event)); } // WebWidget ------------------------------------------------------------------- void WebPopupMenuImpl::close() { if (m_widget) m_widget->hide(); m_client = 0; deref(); // Balances ref() from WebPopupMenu::create. } void WebPopupMenuImpl::willStartLiveResize() { } void WebPopupMenuImpl::resize(const WebSize& newSize) { if (m_size == newSize) return; m_size = newSize; if (m_widget) { IntRect newGeometry(0, 0, m_size.width, m_size.height); m_widget->setFrameRect(newGeometry); } if (m_client) { WebRect damagedRect(0, 0, m_size.width, m_size.height); m_client->didInvalidateRect(damagedRect); } } void WebPopupMenuImpl::willEndLiveResize() { } void WebPopupMenuImpl::animate(double) { } void WebPopupMenuImpl::layout() { } void WebPopupMenuImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions) { if (!m_widget) return; if (!rect.isEmpty()) { GraphicsContext context(canvas); context.applyDeviceScaleFactor(m_client->deviceScaleFactor()); m_widget->paint(&context, rect); } } void WebPopupMenuImpl::themeChanged() { notImplemented(); } bool WebPopupMenuImpl::handleInputEvent(const WebInputEvent& inputEvent) { if (!m_widget) return false; // FIXME: WebKit seems to always return false on mouse events methods. For // now we'll assume it has processed them (as we are only interested in // whether keyboard events are processed). switch (inputEvent.type) { case WebInputEvent::MouseMove: handleMouseMove(*static_cast(&inputEvent)); return true; case WebInputEvent::MouseLeave: handleMouseLeave(*static_cast(&inputEvent)); return true; case WebInputEvent::MouseWheel: handleMouseWheel(*static_cast(&inputEvent)); return true; case WebInputEvent::MouseDown: handleMouseDown(*static_cast(&inputEvent)); return true; case WebInputEvent::MouseUp: handleMouseUp(*static_cast(&inputEvent)); return true; // In Windows, RawKeyDown only has information about the physical key, but // for "selection", we need the information about the character the key // translated into. For English, the physical key value and the character // value are the same, hence, "selection" works for English. But for other // languages, such as Hebrew, the character value is different from the // physical key value. Thus, without accepting Char event type which // contains the key's character value, the "selection" won't work for // non-English languages, such as Hebrew. case WebInputEvent::RawKeyDown: case WebInputEvent::KeyDown: case WebInputEvent::KeyUp: case WebInputEvent::Char: return handleKeyEvent(*static_cast(&inputEvent)); case WebInputEvent::TouchStart: case WebInputEvent::TouchMove: case WebInputEvent::TouchEnd: case WebInputEvent::TouchCancel: return handleTouchEvent(*static_cast(&inputEvent)); case WebInputEvent::GestureScrollBegin: case WebInputEvent::GestureScrollEnd: case WebInputEvent::GestureScrollUpdate: case WebInputEvent::GestureScrollUpdateWithoutPropagation: case WebInputEvent::GestureFlingStart: case WebInputEvent::GestureFlingCancel: case WebInputEvent::GestureTap: case WebInputEvent::GestureTapUnconfirmed: case WebInputEvent::GestureTapDown: case WebInputEvent::GestureShowPress: case WebInputEvent::GestureTapCancel: case WebInputEvent::GestureDoubleTap: case WebInputEvent::GestureTwoFingerTap: case WebInputEvent::GestureLongPress: case WebInputEvent::GestureLongTap: case WebInputEvent::GesturePinchBegin: case WebInputEvent::GesturePinchEnd: case WebInputEvent::GesturePinchUpdate: return handleGestureEvent(*static_cast(&inputEvent)); case WebInputEvent::Undefined: case WebInputEvent::MouseEnter: case WebInputEvent::ContextMenu: return false; } return false; } void WebPopupMenuImpl::mouseCaptureLost() { } void WebPopupMenuImpl::setFocus(bool) { } void WebPopupMenu::setMinimumRowHeight(int minimumRowHeight) { PopupMenuChromium::setMinimumRowHeight(minimumRowHeight); } bool WebPopupMenuImpl::setComposition(const WebString&, const WebVector&, int, int) { return false; } bool WebPopupMenuImpl::confirmComposition() { return false; } bool WebPopupMenuImpl::confirmComposition(ConfirmCompositionBehavior) { return false; } bool WebPopupMenuImpl::confirmComposition(const WebString&) { return false; } bool WebPopupMenuImpl::compositionRange(size_t* location, size_t* length) { *location = 0; *length = 0; return false; } bool WebPopupMenuImpl::caretOrSelectionRange(size_t* location, size_t* length) { *location = 0; *length = 0; return false; } void WebPopupMenuImpl::setTextDirection(WebTextDirection) { } //----------------------------------------------------------------------------- // WebCore::HostWindow void WebPopupMenuImpl::invalidateContentsAndRootView(const IntRect& paintRect) { if (paintRect.isEmpty()) return; if (m_client) m_client->didInvalidateRect(paintRect); } void WebPopupMenuImpl::invalidateContentsForSlowScroll(const IntRect& updateRect) { invalidateContentsAndRootView(updateRect); } void WebPopupMenuImpl::scheduleAnimation() { } void WebPopupMenuImpl::scroll(const IntSize& scrollDelta, const IntRect& scrollRect, const IntRect& clipRect) { if (m_client) { int dx = scrollDelta.width(); int dy = scrollDelta.height(); m_client->didScrollRect(dx, dy, clipRect); } } IntPoint WebPopupMenuImpl::screenToRootView(const IntPoint& point) const { notImplemented(); return IntPoint(); } IntRect WebPopupMenuImpl::rootViewToScreen(const IntRect& rect) const { notImplemented(); return IntRect(); } WebScreenInfo WebPopupMenuImpl::screenInfo() const { return WebScreenInfo(); } //----------------------------------------------------------------------------- // WebCore::FramelessScrollViewClient void WebPopupMenuImpl::popupClosed(FramelessScrollView* widget) { ASSERT(widget == m_widget); if (m_widget) { m_widget->setClient(0); m_widget = 0; } if (m_client) m_client->closeWidgetSoon(); } } // namespace blink