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