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