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