Implement a custom appearance for the snapshotted plugin background
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Mar 2013 10:01:21 +0000 (10:01 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Mar 2013 10:01:21 +0000 (10:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=108368

Reviewed by NOBODY (OOPS!).

Source/WebCore:

After https://bugs.webkit.org/show_bug.cgi?id=108284 (r142507), a
snapshotted plugin was no longer drawing the background of the
label blurred. Since the snapshot content was now a shadow tree,
it wasn't feasible to pre-blur a region of the snapshot: the label
could be any size and in any location, with ports being able to
override the appearance through their UA style sheet.

Instead we now use one of the elements in the tree, the snapshot-overlay,
as a hook where ports can add any effect they want. This could be simply
a border, or a transparent mask, or even a CSS filter. We introduce a custom
CSS appearance "snapshotted-plugin-overlay", which could be added to the
element in the injected UA stylesheet. This calls into RenderTheme in
the same way that custom controls do.

Meanwhile, in RenderThemeMac, we implement the appearance by drawing the
content of the plugin snapshot into the background of the element. That
way we can add effects in CSS.

Test: plugins/snapshot-appearance.html

* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue): Handle SnapshottedPluginOverlayPart.
* css/CSSValueKeywords.in: New appearance value snapshotted-plugin-overlay.
* platform/ThemeTypes.h: New value SnapshottedPluginOverlayPart.
* html/HTMLPlugInElement.h:
(WebCore::toHTMLPlugInElement): Add safer casting helpers.
* html/HTMLPlugInImageElement.h:
(WebCore::toHTMLPlugInImageElement): Ditto.
* rendering/RenderSnapshottedPlugIn.cpp: Remove the code for handling
    the blur directly in the renderer.
(WebCore::RenderSnapshottedPlugIn::paint): Simplify the paint logic since we're
    no longer trying to blur here.
(WebCore::RenderSnapshottedPlugIn::paintSnapshot): Ditto.
* rendering/RenderSnapshottedPlugIn.h: Remove the methods that were trying
    to blur the image directly.
* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::paint): Call paintSnapshottedPluginOverlay.
* rendering/RenderTheme.h:
(WebCore::RenderTheme::paintSnapshottedPluginOverlay): New virtual method with default implementation.
* rendering/RenderThemeMacShared.h:
(RenderThemeMacShared): Override paintSnapshottedPluginOverlay.
* rendering/RenderThemeMacShared.mm:
(WebCore::RenderThemeMacShared::paintSnapshottedPluginOverlay): Implement a custom render path
    that takes the snapshot image from the node's parent, and draws it into the background.
    Along the way make sure we're actually using the right type of element (an HTMLPlugInImageElement).

LayoutTests:

Toggles our new snapshotted-plugin-overlay appearance, to make sure it
isn't getting applied to non-plugins.

* plugins/snapshot-appearance-expected.html: Added.
* plugins/snapshot-appearance.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@145196 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/plugins/snapshot-appearance-expected.html [new file with mode: 0644]
LayoutTests/plugins/snapshot-appearance.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/html/HTMLPlugInElement.h
Source/WebCore/html/HTMLPlugInImageElement.h
Source/WebCore/platform/ThemeTypes.h
Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
Source/WebCore/rendering/RenderSnapshottedPlugIn.h
Source/WebCore/rendering/RenderTheme.cpp
Source/WebCore/rendering/RenderTheme.h
Source/WebCore/rendering/RenderThemeMacShared.h
Source/WebCore/rendering/RenderThemeMacShared.mm

index 5c6d42d..0940db6 100644 (file)
@@ -1,3 +1,16 @@
+2013-03-07  Dean Jackson  <dino@apple.com>
+
+        Implement a custom appearance for the snapshotted plugin background
+        https://bugs.webkit.org/show_bug.cgi?id=108368
+
+        Reviewed by Tim Horton.
+
+        Toggles our new snapshotted-plugin-overlay appearance, to make sure it
+        isn't getting applied to non-plugins.
+
+        * plugins/snapshot-appearance-expected.html: Added.
+        * plugins/snapshot-appearance.html: Added.
+
 2013-03-08  Sergio Villar Senin  <svillar@igalia.com>
 
         Improve drag&drop of list items in contentEditable divs
