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