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