diff --git a/LayoutTests/plugins/snapshot-appearance-expected.html b/LayoutTests/plugins/snapshot-appearance-expected.html
new file mode 100644 (file)
index 0000000..f9677ce
--- /dev/null
@@ -0,0 +1,9 @@
+<style>
+div {
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+}
+</style>
+<div id="normal"></div>
+<div id="normal"></div>
diff --git a/LayoutTests/plugins/snapshot-appearance.html b/LayoutTests/plugins/snapshot-appearance.html
new file mode 100644 (file)
index 0000000..a98809b
--- /dev/null
@@ -0,0 +1,14 @@
+<!-- Since we're not a snapshotted plugin, this test should do nothing (and not crash) -->
+<style>
+div {
+    width: 50px;
+    height: 50px;
+    background-color: blue;
+}
+
+#snapshot {
+    -webkit-appearance: snapshotted-plugin-overlay;
+}
+</style>
+<div id="normal"></div>
+<div id="snapshot"></div>
index 3070f6f..eccc27e 100644 (file)
@@ -1,3 +1,56 @@
+2013-03-07  Dean Jackson  <dino@apple.com>
+
+        Implement a custom appearance for the snapshotted plugin background
+        https://bugs.webkit.org/show_bug.cgi?id=108368
+
+        Reviewed by Tim Horton.
+
+        After https://bugs.webkit.org/show_bug.cgi?id=108284 (r142507), a
+        snapshotted plugin was no longer drawing the background of the
+        label blurred. Since the snapshot content was now a shadow tree,
+        it wasn't feasible to pre-blur a region of the snapshot: the label
+        could be any size and in any location, with ports being able to
+        override the appearance through their UA style sheet.
+
+        Instead we now use one of the elements in the tree, the snapshot-overlay,
+        as a hook where ports can add any effect they want. This could be simply
+        a border, or a transparent mask, or even a CSS filter. We introduce a custom
+        CSS appearance "snapshotted-plugin-overlay", which could be added to the
+        element in the injected UA stylesheet. This calls into RenderTheme in
+        the same way that custom controls do.
+
+        Meanwhile, in RenderThemeMac, we implement the appearance by drawing the
+        content of the plugin snapshot into the background of the element. That
+        way we can add effects in CSS.
+
+        Test: plugins/snapshot-appearance.html
+
+        * css/CSSPrimitiveValueMappings.h:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue): Handle SnapshottedPluginOverlayPart.
+        * css/CSSValueKeywords.in: New appearance value snapshotted-plugin-overlay.
+        * platform/ThemeTypes.h: New value SnapshottedPluginOverlayPart.
+        * html/HTMLPlugInElement.h:
+        (WebCore::toHTMLPlugInElement): Add safer casting helpers.
+        * html/HTMLPlugInImageElement.h:
+        (WebCore::toHTMLPlugInImageElement): Ditto.
+        * rendering/RenderSnapshottedPlugIn.cpp: Remove the code for handling
+            the blur directly in the renderer.
+        (WebCore::RenderSnapshottedPlugIn::paint): Simplify the paint logic since we're
+            no longer trying to blur here.
+        (WebCore::RenderSnapshottedPlugIn::paintSnapshot): Ditto.
+        * rendering/RenderSnapshottedPlugIn.h: Remove the methods that were trying
+            to blur the image directly.
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::paint): Call paintSnapshottedPluginOverlay.
+        * rendering/RenderTheme.h:
+        (WebCore::RenderTheme::paintSnapshottedPluginOverlay): New virtual method with default implementation.
+        * rendering/RenderThemeMacShared.h:
+        (RenderThemeMacShared): Override paintSnapshottedPluginOverlay.
+        * rendering/RenderThemeMacShared.mm:
+        (WebCore::RenderThemeMacShared::paintSnapshottedPluginOverlay): Implement a custom render path
+            that takes the snapshot image from the node's parent, and draws it into the background.
+            Along the way make sure we're actually using the right type of element (an HTMLPlugInImageElement).
+
 2013-03-08  Sergio Villar Senin  <svillar@igalia.com>
 
         Improve drag&drop of list items in contentEditable divs
