+2011-02-04 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Crashes in ShadowBlur via WebKit2 FindController
+ https://bugs.webkit.org/show_bug.cgi?id=53830
+
+ Fix a crash cause by re-entering ShadowBlur, and add assertions to
+ detect when it happens.
+
+ The re-entrancy occurred when drawRectShadowWithTiling() filled
+ the interior of the shadow with fillRect() on the context
+ which still had the shadow state set. This would make another ShadowBlur
+ on the stack and call into the code again, potentially blowing away
+ the image buffer.
+
+ Fix by turning off shadows in the destination context while we're
+ drawing the tiled shadow. The non-tiled code path already did this.
+
+ Not testable because CSS shadows clip out the inside of the rect
+ being shadowed, and SVG uses fillPath, even for rects.
+
+ * platform/graphics/ShadowBlur.cpp:
+ (WebCore::ScratchBuffer::ScratchBuffer):
+ (WebCore::ScratchBuffer::getScratchBuffer):
+ (WebCore::ScratchBuffer::scheduleScratchBufferPurge):
+ (WebCore::ShadowBlur::ShadowBlur):
+ (WebCore::ShadowBlur::drawRectShadowWithTiling):
+
2011-02-04 Carlos Garcia Campos <cgarcia@igalia.com>
Reviewed by Martin Robinson.
public:
ScratchBuffer()
: m_purgeTimer(this, &ScratchBuffer::timerFired)
+#if !ASSERT_DISABLED
+ , m_bufferInUse(false)
+#endif
{
}
ImageBuffer* getScratchBuffer(const IntSize& size)
{
+ ASSERT(!m_bufferInUse);
+#if !ASSERT_DISABLED
+ m_bufferInUse = true;
+#endif
// We do not need to recreate the buffer if the current buffer is large enough.
if (m_imageBuffer && m_imageBuffer->width() >= size.width() && m_imageBuffer->height() >= size.height())
return m_imageBuffer.get();
void scheduleScratchBufferPurge()
{
+#if !ASSERT_DISABLED
+ m_bufferInUse = false;
+#endif
if (m_purgeTimer.isActive())
m_purgeTimer.stop();
OwnPtr<ImageBuffer> m_imageBuffer;
Timer<ScratchBuffer> m_purgeTimer;
+#if !ASSERT_DISABLED
+ bool m_bufferInUse;
+#endif
};
ScratchBuffer& ScratchBuffer::shared()
, m_colorSpace(colorSpace)
, m_blurRadius(radius)
, m_offset(offset)
+ , m_layerImage(0)
, m_shadowsIgnoreTransforms(false)
{
// Limit blur radius to 128 to avoid lots of very expensive blurring.
void ShadowBlur::drawRectShadowWithTiling(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii, const IntSize& shadowTemplateSize)
{
+ graphicsContext->save();
+ graphicsContext->clearShadow();
+
const float roundedRadius = ceilf(m_blurRadius);
const float twiceRadius = roundedRadius * 2;
destRect = FloatRect(shadowBounds.x(), shadowBounds.maxY() - bottomOffset, leftOffset, bottomOffset);
graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect);
+ graphicsContext->restore();
+
m_layerImage = 0;
// Schedule a purge of the scratch buffer.
ScratchBuffer::shared().scheduleScratchBufferPurge();