| Index: Source/core/rendering/FilterEffectRenderer.cpp | 
| diff --git a/Source/core/rendering/FilterEffectRenderer.cpp b/Source/core/rendering/FilterEffectRenderer.cpp | 
| index dc57d05096d70b2078582fb64309e7ce90834aad..7ee85c3e1a803608c4a579096b2db2bd1d4bb468 100644 | 
| --- a/Source/core/rendering/FilterEffectRenderer.cpp | 
| +++ b/Source/core/rendering/FilterEffectRenderer.cpp | 
| @@ -28,8 +28,6 @@ | 
|  | 
| #include "core/rendering/FilterEffectRenderer.h" | 
|  | 
| -#include "SVGNames.h" | 
| -#include "core/css/CSSPrimitiveValueMappings.h" | 
| #include "core/dom/Document.h" | 
| #include "core/loader/cache/CachedDocument.h" | 
| #include "core/loader/cache/CachedSVGDocumentReference.h" | 
| @@ -39,13 +37,14 @@ | 
| #include "core/platform/graphics/filters/FEComponentTransfer.h" | 
| #include "core/platform/graphics/filters/FEDropShadow.h" | 
| #include "core/platform/graphics/filters/FEGaussianBlur.h" | 
| -#include "core/platform/graphics/filters/SourceAlpha.h" | 
| #include "core/platform/graphics/filters/custom/CustomFilterGlobalContext.h" | 
| #include "core/platform/graphics/filters/custom/CustomFilterValidatedProgram.h" | 
| #include "core/platform/graphics/filters/custom/FECustomFilter.h" | 
| #include "core/platform/graphics/filters/custom/ValidatedCustomFilterOperation.h" | 
| #include "core/rendering/RenderLayer.h" | 
| #include "core/rendering/RenderView.h" | 
| +#include "core/rendering/svg/ReferenceFilterBuilder.h" | 
| + | 
| #include "core/svg/SVGElement.h" | 
| #include "core/svg/SVGFilterPrimitiveStandardAttributes.h" | 
| #include "wtf/MathExtras.h" | 
| @@ -90,46 +89,6 @@ static PassRefPtr<FECustomFilter> createCustomFilterEffect(Filter* filter, Docum | 
| operation->meshRows(), operation->meshColumns(),  operation->meshType()); | 
| } | 
|  | 
| -// Returns whether or not the SVGStyledElement object contains a valid color-interpolation-filters attribute | 
| -static bool getSVGStyledElementColorSpace(SVGStyledElement* svgStyledElement, ColorSpace& cs) | 
| -{ | 
| -    if (!svgStyledElement) | 
| -        return false; | 
| - | 
| -    const RenderObject* renderer = svgStyledElement->renderer(); | 
| -    const RenderStyle* style = renderer ? renderer->style() : 0; | 
| -    const SVGRenderStyle* svgStyle = style ? style->svgStyle() : 0; | 
| -    EColorInterpolation eColorInterpolation = CI_AUTO; | 
| -    if (svgStyle) { | 
| -        // If a layout has been performed, then we can use the fast path to get this attribute | 
| -        eColorInterpolation = svgStyle->colorInterpolationFilters(); | 
| -    } else { | 
| -        // Otherwise, use the slow path by using string comparison (used by external svg files) | 
| -        RefPtr<CSSValue> cssValue = svgStyledElement->getPresentationAttribute( | 
| -            SVGNames::color_interpolation_filtersAttr.toString()); | 
| -        if (cssValue.get() && cssValue->isPrimitiveValue()) { | 
| -            const CSSPrimitiveValue& primitiveValue = *((CSSPrimitiveValue*)cssValue.get()); | 
| -            eColorInterpolation = (EColorInterpolation)primitiveValue; | 
| -        } else { | 
| -            return false; | 
| -        } | 
| -    } | 
| - | 
| -    switch (eColorInterpolation) { | 
| -    case CI_AUTO: | 
| -    case CI_SRGB: | 
| -        cs = ColorSpaceDeviceRGB; | 
| -        break; | 
| -    case CI_LINEARRGB: | 
| -        cs = ColorSpaceLinearRGB; | 
| -        break; | 
| -    default: | 
| -        return false; | 
| -    } | 
| - | 
| -    return true; | 
| -} | 
| - | 
| FilterEffectRenderer::FilterEffectRenderer() | 
| : Filter(AffineTransform()) | 
| , m_graphicsBufferAttached(false) | 
| @@ -149,95 +108,11 @@ GraphicsContext* FilterEffectRenderer::inputContext() | 
| return sourceImage() ? sourceImage()->context() : 0; | 
| } | 
|  | 
| -PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderObject* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation) | 
| -{ | 
| -    if (!renderer) | 
| -        return 0; | 
| - | 
| -    Document* document = renderer->document(); | 
| -    ASSERT(document); | 
| - | 
| -    CachedSVGDocumentReference* cachedSVGDocumentReference = filterOperation->cachedSVGDocumentReference(); | 
| -    CachedDocument* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : 0; | 
| - | 
| -    // If we have an SVG document, this is an external reference. Otherwise | 
| -    // we look up the referenced node in the current document. | 
| -    if (cachedSVGDocument) | 
| -        document = cachedSVGDocument->document(); | 
| - | 
| -    if (!document) | 
| -        return 0; | 
| - | 
| -    Element* filter = document->getElementById(filterOperation->fragment()); | 
| -    if (!filter) { | 
| -        // Although we did not find the referenced filter, it might exist later | 
| -        // in the document | 
| -        document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), toElement(renderer->node())); | 
| -        return 0; | 
| -    } | 
| - | 
| -    if (!filter->isSVGElement() || !filter->hasTagName(SVGNames::filterTag)) | 
| -        return 0; | 
| - | 
| -    SVGFilterElement* filterElement = toSVGFilterElement(toSVGElement(filter)); | 
| - | 
| -    RefPtr<FilterEffect> effect; | 
| - | 
| -    // FIXME: Figure out what to do with SourceAlpha. Right now, we're | 
| -    // using the alpha of the original input layer, which is obviously | 
| -    // wrong. We should probably be extracting the alpha from the | 
| -    // previousEffect, but this requires some more processing. | 
| -    // This may need a spec clarification. | 
| -    RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(this)); | 
| - | 
| -    ColorSpace filterColorSpace = ColorSpaceDeviceRGB; | 
| -    const bool useFilterColorSpace = getSVGStyledElementColorSpace(filterElement, filterColorSpace); | 
| - | 
| -    for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { | 
| -        if (!node->isSVGElement()) | 
| -            continue; | 
| - | 
| -        SVGElement* element = toSVGElement(node); | 
| -        if (!element->isFilterEffect()) | 
| -            continue; | 
| - | 
| -        SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); | 
| - | 
| -        effect = effectElement->build(builder.get(), this); | 
| -        if (!effect) | 
| -            continue; | 
| - | 
| -        effectElement->setStandardAttributes(effect.get()); | 
| -        effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits(), sourceImageRect())); | 
| - | 
| -        ColorSpace colorSpace = filterColorSpace; | 
| -        if (useFilterColorSpace || getSVGStyledElementColorSpace(effectElement, colorSpace)) | 
| -            effect->setOperatingColorSpace(colorSpace); | 
| -        builder->add(effectElement->result(), effect); | 
| -        m_effects.append(effect); | 
| -    } | 
| -    return effect; | 
| -} | 
| - | 
| bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations) | 
| { | 
| m_hasCustomShaderFilter = false; | 
| m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); | 
|  | 
| -    // Keep the old effects on the stack until we've created the new effects. | 
| -    // New FECustomFilters can reuse cached resources from old FECustomFilters. | 
| -    FilterEffectList oldEffects; | 
| -    m_effects.swap(oldEffects); | 
| - | 
| -    // Inverse zoom the pre-zoomed CSS shorthand filters, so that they are in the zoom as the unzoomed reference filters | 
| -    const RenderStyle* style = renderer->style(); | 
| -    float zoom = style ? style->effectiveZoom() : 1.0f; | 
| -    float invZoom = 1.0f / zoom; | 
| -    // Apply zoom to filter region here so that applyHorizontalScale/applyVerticalScale will | 
| -    // work while create hardware filters through FE<some filter effect>::createImageFilter() | 
| -    setFilterRegion(FloatRect(0, 0, 1, 1)); | 
| -    setAbsoluteFilterRegion(FloatRect(0, 0, zoom, zoom)); | 
| - | 
| RefPtr<FilterEffect> previousEffect = m_sourceGraphic; | 
| for (size_t i = 0; i < operations.operations().size(); ++i) { | 
| RefPtr<FilterEffect> effect; | 
| @@ -245,8 +120,7 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| switch (filterOperation->getOperationType()) { | 
| case FilterOperation::REFERENCE: { | 
| ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation); | 
| -            effect = buildReferenceFilter(renderer, previousEffect, referenceOperation); | 
| -            referenceOperation->setFilterEffect(effect, this); | 
| +            effect = ReferenceFilterBuilder::build(this, renderer, previousEffect.get(), referenceOperation); | 
| break; | 
| } | 
| case FilterOperation::GRAYSCALE: { | 
| @@ -370,15 +244,15 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| } | 
| case FilterOperation::BLUR: { | 
| BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation); | 
| -            float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0) * invZoom; | 
| +            float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); | 
| effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation); | 
| break; | 
| } | 
| case FilterOperation::DROP_SHADOW: { | 
| DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation); | 
| -            float stdDeviation = dropShadowOperation->stdDeviation() * invZoom; | 
| -            float x = dropShadowOperation->x() * invZoom; | 
| -            float y = dropShadowOperation->y() * invZoom; | 
| +            float stdDeviation = dropShadowOperation->stdDeviation(); | 
| +            float x = dropShadowOperation->x(); | 
| +            float y = dropShadowOperation->y(); | 
| effect = FEDropShadow::create(this, stdDeviation, stdDeviation, x, y, dropShadowOperation->color(), 1); | 
| break; | 
| } | 
| @@ -405,14 +279,17 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| effect->setClipsToBounds(false); | 
| effect->setOperatingColorSpace(ColorSpaceDeviceRGB); | 
| effect->inputEffects().append(previousEffect); | 
| -                m_effects.append(effect); | 
| } | 
| previousEffect = effect.release(); | 
| } | 
| } | 
|  | 
| +    // We need to keep the old effects alive until this point, so that filters like FECustomFilter | 
| +    // can share cached resources across frames. | 
| +    m_lastEffect = previousEffect; | 
| + | 
| // If we didn't make any effects, tell our caller we are not valid | 
| -    if (!m_effects.size()) | 
| +    if (!m_lastEffect.get()) | 
| return false; | 
|  | 
| return true; | 
| @@ -445,9 +322,8 @@ void FilterEffectRenderer::allocateBackingStoreIfNeeded() | 
|  | 
| void FilterEffectRenderer::clearIntermediateResults() | 
| { | 
| -    m_sourceGraphic->clearResult(); | 
| -    for (size_t i = 0; i < m_effects.size(); ++i) | 
| -        m_effects[i]->clearResult(); | 
| +    if (m_lastEffect.get()) | 
| +        m_lastEffect->clearResultsRecursive(); | 
| } | 
|  | 
| void FilterEffectRenderer::apply() | 
|  |