index 0de3f76..c0e55c3 100644 (file)
@@ -546,6 +546,9 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e)
         case SearchFieldCancelButtonPart:
             m_value.ident = CSSValueSearchfieldCancelButton;
             break;
+        case SnapshottedPluginOverlayPart:
+            m_value.ident = CSSValueSnapshottedPluginOverlay;
+            break;
         case TextFieldPart:
             m_value.ident = CSSValueTextfield;
             break;
index f8402c5..9bdb2f4 100644 (file)
@@ -684,6 +684,7 @@ searchfield-decoration
 searchfield-results-decoration
 searchfield-results-button
 searchfield-cancel-button
+snapshotted-plugin-overlay
 textfield
 relevancy-level-indicator
 continuous-capacity-level-indicator
index a7559a8..b320f37 100644 (file)
@@ -111,6 +111,21 @@ private:
     DisplayState m_displayState;
 };
 
+inline HTMLPlugInElement* toHTMLPlugInElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    return static_cast<HTMLPlugInElement*>(node);
+}
+
+inline const HTMLPlugInElement* toHTMLPlugInElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    return static_cast<const HTMLPlugInElement*>(node);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLPlugInElement(const HTMLPlugInElement*);
+
 } // namespace WebCore
 
 #endif // HTMLPlugInElement_h
index f85b3f2..b50d53a 100644 (file)
@@ -124,6 +124,25 @@ private:
     RefPtr<Image> m_snapshotImage;
 };
 
+inline HTMLPlugInImageElement* toHTMLPlugInImageElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    HTMLPlugInElement* plugInElement = static_cast<HTMLPlugInElement*>(node);
+    ASSERT_WITH_SECURITY_IMPLICATION(plugInElement->isPlugInImageElement());
+    return static_cast<HTMLPlugInImageElement*>(plugInElement);
+}
+
+inline const HTMLPlugInImageElement* toHTMLPlugInImageElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    const HTMLPlugInElement* plugInElement = static_cast<const HTMLPlugInElement*>(node);
+    ASSERT_WITH_SECURITY_IMPLICATION(plugInElement->isPlugInImageElement());
+    return static_cast<const HTMLPlugInImageElement*>(plugInElement);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLPlugInImageElement(const HTMLPlugInImageElement*);
+
 } // namespace WebCore
 
 #endif // HTMLPlugInImageElement_h
index 8ef6b23..4421c51 100644 (file)
@@ -56,7 +56,7 @@ enum ControlPart {
     SliderHorizontalPart, SliderVerticalPart, SliderThumbHorizontalPart,
     SliderThumbVerticalPart, CaretPart, SearchFieldPart, SearchFieldDecorationPart,
     SearchFieldResultsDecorationPart, SearchFieldResultsButtonPart,
-    SearchFieldCancelButtonPart, TextFieldPart,
+    SearchFieldCancelButtonPart, SnapshottedPluginOverlayPart, TextFieldPart,
     RelevancyLevelIndicatorPart, ContinuousCapacityLevelIndicatorPart, DiscreteCapacityLevelIndicatorPart, RatingLevelIndicatorPart,
     TextAreaPart, CapsLockIndicatorPart
 };
index dadbb92..6284382 100644 (file)
@@ -29,7 +29,6 @@
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "Cursor.h"
-#include "FEGaussianBlur.h"
 #include "Filter.h"
 #include "FrameLoaderClient.h"
 #include "FrameView.h"
 #include "PaintInfo.h"
 #include "Path.h"
 #include "RenderView.h"
