• 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 "web/WebPluginContainerImpl.h"
33 
34 #include "core/page/Chrome.h"
35 #include "core/page/EventHandler.h"
36 #include "platform/exported/WrappedResourceResponse.h"
37 #include "public/web/WebElement.h"
38 #include "public/web/WebInputEvent.h"
39 #include "public/web/WebPlugin.h"
40 #include "public/web/WebViewClient.h"
41 #include "web/ChromeClientImpl.h"
42 #include "web/ScrollbarGroup.h"
43 #include "web/WebDataSourceImpl.h"
44 #include "web/WebInputEventConversion.h"
45 #include "web/WebViewImpl.h"
46 
47 #include "bindings/v8/ScriptController.h"
48 #include "core/HTMLNames.h"
49 #include "core/clipboard/Clipboard.h"
50 #include "core/clipboard/DataObject.h"
51 #include "core/events/GestureEvent.h"
52 #include "core/events/KeyboardEvent.h"
53 #include "core/events/MouseEvent.h"
54 #include "core/events/TouchEvent.h"
55 #include "core/events/WheelEvent.h"
56 #include "core/frame/FrameView.h"
57 #include "core/frame/LocalFrame.h"
58 #include "core/html/HTMLFormElement.h"
59 #include "core/html/HTMLPlugInElement.h"
60 #include "core/loader/FormState.h"
61 #include "core/loader/FrameLoadRequest.h"
62 #include "core/page/FocusController.h"
63 #include "core/page/Page.h"
64 #include "core/page/scrolling/ScrollingCoordinator.h"
65 #include "core/plugins/PluginOcclusionSupport.h"
66 #include "core/rendering/HitTestResult.h"
67 #include "core/rendering/RenderBox.h"
68 #include "core/rendering/RenderLayer.h"
69 #include "platform/HostWindow.h"
70 #include "platform/KeyboardCodes.h"
71 #include "platform/PlatformGestureEvent.h"
72 #include "platform/UserGestureIndicator.h"
73 #include "platform/graphics/GraphicsContext.h"
74 #include "platform/graphics/GraphicsLayer.h"
75 #include "platform/scroll/ScrollAnimator.h"
76 #include "platform/scroll/ScrollView.h"
77 #include "platform/scroll/ScrollbarTheme.h"
78 #include "public/platform/Platform.h"
79 #include "public/platform/WebClipboard.h"
80 #include "public/platform/WebCompositorSupport.h"
81 #include "public/platform/WebCursorInfo.h"
82 #include "public/platform/WebDragData.h"
83 #include "public/platform/WebExternalTextureLayer.h"
84 #include "public/platform/WebRect.h"
85 #include "public/platform/WebString.h"
86 #include "public/platform/WebURL.h"
87 #include "public/platform/WebURLError.h"
88 #include "public/platform/WebURLRequest.h"
89 #include "public/platform/WebVector.h"
90 #include "public/web/WebPrintParams.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->invalidatePaintRectangle(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     RefPtr<WebPluginContainerImpl> protector(this);
183     // The events we pass are defined at:
184     //    http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/structures5.html#1000000
185     // Don't take the documentation as truth, however.  There are many cases
186     // where mozilla behaves differently than the spec.
187     if (event->isMouseEvent())
188         handleMouseEvent(toMouseEvent(event));
189     else if (event->isWheelEvent())
190         handleWheelEvent(toWheelEvent(event));
191     else if (event->isKeyboardEvent())
192         handleKeyboardEvent(toKeyboardEvent(event));
193     else if (event->isTouchEvent())
194         handleTouchEvent(toTouchEvent(event));
195     else if (event->isGestureEvent())
196         handleGestureEvent(toGestureEvent(event));
197 
198     // FIXME: it would be cleaner if Widget::handleEvent returned true/false and
199     // HTMLPluginElement called setDefaultHandled or defaultEventHandler.
200     if (!event->defaultHandled())
201         m_element->Node::defaultEventHandler(event);
202 }
203 
frameRectsChanged()204 void WebPluginContainerImpl::frameRectsChanged()
205 {
206     Widget::frameRectsChanged();
207     reportGeometry();
208 }
209 
widgetPositionsUpdated()210 void WebPluginContainerImpl::widgetPositionsUpdated()
211 {
212     Widget::widgetPositionsUpdated();
213     reportGeometry();
214 }
215 
eventListenersRemoved()216 void WebPluginContainerImpl::eventListenersRemoved()
217 {
218     // We're no longer registered to receive touch events, so don't try to remove
219     // the touch event handlers in our destructor.
220     m_touchEventRequestType = TouchEventRequestTypeNone;
221 }
222 
setParentVisible(bool parentVisible)223 void WebPluginContainerImpl::setParentVisible(bool parentVisible)
224 {
225     // We override this function to make sure that geometry updates are sent
226     // over to the plugin. For e.g. when a plugin is instantiated it does not
227     // have a valid parent. As a result the first geometry update from webkit
228     // is ignored. This function is called when the plugin eventually gets a
229     // parent.
230 
231     if (isParentVisible() == parentVisible)
232         return;  // No change.
233 
234     Widget::setParentVisible(parentVisible);
235     if (!isSelfVisible())
236         return;  // This widget has explicitely been marked as not visible.
237 
238     m_webPlugin->updateVisibility(isVisible());
239 }
240 
setParent(Widget * widget)241 void WebPluginContainerImpl::setParent(Widget* widget)
242 {
243     // We override this function so that if the plugin is windowed, we can call
244     // NPP_SetWindow at the first possible moment.  This ensures that
245     // NPP_SetWindow is called before the manual load data is sent to a plugin.
246     // If this order is reversed, Flash won't load videos.
247 
248     Widget::setParent(widget);
249     if (widget)
250         reportGeometry();
251     else if (m_webPlugin)
252         m_webPlugin->containerDidDetachFromParent();
253 }
254 
setPlugin(WebPlugin * plugin)255 void WebPluginContainerImpl::setPlugin(WebPlugin* plugin)
256 {
257     if (plugin != m_webPlugin) {
258         m_element->resetInstance();
259         m_webPlugin = plugin;
260     }
261 }
262 
deviceScaleFactor()263 float WebPluginContainerImpl::deviceScaleFactor()
264 {
265     Page* page = m_element->document().page();
266     if (!page)
267         return 1.0;
268     return page->deviceScaleFactor();
269 }
270 
pageScaleFactor()271 float WebPluginContainerImpl::pageScaleFactor()
272 {
273     Page* page = m_element->document().page();
274     if (!page)
275         return 1.0;
276     return page->pageScaleFactor();
277 }
278 
pageZoomFactor()279 float WebPluginContainerImpl::pageZoomFactor()
280 {
281     LocalFrame* frame = m_element->document().frame();
282     if (!frame)
283         return 1.0;
284     return frame->pageZoomFactor();
285 }
286 
setWebLayer(WebLayer * layer)287 void WebPluginContainerImpl::setWebLayer(WebLayer* layer)
288 {
289     if (m_webLayer == layer)
290         return;
291 
292     if (m_webLayer)
293         GraphicsLayer::unregisterContentsLayer(m_webLayer);
294     if (layer)
295         GraphicsLayer::registerContentsLayer(layer);
296 
297     // If either of the layers is null we need to switch between hardware
298     // and software compositing.
299     bool needsCompositingUpdate = !m_webLayer || !layer;
300 
301     m_webLayer = layer;
302 
303     if (!needsCompositingUpdate)
304         return;
305 
306     m_element->setNeedsCompositingUpdate();
307     // Being composited or not affects the self painting layer bit
308     // on the RenderLayer.
309     if (RenderPart* renderer = m_element->renderPart()) {
310         ASSERT(renderer->hasLayer());
311         renderer->layer()->updateSelfPaintingLayer();
312     }
313 }
314 
supportsPaginatedPrint() const315 bool WebPluginContainerImpl::supportsPaginatedPrint() const
316 {
317     return m_webPlugin->supportsPaginatedPrint();
318 }
319 
isPrintScalingDisabled() const320 bool WebPluginContainerImpl::isPrintScalingDisabled() const
321 {
322     return m_webPlugin->isPrintScalingDisabled();
323 }
324 
printBegin(const WebPrintParams & printParams) const325 int WebPluginContainerImpl::printBegin(const WebPrintParams& printParams) const
326 {
327     return m_webPlugin->printBegin(printParams);
328 }
329 
printPage(int pageNumber,WebCore::GraphicsContext * gc)330 bool WebPluginContainerImpl::printPage(int pageNumber,
331                                        WebCore::GraphicsContext* gc)
332 {
333     if (gc->paintingDisabled())
334         return true;
335     gc->save();
336     WebCanvas* canvas = gc->canvas();
337     bool ret = m_webPlugin->printPage(pageNumber, canvas);
338     gc->restore();
339     return ret;
340 }
341 
printEnd()342 void WebPluginContainerImpl::printEnd()
343 {
344     m_webPlugin->printEnd();
345 }
346 
copy()347 void WebPluginContainerImpl::copy()
348 {
349     if (!m_webPlugin->hasSelection())
350         return;
351 
352     blink::Platform::current()->clipboard()->writeHTML(m_webPlugin->selectionAsMarkup(), WebURL(), m_webPlugin->selectionAsText(), false);
353 }
354 
executeEditCommand(const WebString & name)355 bool WebPluginContainerImpl::executeEditCommand(const WebString& name)
356 {
357     if (m_webPlugin->executeEditCommand(name))
358         return true;
359 
360     if (name != "Copy")
361         return false;
362 
363     copy();
364     return true;
365 }
366 
executeEditCommand(const WebString & name,const WebString & value)367 bool WebPluginContainerImpl::executeEditCommand(const WebString& name, const WebString& value)
368 {
369     return m_webPlugin->executeEditCommand(name, value);
370 }
371 
element()372 WebElement WebPluginContainerImpl::element()
373 {
374     return WebElement(m_element);
375 }
376 
invalidate()377 void WebPluginContainerImpl::invalidate()
378 {
379     Widget::invalidate();
380 }
381 
invalidateRect(const WebRect & rect)382 void WebPluginContainerImpl::invalidateRect(const WebRect& rect)
383 {
384     invalidateRect(static_cast<IntRect>(rect));
385 }
386 
scrollRect(int dx,int dy,const WebRect & rect)387 void WebPluginContainerImpl::scrollRect(int dx, int dy, const WebRect& rect)
388 {
389     Widget* parentWidget = parent();
390     if (parentWidget->isFrameView()) {
391         FrameView* parentFrameView = toFrameView(parentWidget);
392         if (!parentFrameView->isOverlapped()) {
393             IntRect damageRect = convertToContainingWindow(static_cast<IntRect>(rect));
394             IntSize scrollDelta(dx, dy);
395             // scroll() only uses the second rectangle, clipRect, and ignores the first
396             // rectangle.
397             parent()->hostWindow()->scroll(scrollDelta, damageRect, damageRect);
398             return;
399         }
400     }
401 
402     // Use slow scrolling instead.
403     invalidateRect(rect);
404 }
405 
reportGeometry()406 void WebPluginContainerImpl::reportGeometry()
407 {
408     if (!parent())
409         return;
410 
411     IntRect windowRect, clipRect;
412     Vector<IntRect> cutOutRects;
413     calculateGeometry(frameRect(), windowRect, clipRect, cutOutRects);
414 
415     m_webPlugin->updateGeometry(windowRect, clipRect, cutOutRects, isVisible());
416 
417     if (m_scrollbarGroup) {
418         m_scrollbarGroup->scrollAnimator()->contentsResized();
419         m_scrollbarGroup->setFrameRect(frameRect());
420     }
421 }
422 
allowScriptObjects()423 void WebPluginContainerImpl::allowScriptObjects()
424 {
425 }
426 
clearScriptObjects()427 void WebPluginContainerImpl::clearScriptObjects()
428 {
429     LocalFrame* frame = m_element->document().frame();
430     if (!frame)
431         return;
432     frame->script().cleanupScriptObjectsForPlugin(this);
433 }
434 
scriptableObjectForElement()435 NPObject* WebPluginContainerImpl::scriptableObjectForElement()
436 {
437     return m_element->getNPObject();
438 }
439 
executeScriptURL(const WebURL & url,bool popupsAllowed)440 WebString WebPluginContainerImpl::executeScriptURL(const WebURL& url, bool popupsAllowed)
441 {
442     LocalFrame* frame = m_element->document().frame();
443     if (!frame)
444         return WebString();
445 
446     const KURL& kurl = url;
447     ASSERT(kurl.protocolIs("javascript"));
448 
449     String script = decodeURLEscapeSequences(
450         kurl.string().substring(strlen("javascript:")));
451 
452     UserGestureIndicator gestureIndicator(popupsAllowed ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture);
453     v8::HandleScope handleScope(toIsolate(frame));
454     v8::Local<v8::Value> result = frame->script().executeScriptInMainWorldAndReturnValue(ScriptSourceCode(script));
455 
456     // Failure is reported as a null string.
457     if (result.IsEmpty() || !result->IsString())
458         return WebString();
459     return toCoreString(v8::Handle<v8::String>::Cast(result));
460 }
461 
loadFrameRequest(const WebURLRequest & request,const WebString & target,bool notifyNeeded,void * notifyData)462 void WebPluginContainerImpl::loadFrameRequest(const WebURLRequest& request, const WebString& target, bool notifyNeeded, void* notifyData)
463 {
464     LocalFrame* frame = m_element->document().frame();
465     if (!frame || !frame->loader().documentLoader())
466         return;  // FIXME: send a notification in this case?
467 
468     if (notifyNeeded) {
469         // FIXME: This is a bit of hack to allow us to observe completion of
470         // our frame request.  It would be better to evolve FrameLoader to
471         // support a completion callback instead.
472         OwnPtr<WebPluginLoadObserver> observer = adoptPtr(new WebPluginLoadObserver(this, request.url(), notifyData));
473         // FIXME: Calling get here is dangerous! What if observer is freed?
474         m_pluginLoadObservers.append(observer.get());
475         WebDataSourceImpl::setNextPluginLoadObserver(observer.release());
476     }
477 
478     FrameLoadRequest frameRequest(frame->document(), request.toResourceRequest(), target);
479     UserGestureIndicator gestureIndicator(request.hasUserGesture() ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture);
480     frame->loader().load(frameRequest);
481 }
482 
zoomLevelChanged(double zoomLevel)483 void WebPluginContainerImpl::zoomLevelChanged(double zoomLevel)
484 {
485     WebViewImpl* view = WebViewImpl::fromPage(m_element->document().frame()->page());
486     view->fullFramePluginZoomLevelChanged(zoomLevel);
487 }
488 
isRectTopmost(const WebRect & rect)489 bool WebPluginContainerImpl::isRectTopmost(const WebRect& rect)
490 {
491     LocalFrame* frame = m_element->document().frame();
492     if (!frame)
493         return false;
494 
495     // hitTestResultAtPoint() takes a padding rectangle.
496     // FIXME: We'll be off by 1 when the width or height is even.
497     IntRect documentRect(x() + rect.x, y() + rect.y, rect.width, rect.height);
498     LayoutPoint center = documentRect.center();
499     // Make the rect we're checking (the point surrounded by padding rects) contained inside the requested rect. (Note that -1/2 is 0.)
500     LayoutSize padding((documentRect.width() - 1) / 2, (documentRect.height() - 1) / 2);
501     HitTestResult result = frame->eventHandler().hitTestResultAtPoint(center, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, padding);
502     const HitTestResult::NodeSet& nodes = result.rectBasedTestResult();
503     if (nodes.size() != 1)
504         return false;
505     return nodes.first().get() == m_element;
506 }
507 
requestTouchEventType(TouchEventRequestType requestType)508 void WebPluginContainerImpl::requestTouchEventType(TouchEventRequestType requestType)
509 {
510     if (m_touchEventRequestType == requestType)
511         return;
512 
513     if (requestType != TouchEventRequestTypeNone && m_touchEventRequestType == TouchEventRequestTypeNone)
514         m_element->document().didAddTouchEventHandler(m_element);
515     else if (requestType == TouchEventRequestTypeNone && m_touchEventRequestType != TouchEventRequestTypeNone)
516         m_element->document().didRemoveTouchEventHandler(m_element);
517     m_touchEventRequestType = requestType;
518 }
519 
setWantsWheelEvents(bool wantsWheelEvents)520 void WebPluginContainerImpl::setWantsWheelEvents(bool wantsWheelEvents)
521 {
522     if (m_wantsWheelEvents == wantsWheelEvents)
523         return;
524     m_wantsWheelEvents = wantsWheelEvents;
525     if (Page* page = m_element->document().page()) {
526         if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
527             if (parent() && parent()->isFrameView())
528                 scrollingCoordinator->notifyLayoutUpdated();
529         }
530     }
531 }
532 
windowToLocalPoint(const WebPoint & point)533 WebPoint WebPluginContainerImpl::windowToLocalPoint(const WebPoint& point)
534 {
535     ScrollView* view = toScrollView(parent());
536     if (!view)
537         return point;
538     WebPoint windowPoint = view->windowToContents(point);
539     return roundedIntPoint(m_element->renderer()->absoluteToLocal(LayoutPoint(windowPoint), UseTransforms));
540 }
541 
localToWindowPoint(const WebPoint & point)542 WebPoint WebPluginContainerImpl::localToWindowPoint(const WebPoint& point)
543 {
544     ScrollView* view = toScrollView(parent());
545     if (!view)
546         return point;
547     IntPoint absolutePoint = roundedIntPoint(m_element->renderer()->localToAbsolute(LayoutPoint(point), UseTransforms));
548     return view->contentsToWindow(absolutePoint);
549 }
550 
didReceiveResponse(const ResourceResponse & response)551 void WebPluginContainerImpl::didReceiveResponse(const ResourceResponse& response)
552 {
553     // Make sure that the plugin receives window geometry before data, or else
554     // plugins misbehave.
555     frameRectsChanged();
556 
557     WrappedResourceResponse urlResponse(response);
558     m_webPlugin->didReceiveResponse(urlResponse);
559 }
560 
didReceiveData(const char * data,int dataLength)561 void WebPluginContainerImpl::didReceiveData(const char *data, int dataLength)
562 {
563     m_webPlugin->didReceiveData(data, dataLength);
564 }
565 
didFinishLoading()566 void WebPluginContainerImpl::didFinishLoading()
567 {
568     m_webPlugin->didFinishLoading();
569 }
570 
didFailLoading(const ResourceError & error)571 void WebPluginContainerImpl::didFailLoading(const ResourceError& error)
572 {
573     m_webPlugin->didFailLoading(error);
574 }
575 
platformLayer() const576 WebLayer* WebPluginContainerImpl::platformLayer() const
577 {
578     return m_webLayer;
579 }
580 
scriptableObject()581 NPObject* WebPluginContainerImpl::scriptableObject()
582 {
583     return m_webPlugin->scriptableObject();
584 }
585 
getFormValue(String & value)586 bool WebPluginContainerImpl::getFormValue(String& value)
587 {
588     WebString webValue;
589     if (m_webPlugin->getFormValue(webValue)) {
590         value = webValue;
591         return true;
592     }
593     return false;
594 }
595 
supportsKeyboardFocus() const596 bool WebPluginContainerImpl::supportsKeyboardFocus() const
597 {
598     return m_webPlugin->supportsKeyboardFocus();
599 }
600 
supportsInputMethod() const601 bool WebPluginContainerImpl::supportsInputMethod() const
602 {
603     return m_webPlugin->supportsInputMethod();
604 }
605 
canProcessDrag() const606 bool WebPluginContainerImpl::canProcessDrag() const
607 {
608     return m_webPlugin->canProcessDrag();
609 }
610 
wantsWheelEvents()611 bool WebPluginContainerImpl::wantsWheelEvents()
612 {
613     return m_wantsWheelEvents;
614 }
615 
willDestroyPluginLoadObserver(WebPluginLoadObserver * observer)616 void WebPluginContainerImpl::willDestroyPluginLoadObserver(WebPluginLoadObserver* observer)
617 {
618     size_t pos = m_pluginLoadObservers.find(observer);
619     if (pos == kNotFound)
620         return;
621     m_pluginLoadObservers.remove(pos);
622 }
623 
scrollbarGroup()624 ScrollbarGroup* WebPluginContainerImpl::scrollbarGroup()
625 {
626     if (!m_scrollbarGroup)
627         m_scrollbarGroup = adoptPtr(new ScrollbarGroup(m_element->document().frame()->view(), frameRect()));
628     return m_scrollbarGroup.get();
629 }
630 
willStartLiveResize()631 void WebPluginContainerImpl::willStartLiveResize()
632 {
633     if (m_scrollbarGroup)
634         m_scrollbarGroup->willStartLiveResize();
635 }
636 
willEndLiveResize()637 void WebPluginContainerImpl::willEndLiveResize()
638 {
639     if (m_scrollbarGroup)
640         m_scrollbarGroup->willEndLiveResize();
641 }
642 
paintCustomOverhangArea(GraphicsContext * context,const IntRect & horizontalOverhangArea,const IntRect & verticalOverhangArea,const IntRect & dirtyRect)643 bool WebPluginContainerImpl::paintCustomOverhangArea(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
644 {
645     context->save();
646     context->setFillColor(Color(0xCC, 0xCC, 0xCC));
647     context->fillRect(intersection(horizontalOverhangArea, dirtyRect));
648     context->fillRect(intersection(verticalOverhangArea, dirtyRect));
649     context->restore();
650     return true;
651 }
652 
653 // Private methods -------------------------------------------------------------
654 
WebPluginContainerImpl(WebCore::HTMLPlugInElement * element,WebPlugin * webPlugin)655 WebPluginContainerImpl::WebPluginContainerImpl(WebCore::HTMLPlugInElement* element, WebPlugin* webPlugin)
656     : m_element(element)
657     , m_webPlugin(webPlugin)
658     , m_webLayer(0)
659     , m_touchEventRequestType(TouchEventRequestTypeNone)
660     , m_wantsWheelEvents(false)
661 {
662 }
663 
~WebPluginContainerImpl()664 WebPluginContainerImpl::~WebPluginContainerImpl()
665 {
666     if (m_touchEventRequestType != TouchEventRequestTypeNone)
667         m_element->document().didRemoveTouchEventHandler(m_element);
668 
669     for (size_t i = 0; i < m_pluginLoadObservers.size(); ++i)
670         m_pluginLoadObservers[i]->clearPluginContainer();
671     m_webPlugin->destroy();
672     if (m_webLayer)
673         GraphicsLayer::unregisterContentsLayer(m_webLayer);
674 }
675 
handleMouseEvent(MouseEvent * event)676 void WebPluginContainerImpl::handleMouseEvent(MouseEvent* event)
677 {
678     ASSERT(parent()->isFrameView());
679 
680     if (event->isDragEvent()) {
681         if (m_webPlugin->canProcessDrag())
682             handleDragEvent(event);
683         return;
684     }
685 
686     // We cache the parent FrameView here as the plugin widget could be deleted
687     // in the call to HandleEvent. See http://b/issue?id=1362948
688     FrameView* parentView = toFrameView(parent());
689 
690     WebMouseEventBuilder webEvent(this, m_element->renderer(), *event);
691     if (webEvent.type == WebInputEvent::Undefined)
692         return;
693 
694     if (event->type() == EventTypeNames::mousedown)
695         focusPlugin();
696 
697     if (m_scrollbarGroup) {
698         // This needs to be set before the other callbacks in this scope, since
699         // the scroll animator class might query the position in response.
700         m_scrollbarGroup->setLastMousePosition(IntPoint(event->x(), event->y()));
701         if (event->type() == EventTypeNames::mousemove)
702             m_scrollbarGroup->scrollAnimator()->mouseMovedInContentArea();
703         else if (event->type() == EventTypeNames::mouseover)
704             m_scrollbarGroup->scrollAnimator()->mouseEnteredContentArea();
705         else if (event->type() == EventTypeNames::mouseout)
706             m_scrollbarGroup->scrollAnimator()->mouseExitedContentArea();
707     }
708 
709     WebCursorInfo cursorInfo;
710     if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
711         event->setDefaultHandled();
712 
713     // A windowless plugin can change the cursor in response to a mouse move
714     // event.  We need to reflect the changed cursor in the frame view as the
715     // mouse is moved in the boundaries of the windowless plugin.
716     Page* page = parentView->frame().page();
717     if (!page)
718         return;
719     toChromeClientImpl(page->chrome().client()).setCursorForPlugin(cursorInfo);
720 }
721 
handleDragEvent(MouseEvent * event)722 void WebPluginContainerImpl::handleDragEvent(MouseEvent* event)
723 {
724     ASSERT(event->isDragEvent());
725 
726     WebDragStatus dragStatus = WebDragStatusUnknown;
727     if (event->type() == EventTypeNames::dragenter)
728         dragStatus = WebDragStatusEnter;
729     else if (event->type() == EventTypeNames::dragleave)
730         dragStatus = WebDragStatusLeave;
731     else if (event->type() == EventTypeNames::dragover)
732         dragStatus = WebDragStatusOver;
733     else if (event->type() == EventTypeNames::drop)
734         dragStatus = WebDragStatusDrop;
735 
736     if (dragStatus == WebDragStatusUnknown)
737         return;
738 
739     Clipboard* clipboard = event->dataTransfer();
740     WebDragData dragData(clipboard->dataObject());
741     WebDragOperationsMask dragOperationMask = static_cast<WebDragOperationsMask>(clipboard->sourceOperation());
742     WebPoint dragScreenLocation(event->screenX(), event->screenY());
743     WebPoint dragLocation(event->absoluteLocation().x() - location().x(), event->absoluteLocation().y() - location().y());
744 
745     m_webPlugin->handleDragStatusUpdate(dragStatus, dragData, dragOperationMask, dragLocation, dragScreenLocation);
746 }
747 
handleWheelEvent(WheelEvent * event)748 void WebPluginContainerImpl::handleWheelEvent(WheelEvent* event)
749 {
750     WebMouseWheelEventBuilder webEvent(this, m_element->renderer(), *event);
751     if (webEvent.type == WebInputEvent::Undefined)
752         return;
753 
754     WebCursorInfo cursorInfo;
755     if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
756         event->setDefaultHandled();
757 }
758 
handleKeyboardEvent(KeyboardEvent * event)759 void WebPluginContainerImpl::handleKeyboardEvent(KeyboardEvent* event)
760 {
761     WebKeyboardEventBuilder webEvent(*event);
762     if (webEvent.type == WebInputEvent::Undefined)
763         return;
764 
765     if (webEvent.type == WebInputEvent::KeyDown) {
766 #if OS(MACOSX)
767         if (webEvent.modifiers == WebInputEvent::MetaKey
768 #else
769         if (webEvent.modifiers == WebInputEvent::ControlKey
770 #endif
771             && webEvent.windowsKeyCode == VKEY_C
772             // Only copy if there's a selection, so that we only ever do this
773             // for Pepper plugins that support copying.  Windowless NPAPI
774             // plugins will get the event as before.
775             && m_webPlugin->hasSelection()) {
776             copy();
777             event->setDefaultHandled();
778             return;
779         }
780     }
781 
782     const WebInputEvent* currentInputEvent = WebViewImpl::currentInputEvent();
783 
784     // Copy stashed info over, and only copy here in order not to interfere
785     // the ctrl-c logic above.
786     if (currentInputEvent
787         && WebInputEvent::isKeyboardEventType(currentInputEvent->type)) {
788         webEvent.modifiers |= currentInputEvent->modifiers &
789             (WebInputEvent::CapsLockOn | WebInputEvent::NumLockOn);
790     }
791 
792     // Give the client a chance to issue edit comamnds.
793     WebViewImpl* view = WebViewImpl::fromPage(m_element->document().frame()->page());
794     if (m_webPlugin->supportsEditCommands() && view->client())
795         view->client()->handleCurrentKeyboardEvent();
796 
797     WebCursorInfo cursorInfo;
798     if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
799         event->setDefaultHandled();
800 }
801 
handleTouchEvent(TouchEvent * event)802 void WebPluginContainerImpl::handleTouchEvent(TouchEvent* event)
803 {
804     switch (m_touchEventRequestType) {
805     case TouchEventRequestTypeNone:
806         return;
807     case TouchEventRequestTypeRaw: {
808         WebTouchEventBuilder webEvent(this, m_element->renderer(), *event);
809         if (webEvent.type == WebInputEvent::Undefined)
810             return;
811 
812         if (event->type() == EventTypeNames::touchstart)
813             focusPlugin();
814 
815         WebCursorInfo cursorInfo;
816         if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
817             event->setDefaultHandled();
818         // FIXME: Can a plugin change the cursor from a touch-event callback?
819         return;
820     }
821     case TouchEventRequestTypeSynthesizedMouse:
822         synthesizeMouseEventIfPossible(event);
823         return;
824     }
825 }
826 
gestureScrollHelper(ScrollbarGroup * scrollbarGroup,ScrollDirection positiveDirection,ScrollDirection negativeDirection,float delta)827 static inline bool gestureScrollHelper(ScrollbarGroup* scrollbarGroup, ScrollDirection positiveDirection, ScrollDirection negativeDirection, float delta)
828 {
829     if (!delta)
830         return false;
831     float absDelta = delta > 0 ? delta : -delta;
832     return scrollbarGroup->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPrecisePixel, absDelta);
833 }
834 
handleGestureEvent(GestureEvent * event)835 void WebPluginContainerImpl::handleGestureEvent(GestureEvent* event)
836 {
837     WebGestureEventBuilder webEvent(this, m_element->renderer(), *event);
838     if (webEvent.type == WebInputEvent::Undefined)
839         return;
840     if (event->type() == EventTypeNames::gesturetapdown)
841         focusPlugin();
842     WebCursorInfo cursorInfo;
843     if (m_webPlugin->handleInputEvent(webEvent, cursorInfo)) {
844         event->setDefaultHandled();
845         return;
846     }
847 
848     if (webEvent.type == WebInputEvent::GestureScrollUpdate || webEvent.type == WebInputEvent::GestureScrollUpdateWithoutPropagation) {
849         if (!m_scrollbarGroup)
850             return;
851         if (gestureScrollHelper(m_scrollbarGroup.get(), ScrollLeft, ScrollRight, webEvent.data.scrollUpdate.deltaX))
852             event->setDefaultHandled();
853         if (gestureScrollHelper(m_scrollbarGroup.get(), ScrollUp, ScrollDown, webEvent.data.scrollUpdate.deltaY))
854             event->setDefaultHandled();
855     }
856     // FIXME: Can a plugin change the cursor from a touch-event callback?
857 }
858 
synthesizeMouseEventIfPossible(TouchEvent * event)859 void WebPluginContainerImpl::synthesizeMouseEventIfPossible(TouchEvent* event)
860 {
861     WebMouseEventBuilder webEvent(this, m_element->renderer(), *event);
862     if (webEvent.type == WebInputEvent::Undefined)
863         return;
864 
865     WebCursorInfo cursorInfo;
866     if (m_webPlugin->handleInputEvent(webEvent, cursorInfo))
867         event->setDefaultHandled();
868 }
869 
focusPlugin()870 void WebPluginContainerImpl::focusPlugin()
871 {
872     LocalFrame& containingFrame = toFrameView(parent())->frame();
873     if (Page* currentPage = containingFrame.page())
874         currentPage->focusController().setFocusedElement(m_element, &containingFrame);
875     else
876         containingFrame.document()->setFocusedElement(m_element);
877 }
878 
calculateGeometry(const IntRect & frameRect,IntRect & windowRect,IntRect & clipRect,Vector<IntRect> & cutOutRects)879 void WebPluginContainerImpl::calculateGeometry(const IntRect& frameRect,
880                                                IntRect& windowRect,
881                                                IntRect& clipRect,
882                                                Vector<IntRect>& cutOutRects)
883 {
884     windowRect = toScrollView(parent())->contentsToWindow(frameRect);
885 
886     // Calculate a clip-rect so that we don't overlap the scrollbars, etc.
887     clipRect = windowClipRect();
888     clipRect.move(-windowRect.x(), -windowRect.y());
889 
890     getPluginOcclusions(m_element, this->parent(), frameRect, cutOutRects);
891     // Convert to the plugin position.
892     for (size_t i = 0; i < cutOutRects.size(); i++)
893         cutOutRects[i].move(-frameRect.x(), -frameRect.y());
894 }
895 
windowClipRect() const896 WebCore::IntRect WebPluginContainerImpl::windowClipRect() const
897 {
898     // Start by clipping to our bounds.
899     IntRect clipRect =
900         convertToContainingWindow(IntRect(0, 0, width(), height()));
901 
902     // document().renderView() can be 0 when we receive messages from the
903     // plugins while we are destroying a frame.
904     // FIXME: Can we just check m_element->document().isActive() ?
905     if (m_element->renderer()->document().renderView()) {
906         // Take our element and get the clip rect from the enclosing layer and
907         // frame view.
908         clipRect.intersect(
909             m_element->document().view()->windowClipRectForFrameOwner(m_element));
910     }
911 
912     return clipRect;
913 }
914 
pluginShouldPersist() const915 bool WebPluginContainerImpl::pluginShouldPersist() const
916 {
917     return m_webPlugin->shouldPersist();
918 }
919 
920 } // namespace blink
921