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 "WebPluginContainerImpl.h" 33 34 #include "ChromeClientImpl.h" 35 #include "ScrollbarGroup.h" 36 #include "WebCursorInfo.h" 37 #include "WebDataSourceImpl.h" 38 #include "WebElement.h" 39 #include "WebInputEvent.h" 40 #include "WebInputEventConversion.h" 41 #include "WebPlugin.h" 42 #include "WebViewClient.h" 43 #include "WebViewImpl.h" 44 #include "core/page/Chrome.h" 45 #include "core/page/EventHandler.h" 46 #include "core/platform/chromium/ClipboardChromium.h" 47 #include "core/platform/chromium/support/WrappedResourceResponse.h" 48 49 #include "HTMLNames.h" 50 #include "WebPrintParams.h" 51 #include "bindings/v8/ScriptController.h" 52 #include "core/dom/EventNames.h" 53 #include "core/dom/GestureEvent.h" 54 #include "core/dom/KeyboardEvent.h" 55 #include "core/dom/MouseEvent.h" 56 #include "core/dom/TouchEvent.h" 57 #include "core/dom/UserGestureIndicator.h" 58 #include "core/dom/WheelEvent.h" 59 #include "core/html/HTMLFormElement.h" 60 #include "core/html/HTMLPlugInElement.h" 61 #include "core/loader/FormState.h" 62 #include "core/loader/FrameLoadRequest.h" 63 #include "core/page/FocusController.h" 64 #include "core/page/Frame.h" 65 #include "core/page/FrameView.h" 66 #include "core/page/Page.h" 67 #include "core/page/scrolling/ScrollingCoordinator.h" 68 #include "core/platform/HostWindow.h" 69 #include "core/platform/PlatformGestureEvent.h" 70 #include "core/platform/ScrollAnimator.h" 71 #include "core/platform/ScrollView.h" 72 #include "core/platform/ScrollbarTheme.h" 73 #include "core/platform/chromium/KeyboardCodes.h" 74 #include "core/platform/graphics/GraphicsContext.h" 75 #include "core/platform/graphics/GraphicsLayer.h" 76 #include "core/plugins/IFrameShimSupport.h" 77 #include "core/rendering/HitTestResult.h" 78 #include "core/rendering/RenderBox.h" 79 #include "public/platform/Platform.h" 80 #include "public/platform/WebClipboard.h" 81 #include "public/platform/WebCompositorSupport.h" 82 #include "public/platform/WebDragData.h" 83 #include "public/platform/WebExternalTextureLayer.h" 84 #include "public/platform/WebRect.h" 85 #include "public/platform/WebString.h" 86 #include "public/platform/WebURL.h" 87 #include "public/platform/WebURLError.h" 88 #include "public/platform/WebURLRequest.h" 89 #include "public/platform/WebVector.h" 90 91 using namespace WebCore; 92 93 namespace WebKit { 94 95 // Public methods -------------------------------------------------------------- 96 97 void WebPluginContainerImpl::setFrameRect(const IntRect& frameRect) 98 { 99 Widget::setFrameRect(frameRect); 100 reportGeometry(); 101 } 102 103 void WebPluginContainerImpl::paint(GraphicsContext* gc, const IntRect& damageRect) 104 { 105 if (gc->updatingControlTints() && m_scrollbarGroup) { 106 // See comment in FrameView::updateControlTints(). 107 if (m_scrollbarGroup->horizontalScrollbar()) 108 m_scrollbarGroup->horizontalScrollbar()->invalidate(); 109 if (m_scrollbarGroup->verticalScrollbar()) 110 m_scrollbarGroup->verticalScrollbar()->invalidate(); 111 } 112 113 if (gc->paintingDisabled()) 114 return; 115 116 if (!parent()) 117 return; 118 119 // Don't paint anything if the plugin doesn't intersect the damage rect. 120 if (!frameRect().intersects(damageRect)) 121 return; 122 123 gc->save(); 124 125 ASSERT(parent()->isFrameView()); 126 ScrollView* view = parent(); 127 128 // The plugin is positioned in window coordinates, so it needs to be painted 129 // in window coordinates. 130 IntPoint origin = view->contentsToWindow(IntPoint(0, 0)); 131 gc->translate(static_cast<float>(-origin.x()), static_cast<float>(-origin.y())); 132 133 WebCanvas* canvas = gc->canvas(); 134 135 IntRect windowRect = view->contentsToWindow(damageRect); 136 m_webPlugin->paint(canvas, windowRect); 137 138 gc->restore(); 139 } 140 141 void WebPluginContainerImpl::invalidateRect(const IntRect& rect) 142 { 143 if (!parent()) 144 return; 145 146 RenderBox* renderer = toRenderBox(m_element->renderer()); 147 148 IntRect dirtyRect = rect; 149 dirtyRect.move(renderer->borderLeft() + renderer->paddingLeft(), 150 renderer->borderTop() + renderer->paddingTop()); 151 renderer->repaintRectangle(dirtyRect); 152 } 153 154 void WebPluginContainerImpl::setFocus(bool focused) 155 { 156 Widget::setFocus(focused); 157 m_webPlugin->updateFocus(focused); 158 } 159 160 void WebPluginContainerImpl::show() 161 { 162 setSelfVisible(true); 163 m_webPlugin->updateVisibility(true); 164 165 Widget::show(); 166 } 167 168 void WebPluginContainerImpl::hide() 169 { 170 setSelfVisible(false); 171 m_webPlugin->updateVisibility(false); 172 173 Widget::hide(); 174 } 175 176 void WebPluginContainerImpl::handleEvent(Event* event) 177 { 178 if (!m_webPlugin->acceptsInputEvents()) 179 return; 180 181 const WebInputEvent* currentInputEvent = WebViewImpl::currentInputEvent(); 182 UserGestureIndicator gestureIndicator(currentInputEvent && WebInputEvent::isUserGestureEventType(currentInputEvent->type) ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture); 183 184 RefPtr<WebPluginContainerImpl> protector(this); 185 // The events we pass are defined at: 186 // http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/structures5.html#1000000 187 // Don't take the documentation as truth, however. There are many cases 188 // where mozilla behaves differently than the spec. 189 if (event->isMouseEvent()) 190 handleMouseEvent(toMouseEvent(event)); 191 else if (event->hasInterface(eventNames().interfaceForWheelEvent)) 192 handleWheelEvent(static_cast<WheelEvent*>(event)); 193 else if (event->isKeyboardEvent()) 194 handleKeyboardEvent(toKeyboardEvent(event)); 195 else if (eventNames().isTouchEventType(event->type())) 196 handleTouchEvent(static_cast<TouchEvent*>(event)); 197 else if (eventNames().isGestureEventType(event->type())) 198 handleGestureEvent(static_cast<GestureEvent*>(event)); 199 200 // FIXME: it would be cleaner if Widget::handleEvent returned true/false and 201 // HTMLPluginElement called setDefaultHandled or defaultEventHandler. 202 if (!event->defaultHandled()) 203 m_element->Node::defaultEventHandler(event); 204 } 205 206 void WebPluginContainerImpl::frameRectsChanged() 207 { 208 Widget::frameRectsChanged(); 209 reportGeometry(); 210 } 211 212 void WebPluginContainerImpl::widgetPositionsUpdated() 213 { 214 Widget::widgetPositionsUpdated(); 215 reportGeometry(); 216 } 217 218 void WebPluginContainerImpl::clipRectChanged() 219 { 220 reportGeometry(); 221 } 222 223 void WebPluginContainerImpl::setParentVisible(bool parentVisible) 224 { 225 // We override this function to make sure that geometry updates are sent 226 // over to the plugin. For e.g. when a plugin is instantiated it does not 227 // have a valid parent. As a result the first geometry update from webkit 228 // is ignored. This function is called when the plugin eventually gets a 229 // parent. 230 231 if (isParentVisible() == parentVisible) 232 return; // No change. 233 234 Widget::setParentVisible(parentVisible); 235 if (!isSelfVisible()) 236 return; // This widget has explicitely been marked as not visible. 237 238 m_webPlugin->updateVisibility(isVisible()); 239 } 240 241 void WebPluginContainerImpl::setParent(ScrollView* view) 242 { 243 // We override this function so that if the plugin is windowed, we can call 244 // NPP_SetWindow at the first possible moment. This ensures that 245 // NPP_SetWindow is called before the manual load data is sent to a plugin. 246 // If this order is reversed, Flash won't load videos. 247 248 Widget::setParent(view); 249 if (view) 250 reportGeometry(); 251 } 252 253 void WebPluginContainerImpl::setPlugin(WebPlugin* plugin) 254 { 255 if (plugin != m_webPlugin) { 256 m_element->resetInstance(); 257 m_webPlugin = plugin; 258 } 259 } 260 261 float WebPluginContainerImpl::deviceScaleFactor() 262 { 263 Page* page = m_element->document()->page(); 264 if (!page) 265 return 1.0; 266 return page->deviceScaleFactor(); 267 } 268 269 float WebPluginContainerImpl::pageScaleFactor() 270 { 271 Page* page = m_element->document()->page(); 272 if (!page) 273 return 1.0; 274 return page->pageScaleFactor(); 275 } 276 277 float WebPluginContainerImpl::pageZoomFactor() 278 { 279 Frame* frame = m_element->document()->frame(); 280 if (!frame) 281 return 1.0; 282 return frame->pageZoomFactor(); 283 } 284 285 void WebPluginContainerImpl::setWebLayer(WebLayer* layer) 286 { 287 if (m_webLayer == layer) 288 return; 289 290 // If anyone of the layers is null we need to switch between hardware 291 // and software compositing. 292 if (!m_webLayer || !layer) 293 m_element->scheduleLayerUpdate(); 294 if (m_webLayer) 295 GraphicsLayer::unregisterContentsLayer(m_webLayer); 296 if (layer) 297 GraphicsLayer::registerContentsLayer(layer); 298 m_webLayer = layer; 299 } 300 301 bool WebPluginContainerImpl::supportsPaginatedPrint() const 302 { 303 return m_webPlugin->supportsPaginatedPrint(); 304 } 305 306 bool WebPluginContainerImpl::isPrintScalingDisabled() const 307 { 308 return m_webPlugin->isPrintScalingDisabled(); 309 } 310 311 int WebPluginContainerImpl::printBegin(const WebPrintParams& printParams) const 312 { 313 return m_webPlugin->printBegin(printParams); 314 } 315 316 bool WebPluginContainerImpl::printPage(int pageNumber, 317 WebCore::GraphicsContext* gc) 318 { 319 gc->save(); 320 WebCanvas* canvas = gc->canvas(); 321 bool ret = m_webPlugin->printPage(pageNumber, canvas); 322 gc->restore(); 323 return ret; 324 } 325 326 void WebPluginContainerImpl::printEnd() 327 { 328 m_webPlugin->printEnd(); 329 } 330 331 void WebPluginContainerImpl::copy() 332 { 333 if (!m_webPlugin->hasSelection()) 334 return; 335 336 WebKit::Platform::current()->clipboard()->writeHTML(m_webPlugin->selectionAsMarkup(), WebURL(), m_webPlugin->selectionAsText(), false); 337 } 338 339 bool WebPluginContainerImpl::executeEditCommand(const WebString& name) 340 { 341 if (m_webPlugin->executeEditCommand(name)) 342 return true; 343 344 if (name != "Copy") 345 return false; 346 347 copy(); 348 return true; 349 } 350 351 bool WebPluginContainerImpl::executeEditCommand(const WebString& name, const WebString& value) 352 { 353 return m_webPlugin->executeEditCommand(name, value); 354 } 355 356 WebElement WebPluginContainerImpl::element() 357 { 358 return WebElement(m_element); 359 } 360 361 void WebPluginContainerImpl::invalidate() 362 { 363 Widget::invalidate(); 364 } 365 366 void WebPluginContainerImpl::invalidateRect(const WebRect& rect) 367 { 368 invalidateRect(static_cast<IntRect>(rect)); 369 } 370 371 void WebPluginContainerImpl::scrollRect(int dx, int dy, const WebRect& rect) 372 { 373 Widget* parentWidget = parent(); 374 if (parentWidget->isFrameView()) { 375 FrameView* parentFrameView = toFrameView(parentWidget); 376 if (!parentFrameView->isOverlapped()) { 377 IntRect damageRect = convertToContainingWindow(static_cast<IntRect>(rect)); 378 IntSize scrollDelta(dx, dy); 379 // scroll() only uses the second rectangle, clipRect, and ignores the first 380 // rectangle. 381 parent()->hostWindow()->scroll(scrollDelta, damageRect, damageRect); 382 return; 383 } 384 } 385 386 // Use slow scrolling instead. 387 invalidateRect(rect); 388 } 389 390 void WebPluginContainerImpl::reportGeometry() 391 { 392 if (!parent()) 393 return; 394 395 IntRect windowRect, clipRect; 396 Vector<IntRect> cutOutRects; 397 calculateGeometry(frameRect(), windowRect, clipRect, cutOutRects); 398 399 m_webPlugin->updateGeometry(windowRect, clipRect, cutOutRects, isVisible()); 400 401 if (m_scrollbarGroup) { 402 m_scrollbarGroup->scrollAnimator()->contentsResized(); 403 m_scrollbarGroup->setFrameRect(frameRect()); 404 } 405 } 406 407 void WebPluginContainerImpl::allowScriptObjects() 408 { 409 } 410 411 void WebPluginContainerImpl::clearScriptObjects() 412 { 413 Frame* frame = m_element->document()->frame(); 414 if (!frame) 415 return; 416 frame->script()->cleanupScriptObjectsForPlugin(this); 417 } 418 419 NPObject* WebPluginContainerImpl::scriptableObjectForElement() 420 { 421 return m_element->getNPObject(); 422 } 423 424 WebString WebPluginContainerImpl::executeScriptURL(const WebURL& url, bool popupsAllowed) 425 { 426 Frame* frame = m_element->document()->frame(); 427 if (!frame) 428 return WebString(); 429 430 const KURL& kurl = url; 431 ASSERT(kurl.protocolIs("javascript")); 432 433 String script = decodeURLEscapeSequences( 434 kurl.string().substring(strlen("javascript:"))); 435 436 ScriptValue result = frame->script()->executeScript(script, popupsAllowed); 437 438 // Failure is reported as a null string. 439 String resultStr; 440 result.getString(resultStr); 441 return resultStr; 442 } 443 444 void WebPluginContainerImpl::loadFrameRequest(const WebURLRequest& request, const WebString& target, bool notifyNeeded, void* notifyData) 445 { 446 Frame* frame = m_element->document()->frame(); 447 if (!frame || !frame->loader()->documentLoader()) 448 return; // FIXME: send a notification in this case? 449 450 if (notifyNeeded) { 451 // FIXME: This is a bit of hack to allow us to observe completion of 452 // our frame request. It would be better to evolve FrameLoader to 453 // support a completion callback instead. 454 OwnPtr<WebPluginLoadObserver> observer = adoptPtr(new WebPluginLoadObserver(this, request.url(), notifyData)); 455 // FIXME: Calling get here is dangerous! What if observer is freed? 456 m_pluginLoadObservers.append(observer.get()); 457 WebDataSourceImpl::setNextPluginLoadObserver(observer.release()); 458 } 459 460 FrameLoadRequest frameRequest(frame->document()->securityOrigin(), request.toResourceRequest(), target); 461 UserGestureIndicator gestureIndicator(request.hasUserGesture() ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture); 462 frame->loader()->load(frameRequest); 463 } 464 465 void WebPluginContainerImpl::zoomLevelChanged(double zoomLevel) 466 { 467 WebViewImpl* view = WebViewImpl::fromPage(m_element->document()->frame()->page()); 468 view->fullFramePluginZoomLevelChanged(zoomLevel); 469 } 470 471 bool WebPluginContainerImpl::isRectTopmost(const WebRect& rect) 472 { 473 Frame* frame = m_element->document()->frame(); 474 if (!frame) 475 return false; 476 477 // hitTestResultAtPoint() takes a padding rectangle. 478 // FIXME: We'll be off by 1 when the width or height is even. 479 IntRect documentRect(x() + rect.x, y() + rect.y, rect.width, rect.height); 480 LayoutPoint center = documentRect.center(); 481 // Make the rect we're checking (the point surrounded by padding rects) contained inside the requested rect. (Note that -1/2 is 0.) 482 LayoutSize padding((documentRect.width() - 1) / 2, (documentRect.height() - 1) / 2); 483 HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(center, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent, padding); 484 const HitTestResult::NodeSet& nodes = result.rectBasedTestResult(); 485 if (nodes.size() != 1) 486 return false; 487 return nodes.first().get() == m_element; 488 } 489 490 void WebPluginContainerImpl::requestTouchEventType(TouchEventRequestType requestType) 491 { 492 if (m_touchEventRequestType == requestType) 493 return; 494 495 if (requestType != TouchEventRequestTypeNone && m_touchEventRequestType == TouchEventRequestTypeNone) 496 m_element->document()->didAddTouchEventHandler(m_element); 497 else if (requestType == TouchEventRequestTypeNone && m_touchEventRequestType != TouchEventRequestTypeNone) 498 m_element->document()->didRemoveTouchEventHandler(m_element); 499 m_touchEventRequestType = requestType; 500 } 501 502 void WebPluginContainerImpl::setWantsWheelEvents(bool wantsWheelEvents) 503 { 504 if (m_wantsWheelEvents == wantsWheelEvents) 505 return; 506 m_wantsWheelEvents = wantsWheelEvents; 507 if (Page* page = m_element->document()->page()) { 508 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { 509 if (parent() && parent()->isFrameView()) 510 scrollingCoordinator->frameViewLayoutUpdated(toFrameView(parent())); 511 } 512 } 513 } 514 515 WebPoint WebPluginContainerImpl::windowToLocalPoint(const WebPoint& point) 516 { 517 ScrollView* view = parent(); 518 if (!view) 519 return point; 520 WebPoint windowPoint = view->windowToContents(point); 521 return roundedIntPoint(m_element->renderer()->absoluteToLocal(LayoutPoint(windowPoint), UseTransforms)); 522 } 523 524 WebPoint WebPluginContainerImpl::localToWindowPoint(const WebPoint& point) 525 { 526 ScrollView* view = parent(); 527 if (!view) 528 return point; 529 IntPoint absolutePoint = roundedIntPoint(m_element->renderer()->localToAbsolute(LayoutPoint(point), UseTransforms)); 530 return view->contentsToWindow(absolutePoint); 531 } 532 533 void WebPluginContainerImpl::didReceiveResponse(const ResourceResponse& response) 534 { 535 // Make sure that the plugin receives window geometry before data, or else 536 // plugins misbehave. 537 frameRectsChanged(); 538 539 WrappedResourceResponse urlResponse(response); 540 m_webPlugin->didReceiveResponse(urlResponse); 541 } 542 543 void WebPluginContainerImpl::didReceiveData(const char *data, int dataLength) 544 { 545 m_webPlugin->didReceiveData(data, dataLength); 546 } 547 548 void WebPluginContainerImpl::didFinishLoading() 549 { 550 m_webPlugin->didFinishLoading(); 551 } 552 553 void WebPluginContainerImpl::didFailLoading(const ResourceError& error) 554 { 555 m_webPlugin->didFailLoading(error); 556 } 557 558 WebLayer* WebPluginContainerImpl::platformLayer() const 559 { 560 return m_webLayer; 561 } 562 563 NPObject* WebPluginContainerImpl::scriptableObject() 564 { 565 return m_webPlugin->scriptableObject(); 566 } 567 568 bool WebPluginContainerImpl::getFormValue(String& value) 569 { 570 WebString webValue; 571 if (m_webPlugin->getFormValue(webValue)) { 572 value = webValue; 573 return true; 574 } 575 return false; 576 } 577 578 bool WebPluginContainerImpl::supportsKeyboardFocus() const 579 { 580 return m_webPlugin->supportsKeyboardFocus(); 581 } 582 583 bool WebPluginContainerImpl::canProcessDrag() const 584 { 585 return m_webPlugin->canProcessDrag(); 586 } 587 588 bool WebPluginContainerImpl::wantsWheelEvents() 589 { 590 return m_wantsWheelEvents; 591 } 592 593 void WebPluginContainerImpl::willDestroyPluginLoadObserver(WebPluginLoadObserver* observer) 594 { 595 size_t pos = m_pluginLoadObservers.find(observer); 596 if (pos == notFound) 597 return; 598 m_pluginLoadObservers.remove(pos); 599 } 600 601 ScrollbarGroup* WebPluginContainerImpl::scrollbarGroup() 602 { 603 if (!m_scrollbarGroup) 604 m_scrollbarGroup = adoptPtr(new ScrollbarGroup(m_element->document()->frame()->view(), frameRect())); 605 return m_scrollbarGroup.get(); 606 } 607 608 void WebPluginContainerImpl::willStartLiveResize() 609 { 610 if (m_scrollbarGroup) 611 m_scrollbarGroup->willStartLiveResize(); 612 } 613 614 void WebPluginContainerImpl::willEndLiveResize() 615 { 616 if (m_scrollbarGroup) 617 m_scrollbarGroup->willEndLiveResize(); 618 } 619 620 bool WebPluginContainerImpl::paintCustomOverhangArea(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect) 621 { 622 context->save(); 623 context->setFillColor(Color(0xCC, 0xCC, 0xCC)); 624 context->fillRect(intersection(horizontalOverhangArea, dirtyRect)); 625 context->fillRect(intersection(verticalOverhangArea, dirtyRect)); 626 context->restore(); 627 return true; 628 } 629 630 // Private methods ------------------------------------------------------------- 631 632 WebPluginContainerImpl::WebPluginContainerImpl(WebCore::HTMLPlugInElement* element, WebPlugin* webPlugin) 633 : m_element(element) 634 , m_webPlugin(webPlugin) 635 , m_webLayer(0) 636 , m_touchEventRequestType(TouchEventRequestTypeNone) 637 , m_wantsWheelEvents(false) 638 { 639 } 640 641 WebPluginContainerImpl::~WebPluginContainerImpl() 642 { 643 if (m_touchEventRequestType != TouchEventRequestTypeNone) 644 m_element->document()->didRemoveTouchEventHandler(m_element); 645 646 for (size_t i = 0; i < m_pluginLoadObservers.size(); ++i) 647 m_pluginLoadObservers[i]->clearPluginContainer(); 648 m_webPlugin->destroy(); 649 if (m_webLayer) 650 GraphicsLayer::unregisterContentsLayer(m_webLayer); 651 } 652 653 void WebPluginContainerImpl::handleMouseEvent(MouseEvent* event) 654 { 655 ASSERT(parent()->isFrameView()); 656 657 if (event->isDragEvent()) { 658 if (m_webPlugin->canProcessDrag()) 659 handleDragEvent(event); 660 return; 661 } 662 663 // We cache the parent FrameView here as the plugin widget could be deleted 664 // in the call to HandleEvent. See http://b/issue?id=1362948 665 FrameView* parentView = toFrameView(parent()); 666 667 WebMouseEventBuilder webEvent(this, m_element->renderer(), *event); 668 if (webEvent.type == WebInputEvent::Undefined) 669 return; 670 671 if (event->type() == eventNames().mousedownEvent) 672 focusPlugin(); 673 674 if (m_scrollbarGroup) { 675 // This needs to be set before the other callbacks in this scope, since 676 // the scroll animator class might query the position in response. 677 m_scrollbarGroup->setLastMousePosition(IntPoint(event->x(), event->y())); 678 if (event->type() == eventNames().mousemoveEvent) 679 m_scrollbarGroup->scrollAnimator()->mouseMovedInContentArea(); 680 else if (event->type() == eventNames().mouseoverEvent) 681 m_scrollbarGroup->scrollAnimator()->mouseEnteredContentArea(); 682 else if (event->type() == eventNames().mouseoutEvent) 683 m_scrollbarGroup->scrollAnimator()->mouseExitedContentArea(); 684 } 685 686 WebCursorInfo cursorInfo; 687 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) 688 event->setDefaultHandled(); 689 690 // A windowless plugin can change the cursor in response to a mouse move 691 // event. We need to reflect the changed cursor in the frame view as the 692 // mouse is moved in the boundaries of the windowless plugin. 693 Page* page = parentView->frame()->page(); 694 if (!page) 695 return; 696 ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome().client()); 697 chromeClient->setCursorForPlugin(cursorInfo); 698 } 699 700 void WebPluginContainerImpl::handleDragEvent(MouseEvent* event) 701 { 702 ASSERT(event->isDragEvent()); 703 704 WebDragStatus dragStatus = WebDragStatusUnknown; 705 if (event->type() == eventNames().dragenterEvent) 706 dragStatus = WebDragStatusEnter; 707 else if (event->type() == eventNames().dragleaveEvent) 708 dragStatus = WebDragStatusLeave; 709 else if (event->type() == eventNames().dragoverEvent) 710 dragStatus = WebDragStatusOver; 711 else if (event->type() == eventNames().dropEvent) 712 dragStatus = WebDragStatusDrop; 713 714 if (dragStatus == WebDragStatusUnknown) 715 return; 716 717 ClipboardChromium* clipboard = static_cast<ClipboardChromium*>(event->dataTransfer()); 718 WebDragData dragData = clipboard->dataObject(); 719 WebDragOperationsMask dragOperationMask = static_cast<WebDragOperationsMask>(clipboard->sourceOperation()); 720 WebPoint dragScreenLocation(event->screenX(), event->screenY()); 721 WebPoint dragLocation(event->absoluteLocation().x() - location().x(), event->absoluteLocation().y() - location().y()); 722 723 m_webPlugin->handleDragStatusUpdate(dragStatus, dragData, dragOperationMask, dragLocation, dragScreenLocation); 724 } 725 726 void WebPluginContainerImpl::handleWheelEvent(WheelEvent* event) 727 { 728 WebMouseWheelEventBuilder webEvent(this, m_element->renderer(), *event); 729 if (webEvent.type == WebInputEvent::Undefined) 730 return; 731 732 WebCursorInfo cursorInfo; 733 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) 734 event->setDefaultHandled(); 735 } 736 737 void WebPluginContainerImpl::handleKeyboardEvent(KeyboardEvent* event) 738 { 739 WebKeyboardEventBuilder webEvent(*event); 740 if (webEvent.type == WebInputEvent::Undefined) 741 return; 742 743 if (webEvent.type == WebInputEvent::KeyDown) { 744 #if OS(DARWIN) 745 if (webEvent.modifiers == WebInputEvent::MetaKey 746 #else 747 if (webEvent.modifiers == WebInputEvent::ControlKey 748 #endif 749 && webEvent.windowsKeyCode == VKEY_C 750 // Only copy if there's a selection, so that we only ever do this 751 // for Pepper plugins that support copying. Windowless NPAPI 752 // plugins will get the event as before. 753 && m_webPlugin->hasSelection()) { 754 copy(); 755 event->setDefaultHandled(); 756 return; 757 } 758 } 759 760 const WebInputEvent* currentInputEvent = WebViewImpl::currentInputEvent(); 761 762 // Copy stashed info over, and only copy here in order not to interfere 763 // the ctrl-c logic above. 764 if (currentInputEvent 765 && WebInputEvent::isKeyboardEventType(currentInputEvent->type)) { 766 webEvent.modifiers |= currentInputEvent->modifiers & 767 (WebInputEvent::CapsLockOn | WebInputEvent::NumLockOn); 768 } 769 770 // Give the client a chance to issue edit comamnds. 771 WebViewImpl* view = WebViewImpl::fromPage(m_element->document()->frame()->page()); 772 if (m_webPlugin->supportsEditCommands() && view->client()) 773 view->client()->handleCurrentKeyboardEvent(); 774 775 WebCursorInfo cursorInfo; 776 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) 777 event->setDefaultHandled(); 778 } 779 780 void WebPluginContainerImpl::handleTouchEvent(TouchEvent* event) 781 { 782 switch (m_touchEventRequestType) { 783 case TouchEventRequestTypeNone: 784 return; 785 case TouchEventRequestTypeRaw: { 786 WebTouchEventBuilder webEvent(this, m_element->renderer(), *event); 787 if (webEvent.type == WebInputEvent::Undefined) 788 return; 789 790 if (event->type() == eventNames().touchstartEvent) 791 focusPlugin(); 792 793 WebCursorInfo cursorInfo; 794 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) 795 event->setDefaultHandled(); 796 // FIXME: Can a plugin change the cursor from a touch-event callback? 797 return; 798 } 799 case TouchEventRequestTypeSynthesizedMouse: 800 synthesizeMouseEventIfPossible(event); 801 return; 802 } 803 } 804 805 static inline bool gestureScrollHelper(ScrollbarGroup* scrollbarGroup, ScrollDirection positiveDirection, ScrollDirection negativeDirection, float delta) 806 { 807 if (!delta) 808 return false; 809 float absDelta = delta > 0 ? delta : -delta; 810 return scrollbarGroup->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPrecisePixel, absDelta); 811 } 812 813 void WebPluginContainerImpl::handleGestureEvent(GestureEvent* event) 814 { 815 WebGestureEventBuilder webEvent(this, m_element->renderer(), *event); 816 if (webEvent.type == WebInputEvent::Undefined) 817 return; 818 WebCursorInfo cursorInfo; 819 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) { 820 event->setDefaultHandled(); 821 return; 822 } 823 824 if (webEvent.type == WebInputEvent::GestureScrollUpdate || webEvent.type == WebInputEvent::GestureScrollUpdateWithoutPropagation) { 825 if (!m_scrollbarGroup) 826 return; 827 if (gestureScrollHelper(m_scrollbarGroup.get(), ScrollLeft, ScrollRight, webEvent.data.scrollUpdate.deltaX)) 828 event->setDefaultHandled(); 829 if (gestureScrollHelper(m_scrollbarGroup.get(), ScrollUp, ScrollDown, webEvent.data.scrollUpdate.deltaY)) 830 event->setDefaultHandled(); 831 } 832 // FIXME: Can a plugin change the cursor from a touch-event callback? 833 } 834 835 void WebPluginContainerImpl::synthesizeMouseEventIfPossible(TouchEvent* event) 836 { 837 WebMouseEventBuilder webEvent(this, m_element->renderer(), *event); 838 if (webEvent.type == WebInputEvent::Undefined) 839 return; 840 841 WebCursorInfo cursorInfo; 842 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) 843 event->setDefaultHandled(); 844 } 845 846 void WebPluginContainerImpl::focusPlugin() 847 { 848 Frame* containingFrame = static_cast<FrameView*>(parent())->frame(); 849 if (Page* currentPage = containingFrame->page()) 850 currentPage->focusController().setFocusedElement(m_element, containingFrame); 851 else 852 containingFrame->document()->setFocusedElement(m_element); 853 } 854 855 void WebPluginContainerImpl::calculateGeometry(const IntRect& frameRect, 856 IntRect& windowRect, 857 IntRect& clipRect, 858 Vector<IntRect>& cutOutRects) 859 { 860 windowRect = parent()->contentsToWindow(frameRect); 861 862 // Calculate a clip-rect so that we don't overlap the scrollbars, etc. 863 clipRect = windowClipRect(); 864 clipRect.move(-windowRect.x(), -windowRect.y()); 865 866 getPluginOcclusions(m_element, this->parent(), frameRect, cutOutRects); 867 // Convert to the plugin position. 868 for (size_t i = 0; i < cutOutRects.size(); i++) 869 cutOutRects[i].move(-frameRect.x(), -frameRect.y()); 870 } 871 872 WebCore::IntRect WebPluginContainerImpl::windowClipRect() const 873 { 874 // Start by clipping to our bounds. 875 IntRect clipRect = 876 convertToContainingWindow(IntRect(0, 0, width(), height())); 877 878 // document()->renderer() can be 0 when we receive messages from the 879 // plugins while we are destroying a frame. 880 if (m_element->renderer()->document()->renderer()) { 881 // Take our element and get the clip rect from the enclosing layer and 882 // frame view. 883 clipRect.intersect( 884 m_element->document()->view()->windowClipRectForFrameOwner(m_element, true)); 885 } 886 887 return clipRect; 888 } 889 890 } // namespace WebKit 891