-#include "SourceGraphic.h"
 
 namespace WebCore {
 
-static const int autoStartPlugInSizeThresholdWidth = 1;
-static const int autoStartPlugInSizeThresholdHeight = 1;
 static const double showLabelAfterMouseOverDelay = 1;
 static const double showLabelAutomaticallyDelay = 3;
-static const int snapshotLabelBlurRadius = 5;
-
-#if ENABLE(FILTERS)
-class RenderSnapshottedPlugInBlurFilter : public Filter {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    static PassRefPtr<RenderSnapshottedPlugInBlurFilter> create(int radius)
-    {
-        return adoptRef(new RenderSnapshottedPlugInBlurFilter(radius));
-    }
-
-    void setSourceImageRect(const FloatRect& r)
-    {
-        m_sourceImageRect = r;
-        m_filterRegion = r;
-        m_sourceGraphic->setMaxEffectRect(r);
-        m_blur->setMaxEffectRect(r);
-    }
-    virtual FloatRect sourceImageRect() const { return m_sourceImageRect; }
-    virtual FloatRect filterRegion() const { return m_filterRegion; }
-
-    void apply();
-    ImageBuffer* output() const { return m_blur->asImageBuffer(); }
-
-private:
-    RenderSnapshottedPlugInBlurFilter(int radius);
-
-    FloatRect m_sourceImageRect;
-    FloatRect m_filterRegion;
-    RefPtr<SourceGraphic> m_sourceGraphic;
-    RefPtr<FEGaussianBlur> m_blur;
-};
-
-RenderSnapshottedPlugInBlurFilter::RenderSnapshottedPlugInBlurFilter(int radius)
-{
-    setFilterResolution(FloatSize(1, 1));
-    m_sourceGraphic = SourceGraphic::create(this);
-    m_blur = FEGaussianBlur::create(this, radius, radius);
-    m_blur->inputEffects().append(m_sourceGraphic);
-}
-
-void RenderSnapshottedPlugInBlurFilter::apply()
-{
-    m_sourceGraphic->clearResult();
-    m_blur->clearResult();
-    m_blur->apply();
-}
-#endif
 
 RenderSnapshottedPlugIn::RenderSnapshottedPlugIn(HTMLPlugInImageElement* element)
     : RenderBlock(element)
@@ -160,17 +108,18 @@ void RenderSnapshottedPlugIn::updateSnapshot(PassRefPtr<Image> image)
 void RenderSnapshottedPlugIn::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
     if (paintInfo.phase == PaintPhaseBlockBackground && plugInImageElement()->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick) {
-        if (m_shouldShowLabel)
-            paintSnapshotWithLabel(paintInfo, paintOffset);
-        else
-            paintSnapshot(paintInfo, paintOffset);
+        paintSnapshot(paintInfo, paintOffset);
     }
 
     RenderBlock::paint(paintInfo, paintOffset);
 }
 
