Index: Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp |
=================================================================== |
--- Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp (revision 132808) |
+++ Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp (working copy) |
@@ -57,6 +57,25 @@ |
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) |
@@ -153,7 +172,7 @@ |
// draw the stored filter output, not the unfiltered object as well. |
if (m_filter.contains(object)) { |
FilterData* filterData = m_filter.get(object); |
- if (filterData->builded) |
+ if (filterData->isBuilt || filterData->isApplying) |
return false; |
delete m_filter.take(object); // Oops, have to rebuild, go through normal code path |
@@ -278,7 +297,12 @@ |
return; |
} |
- if (!filterData->builded) { |
+ // 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) |
+ return; |
+ |
+ if (!filterData->isBuilt) { |
if (!filterData->savedContext) { |
removeClientFromCache(object); |
return; |
@@ -288,16 +312,18 @@ |
filterData->savedContext = 0; |
} |
+ 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->builded) |
+ if (!filterData->isBuilt) |
filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release()); |
- // Always true if filterData is just built (filterData->builded is false). |
+ // Always true if filterData is just built (filterData->isBuilt is false). |
if (!lastEffect->hasResult()) { |
lastEffect->apply(); |
lastEffect->correctFilterResultIfNeeded(); |
@@ -307,7 +333,7 @@ |
resultImage->transformColorSpace(lastEffect->colorSpace(), ColorSpaceDeviceRGB); |
#endif |
} |
- filterData->builded = true; |
+ filterData->isBuilt = true; |
ImageBuffer* resultImage = lastEffect->asImageBuffer(); |
if (resultImage) { |
@@ -339,7 +365,7 @@ |
for (; it != end; ++it) { |
FilterData* filterData = it->second; |
- if (!filterData->builded) |
+ if (!filterData->isBuilt) |
continue; |
SVGFilterBuilder* builder = filterData->builder.get(); |