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