Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / WebPluginContainerImpl.cpp
blobddf1f76d392af52adadb8ad96235638c994d9bb3
1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * Copyright (C) 2014 Opera Software ASA. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
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.
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.
32 #include "config.h"
33 #include "web/WebPluginContainerImpl.h"
35 #include "bindings/core/v8/ScriptController.h"
36 #include "bindings/core/v8/ScriptSourceCode.h"
37 #include "bindings/core/v8/V8Element.h"
38 #include "bindings/core/v8/V8NPObject.h"
39 #include "core/HTMLNames.h"
40 #include "core/clipboard/DataObject.h"
41 #include "core/clipboard/DataTransfer.h"
42 #include "core/events/DragEvent.h"
43 #include "core/events/GestureEvent.h"
44 #include "core/events/KeyboardEvent.h"
45 #include "core/events/MouseEvent.h"
46 #include "core/events/TouchEvent.h"
47 #include "core/events/WheelEvent.h"
48 #include "core/frame/EventHandlerRegistry.h"
49 #include "core/frame/FrameView.h"
50 #include "core/frame/LocalFrame.h"
51 #include "core/html/HTMLFormElement.h"
52 #include "core/html/HTMLPlugInElement.h"
53 #include "core/input/EventHandler.h"
54 #include "core/layout/HitTestResult.h"
55 #include "core/layout/LayoutBox.h"
56 #include "core/layout/LayoutPart.h"
57 #include "core/loader/FrameLoadRequest.h"
58 #include "core/page/FocusController.h"
59 #include "core/page/Page.h"
60 #include "core/page/scrolling/ScrollingCoordinator.h"
61 #include "core/paint/DeprecatedPaintLayer.h"
62 #include "core/paint/LayoutObjectDrawingRecorder.h"
63 #include "modules/plugins/PluginOcclusionSupport.h"
64 #include "platform/HostWindow.h"
65 #include "platform/KeyboardCodes.h"
66 #include "platform/PlatformGestureEvent.h"
67 #include "platform/UserGestureIndicator.h"
68 #include "platform/exported/WrappedResourceResponse.h"
69 #include "platform/graphics/GraphicsContext.h"
70 #include "platform/graphics/GraphicsLayer.h"
71 #include "platform/scroll/ScrollAnimator.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/web/WebElement.h"
85 #include "public/web/WebInputEvent.h"
86 #include "public/web/WebPlugin.h"
87 #include "public/web/WebPrintParams.h"
88 #include "public/web/WebPrintPresetOptions.h"
89 #include "public/web/WebViewClient.h"
90 #include "web/ChromeClientImpl.h"
91 #include "web/WebDataSourceImpl.h"
92 #include "web/WebInputEventConversion.h"
93 #include "web/WebViewImpl.h"
94 #include "wtf/Assertions.h"
96 namespace blink {
98 // Public methods --------------------------------------------------------------
100 void WebPluginContainerImpl::setFrameRect(const IntRect& frameRect)
102 Widget::setFrameRect(frameRect);
103 reportGeometry();
106 void WebPluginContainerImpl::layoutIfNeeded()
108 RELEASE_ASSERT(m_webPlugin);
109 m_webPlugin->layoutIfNeeded();
112 void WebPluginContainerImpl::paint(GraphicsContext* context, const IntRect& rect)
114 if (!parent())
115 return;
117 // Don't paint anything if the plugin doesn't intersect.
118 if (!frameRect().intersects(rect))
119 return;
121 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, LayoutPoint()))
122 return;
124 LayoutObjectDrawingRecorder drawingRecorder(*context, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, rect, LayoutPoint());
125 context->save();
127 ASSERT(parent()->isFrameView());
128 FrameView* view = toFrameView(parent());
130 // The plugin is positioned in the root frame's coordinates, so it needs to
131 // be painted in them too.
132 IntPoint origin = view->contentsToRootFrame(IntPoint(0, 0));
133 context->translate(static_cast<float>(-origin.x()), static_cast<float>(-origin.y()));
135 WebCanvas* canvas = context->canvas();
137 IntRect windowRect = view->contentsToRootFrame(rect);
138 m_webPlugin->paint(canvas, windowRect);
140 context->restore();
143 void WebPluginContainerImpl::invalidateRect(const IntRect& rect)
145 if (!parent())
146 return;
148 LayoutBox* layoutObject = toLayoutBox(m_element->layoutObject());
149 if (!layoutObject)
150 return;
152 IntRect dirtyRect = rect;
153 dirtyRect.move(
154 layoutObject->borderLeft() + layoutObject->paddingLeft(),
155 layoutObject->borderTop() + layoutObject->paddingTop());
157 m_pendingInvalidationRect.unite(dirtyRect);
159 layoutObject->setMayNeedPaintInvalidation();
162 void WebPluginContainerImpl::setFocus(bool focused, WebFocusType focusType)
164 Widget::setFocus(focused, focusType);
165 m_webPlugin->updateFocus(focused, focusType);
168 void WebPluginContainerImpl::show()
170 setSelfVisible(true);
171 m_webPlugin->updateVisibility(true);
173 Widget::show();
176 void WebPluginContainerImpl::hide()
178 setSelfVisible(false);
179 m_webPlugin->updateVisibility(false);
181 Widget::hide();
184 void WebPluginContainerImpl::handleEvent(Event* event)
186 if (!m_webPlugin->acceptsInputEvents())
187 return;
189 RefPtrWillBeRawPtr<WebPluginContainerImpl> protector(this);
190 // The events we pass are defined at:
191 // http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/structures5.html#1000000
192 // Don't take the documentation as truth, however. There are many cases
193 // where mozilla behaves differently than the spec.
194 if (event->isMouseEvent())
195 handleMouseEvent(toMouseEvent(event));
196 else if (event->isWheelEvent())
197 handleWheelEvent(toWheelEvent(event));
198 else if (event->isKeyboardEvent())
199 handleKeyboardEvent(toKeyboardEvent(event));
200 else if (event->isTouchEvent())
201 handleTouchEvent(toTouchEvent(event));
202 else if (event->isGestureEvent())
203 handleGestureEvent(toGestureEvent(event));
204 else if (event->isDragEvent() && m_webPlugin->canProcessDrag())
205 handleDragEvent(toDragEvent(event));
207 // FIXME: it would be cleaner if Widget::handleEvent returned true/false and
208 // HTMLPluginElement called setDefaultHandled or defaultEventHandler.
209 if (!event->defaultHandled())
210 m_element->Node::defaultEventHandler(event);
213 void WebPluginContainerImpl::frameRectsChanged()
215 Widget::frameRectsChanged();
216 reportGeometry();
219 void WebPluginContainerImpl::widgetPositionsUpdated()
221 Widget::widgetPositionsUpdated();
222 reportGeometry();
225 void WebPluginContainerImpl::eventListenersRemoved()
227 // We're no longer registered to receive touch events, so don't try to remove
228 // the touch event handlers in our destructor.
229 m_touchEventRequestType = TouchEventRequestTypeNone;
232 void WebPluginContainerImpl::setParentVisible(bool parentVisible)
234 // We override this function to make sure that geometry updates are sent
235 // over to the plugin. For e.g. when a plugin is instantiated it does not
236 // have a valid parent. As a result the first geometry update from webkit
237 // is ignored. This function is called when the plugin eventually gets a
238 // parent.
240 if (isParentVisible() == parentVisible)
241 return; // No change.
243 Widget::setParentVisible(parentVisible);
244 if (!isSelfVisible())
245 return; // This widget has explicitely been marked as not visible.
247 if (m_webPlugin)
248 m_webPlugin->updateVisibility(isVisible());
251 void WebPluginContainerImpl::setParent(Widget* widget)
253 // We override this function so that if the plugin is windowed, we can call
254 // NPP_SetWindow at the first possible moment. This ensures that
255 // NPP_SetWindow is called before the manual load data is sent to a plugin.
256 // If this order is reversed, Flash won't load videos.
258 Widget::setParent(widget);
259 if (widget)
260 reportGeometry();
261 else if (m_webPlugin)
262 m_webPlugin->containerDidDetachFromParent();
265 void WebPluginContainerImpl::setPlugin(WebPlugin* plugin)
267 if (plugin != m_webPlugin) {
268 m_element->resetInstance();
269 m_webPlugin = plugin;
273 float WebPluginContainerImpl::deviceScaleFactor()
275 Page* page = m_element->document().page();
276 if (!page)
277 return 1.0;
278 return page->deviceScaleFactor();
281 float WebPluginContainerImpl::pageScaleFactor()
283 Page* page = m_element->document().page();
284 if (!page)
285 return 1.0;
286 return page->pageScaleFactor();
289 float WebPluginContainerImpl::pageZoomFactor()
291 LocalFrame* frame = m_element->document().frame();
292 if (!frame)
293 return 1.0;
294 return frame->pageZoomFactor();
297 void WebPluginContainerImpl::setWebLayer(WebLayer* layer)
299 if (m_webLayer == layer)
300 return;
302 if (m_webLayer)
303 GraphicsLayer::unregisterContentsLayer(m_webLayer);
304 if (layer)
305 GraphicsLayer::registerContentsLayer(layer);
307 // If either of the layers is null we need to switch between hardware
308 // and software compositing.
309 bool needsCompositingUpdate = !m_webLayer || !layer;
311 m_webLayer = layer;
313 if (!needsCompositingUpdate)
314 return;
316 #if ENABLE(OILPAN)
317 if (!m_element)
318 return;
319 #endif
321 m_element->setNeedsCompositingUpdate();
324 bool WebPluginContainerImpl::supportsPaginatedPrint() const
326 return m_webPlugin->supportsPaginatedPrint();
329 bool WebPluginContainerImpl::isPrintScalingDisabled() const
331 return m_webPlugin->isPrintScalingDisabled();
334 bool WebPluginContainerImpl::getPrintPresetOptionsFromDocument(WebPrintPresetOptions* presetOptions) const
336 return m_webPlugin->getPrintPresetOptionsFromDocument(presetOptions);
339 int WebPluginContainerImpl::printBegin(const WebPrintParams& printParams) const
341 return m_webPlugin->printBegin(printParams);
344 void WebPluginContainerImpl::printPage(int pageNumber, GraphicsContext* gc, const IntRect& printRect)
346 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*gc, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, LayoutPoint()))
347 return;
349 LayoutObjectDrawingRecorder drawingRecorder(*gc, *m_element->layoutObject(), DisplayItem::Type::WebPlugin, printRect, LayoutPoint());
350 gc->save();
351 WebCanvas* canvas = gc->canvas();
352 m_webPlugin->printPage(pageNumber, canvas);
353 gc->restore();
356 void WebPluginContainerImpl::printEnd()
358 m_webPlugin->printEnd();
361 void WebPluginContainerImpl::copy()
363 if (!m_webPlugin->hasSelection())
364 return;
366 Platform::current()->clipboard()->writeHTML(m_webPlugin->selectionAsMarkup(), WebURL(), m_webPlugin->selectionAsText(), false);
369 bool WebPluginContainerImpl::executeEditCommand(const WebString& name)
371 if (m_webPlugin->executeEditCommand(name))
372 return true;
374 if (name != "Copy")
375 return false;
377 copy();
378 return true;
381 bool WebPluginContainerImpl::executeEditCommand(const WebString& name, const WebString& value)
383 return m_webPlugin->executeEditCommand(name, value);
386 WebElement WebPluginContainerImpl::element()
388 return WebElement(m_element);
391 void WebPluginContainerImpl::invalidate()
393 Widget::invalidate();
396 void WebPluginContainerImpl::invalidateRect(const WebRect& rect)
398 invalidateRect(static_cast<IntRect>(rect));
401 void WebPluginContainerImpl::scrollRect(const WebRect& rect)
403 invalidateRect(rect);
406 void WebPluginContainerImpl::setNeedsLayout()
408 if (m_element->layoutObject())
409 m_element->layoutObject()->setNeedsLayoutAndFullPaintInvalidation("Plugin needs layout");
412 void WebPluginContainerImpl::reportGeometry()
414 // We cannot compute geometry without a parent or layoutObject.
415 if (!parent() || !m_element || !m_element->layoutObject())
416 return;
418 IntRect windowRect, clipRect, unobscuredRect;
419 Vector<IntRect> cutOutRects;
420 calculateGeometry(windowRect, clipRect, unobscuredRect, cutOutRects);
422 m_webPlugin->updateGeometry(windowRect, clipRect, unobscuredRect, cutOutRects, isVisible());
425 void WebPluginContainerImpl::allowScriptObjects()
429 void WebPluginContainerImpl::clearScriptObjects()
431 if (!frame())
432 return;
434 frame()->script().cleanupScriptObjectsForPlugin(this);
437 NPObject* WebPluginContainerImpl::scriptableObjectForElement()
439 return m_element->getNPObject();
442 v8::Local<v8::Object> WebPluginContainerImpl::v8ObjectForElement()
444 LocalFrame* frame = m_element->document().frame();
445 if (!frame)
446 return v8::Local<v8::Object>();
448 if (!frame->script().canExecuteScripts(NotAboutToExecuteScript))
449 return v8::Local<v8::Object>();
451 ScriptState* scriptState = ScriptState::forMainWorld(frame);
452 if (!scriptState->contextIsValid())
453 return v8::Local<v8::Object>();
455 v8::Local<v8::Value> v8value = toV8(m_element.get(), scriptState->context()->Global(), scriptState->isolate());
456 if (v8value.IsEmpty())
457 return v8::Local<v8::Object>();
458 ASSERT(v8value->IsObject());
460 return v8::Local<v8::Object>::Cast(v8value);
463 WebString WebPluginContainerImpl::executeScriptURL(const WebURL& url, bool popupsAllowed)
465 LocalFrame* frame = m_element->document().frame();
466 if (!frame)
467 return WebString();
469 const KURL& kurl = url;
470 ASSERT(kurl.protocolIs("javascript"));
472 String script = decodeURLEscapeSequences(
473 kurl.string().substring(strlen("javascript:")));
475 UserGestureIndicator gestureIndicator(popupsAllowed ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture);
476 v8::HandleScope handleScope(toIsolate(frame));
477 v8::Local<v8::Value> result = frame->script().executeScriptInMainWorldAndReturnValue(ScriptSourceCode(script));
479 // Failure is reported as a null string.
480 if (result.IsEmpty() || !result->IsString())
481 return WebString();
482 return toCoreString(v8::Local<v8::String>::Cast(result));
485 void WebPluginContainerImpl::loadFrameRequest(const WebURLRequest& request, const WebString& target, bool notifyNeeded, void* notifyData)
487 LocalFrame* frame = m_element->document().frame();
488 if (!frame || !frame->loader().documentLoader())
489 return; // FIXME: send a notification in this case?
491 if (notifyNeeded) {
492 // FIXME: This is a bit of hack to allow us to observe completion of
493 // our frame request. It would be better to evolve FrameLoader to
494 // support a completion callback instead.
495 OwnPtr<WebPluginLoadObserver> observer = adoptPtr(new WebPluginLoadObserver(this, request.url(), notifyData));
496 // FIXME: Calling get here is dangerous! What if observer is freed?
497 m_pluginLoadObservers.append(observer.get());
498 WebDataSourceImpl::setNextPluginLoadObserver(observer.release());
501 FrameLoadRequest frameRequest(frame->document(), request.toResourceRequest(), target);
502 frame->loader().load(frameRequest);
505 bool WebPluginContainerImpl::isRectTopmost(const WebRect& rect)
507 // Disallow access to the frame during dispose(), because it is not guaranteed to
508 // be valid memory once this object has started disposal. In particular, we might be being
509 // disposed because the frame has already be deleted and then something else dropped the
510 // last reference to the this object.
511 if (m_inDispose || !m_element)
512 return false;
514 LocalFrame* frame = m_element->document().frame();
515 if (!frame)
516 return false;
518 IntRect documentRect(x() + rect.x, y() + rect.y, rect.width, rect.height);
519 // hitTestResultAtPoint() takes a padding rectangle.
520 // FIXME: We'll be off by 1 when the width or height is even.
521 LayoutPoint center = documentRect.center();
522 // Make the rect we're checking (the point surrounded by padding rects) contained inside the requested rect. (Note that -1/2 is 0.)
523 LayoutSize padding((documentRect.width() - 1) / 2, (documentRect.height() - 1) / 2);
524 HitTestResult result = frame->eventHandler().hitTestResultAtPoint(center, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased, padding);
525 const HitTestResult::NodeSet& nodes = result.listBasedTestResult();
526 if (nodes.size() != 1)
527 return false;
528 return nodes.first().get() == m_element;
531 void WebPluginContainerImpl::requestTouchEventType(TouchEventRequestType requestType)
533 if (m_touchEventRequestType == requestType)
534 return;
536 if (m_element->document().frameHost()) {
537 EventHandlerRegistry& registry = m_element->document().frameHost()->eventHandlerRegistry();
538 if (requestType != TouchEventRequestTypeNone && m_touchEventRequestType == TouchEventRequestTypeNone)
539 registry.didAddEventHandler(*m_element, EventHandlerRegistry::TouchEvent);
540 else if (requestType == TouchEventRequestTypeNone && m_touchEventRequestType != TouchEventRequestTypeNone)
541 registry.didRemoveEventHandler(*m_element, EventHandlerRegistry::TouchEvent);
543 m_touchEventRequestType = requestType;
546 void WebPluginContainerImpl::setWantsWheelEvents(bool wantsWheelEvents)
548 if (m_wantsWheelEvents == wantsWheelEvents)
549 return;
550 m_wantsWheelEvents = wantsWheelEvents;
551 if (Page* page = m_element->document().page()) {
552 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
553 if (parent() && parent()->isFrameView())
554 scrollingCoordinator->notifyLayoutUpdated();
559 WebPoint WebPluginContainerImpl::rootFrameToLocalPoint(const WebPoint& pointInRootFrame)
561 FrameView* view = toFrameView(parent());
562 if (!view)
563 return pointInRootFrame;
564 WebPoint pointInContent = view->rootFrameToContents(pointInRootFrame);
565 return roundedIntPoint(m_element->layoutObject()->absoluteToLocal(FloatPoint(pointInContent), UseTransforms));
568 WebPoint WebPluginContainerImpl::localToRootFramePoint(const WebPoint& pointInLocal)
570 FrameView* view = toFrameView(parent());
571 if (!view)
572 return pointInLocal;
573 IntPoint absolutePoint = roundedIntPoint(m_element->layoutObject()->localToAbsolute(FloatPoint(pointInLocal), UseTransforms));
574 return view->contentsToRootFrame(absolutePoint);
577 void WebPluginContainerImpl::didReceiveResponse(const ResourceResponse& response)
579 // Make sure that the plugin receives window geometry before data, or else
580 // plugins misbehave.
581 frameRectsChanged();
583 WrappedResourceResponse urlResponse(response);
584 m_webPlugin->didReceiveResponse(urlResponse);
587 void WebPluginContainerImpl::didReceiveData(const char *data, int dataLength)
589 m_webPlugin->didReceiveData(data, dataLength);
592 void WebPluginContainerImpl::didFinishLoading()
594 m_webPlugin->didFinishLoading();
597 void WebPluginContainerImpl::didFailLoading(const ResourceError& error)
599 m_webPlugin->didFailLoading(error);
602 WebLayer* WebPluginContainerImpl::platformLayer() const
604 return m_webLayer;
607 v8::Local<v8::Object> WebPluginContainerImpl::scriptableObject(v8::Isolate* isolate)
609 #if ENABLE(OILPAN)
610 // With Oilpan, on plugin element detach dispose() will be called to safely
611 // clear out references, including the pre-emptive destruction of the plugin.
613 // It clearly has no scriptable object if in such a disposed state.
614 if (!m_webPlugin)
615 return v8::Local<v8::Object>();
616 #endif
618 // The plugin may be destroyed due to re-entrancy when calling
619 // v8ScriptableObject below. crbug.com/458776. Hold a reference to the
620 // plugin container to prevent this from happening. For Oilpan, 'this'
621 // is already stack reachable, so redundant.
622 RefPtrWillBeRawPtr<WebPluginContainerImpl> protector(this);
624 v8::Local<v8::Object> object = m_webPlugin->v8ScriptableObject(isolate);
626 // If the plugin has been destroyed and the reference on the stack is the
627 // only one left, then don't return the scriptable object.
628 #if ENABLE(OILPAN)
629 if (!m_webPlugin)
630 #else
631 if (hasOneRef())
632 #endif
633 return v8::Local<v8::Object>();
635 if (!object.IsEmpty()) {
636 // WebPlugin implementation can't provide the obsolete NPObject at the same time:
637 ASSERT(!m_webPlugin->scriptableObject());
638 return object;
641 NPObject* npObject = m_webPlugin->scriptableObject();
642 if (npObject)
643 return createV8ObjectForNPObject(isolate, npObject, 0);
644 return v8::Local<v8::Object>();
647 bool WebPluginContainerImpl::getFormValue(String& value)
649 WebString webValue;
650 if (m_webPlugin->getFormValue(webValue)) {
651 value = webValue;
652 return true;
654 return false;
657 bool WebPluginContainerImpl::supportsKeyboardFocus() const
659 return m_webPlugin->supportsKeyboardFocus();
662 bool WebPluginContainerImpl::supportsInputMethod() const
664 return m_webPlugin->supportsInputMethod();
667 bool WebPluginContainerImpl::canProcessDrag() const
669 return m_webPlugin->canProcessDrag();
672 bool WebPluginContainerImpl::wantsWheelEvents()
674 return m_wantsWheelEvents;
677 void WebPluginContainerImpl::willDestroyPluginLoadObserver(WebPluginLoadObserver* observer)
679 size_t pos = m_pluginLoadObservers.find(observer);
680 if (pos == kNotFound)
681 return;
682 m_pluginLoadObservers.remove(pos);
685 // Private methods -------------------------------------------------------------
687 WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement* element, WebPlugin* webPlugin)
688 : LocalFrameLifecycleObserver(element->document().frame())
689 , m_element(element)
690 , m_webPlugin(webPlugin)
691 , m_webLayer(nullptr)
692 , m_touchEventRequestType(TouchEventRequestTypeNone)
693 , m_wantsWheelEvents(false)
694 , m_inDispose(false)
695 #if ENABLE(OILPAN)
696 , m_shouldDisposePlugin(false)
697 #endif
701 WebPluginContainerImpl::~WebPluginContainerImpl()
703 #if ENABLE(OILPAN)
704 if (m_shouldDisposePlugin)
705 dispose();
706 // The plugin container must have been disposed of by now.
707 ASSERT(!m_webPlugin);
708 #else
709 dispose();
710 #endif
713 void WebPluginContainerImpl::dispose()
715 m_inDispose = true;
717 if (m_element && m_touchEventRequestType != TouchEventRequestTypeNone && m_element->document().frameHost())
718 m_element->document().frameHost()->eventHandlerRegistry().didRemoveEventHandler(*m_element, EventHandlerRegistry::TouchEvent);
720 for (size_t i = 0; i < m_pluginLoadObservers.size(); ++i)
721 m_pluginLoadObservers[i]->clearPluginContainer();
723 if (m_webPlugin)
724 m_webPlugin->destroy();
725 m_webPlugin = nullptr;
727 if (m_webLayer) {
728 GraphicsLayer::unregisterContentsLayer(m_webLayer);
729 m_webLayer = nullptr;
732 m_pluginLoadObservers.clear();
733 m_element = nullptr;
736 #if ENABLE(OILPAN)
737 void WebPluginContainerImpl::shouldDisposePlugin()
739 // If the LocalFrame is still alive, but the plugin element isn't, the
740 // LocalFrame will set m_shouldDisposePlugin via its weak pointer
741 // callback. This is a signal that the plugin container
742 // must dispose of its plugin when finalizing. The LocalFrame and
743 // all objects accessible from it can safely be accessed, but not
744 // the plugin element itself.
745 ASSERT(!m_shouldDisposePlugin);
746 m_shouldDisposePlugin = true;
747 m_element = nullptr;
749 #endif
751 DEFINE_TRACE(WebPluginContainerImpl)
753 visitor->trace(m_element);
754 LocalFrameLifecycleObserver::trace(visitor);
755 PluginView::trace(visitor);
758 void WebPluginContainerImpl::handleMouseEvent(MouseEvent* event)
760 ASSERT(parent()->isFrameView());
762 // We cache the parent FrameView here as the plugin widget could be deleted
763 // in the call to HandleEvent. See http://b/issue?id=1362948
764 FrameView* parentView = toFrameView(parent());
766 WebMouseEventBuilder webEvent(this, m_element->layoutObject(), *event);
767 if (webEvent.type == WebInputEvent::Undefined)
768 return;
770 if (event->type() == EventTypeNames::mousedown)
771 focusPlugin();
773 WebCursorInfo cursorInfo;
774 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
775 event->setDefaultHandled();
777 // A windowless plugin can change the cursor in response to a mouse move
778 // event. We need to reflect the changed cursor in the frame view as the
779 // mouse is moved in the boundaries of the windowless plugin.
780 Page* page = parentView->frame().page();
781 if (!page)
782 return;
783 toChromeClientImpl(page->chromeClient()).setCursorForPlugin(cursorInfo);
786 void WebPluginContainerImpl::handleDragEvent(MouseEvent* event)
788 ASSERT(event->isDragEvent());
790 WebDragStatus dragStatus = WebDragStatusUnknown;
791 if (event->type() == EventTypeNames::dragenter)
792 dragStatus = WebDragStatusEnter;
793 else if (event->type() == EventTypeNames::dragleave)
794 dragStatus = WebDragStatusLeave;
795 else if (event->type() == EventTypeNames::dragover)
796 dragStatus = WebDragStatusOver;
797 else if (event->type() == EventTypeNames::drop)
798 dragStatus = WebDragStatusDrop;
800 if (dragStatus == WebDragStatusUnknown)
801 return;
803 DataTransfer* dataTransfer = event->dataTransfer();
804 WebDragData dragData = dataTransfer->dataObject()->toWebDragData();
805 WebDragOperationsMask dragOperationMask = static_cast<WebDragOperationsMask>(dataTransfer->sourceOperation());
806 WebPoint dragScreenLocation(event->screenX(), event->screenY());
807 WebPoint dragLocation(event->absoluteLocation().x() - location().x(), event->absoluteLocation().y() - location().y());
809 m_webPlugin->handleDragStatusUpdate(dragStatus, dragData, dragOperationMask, dragLocation, dragScreenLocation);
812 void WebPluginContainerImpl::handleWheelEvent(WheelEvent* event)
814 WebMouseWheelEventBuilder webEvent(this, m_element->layoutObject(), *event);
815 if (webEvent.type == WebInputEvent::Undefined)
816 return;
818 WebCursorInfo cursorInfo;
819 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
820 event->setDefaultHandled();
823 void WebPluginContainerImpl::handleKeyboardEvent(KeyboardEvent* event)
825 WebKeyboardEventBuilder webEvent(*event);
826 if (webEvent.type == WebInputEvent::Undefined)
827 return;
829 if (webEvent.type == WebInputEvent::KeyDown) {
830 #if OS(MACOSX)
831 if (webEvent.modifiers == WebInputEvent::MetaKey
832 #else
833 if (webEvent.modifiers == WebInputEvent::ControlKey
834 #endif
835 && (webEvent.windowsKeyCode == VKEY_C || webEvent.windowsKeyCode == VKEY_INSERT)
836 // Only copy if there's a selection, so that we only ever do this
837 // for Pepper plugins that support copying. Windowless NPAPI
838 // plugins will get the event as before.
839 && m_webPlugin->hasSelection()) {
840 copy();
841 event->setDefaultHandled();
842 return;
846 const WebInputEvent* currentInputEvent = WebViewImpl::currentInputEvent();
848 // Copy stashed info over, and only copy here in order not to interfere
849 // the ctrl-c logic above.
850 if (currentInputEvent
851 && WebInputEvent::isKeyboardEventType(currentInputEvent->type)) {
852 webEvent.modifiers |= currentInputEvent->modifiers &
853 (WebInputEvent::CapsLockOn | WebInputEvent::NumLockOn);
856 // Give the client a chance to issue edit comamnds.
857 WebViewImpl* view = WebViewImpl::fromPage(m_element->document().frame()->page());
858 if (m_webPlugin->supportsEditCommands() && view->client())
859 view->client()->handleCurrentKeyboardEvent();
861 WebCursorInfo cursorInfo;
862 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
863 event->setDefaultHandled();
866 void WebPluginContainerImpl::handleTouchEvent(TouchEvent* event)
868 switch (m_touchEventRequestType) {
869 case TouchEventRequestTypeNone:
870 return;
871 case TouchEventRequestTypeRaw: {
872 WebTouchEventBuilder webEvent(m_element->layoutObject(), *event);
873 if (webEvent.type == WebInputEvent::Undefined)
874 return;
876 if (event->type() == EventTypeNames::touchstart)
877 focusPlugin();
879 WebCursorInfo cursorInfo;
880 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
881 event->setDefaultHandled();
882 // FIXME: Can a plugin change the cursor from a touch-event callback?
883 return;
885 case TouchEventRequestTypeSynthesizedMouse:
886 synthesizeMouseEventIfPossible(event);
887 return;
891 void WebPluginContainerImpl::handleGestureEvent(GestureEvent* event)
893 WebGestureEventBuilder webEvent(m_element->layoutObject(), *event);
894 if (webEvent.type == WebInputEvent::Undefined)
895 return;
896 if (event->type() == EventTypeNames::gesturetapdown)
897 focusPlugin();
898 WebCursorInfo cursorInfo;
899 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) {
900 event->setDefaultHandled();
901 return;
904 // FIXME: Can a plugin change the cursor from a touch-event callback?
907 void WebPluginContainerImpl::synthesizeMouseEventIfPossible(TouchEvent* event)
909 WebMouseEventBuilder webEvent(this, m_element->layoutObject(), *event);
910 if (webEvent.type == WebInputEvent::Undefined)
911 return;
913 WebCursorInfo cursorInfo;
914 if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
915 event->setDefaultHandled();
918 void WebPluginContainerImpl::focusPlugin()
920 LocalFrame& containingFrame = toFrameView(parent())->frame();
921 if (Page* currentPage = containingFrame.page())
922 currentPage->focusController().setFocusedElement(m_element, &containingFrame);
923 else
924 containingFrame.document()->setFocusedElement(m_element);
927 void WebPluginContainerImpl::issuePaintInvalidations()
929 if (m_pendingInvalidationRect.isEmpty())
930 return;
932 LayoutBox* layoutObject = toLayoutBox(m_element->layoutObject());
933 if (!layoutObject)
934 return;
936 layoutObject->invalidatePaintRectangle(LayoutRect(m_pendingInvalidationRect));
937 m_pendingInvalidationRect = IntRect();
940 void WebPluginContainerImpl::calculateGeometry(IntRect& windowRect, IntRect& clipRect, IntRect& unobscuredRect, Vector<IntRect>& cutOutRects)
942 windowRect = toFrameView(parent())->contentsToRootFrame(frameRect());
944 // Calculate a clip-rect so that we don't overlap the scrollbars, etc.
945 clipRect = convertToContainingWindow(IntRect(0, 0, width(), height()));
946 unobscuredRect = clipRect;
948 // document().layoutView() can be 0 when we receive messages from the
949 // plugins while we are destroying a frame.
950 // FIXME: Can we just check m_element->document().isActive() ?
951 if (m_element->layoutObject()->document().layoutView()) {
952 // Take our element and get the clip rect from the enclosing layer and
953 // frame view.
954 IntRect elementUnobscuredRect;
955 IntRect elementWindowClipRect = m_element->document().view()->clipRectsForFrameOwner(m_element, &elementUnobscuredRect);
956 clipRect.intersect(elementWindowClipRect);
957 unobscuredRect.intersect(elementUnobscuredRect);
960 clipRect.move(-windowRect.x(), -windowRect.y());
961 unobscuredRect.move(-windowRect.x(), -windowRect.y());
963 getPluginOcclusions(m_element, this->parent(), frameRect(), cutOutRects);
964 // Convert to the plugin position.
965 for (size_t i = 0; i < cutOutRects.size(); i++)
966 cutOutRects[i].move(-frameRect().x(), -frameRect().y());
969 } // namespace blink