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