b982504a7627d498950f081f32ff77edc2dc6ed7
[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 "EventNames.h"
33 #include "FontCascade.h"
34 #include "FontSelector.h"
35 #include "Frame.h"
36 #include "FrameLoaderClient.h"
37 #include "GraphicsContext.h"
38 #include "HTMLAppletElement.h"
39 #include "HTMLEmbedElement.h"
40 #include "HTMLNames.h"
41 #include "HTMLObjectElement.h"
42 #include "HTMLParamElement.h"
43 #include "HTMLPlugInElement.h"
44 #include "HitTestResult.h"
45 #include "LayoutState.h"
46 #include "LocalizedStrings.h"
47 #include "MouseEvent.h"
48 #include "Page.h"
49 #include "PaintInfo.h"
50 #include "Path.h"
51 #include "PlatformMouseEvent.h"
52 #include "PluginViewBase.h"
53 #include "RenderTheme.h"
54 #include "RenderView.h"
55 #include "Settings.h"
56 #include "Text.h"
57 #include "TextRun.h"
58 #include <wtf/IsoMallocInlines.h>
59 #include <wtf/StackStats.h>
60
61 namespace WebCore {
62
63 using namespace HTMLNames;
64
65 WTF_MAKE_ISO_ALLOCATED_IMPL(RenderEmbeddedObject);
66
67 static const float replacementTextRoundedRectHeight = 22;
68 static const float replacementTextRoundedRectLeftTextMargin = 10;
69 static const float replacementTextRoundedRectRightTextMargin = 10;
70 static const float replacementTextRoundedRectRightTextMarginWithArrow = 5;
71 static const float replacementTextRoundedRectTopTextMargin = -1;
72 static const float replacementTextRoundedRectRadius = 11;
73 static const float replacementArrowLeftMargin = -4;
74 static const float replacementArrowPadding = 4;
75 static const float replacementArrowCirclePadding = 3;
76
77 static const Color& replacementTextRoundedRectPressedColor()
78 {
79     static NeverDestroyed<Color> pressed(105, 105, 105, 242);
80     return pressed;
81 }
82
83 static const Color& replacementTextRoundedRectColor()
84 {
85     static NeverDestroyed<Color> standard(125, 125, 125, 242);
86     return standard;
87 }
88
89 static const Color& replacementTextColor()
90 {
91     static NeverDestroyed<Color> standard(240, 240, 240, 255);
92     return standard;
93 }
94
95 static const Color& unavailablePluginBorderColor()
96 {
97     static NeverDestroyed<Color> standard(255, 255, 255, 216);
98     return standard;
99 }
100
101 RenderEmbeddedObject::RenderEmbeddedObject(HTMLFrameOwnerElement& element, RenderStyle&& style)
102     : RenderWidget(element, WTFMove(style))
103     , m_isPluginUnavailable(false)
104     , m_unavailablePluginIndicatorIsPressed(false)
105     , m_mouseDownWasInUnavailablePluginIndicator(false)
106 {
107     // Actual size is not known yet, report the default intrinsic size.
108     view().frameView().incrementVisuallyNonEmptyPixelCount(roundedIntSize(intrinsicSize()));
109 }
110
111 RenderEmbeddedObject::~RenderEmbeddedObject()
112 {
113     // Do not add any code here. Add it to willBeDestroyed() instead.
114 }
115
116 void RenderEmbeddedObject::willBeDestroyed()
117 {
118     view().frameView().removeEmbeddedObjectToUpdate(*this);
119     RenderWidget::willBeDestroyed();
120 }
121
122 RenderPtr<RenderEmbeddedObject> RenderEmbeddedObject::createForApplet(HTMLAppletElement& applet, RenderStyle&& style)
123 {
124     auto renderer = createRenderer<RenderEmbeddedObject>(applet, WTFMove(style));
125     renderer->setInline(true);
126     return renderer;
127 }
128
129 bool RenderEmbeddedObject::requiresLayer() const
130 {
131     if (RenderWidget::requiresLayer())
132         return true;
133     
134     return allowsAcceleratedCompositing();
135 }
136
137 bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
138 {
139 #if PLATFORM(IOS)
140     // The timing of layer creation is different on the phone, since the plugin can only be manipulated from the main thread.
141     return is<PluginViewBase>(widget()) && downcast<PluginViewBase>(*widget()).willProvidePluginLayer();
142 #else
143     return is<PluginViewBase>(widget()) && downcast<PluginViewBase>(*widget()).platformLayer();
144 #endif
145 }
146
147 #if !PLATFORM(IOS)
148 static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
149 {
150     switch (pluginUnavailabilityReason) {
151     case RenderEmbeddedObject::PluginMissing:
152         return missingPluginText();
153     case RenderEmbeddedObject::PluginCrashed:
154         return crashedPluginText();
155     case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
156         return blockedPluginByContentSecurityPolicyText();
157     case RenderEmbeddedObject::InsecurePluginVersion:
158         return insecurePluginVersionText();
159     case RenderEmbeddedObject::UnsupportedPlugin:
160         return unsupportedPluginText();
161     }
162
163     ASSERT_NOT_REACHED();
164     return String();
165 }
166 #endif
167
168 static bool shouldUnavailablePluginMessageBeButton(Page& page, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
169 {
170     return page.chrome().client().shouldUnavailablePluginMessageBeButton(pluginUnavailabilityReason);
171 }
172
173 void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason)
174 {
175 #if PLATFORM(IOS)
176     UNUSED_PARAM(pluginUnavailabilityReason);
177 #else
178     setPluginUnavailabilityReasonWithDescription(pluginUnavailabilityReason, unavailablePluginReplacementText(pluginUnavailabilityReason));
179 #endif
180 }
181
182 void RenderEmbeddedObject::setPluginUnavailabilityReasonWithDescription(PluginUnavailabilityReason pluginUnavailabilityReason, const String& description)
183 {
184 #if PLATFORM(IOS)
185     UNUSED_PARAM(pluginUnavailabilityReason);
186     UNUSED_PARAM(description);
187 #else
188     ASSERT(!m_isPluginUnavailable);
189     m_isPluginUnavailable = true;
190     m_pluginUnavailabilityReason = pluginUnavailabilityReason;
191
192     if (description.isEmpty())
193         m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason);
194     else
195         m_unavailablePluginReplacementText = description;
196 #endif
197 }
198
199 void RenderEmbeddedObject::setUnavailablePluginIndicatorIsPressed(bool pressed)
200 {
201     if (m_unavailablePluginIndicatorIsPressed == pressed)
202         return;
203     m_unavailablePluginIndicatorIsPressed = pressed;
204     repaint();
205 }
206
207 void RenderEmbeddedObject::paintSnapshotImage(PaintInfo& paintInfo, const LayoutPoint& paintOffset, Image& image)
208 {
209     LayoutUnit cWidth = contentWidth();
210     LayoutUnit cHeight = contentHeight();
211     if (!cWidth || !cHeight)
212         return;
213
214     GraphicsContext& context = paintInfo.context();
215     LayoutSize contentSize(cWidth, cHeight);
216     LayoutPoint contentLocation = location() + paintOffset;
217     contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
218
219     LayoutRect rect(contentLocation, contentSize);
220     IntRect alignedRect = snappedIntRect(rect);
221     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
222         return;
223
224     InterpolationQuality interpolation = chooseInterpolationQuality(context, image, &image, alignedRect.size());
225     ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
226     context.drawImage(image, alignedRect, ImagePaintingOptions(orientationDescription, interpolation));
227 }
228
229 void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
230 {
231     if (!is<HTMLPlugInElement>(frameOwnerElement()))
232         return;
233
234     HTMLPlugInElement& plugInElement = downcast<HTMLPlugInElement>(frameOwnerElement());
235
236     if (plugInElement.displayState() > HTMLPlugInElement::DisplayingSnapshot) {
237         RenderWidget::paintContents(paintInfo, paintOffset);
238         if (!plugInElement.isRestartedPlugin())
239             return;
240     }
241
242     if (!is<HTMLPlugInImageElement>(plugInElement))
243         return;
244
245     if (Image* snapshot = downcast<HTMLPlugInImageElement>(plugInElement).snapshotImage())
246         paintSnapshotImage(paintInfo, paintOffset, *snapshot);
247 }
248
249 void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
250 {
251     // The relevant repainted object heuristic is not tuned for plugin documents.
252     bool countsTowardsRelevantObjects = !document().isPluginDocument() && paintInfo.phase == PaintPhaseForeground;
253
254     if (isPluginUnavailable()) {
255         if (countsTowardsRelevantObjects)
256             page().addRelevantUnpaintedObject(this, visualOverflowRect());
257         RenderReplaced::paint(paintInfo, paintOffset);
258         return;
259     }
260
261     if (countsTowardsRelevantObjects)
262         page().addRelevantRepaintedObject(this, visualOverflowRect());
263
264     RenderWidget::paint(paintInfo, paintOffset);
265 }
266
267 static void drawReplacementArrow(GraphicsContext& context, const FloatRect& insideRect)
268 {
269     GraphicsContextStateSaver stateSaver(context);
270
271     FloatRect rect(insideRect);
272     rect.inflate(-replacementArrowPadding);
273
274     FloatPoint center(rect.center());
275     FloatPoint arrowTip(rect.maxX(), center.y());
276
277     context.setStrokeThickness(2);
278     context.setLineCap(RoundCap);
279     context.setLineJoin(RoundJoin);
280
281     Path path;
282     path.moveTo(FloatPoint(rect.x(), center.y()));
283     path.addLineTo(arrowTip);
284     path.addLineTo(FloatPoint(center.x(), rect.y()));
285     path.moveTo(arrowTip);
286     path.addLineTo(FloatPoint(center.x(), rect.maxY()));
287     context.strokePath(path);
288 }
289
290 void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
291 {
292     if (!showsUnavailablePluginIndicator())
293         return;
294
295     if (paintInfo.phase == PaintPhaseSelection)
296         return;
297
298     GraphicsContext& context = paintInfo.context();
299     if (context.paintingDisabled())
300         return;
301
302     FloatRect contentRect;
303     FloatRect indicatorRect;
304     FloatRect replacementTextRect;
305     FloatRect arrowRect;
306     FontCascade font;
307     TextRun run(emptyString());
308     float textWidth;
309     getReplacementTextGeometry(paintOffset, contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth);
310
311     Path background;
312     background.addRoundedRect(indicatorRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
313
314     GraphicsContextStateSaver stateSaver(context);
315     context.clip(contentRect);
316     context.setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor());
317     context.fillPath(background);
318
319     Path strokePath;
320     FloatRect strokeRect(indicatorRect);
321     strokeRect.inflate(1);
322     strokePath.addRoundedRect(strokeRect, FloatSize(replacementTextRoundedRectRadius + 1, replacementTextRoundedRectRadius + 1));
323
324     context.setStrokeColor(unavailablePluginBorderColor());
325     context.setStrokeThickness(2);
326     context.strokePath(strokePath);
327
328     const FontMetrics& fontMetrics = font.fontMetrics();
329     float labelX = roundf(replacementTextRect.location().x() + replacementTextRoundedRectLeftTextMargin);
330     float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent() + replacementTextRoundedRectTopTextMargin);
331     context.setFillColor(replacementTextColor());
332     context.drawBidiText(font, run, FloatPoint(labelX, labelY));
333
334     if (shouldUnavailablePluginMessageBeButton(page(), m_pluginUnavailabilityReason)) {
335         arrowRect.inflate(-replacementArrowCirclePadding);
336
337         context.beginTransparencyLayer(1.0);
338         context.setFillColor(replacementTextColor());
339         context.fillEllipse(arrowRect);
340
341         context.setCompositeOperation(CompositeClear);
342         drawReplacementArrow(context, arrowRect);
343         context.endTransparencyLayer();
344     }
345 }
346
347 void RenderEmbeddedObject::setUnavailablePluginIndicatorIsHidden(bool hidden)
348 {
349     auto newState = hidden ? UnavailablePluginIndicatorState::Hidden : UnavailablePluginIndicatorState::Visible;
350     if (m_isUnavailablePluginIndicatorState == newState)
351         return;
352     m_isUnavailablePluginIndicatorState = newState;
353     repaint();
354 }
355
356 LayoutRect RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset) const
357 {
358     FloatRect contentRect;
359     FloatRect indicatorRect;
360     FloatRect replacementTextRect;
361     FloatRect arrowRect;
362     FontCascade font;
363     TextRun run(emptyString());
364     float textWidth;
365     getReplacementTextGeometry(accumulatedOffset, contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth);
366     return LayoutRect(indicatorRect);
367 }
368
369 void RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, FloatRect& indicatorRect, FloatRect& replacementTextRect, FloatRect& arrowRect, FontCascade& font, TextRun& run, float& textWidth) const
370 {
371     bool includesArrow = shouldUnavailablePluginMessageBeButton(page(), m_pluginUnavailabilityReason);
372
373     contentRect = contentBoxRect();
374     contentRect.moveBy(roundedIntPoint(accumulatedOffset));
375
376     FontCascadeDescription fontDescription;
377     RenderTheme::singleton().systemFont(CSSValueWebkitSmallControl, fontDescription);
378     fontDescription.setWeight(boldWeightValue());
379     fontDescription.setRenderingMode(settings().fontRenderingMode());
380     fontDescription.setComputedSize(12);
381     font = FontCascade(WTFMove(fontDescription), 0, 0);
382     font.update(0);
383
384     run = TextRun(m_unavailablePluginReplacementText);
385     textWidth = font.width(run);
386
387     replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftTextMargin + (includesArrow ? replacementTextRoundedRectRightTextMarginWithArrow : replacementTextRoundedRectRightTextMargin), replacementTextRoundedRectHeight));
388     replacementTextRect.setLocation(contentRect.location() + (contentRect.size() / 2 - replacementTextRect.size() / 2));
389
390     indicatorRect = replacementTextRect;
391
392     // Expand the background rect to include the arrow, if it will be used.
393     if (includesArrow) {
394         arrowRect = indicatorRect;
395         arrowRect.setX(ceilf(arrowRect.maxX() + replacementArrowLeftMargin));
396         arrowRect.setWidth(arrowRect.height());
397         indicatorRect.unite(arrowRect);
398     }
399 }
400
401 LayoutRect RenderEmbeddedObject::unavailablePluginIndicatorBounds(const LayoutPoint& accumulatedOffset) const
402 {
403     return getReplacementTextGeometry(accumulatedOffset);
404 }
405
406 void RenderEmbeddedObject::layout()
407 {
408     StackStats::LayoutCheckPoint layoutCheckPoint;
409     ASSERT(needsLayout());
410
411     LayoutSize oldSize = contentBoxRect().size();
412
413     updateLogicalWidth();
414     updateLogicalHeight();
415
416     RenderWidget::layout();
417
418     clearOverflow();
419     addVisualEffectOverflow();
420
421     updateLayerTransform();
422
423     bool wasMissingWidget = false;
424     if (!widget() && canHaveWidget()) {
425         wasMissingWidget = true;
426         view().frameView().addEmbeddedObjectToUpdate(*this);
427     }
428
429     clearNeedsLayout();
430
431     LayoutSize newSize = contentBoxRect().size();
432
433     if (!wasMissingWidget && newSize.width() >= oldSize.width() && newSize.height() >= oldSize.height()) {
434         HTMLFrameOwnerElement& element = frameOwnerElement();
435         if (is<HTMLPlugInImageElement>(element)) {
436             HTMLPlugInImageElement& plugInImageElement = downcast<HTMLPlugInImageElement>(element);
437             if (plugInImageElement.displayState() > HTMLPlugInElement::DisplayingSnapshot && plugInImageElement.snapshotDecision() == HTMLPlugInImageElement::MaySnapshotWhenResized) {
438                 plugInImageElement.setNeedsCheckForSizeChange();
439                 view().frameView().addEmbeddedObjectToUpdate(*this);
440             }
441         }
442     }
443
444     if (!canHaveChildren())
445         return;
446
447     // This code copied from RenderMedia::layout().
448     RenderObject* child = firstChild();
449
450     if (!child)
451         return;
452
453     auto& childBox = downcast<RenderBox>(*child);
454
455     if (newSize == oldSize && !childBox.needsLayout())
456         return;
457     
458     // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or
459     // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient,
460     // and this method will be called many times per second during playback, use a LayoutStateMaintainer:
461     LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
462     
463     childBox.setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop()));
464     childBox.mutableStyle().setHeight(Length(newSize.height(), Fixed));
465     childBox.mutableStyle().setWidth(Length(newSize.width(), Fixed));
466     childBox.setNeedsLayout(MarkOnlyThis);
467     childBox.layout();
468     clearChildNeedsLayout();
469 }
470
471 bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
472 {
473     if (!RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction))
474         return false;
475
476     if (!is<PluginViewBase>(widget()))
477         return true;
478
479     PluginViewBase& view = downcast<PluginViewBase>(*widget());
480     IntPoint roundedPoint = locationInContainer.roundedPoint();
481
482     if (Scrollbar* horizontalScrollbar = view.horizontalScrollbar()) {
483         if (horizontalScrollbar->shouldParticipateInHitTesting() && horizontalScrollbar->frameRect().contains(roundedPoint)) {
484             result.setScrollbar(horizontalScrollbar);
485             return true;
486         }
487     }
488
489     if (Scrollbar* verticalScrollbar = view.verticalScrollbar()) {
490         if (verticalScrollbar->shouldParticipateInHitTesting() && verticalScrollbar->frameRect().contains(roundedPoint)) {
491             result.setScrollbar(verticalScrollbar);
492             return true;
493         }
494     }
495
496     return true;
497 }
498
499 bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float, Element**, RenderBox*, const IntPoint&)
500 {
501     if (!is<PluginViewBase>(widget()))
502         return false;
503
504     return downcast<PluginViewBase>(*widget()).scroll(direction, granularity);
505 }
506
507 bool RenderEmbeddedObject::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement)
508 {
509     // Plugins don't expose a writing direction, so assuming horizontal LTR.
510     return scroll(logicalToPhysical(direction, true, false), granularity, multiplier, stopElement);
511 }
512
513
514 bool RenderEmbeddedObject::isInUnavailablePluginIndicator(const FloatPoint& point) const
515 {
516     return getReplacementTextGeometry(LayoutPoint()).contains(LayoutPoint(point));
517 }
518
519 bool RenderEmbeddedObject::isInUnavailablePluginIndicator(const MouseEvent& event) const
520 {
521     return isInUnavailablePluginIndicator(absoluteToLocal(event.absoluteLocation(), UseTransforms));
522 }
523
524 void RenderEmbeddedObject::handleUnavailablePluginIndicatorEvent(Event* event)
525 {
526     if (!shouldUnavailablePluginMessageBeButton(page(), m_pluginUnavailabilityReason))
527         return;
528
529     if (!is<MouseEvent>(*event))
530         return;
531
532     MouseEvent& mouseEvent = downcast<MouseEvent>(*event);
533     HTMLPlugInElement& element = downcast<HTMLPlugInElement>(frameOwnerElement());
534     if (mouseEvent.type() == eventNames().mousedownEvent && mouseEvent.button() == LeftButton) {
535         m_mouseDownWasInUnavailablePluginIndicator = isInUnavailablePluginIndicator(mouseEvent);
536         if (m_mouseDownWasInUnavailablePluginIndicator) {
537             frame().eventHandler().setCapturingMouseEventsElement(&element);
538             element.setIsCapturingMouseEvents(true);
539             setUnavailablePluginIndicatorIsPressed(true);
540         }
541         mouseEvent.setDefaultHandled();
542     }
543     if (mouseEvent.type() == eventNames().mouseupEvent && mouseEvent.button() == LeftButton) {
544         if (m_unavailablePluginIndicatorIsPressed) {
545             frame().eventHandler().setCapturingMouseEventsElement(nullptr);
546             element.setIsCapturingMouseEvents(false);
547             setUnavailablePluginIndicatorIsPressed(false);
548         }
549         if (m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent)) {
550             page().chrome().client().unavailablePluginButtonClicked(element, m_pluginUnavailabilityReason);
551         }
552         m_mouseDownWasInUnavailablePluginIndicator = false;
553         event->setDefaultHandled();
554     }
555     if (mouseEvent.type() == eventNames().mousemoveEvent) {
556         setUnavailablePluginIndicatorIsPressed(m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent));
557         mouseEvent.setDefaultHandled();
558     }
559 }
560
561 CursorDirective RenderEmbeddedObject::getCursor(const LayoutPoint& point, Cursor& cursor) const
562 {
563     if (showsUnavailablePluginIndicator() && shouldUnavailablePluginMessageBeButton(page(), m_pluginUnavailabilityReason) && isInUnavailablePluginIndicator(point)) {
564         cursor = handCursor();
565         return SetCursor;
566     }
567     if (widget() && widget()->isPluginViewBase()) {
568         // A plug-in is responsible for setting the cursor when the pointer is over it.
569         return DoNotSetCursor;
570     }
571     return RenderWidget::getCursor(point, cursor);
572 }
573
574 bool RenderEmbeddedObject::canHaveChildren() const
575 {
576     if (isSnapshottedPlugIn())
577         return true;
578
579     return false;
580 }
581
582 }