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