Unavailable plug-in indicator arrow should be inside the rounded rect, not in its...
[WebKit-https.git] / Source / WebCore / rendering / RenderEmbeddedObject.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2000 Simon Hausmann <hausmann@kde.org>
4  *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
5  * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "RenderEmbeddedObject.h"
26
27 #include "CSSValueKeywords.h"
28 #include "Chrome.h"
29 #include "ChromeClient.h"
30 #include "Cursor.h"
31 #include "EventHandler.h"
32 #include "Font.h"
33 #include "FontSelector.h"
34 #include "Frame.h"
35 #include "FrameLoaderClient.h"
36 #include "GraphicsContext.h"
37 #include "HTMLEmbedElement.h"
38 #include "HTMLIFrameElement.h"
39 #include "HTMLNames.h"
40 #include "HTMLObjectElement.h"
41 #include "HTMLParamElement.h"
42 #include "HTMLPlugInElement.h"
43 #include "HitTestResult.h"
44 #include "LocalizedStrings.h"
45 #include "MIMETypeRegistry.h"
46 #include "MouseEvent.h"
47 #include "Page.h"
48 #include "PaintInfo.h"
49 #include "Path.h"
50 #include "PlatformMouseEvent.h"
51 #include "PluginViewBase.h"
52 #include "RenderLayer.h"
53 #include "RenderTheme.h"
54 #include "RenderView.h"
55 #include "RenderWidgetProtector.h"
56 #include "Settings.h"
57 #include "Text.h"
58 #include "TextRun.h"
59 #include <wtf/StackStats.h>
60
61 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
62 #include "HTMLMediaElement.h"
63 #endif
64
65 namespace WebCore {
66
67 using namespace HTMLNames;
68
69 static const float replacementTextRoundedRectHeight = 18;
70 static const float replacementTextRoundedRectLeftRightTextMargin = 6;
71 static const float replacementTextRoundedRectBottomTextPadding = 1;
72 static const float replacementTextRoundedRectOpacity = 0.8f;
73 static const float replacementTextRoundedRectRadius = 5;
74 static const float replacementArrowLeftMargin = -4;
75 static const float replacementArrowPadding = 4;
76
77 static const Color& replacementTextRoundedRectPressedColor()
78 {
79     static const Color pressed(205, 205, 205);
80     return pressed;
81 }
82
83 static const Color& replacementTextRoundedRectColor()
84 {
85     static const Color standard(221, 221, 221);
86     return standard;
87 }
88
89 static const Color& replacementTextColor()
90 {
91     static const Color standard(102, 102, 102);
92     return standard;
93 }
94
95 RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
96     : RenderPart(element)
97     , m_hasFallbackContent(false)
98     , m_isPluginUnavailable(false)
99     , m_isUnavailablePluginIndicatorHidden(false)
100     , m_unavailablePluginIndicatorIsPressed(false)
101     , m_mouseDownWasInUnavailablePluginIndicator(false)
102 {
103     // Actual size is not known yet, report the default intrinsic size.
104     view()->frameView()->incrementVisuallyNonEmptyPixelCount(roundedIntSize(intrinsicSize()));
105 }
106
107 RenderEmbeddedObject::~RenderEmbeddedObject()
108 {
109     if (frameView())
110         frameView()->removeWidgetToUpdate(this);
111 }
112
113 #if USE(ACCELERATED_COMPOSITING)
114 bool RenderEmbeddedObject::requiresLayer() const
115 {
116     if (RenderPart::requiresLayer())
117         return true;
118     
119     return allowsAcceleratedCompositing();
120 }
121
122 bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
123 {
124     return widget() && widget()->isPluginViewBase() && toPluginViewBase(widget())->platformLayer();
125 }
126 #endif
127
128 static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
129 {
130     switch (pluginUnavailabilityReason) {
131     case RenderEmbeddedObject::PluginMissing:
132         return missingPluginText();
133     case RenderEmbeddedObject::PluginCrashed:
134         return crashedPluginText();
135     case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
136         return blockedPluginByContentSecurityPolicyText();
137     case RenderEmbeddedObject::InsecurePluginVersion:
138         return insecurePluginVersionText();
139     }
140
141     ASSERT_NOT_REACHED();
142     return String();
143 }
144
145 static bool shouldUnavailablePluginMessageBeButton(Document* document, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
146 {
147     Page* page = document->page();
148     return page && page->chrome().client()->shouldUnavailablePluginMessageBeButton(pluginUnavailabilityReason);
149 }
150
151 void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason)
152 {
153     setPluginUnavailabilityReasonWithDescription(pluginUnavailabilityReason, unavailablePluginReplacementText(pluginUnavailabilityReason));
154 }
155
156 void RenderEmbeddedObject::setPluginUnavailabilityReasonWithDescription(PluginUnavailabilityReason pluginUnavailabilityReason, const String& description)
157 {
158     ASSERT(!m_isPluginUnavailable);
159     m_isPluginUnavailable = true;
160     m_pluginUnavailabilityReason = pluginUnavailabilityReason;
161
162     if (description.isEmpty())
163         m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason);
164     else
165         m_unavailablePluginReplacementText = description;
166 }
167
168 void RenderEmbeddedObject::setUnavailablePluginIndicatorIsPressed(bool pressed)
169 {
170     if (m_unavailablePluginIndicatorIsPressed == pressed)
171         return;
172
173     m_unavailablePluginIndicatorIsPressed = pressed;
174     repaint();
175 }
176
177 void RenderEmbeddedObject::paintSnapshotImage(PaintInfo& paintInfo, const LayoutPoint& paintOffset, Image* image)
178 {
179     LayoutUnit cWidth = contentWidth();
180     LayoutUnit cHeight = contentHeight();
181     if (!cWidth || !cHeight)
182         return;
183
184     GraphicsContext* context = paintInfo.context;
185     LayoutSize contentSize(cWidth, cHeight);
186     LayoutPoint contentLocation = location() + paintOffset;
187     contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
188
189     LayoutRect rect(contentLocation, contentSize);
190     IntRect alignedRect = pixelSnappedIntRect(rect);
191     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
192         return;
193
194     bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size());
195     context->drawImage(image, style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling);
196 }
197
198 void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
199 {
200     Element* element = toElement(node());
201     if (!element || !element->isPluginElement())
202         return;
203
204     HTMLPlugInElement* plugInElement = toHTMLPlugInElement(element);
205
206     if (plugInElement->displayState() > HTMLPlugInElement::DisplayingSnapshot) {
207         RenderPart::paintContents(paintInfo, paintOffset);
208         if (!plugInElement->isRestartedPlugin())
209             return;
210     }
211
212     if (!plugInElement->isPlugInImageElement())
213         return;
214
215     Image* snapshot = toHTMLPlugInImageElement(plugInElement)->snapshotImage();
216     if (snapshot)
217         paintSnapshotImage(paintInfo, paintOffset, snapshot);
218 }
219
220 void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
221 {
222     Page* page = 0;
223     if (Frame* frame = this->frame())
224         page = frame->page();
225
226     if (isPluginUnavailable()) {
227         if (page && paintInfo.phase == PaintPhaseForeground)
228             page->addRelevantUnpaintedObject(this, visualOverflowRect());
229         RenderReplaced::paint(paintInfo, paintOffset);
230         return;
231     }
232
233     if (page && paintInfo.phase == PaintPhaseForeground)
234         page->addRelevantRepaintedObject(this, visualOverflowRect());
235
236     RenderPart::paint(paintInfo, paintOffset);
237 }
238
239 void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
240 {
241     if (!showsUnavailablePluginIndicator())
242         return;
243
244     if (paintInfo.phase == PaintPhaseSelection)
245         return;
246
247     GraphicsContext* context = paintInfo.context;
248     if (context->paintingDisabled())
249         return;
250
251     FloatRect contentRect;
252     Path path;
253     FloatRect replacementTextRect;
254     FloatRect arrowRect;
255     Font font;
256     TextRun run("");
257     float textWidth;
258     if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, arrowRect, font, run, textWidth))
259         return;
260
261     GraphicsContextStateSaver stateSaver(*context);
262     context->clip(contentRect);
263     context->setAlpha(replacementTextRoundedRectOpacity);
264     context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor(), style()->colorSpace());
265     context->fillPath(path);
266
267     const FontMetrics& fontMetrics = font.fontMetrics();
268     float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
269     float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent());
270     context->setFillColor(replacementTextColor(), style()->colorSpace());
271     context->drawBidiText(font, run, FloatPoint(labelX, labelY));
272 }
273
274 void RenderEmbeddedObject::setUnavailablePluginIndicatorIsHidden(bool hidden)
275 {
276     m_isUnavailablePluginIndicatorHidden = hidden;
277
278     repaint();
279 }
280
281 static void addReplacementArrowPath(Path& path, const FloatRect& insideRect)
282 {
283     FloatRect rect(insideRect);
284     rect.inflate(-replacementArrowPadding);
285
286     FloatPoint center = rect.center();
287     FloatSize arrowEdge(rect.width() / 2, rect.height() / 3);
288     FloatSize arrowHorizontalEdge(arrowEdge.width(), 0);
289     FloatSize arrowVerticalEdge(0, arrowEdge.height());
290
291     path.moveTo(FloatPoint(floorf(center.x()), floorf(rect.y())));
292     path.addLineTo(FloatPoint(floorf(center.x()), floorf(rect.y() + arrowEdge.height())));
293     path.addLineTo(FloatPoint(ceilf(center.x() - arrowEdge.width()), floorf(rect.y() + arrowEdge.height())));
294     path.addLineTo(FloatPoint(ceilf(center.x() - arrowEdge.width()), ceilf(rect.y() + arrowEdge.height() + arrowEdge.height())));
295     path.addLineTo(FloatPoint(floorf(center.x()), ceilf(rect.y() + arrowEdge.height() + arrowEdge.height())));
296     path.addLineTo(FloatPoint(floorf(center.x()), ceilf(rect.y() + arrowEdge.height() + arrowEdge.height() + arrowEdge.height())));
297     path.addLineTo(FloatPoint(ceilf(center.x() + arrowEdge.width()), center.y()));
298     path.closeSubpath();
299 }
300
301 bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, FloatRect& arrowRect, Font& font, TextRun& run, float& textWidth) const
302 {
303     contentRect = contentBoxRect();
304     contentRect.moveBy(roundedIntPoint(accumulatedOffset));
305
306     FontDescription fontDescription;
307     RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription);
308     fontDescription.setWeight(FontWeightBold);
309     Settings* settings = document()->settings();
310     ASSERT(settings);
311     if (!settings)
312         return false;
313     fontDescription.setRenderingMode(settings->fontRenderingMode());
314     fontDescription.setComputedSize(fontDescription.specifiedSize());
315     font = Font(fontDescription, 0, 0);
316     font.update(0);
317
318     run = TextRun(m_unavailablePluginReplacementText);
319     textWidth = font.width(run);
320
321     replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
322     float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
323     float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
324     replacementTextRect.setLocation(FloatPoint(x, y));
325
326     replacementTextRect.setHeight(replacementTextRect.height() + replacementTextRoundedRectBottomTextPadding);
327
328     FloatRect indicatorRect(replacementTextRect);
329
330     // Expand the background rect to include the arrow, if it will be used.
331     if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) {
332         arrowRect = indicatorRect;
333         arrowRect.setX(ceilf(arrowRect.maxX() + replacementArrowLeftMargin));
334         arrowRect.setWidth(arrowRect.height());
335         indicatorRect.unite(arrowRect);
336         arrowRect.inflate(-0.5);
337     }
338
339     path.addRoundedRect(indicatorRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
340
341     if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason))
342         addReplacementArrowPath(path, arrowRect);
343
344     return true;
345 }
346
347 LayoutRect RenderEmbeddedObject::unavailablePluginIndicatorBounds(const LayoutPoint& accumulatedOffset) const
348 {
349     FloatRect contentRect;
350     Path path;
351     FloatRect replacementTextRect;
352     FloatRect arrowRect;
353     Font font;
354     TextRun run("", 0);
355     float textWidth;
356     if (getReplacementTextGeometry(accumulatedOffset, contentRect, path, replacementTextRect, arrowRect, font, run, textWidth))
357         return LayoutRect(path.boundingRect());
358
359     return LayoutRect();
360 }
361
362 bool RenderEmbeddedObject::isReplacementObscured() const
363 {
364     // Return whether or not the replacement content for blocked plugins is accessible to the user.
365
366     // Check the opacity of each layer containing the element or its ancestors.
367     float opacity = 1.0;
368     for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) {
369         RenderLayerModelObject* renderer = layer->renderer();
370         RenderStyle* style = renderer->style();
371         opacity *= style->opacity();
372         if (opacity < 0.1)
373             return true;
374     }
375
376     // Calculate the absolute rect for the blocked plugin replacement text.
377     IntRect absoluteBoundingBox = absoluteBoundingBoxRect();
378     LayoutPoint absoluteLocation(absoluteBoundingBox.location());
379     LayoutRect rect = unavailablePluginIndicatorBounds(absoluteLocation);
380     if (rect.isEmpty())
381         return true;
382
383     RenderView* docRenderer = document()->renderView();
384     ASSERT(docRenderer);
385     if (!docRenderer)
386         return true;
387     
388     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
389     HitTestResult result;
390     HitTestLocation location;
391     
392     LayoutUnit x = rect.x();
393     LayoutUnit y = rect.y();
394     LayoutUnit width = rect.width();
395     LayoutUnit height = rect.height();
396     
397     // Hit test the center and near the corners of the replacement text to ensure
398     // it is visible and is not masked by other elements.
399     bool hit = false;
400     location = LayoutPoint(x + width / 2, y + height / 2);
401     hit = docRenderer->hitTest(request, location, result);
402     if (!hit || result.innerNode() != node())
403         return true;
404     
405     location = LayoutPoint(x, y);
406     hit = docRenderer->hitTest(request, location, result);
407     if (!hit || result.innerNode() != node())
408         return true;
409     
410     location = LayoutPoint(x + width, y);
411     hit = docRenderer->hitTest(request, location, result);
412     if (!hit || result.innerNode() != node())
413         return true;
414     
415     location = LayoutPoint(x + width, y + height);
416     hit = docRenderer->hitTest(request, location, result);
417     if (!hit || result.innerNode() != node())
418         return true;
419     
420     location = LayoutPoint(x, y + height);
421     hit = docRenderer->hitTest(request, location, result);
422     if (!hit || result.innerNode() != node())
423         return true;
424
425     return false;
426 }
427
428 void RenderEmbeddedObject::layout()
429 {
430     StackStats::LayoutCheckPoint layoutCheckPoint;
431     ASSERT(needsLayout());
432
433     LayoutSize oldSize = contentBoxRect().size();
434
435     updateLogicalWidth();
436     updateLogicalHeight();
437
438     RenderPart::layout();
439
440     m_overflow.clear();
441     addVisualEffectOverflow();
442
443     updateLayerTransform();
444
445     bool wasMissingWidget = false;
446     if (!widget() && frameView() && canHaveWidget()) {
447         wasMissingWidget = true;
448         frameView()->addWidgetToUpdate(this);
449     }
450
451     setNeedsLayout(false);
452
453     LayoutSize newSize = contentBoxRect().size();
454
455     if (!wasMissingWidget && newSize.width() >= oldSize.width() && newSize.height() >= oldSize.height()) {
456         Element* element = toElement(node());
457         if (element && element->isPluginElement() && toHTMLPlugInElement(element)->isPlugInImageElement()) {
458             HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(element);
459             if (plugInImageElement->displayState() > HTMLPlugInElement::DisplayingSnapshot && plugInImageElement->snapshotDecision() == HTMLPlugInImageElement::MaySnapshotWhenResized && document()->view()) {
460                 plugInImageElement->setNeedsCheckForSizeChange();
461                 document()->view()->addWidgetToUpdate(this);
462             }
463         }
464     }
465
466     if (!canHaveChildren())
467         return;
468
469     // This code copied from RenderMedia::layout().
470     RenderObject* child = m_children.firstChild();
471
472     if (!child)
473         return;
474
475     RenderBox* childBox = toRenderBox(child);
476
477     if (!childBox)
478         return;
479
480     if (newSize == oldSize && !childBox->needsLayout())
481         return;
482     
483     // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or
484     // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient,
485     // and this method will be called many times per second during playback, use a LayoutStateMaintainer:
486     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
487     
488     childBox->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop()));
489     childBox->style()->setHeight(Length(newSize.height(), Fixed));
490     childBox->style()->setWidth(Length(newSize.width(), Fixed));
491     childBox->setNeedsLayout(true, MarkOnlyThis);
492     childBox->layout();
493     setChildNeedsLayout(false);
494     
495     statePusher.pop();
496 }
497
498 void RenderEmbeddedObject::viewCleared()
499 {
500     // This is required for <object> elements whose contents are rendered by WebCore (e.g. src="foo.html").
501     if (node() && widget() && widget()->isFrameView()) {
502         FrameView* view = toFrameView(widget());
503         int marginWidth = -1;
504         int marginHeight = -1;
505         if (node()->hasTagName(iframeTag)) {
506             HTMLIFrameElement* frame = toHTMLIFrameElement(node());
507             marginWidth = frame->marginWidth();
508             marginHeight = frame->marginHeight();
509         }
510         if (marginWidth != -1)
511             view->setMarginWidth(marginWidth);
512         if (marginHeight != -1)
513             view->setMarginHeight(marginHeight);
514     }
515 }
516
517 bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
518 {
519     if (!RenderPart::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction))
520         return false;
521
522     if (!widget() || !widget()->isPluginViewBase())
523         return true;
524
525     PluginViewBase* view = toPluginViewBase(widget());
526     IntPoint roundedPoint = locationInContainer.roundedPoint();
527
528     if (Scrollbar* horizontalScrollbar = view->horizontalScrollbar()) {
529         if (horizontalScrollbar->shouldParticipateInHitTesting() && horizontalScrollbar->frameRect().contains(roundedPoint)) {
530             result.setScrollbar(horizontalScrollbar);
531             return true;
532         }
533     }
534
535     if (Scrollbar* verticalScrollbar = view->verticalScrollbar()) {
536         if (verticalScrollbar->shouldParticipateInHitTesting() && verticalScrollbar->frameRect().contains(roundedPoint)) {
537             result.setScrollbar(verticalScrollbar);
538             return true;
539         }
540     }
541
542     return true;
543 }
544
545 bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float, Node**)
546 {
547     if (!widget() || !widget()->isPluginViewBase())
548         return false;
549
550     return toPluginViewBase(widget())->scroll(direction, granularity);
551 }
552
553 bool RenderEmbeddedObject::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
554 {
555     // Plugins don't expose a writing direction, so assuming horizontal LTR.
556     return scroll(logicalToPhysical(direction, true, false), granularity, multiplier, stopNode);
557 }
558
559
560 bool RenderEmbeddedObject::isInUnavailablePluginIndicator(const LayoutPoint& point) const
561 {
562     FloatRect contentRect;
563     Path path;
564     FloatRect replacementTextRect;
565     FloatRect arrowRect;
566     Font font;
567     TextRun run("");
568     float textWidth;
569     return getReplacementTextGeometry(IntPoint(), contentRect, path, replacementTextRect, arrowRect, font, run, textWidth)
570         && (path.contains(point) || arrowRect.contains(point));
571 }
572
573 bool RenderEmbeddedObject::isInUnavailablePluginIndicator(MouseEvent* event) const
574 {
575     return isInUnavailablePluginIndicator(roundedLayoutPoint(absoluteToLocal(event->absoluteLocation(), UseTransforms)));
576 }
577
578 void RenderEmbeddedObject::handleUnavailablePluginIndicatorEvent(Event* event)
579 {
580     if (!shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason))
581         return;
582
583     if (!event->isMouseEvent())
584         return;
585
586     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
587     HTMLPlugInElement* element = toHTMLPlugInElement(node());
588     if (event->type() == eventNames().mousedownEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
589         m_mouseDownWasInUnavailablePluginIndicator = isInUnavailablePluginIndicator(mouseEvent);
590         if (m_mouseDownWasInUnavailablePluginIndicator) {
591             if (Frame* frame = document()->frame()) {
592                 frame->eventHandler()->setCapturingMouseEventsNode(element);
593                 element->setIsCapturingMouseEvents(true);
594             }
595             setUnavailablePluginIndicatorIsPressed(true);
596         }
597         event->setDefaultHandled();
598     }
599     if (event->type() == eventNames().mouseupEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
600         if (m_unavailablePluginIndicatorIsPressed) {
601             if (Frame* frame = document()->frame()) {
602                 frame->eventHandler()->setCapturingMouseEventsNode(0);
603                 element->setIsCapturingMouseEvents(false);
604             }
605             setUnavailablePluginIndicatorIsPressed(false);
606         }
607         if (m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent)) {
608             if (Page* page = document()->page())
609                 page->chrome().client()->unavailablePluginButtonClicked(element, m_pluginUnavailabilityReason);
610         }
611         m_mouseDownWasInUnavailablePluginIndicator = false;
612         event->setDefaultHandled();
613     }
614     if (event->type() == eventNames().mousemoveEvent) {
615         setUnavailablePluginIndicatorIsPressed(m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent));
616         event->setDefaultHandled();
617     }
618 }
619
620 CursorDirective RenderEmbeddedObject::getCursor(const LayoutPoint& point, Cursor& cursor) const
621 {
622     if (showsUnavailablePluginIndicator() && shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason) && isInUnavailablePluginIndicator(point)) {
623         cursor = handCursor();
624         return SetCursor;
625     }
626     return RenderPart::getCursor(point, cursor);
627 }
628
629 bool RenderEmbeddedObject::canHaveChildren() const
630 {
631 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
632     if (!node())
633         return false;
634
635     if (toElement(node())->isMediaElement())
636         return true;
637 #endif
638
639     if (isSnapshottedPlugIn())
640         return true;
641
642     return false;
643 }
644
645 }