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