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 55 using namespace WebCore; 56 57 namespace WebKit { 58 59 // WebPopupMenu --------------------------------------------------------------- 60 61 WebPopupMenu* 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 69 WebPopupMenuImpl::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 77 WebPopupMenuImpl::~WebPopupMenuImpl() 78 { 79 if (m_widget) 80 m_widget->setClient(0); 81 } 82 83 void 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 94 void 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 107 void WebPopupMenuImpl::handleMouseLeave(const WebMouseEvent& event) 108 { 109 m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event)); 110 } 111 112 void WebPopupMenuImpl::handleMouseDown(const WebMouseEvent& event) 113 { 114 m_widget->handleMouseDownEvent(PlatformMouseEventBuilder(m_widget, event)); 115 } 116 117 void WebPopupMenuImpl::handleMouseUp(const WebMouseEvent& event) 118 { 119 mouseCaptureLost(); 120 m_widget->handleMouseReleaseEvent(PlatformMouseEventBuilder(m_widget, event)); 121 } 122 123 void WebPopupMenuImpl::handleMouseWheel(const WebMouseWheelEvent& event) 124 { 125 m_widget->handleWheelEvent(PlatformWheelEventBuilder(m_widget, event)); 126 } 127 128 bool WebPopupMenuImpl::handleGestureEvent(const WebGestureEvent& event) 129 { 130 return m_widget->handleGestureEvent(PlatformGestureEventBuilder(m_widget, event)); 131 } 132 133 bool 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 141 bool WebPopupMenuImpl::handleKeyEvent(const WebKeyboardEvent& event) 142 { 143 return m_widget->handleKeyEvent(PlatformKeyboardEventBuilder(event)); 144 } 145 146 // WebWidget ------------------------------------------------------------------- 147 148 void 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 158 void WebPopupMenuImpl::willStartLiveResize() 159 { 160 } 161 162 void 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 179 void WebPopupMenuImpl::willEndLiveResize() 180 { 181 } 182 183 void WebPopupMenuImpl::animate(double) 184 { 185 } 186 187 void WebPopupMenuImpl::layout() 188 { 189 } 190 191 void 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 203 void WebPopupMenuImpl::themeChanged() 204 { 205 notImplemented(); 206 } 207 208 bool 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 284 void WebPopupMenuImpl::mouseCaptureLost() 285 { 286 } 287 288 void WebPopupMenuImpl::setFocus(bool) 289 { 290 } 291 292 void WebPopupMenu::setMinimumRowHeight(int minimumRowHeight) 293 { 294 PopupMenuChromium::setMinimumRowHeight(minimumRowHeight); 295 } 296 297 bool WebPopupMenuImpl::setComposition(const WebString&, const WebVector<WebCompositionUnderline>&, int, int) 298 { 299 return false; 300 } 301 302 bool WebPopupMenuImpl::confirmComposition() 303 { 304 return false; 305 } 306 307 bool WebPopupMenuImpl::confirmComposition(ConfirmCompositionBehavior) 308 { 309 return false; 310 } 311 312 bool WebPopupMenuImpl::confirmComposition(const WebString&) 313 { 314 return false; 315 } 316 317 bool WebPopupMenuImpl::compositionRange(size_t* location, size_t* length) 318 { 319 *location = 0; 320 *length = 0; 321 return false; 322 } 323 324 bool WebPopupMenuImpl::caretOrSelectionRange(size_t* location, size_t* length) 325 { 326 *location = 0; 327 *length = 0; 328 return false; 329 } 330 331 void WebPopupMenuImpl::setTextDirection(WebTextDirection) 332 { 333 } 334 335 336 //----------------------------------------------------------------------------- 337 // WebCore::HostWindow 338 339 void WebPopupMenuImpl::invalidateContentsAndRootView(const IntRect& paintRect) 340 { 341 if (paintRect.isEmpty()) 342 return; 343 if (m_client) 344 m_client->didInvalidateRect(paintRect); 345 } 346 347 void WebPopupMenuImpl::invalidateContentsForSlowScroll(const IntRect& updateRect) 348 { 349 invalidateContentsAndRootView(updateRect); 350 } 351 352 void WebPopupMenuImpl::scheduleAnimation() 353 { 354 } 355 356 void 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 365 IntPoint WebPopupMenuImpl::screenToRootView(const IntPoint& point) const 366 { 367 notImplemented(); 368 return IntPoint(); 369 } 370 371 IntRect WebPopupMenuImpl::rootViewToScreen(const IntRect& rect) const 372 { 373 notImplemented(); 374 return IntRect(); 375 } 376 377 WebScreenInfo WebPopupMenuImpl::screenInfo() const 378 { 379 return WebScreenInfo(); 380 } 381 382 void WebPopupMenuImpl::setCursor(const WebCore::Cursor&) 383 { 384 } 385 386 //----------------------------------------------------------------------------- 387 // WebCore::FramelessScrollViewClient 388 389 void 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