Diff
Copied: branches/chromium/1271/LayoutTests/svg/filters/feImage-self-and-other-referencing-expected.html (from rev 132856, trunk/LayoutTests/svg/filters/feImage-self-and-other-referencing-expected.html) (0 => 134258)
--- branches/chromium/1271/LayoutTests/svg/filters/feImage-self-and-other-referencing-expected.html (rev 0)
+++ branches/chromium/1271/LayoutTests/svg/filters/feImage-self-and-other-referencing-expected.html 2012-11-12 19:03:11 UTC (rev 134258)
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <p>PASS if no crash</p>
+ </body>
+</html>
+
Copied: branches/chromium/1271/LayoutTests/svg/filters/feImage-self-and-other-referencing.html (from rev 132856, trunk/LayoutTests/svg/filters/feImage-self-and-other-referencing.html) (0 => 134258)
--- branches/chromium/1271/LayoutTests/svg/filters/feImage-self-and-other-referencing.html (rev 0)
+++ branches/chromium/1271/LayoutTests/svg/filters/feImage-self-and-other-referencing.html 2012-11-12 19:03:11 UTC (rev 134258)
@@ -0,0 +1,21 @@
+<html>
+ <head>
+ <script>
+ _onload_ = function() {
+ document.getElementById("svgRoot").setAttribute('filter', 'url(#imageFilter)')
+ }
+ </script>
+ </head>
+ <body>
+ <p>PASS if no crash</p>
+ <svg width="10" height="10" id="svgRoot" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <filter id="imageFilter">
+ <feImage id="feImage" xlink:href=""
+ <feOffset dx="50" dy="50" />
+ </filter>
+ <g filter="url(#imageFilter)">
+ <rect x="0" y="0" width="50" height="50" fill="green" />
+ </g>
+ </svg>
+ </body>
+</html>
Modified: branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp (134257 => 134258)
--- branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp 2012-11-12 18:58:45 UTC (rev 134257)
+++ branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp 2012-11-12 19:03:11 UTC (rev 134258)
@@ -57,25 +57,6 @@
namespace WebCore {
-class ApplyingFilterEffectGuard {
-public:
- ApplyingFilterEffectGuard(FilterData* data)
- : m_filterData(data)
- {
- // The guard must be constructed when the filter is not applying.
- ASSERT(!m_filterData->isApplying);
- m_filterData->isApplying = true;
- }
-
- ~ApplyingFilterEffectGuard()
- {
- ASSERT(m_filterData->isApplying);
- m_filterData->isApplying = false;
- }
-
- FilterData* m_filterData;
-};
-
RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType;
RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node)
@@ -108,7 +89,7 @@
if (FilterData* filterData = m_filter.get(client)) {
if (filterData->savedContext)
- filterData->markedForRemoval = true;
+ filterData->state = FilterData::MarkedForRemoval;
else
delete m_filter.take(client);
}
@@ -168,14 +149,11 @@
ASSERT(context);
ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
- // Returning false here, to avoid drawings onto the context. We just want to
- // draw the stored filter output, not the unfiltered object as well.
if (m_filter.contains(object)) {
FilterData* filterData = m_filter.get(object);
- if (filterData->isBuilt || filterData->isApplying)
- return false;
-
- delete m_filter.take(object); // Oops, have to rebuild, go through normal code path
+ if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying)
+ filterData->state = FilterData::CycleDetected;
+ return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now.
}
OwnPtr<FilterData> filterData(adoptPtr(new FilterData));
@@ -292,17 +270,21 @@
if (!filterData)
return;
- if (filterData->markedForRemoval) {
+ switch (filterData->state) {
+ case FilterData::MarkedForRemoval:
delete m_filter.take(object);
return;
- }
- // We have a cycle if we are already applying the data.
- // This can occur due to FeImage referencing a source that makes use of the FEImage itself.
- if (filterData->isApplying)
+ case FilterData::CycleDetected:
+ case FilterData::Applying:
+ // We have a cycle if we are already applying the data.
+ // This can occur due to FeImage referencing a source that makes use of the FEImage itself.
+ // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack
+ // will continue correctly.
+ filterData->state = FilterData::PaintingSource;
return;
- if (!filterData->isBuilt) {
+ case FilterData::PaintingSource:
if (!filterData->savedContext) {
removeClientFromCache(object);
return;
@@ -310,21 +292,23 @@
context = filterData->savedContext;
filterData->savedContext = 0;
+ break;
+
+ case FilterData::Built: { } // Empty
}
- ApplyingFilterEffectGuard isApplyingGuard(filterData);
-
FilterEffect* lastEffect = filterData->builder->lastEffect();
if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
// This is the real filtering of the object. It just needs to be called on the
// initial filtering process. We just take the stored filter result on a
// second drawing.
- if (!filterData->isBuilt)
+ if (filterData->state != FilterData::Built)
filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release());
- // Always true if filterData is just built (filterData->isBuilt is false).
+ // Always true if filterData is just built (filterData->state == FilterData::Built).
if (!lastEffect->hasResult()) {
+ filterData->state = FilterData::Applying;
lastEffect->apply();
lastEffect->correctFilterResultIfNeeded();
#if !USE(CG)
@@ -333,7 +317,7 @@
resultImage->transformColorSpace(lastEffect->colorSpace(), ColorSpaceDeviceRGB);
#endif
}
- filterData->isBuilt = true;
+ filterData->state = FilterData::Built;
ImageBuffer* resultImage = lastEffect->asImageBuffer();
if (resultImage) {
@@ -365,7 +349,7 @@
for (; it != end; ++it) {
FilterData* filterData = it->second;
- if (!filterData->isBuilt)
+ if (filterData->state != FilterData::Built)
continue;
SVGFilterBuilder* builder = filterData->builder.get();
Modified: branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h (134257 => 134258)
--- branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h 2012-11-12 18:58:45 UTC (rev 134257)
+++ branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h 2012-11-12 19:03:11 UTC (rev 134258)
@@ -42,11 +42,11 @@
struct FilterData {
WTF_MAKE_FAST_ALLOCATED;
public:
+ enum FilterDataState { PaintingSource, Applying, Built, CycleDetected, MarkedForRemoval };
+
FilterData()
: savedContext(0)
- , isBuilt(false)
- , isApplying(false)
- , markedForRemoval(false)
+ , state(PaintingSource)
{
}
@@ -57,9 +57,7 @@
AffineTransform shearFreeAbsoluteTransform;
FloatRect boundaries;
FloatSize scale;
- bool isBuilt : 1;
- bool isApplying : 1;
- bool markedForRemoval : 1;
+ FilterDataState state;
};
class GraphicsContext;
Modified: branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGRoot.cpp (134257 => 134258)
--- branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGRoot.cpp 2012-11-12 18:58:45 UTC (rev 134257)
+++ branches/chromium/1271/Source/WebCore/rendering/svg/RenderSVGRoot.cpp 2012-11-12 19:03:11 UTC (rev 134258)
@@ -298,16 +298,20 @@
IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset);
childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x() - x(), adjustedPaintOffset.y() - y()) * localToParentTransform());
- SVGRenderingContext renderingContext;
- bool continueRendering = true;
- if (childPaintInfo.phase == PaintPhaseForeground) {
- renderingContext.prepareToRenderSVGContent(this, childPaintInfo);
- continueRendering = renderingContext.isRenderingPrepared();
+ // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have
+ // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter.
+ {
+ SVGRenderingContext renderingContext;
+ bool continueRendering = true;
+ if (childPaintInfo.phase == PaintPhaseForeground) {
+ renderingContext.prepareToRenderSVGContent(this, childPaintInfo);
+ continueRendering = renderingContext.isRenderingPrepared();
+ }
+
+ if (continueRendering)
+ RenderBox::paint(childPaintInfo, LayoutPoint());
}
- if (continueRendering)
- RenderBox::paint(childPaintInfo, LayoutPoint());
-
childPaintInfo.context->restore();
}