-void RenderSnapshottedPlugIn::paintSnapshotImage(Image* image, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
+    Image* image = m_snapshotResource->image().get();
+    if (!image || image->isNull())
+        return;
+
     LayoutUnit cWidth = contentWidth();
     LayoutUnit cHeight = contentHeight();
     if (!cWidth || !cHeight)
@@ -195,65 +144,6 @@ void RenderSnapshottedPlugIn::paintSnapshotImage(Image* image, PaintInfo& paintI
     context->drawImage(image, style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling);
 }
 
-void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
-{
-    RefPtr<Image> image = m_snapshotResource->image();
-    if (!image || image->isNull())
-        return;
-
-    paintSnapshotImage(image.get(), paintInfo, paintOffset);
-}
-
-#if ENABLE(FILTERS)
-static PassRefPtr<Image> snapshottedPluginImageForLabelDisplay(PassRefPtr<Image> snapshot, const LayoutRect& blurRegion)
-{
-    OwnPtr<ImageBuffer> snapshotBuffer = ImageBuffer::create(snapshot->size());
-    snapshotBuffer->context()->drawImage(snapshot.get(), ColorSpaceDeviceRGB, IntPoint(0, 0));
-
-    OwnPtr<ImageBuffer> blurBuffer = ImageBuffer::create(roundedIntSize(blurRegion.size()));
-    blurBuffer->context()->drawImage(snapshot.get(), ColorSpaceDeviceRGB, IntPoint(-blurRegion.x(), -blurRegion.y()));
-
-    RefPtr<RenderSnapshottedPlugInBlurFilter> blurFilter = RenderSnapshottedPlugInBlurFilter::create(snapshotLabelBlurRadius);
-    blurFilter->setSourceImage(blurBuffer.release());
-    blurFilter->setSourceImageRect(FloatRect(FloatPoint(), blurRegion.size()));
-    blurFilter->apply();
-
-    snapshotBuffer->context()->drawImageBuffer(blurFilter->output(), ColorSpaceDeviceRGB, roundedIntPoint(blurRegion.location()));
-    return snapshotBuffer->copyImage();
-}
-#endif
-
-void RenderSnapshottedPlugIn::paintSnapshotWithLabel(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
-{
-    if (contentBoxRect().isEmpty())
-        return;
-
-    if (!plugInImageElement()->hovered() && m_showReason == UserMousedOver)
-        return;
-
-    m_showedLabelOnce = true;
-    LayoutRect labelRect;
-
-    RefPtr<Image> snapshotImage = m_snapshotResource->image();
-    if (!snapshotImage || snapshotImage->isNull())
-        return;
-
-#if ENABLE(FILTERS)
-    // FIXME: Temporarily disabling the blur behind the label.
-    // https://bugs.webkit.org/show_bug.cgi?id=108368
-    if (!labelRect.isEmpty()) {
-        RefPtr<Image> blurredSnapshotImage = m_snapshotResourceForLabel->image();
-        if (!blurredSnapshotImage || blurredSnapshotImage->isNull()) {
-            blurredSnapshotImage = snapshottedPluginImageForLabelDisplay(snapshotImage, labelRect);
-            m_snapshotResourceForLabel->setCachedImage(new CachedImage(blurredSnapshotImage.get()));
-        }
-        snapshotImage = blurredSnapshotImage;
-    }
-#endif
-
-    paintSnapshotImage(snapshotImage.get(), paintInfo, paintOffset);
-}
-
 void RenderSnapshottedPlugIn::repaintLabel()
 {
     // FIXME: This is unfortunate. We should just repaint the label.
index 4ab3c2b..fce6dea 100644 (file)
@@ -55,8 +55,6 @@ private:
     virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE;
 
     void paintSnapshot(PaintInfo&, const LayoutPoint&);
-    void paintSnapshotWithLabel(PaintInfo&, const LayoutPoint&);
-    void paintSnapshotImage(Image*, PaintInfo&, const LayoutPoint&);
     void repaintLabel();
 
     virtual void layout() OVERRIDE;
index a3581a4..181b73c 100644 (file)
@@ -380,6 +380,8 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRe
         return paintSearchFieldResultsDecoration(o, paintInfo, r);
     case SearchFieldResultsButtonPart:
         return paintSearchFieldResultsButton(o, paintInfo, r);
+    case SnapshottedPluginOverlayPart:
+        return paintSnapshottedPluginOverlay(o, paintInfo, r);
 #if ENABLE(INPUT_SPEECH)
     case InputSpeechButtonPart:
         return paintInputFieldSpeechButton(o, paintInfo, r);
index 18722b7..78c32b3 100644 (file)
@@ -344,6 +344,8 @@ protected:
     virtual bool paintMediaFullScreenVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
     virtual bool paintMediaFullScreenVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
 
+    virtual bool paintSnapshottedPluginOverlay(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
+
 public:
     // Methods for state querying
     ControlStates controlStatesForRenderer(const RenderObject* o) const;
index 5283cb8..53a3ce1 100644 (file)
@@ -149,6 +149,8 @@ protected:
 
     virtual bool shouldShowPlaceholderWhenFocused() const;
 
+    virtual bool paintSnapshottedPluginOverlay(RenderObject*, const PaintInfo&, const IntRect&);
+
 private:
     virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const OVERRIDE;
 
index ac19c93..967cf9a 100644 (file)
 #import "HTMLInputElement.h"
 #import "HTMLMediaElement.h"
 #import "HTMLNames.h"
+#import "HTMLPlugInImageElement.h"
 #import "Image.h"
 #import "ImageBuffer.h"
 #import "LocalCurrentGraphicsContext.h"
 #import "LocalizedStrings.h"
 #import "MediaControlElements.h"
 #import "PaintInfo.h"
+#import "RenderLayer.h"
 #import "RenderMedia.h"
 #import "RenderMediaControls.h"
 #import "RenderSlider.h"
@@ -1702,6 +1704,83 @@ bool RenderThemeMacShared::paintSearchFieldResultsButton(RenderObject* o, const
     return false;
 }
 
+bool RenderThemeMacShared::paintSnapshottedPluginOverlay(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
+{
+    if (paintInfo.phase != PaintPhaseBlockBackground)
+        return true;
+
+    if (!o->isRenderBlock())
+        return true;
+
+    RenderBlock* renderBlock = toRenderBlock(o);
+
+    LayoutUnit contentWidth = renderBlock->contentWidth();
+    LayoutUnit contentHeight = renderBlock->contentHeight();
+    if (!contentWidth || !contentHeight)
+        return true;
+
+    GraphicsContext* context = paintInfo.context;
+
+    LayoutSize contentSize(contentWidth, contentHeight);
+    LayoutPoint contentLocation = renderBlock->location();
+    contentLocation.move(renderBlock->borderLeft() + renderBlock->paddingLeft(), renderBlock->borderTop() + renderBlock->paddingTop());
+
+    LayoutRect rect(contentLocation, contentSize);
+    IntRect alignedRect = pixelSnappedIntRect(rect);
+    if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
+        return true;
+
+    // We need to get the snapshot image from the plugin element, which should be available
+    // from our node. Assuming this node is the plugin overlay element, we should get to the
+    // plugin itself by asking for the shadow root parent, and then its parent.
+
+    if (!renderBlock->node()->isHTMLElement())
+        return true;
+
+    HTMLElement* plugInOverlay = toHTMLElement(renderBlock->node());
+    Element* parent = plugInOverlay->parentOrShadowHostElement();
+    while (parent && !parent->isPluginElement())
+        parent = parent->parentOrShadowHostElement();
+
+    if (!parent)
+        return true;
+
+    HTMLPlugInElement* plugInElement = toHTMLPlugInElement(parent);
+    if (!plugInElement->isPlugInImageElement())
+        return true;
+
+    HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(plugInElement);
+
+    Image* snapshot = plugInImageElement->snapshotImage();
+    if (!snapshot)
+        return true;
+
+    RenderSnapshottedPlugIn* plugInRenderer = toRenderSnapshottedPlugIn(plugInImageElement->renderer());
+    FloatPoint snapshotAbsPos = plugInRenderer->localToAbsolute();
+    snapshotAbsPos.move(plugInRenderer->borderLeft() + plugInRenderer->paddingLeft(), plugInRenderer->borderTop() + plugInRenderer->paddingTop());
+
+    // We could draw the snapshot with that coordinates, but we need to make sure there
+    // isn't a composited layer between us and the plugInRenderer.
+    RenderBox* renderBox = toRenderBox(o);
+    while (renderBox != plugInRenderer) {
+        if (renderBox->hasLayer() && renderBox->layer() && renderBox->layer()->isComposited()) {
+            snapshotAbsPos = -renderBox->location();
+            break;
+        }
+        renderBox = renderBox->parentBox();
+    }
+
+    LayoutSize pluginSize(plugInRenderer->contentWidth(), plugInRenderer->contentHeight());
+    LayoutRect pluginRect(snapshotAbsPos, pluginSize);
+    IntRect alignedPluginRect = pixelSnappedIntRect(pluginRect);
+
+    if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
+        return true;
+
+    context->drawImage(snapshot, plugInRenderer->style()->colorSpace(), alignedPluginRect, CompositeSourceOver);
+    return false;
+}
+
 #if ENABLE(DATALIST_ELEMENT)
 IntSize RenderThemeMacShared::sliderTickSize() const
 {