• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setFrameRect(const IntRect & frameRect)101 void WebPluginContainerImpl::setFrameRect(const IntRect& frameRect)
102 {
103     Widget::setFrameRect(frameRect);
104     reportGeometry();
105 }
106 
paint(GraphicsContext * gc,const IntRect & damageRect)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 
invalidateRect(const IntRect & rect)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 
setFocus(bool focused)151 void WebPluginContainerImpl::setFocus(bool focused)
152 {
153     Widget::setFocus(focused);
154     m_webPlugin->updateFocus(focused);
155 }
156 
show()157 void WebPluginContainerImpl::show()
158 {
159     setSelfVisible(true);
160     m_webPlugin->updateVisibility(true);
161 
162     Widget::show();
163 }
164 
hide()165 void WebPluginContainerImpl::hide()
166 {
167     setSelfVisible(false);
168     m_webPlugin->updateVisibility(false);
169 
170     Widget::hide();
171 }
172 
handleEvent(Event * event)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 
frameRectsChanged()200 void WebPluginContainerImpl::frameRectsChanged()
201 {
202     Widget::frameRectsChanged();
203     reportGeometry();
204 }
205 
widgetPositionsUpdated()206 void WebPluginContainerImpl::widgetPositionsUpdated()
207 {
208     Widget::widgetPositionsUpdated();
209     reportGeometry();
210 }
211 
eventListenersRemoved()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 
setParentVisible(bool parentVisible)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 
setParent(Widget * widget)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 
setPlugin(WebPlugin * plugin)251 void WebPluginContainerImpl::setPlugin(WebPlugin* plugin)
252 {
253     if (plugin != m_webPlugin) {
254         m_element->resetInstance();
255         m_webPlugin = plugin;
256     }
257 }
258 
deviceScaleFactor()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 
pageScaleFactor()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 
pageZoomFactor()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 
setWebLayer(WebLayer * layer)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 
supportsPaginatedPrint() const316 bool WebPluginContainerImpl::supportsPaginatedPrint() const
317 {
318     return m_webPlugin->supportsPaginatedPrint();
319 }
320 
isPrintScalingDisabled() const321 bool WebPluginContainerImpl::isPrintScalingDisabled() const
322 {
323     return m_webPlugin->isPrintScalingDisabled();
324 }
325 
getCopiesToPrint() const326 int WebPluginContainerImpl::getCopiesToPrint() const
327 {
328     return m_webPlugin->getCopiesToPrint();
329 }
330 
printBegin(const WebPrintParams & printParams) const331 int WebPluginContainerImpl::printBegin(const WebPrintParams& printParams) const
332 {
333     return m_webPlugin->printBegin(printParams);
334 }
335 
printPage(int pageNumber,GraphicsContext * gc)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 
printEnd()345 void WebPluginContainerImpl::printEnd()
346 {
347     m_webPlugin->printEnd();
348 }
349 
copy()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 
executeEditCommand(const WebString & name)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 
executeEditCommand(const WebString & name,const WebString & value)370 bool WebPluginContainerImpl::executeEditCommand(const WebString& name, const WebString& value)
371 {
372     return m_webPlugin->executeEditCommand(name, value);
373 }
374 
element()375 WebElement WebPluginContainerImpl::element()
376 {
377     return WebElement(m_element);
378 }
379 
invalidate()380 void WebPluginContainerImpl::invalidate()
381 {
382     Widget::invalidate();
383 }
384 
invalidateRect(const WebRect & rect)385 void WebPluginContainerImpl::invalidateRect(const WebRect& rect)
386 {
387     invalidateRect(static_cast<IntRect>(rect));
388 }
389 
scrollRect(const WebRect & rect)390 void WebPluginContainerImpl::scrollRect(const WebRect& rect)
391 {
392     invalidateRect(rect);
393 }
394 
reportGeometry()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 
allowScriptObjects()412 void WebPluginContainerImpl::allowScriptObjects()
413 {
414 }
415 
clearScriptObjects()416 void WebPluginContainerImpl::clearScriptObjects()
417 {
418     if (!frame())
419         return;
420 
421     frame()->script().cleanupScriptObjectsForPlugin(this);
422 }
423 
scriptableObjectForElement()424 NPObject* WebPluginContainerImpl::scriptableObjectForElement()
425 {
426     return m_element->getNPObject();
427 }
428 
v8ObjectForElement()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 
executeScriptURL(const WebURL & url,bool popupsAllowed)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 
loadFrameRequest(const WebURLRequest & request,const WebString & target,bool notifyNeeded,void * notifyData)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 
zoomLevelChanged(double zoomLevel)491 void WebPluginContainerImpl::zoomLevelChanged(double zoomLevel)
492 {
493     WebViewImpl* view = WebViewImpl::fromPage(m_element->document().frame()->page());
494     view->fullFramePluginZoomLevelChanged(zoomLevel);
495 }
496 
isRectTopmost(const WebRect & rect)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 
requestTouchEventType(TouchEventRequestType requestType)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 
setWantsWheelEvents(bool wantsWheelEvents)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 
windowToLocalPoint(const WebPoint & point)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 
localToWindowPoint(const WebPoint & point)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 
didReceiveResponse(const ResourceResponse & response)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 
didReceiveData(const char * data,int dataLength)572 void WebPluginContainerImpl::didReceiveData(const char *data, int dataLength)
573 {
574     m_webPlugin->didReceiveData(data, dataLength);
575 }
576 
didFinishLoading()577 void WebPluginContainerImpl::didFinishLoading()
578 {
579     m_webPlugin->didFinishLoading();
580 }
581 
didFailLoading(const ResourceError & error)582 void WebPluginContainerImpl::didFailLoading(const ResourceError& error)
583 {
584     m_webPlugin->didFailLoading(error);
585 }
586 
platformLayer() const587 WebLayer* WebPluginContainerImpl::platformLayer() const
588 {
589     return m_webLayer;
590 }
591 
scriptableObject(v8::Isolate * isolate)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 
getFormValue(String & value)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 
supportsKeyboardFocus() const617 bool WebPluginContainerImpl::supportsKeyboardFocus() const
618 {
619     return m_webPlugin->supportsKeyboardFocus();
620 }
621 
supportsInputMethod() const622 bool WebPluginContainerImpl::supportsInputMethod() const
623 {
624     return m_webPlugin->supportsInputMethod();
625 }
626 
canProcessDrag() const627 bool WebPluginContainerImpl::canProcessDrag() const
628 {
629     return m_webPlugin->canProcessDrag();
630 }
631 
wantsWheelEvents()632 bool WebPluginContainerImpl::wantsWheelEvents()
633 {
634     return m_wantsWheelEvents;
635 }
636 
willDestroyPluginLoadObserver(WebPluginLoadObserver * observer)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 
scrollbarGroup()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 
willStartLiveResize()652 void WebPluginContainerImpl::willStartLiveResize()
653 {
654     if (m_scrollbarGroup)
655         m_scrollbarGroup->willStartLiveResize();
656 }
657 
willEndLiveResize()658 void WebPluginContainerImpl::willEndLiveResize()
659 {
660     if (m_scrollbarGroup)
661         m_scrollbarGroup->willEndLiveResize();
662 }
663 
paintCustomOverhangArea(GraphicsContext * context,const IntRect & horizontalOverhangArea,const IntRect & verticalOverhangArea,const IntRect & dirtyRect)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 
WebPluginContainerImpl(HTMLPlugInElement * element,WebPlugin * webPlugin)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 
~WebPluginContainerImpl()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)
detach()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 
handleMouseEvent(MouseEvent * event)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 
handleDragEvent(MouseEvent * event)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 
handleWheelEvent(WheelEvent * event)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 
handleKeyboardEvent(KeyboardEvent * event)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 
handleTouchEvent(TouchEvent * event)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 
gestureScrollHelper(ScrollbarGroup * scrollbarGroup,ScrollDirection positiveDirection,ScrollDirection negativeDirection,float delta)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 
handleGestureEvent(GestureEvent * event)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 
synthesizeMouseEventIfPossible(TouchEvent * event)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 
focusPlugin()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 
calculateGeometry(const IntRect & frameRect,IntRect & windowRect,IntRect & clipRect,Vector<IntRect> & cutOutRects)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 
windowClipRect() const947 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 
pluginShouldPersist() const966 bool WebPluginContainerImpl::pluginShouldPersist() const
967 {
968     return m_webPlugin->shouldPersist();
969 }
970 
971 } // namespace blink
972