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