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