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 "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