| Index: Source/core/rendering/FilterEffectRenderer.cpp | 
| diff --git a/Source/core/rendering/FilterEffectRenderer.cpp b/Source/core/rendering/FilterEffectRenderer.cpp | 
| index 6d6ce158d6ef4900745dbe18ee657e6fa76934b6..2c4aef2a57d53e771c4ec89a7eb41e2925ec0daa 100644 | 
| --- a/Source/core/rendering/FilterEffectRenderer.cpp | 
| +++ b/Source/core/rendering/FilterEffectRenderer.cpp | 
| @@ -50,6 +50,7 @@ | 
| #include "core/rendering/RenderView.h" | 
|  | 
| #if ENABLE(SVG) | 
| +#include "SVGNames.h" | 
| #include "core/loader/cache/CachedSVGDocument.h" | 
| #include "core/loader/cache/CachedSVGDocumentReference.h" | 
| #include "core/platform/graphics/filters/SourceAlpha.h" | 
| @@ -143,6 +144,11 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderObject | 
| 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 | 
| @@ -152,7 +158,7 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderObject | 
| // This may need a spec clarification. | 
| RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(this)); | 
|  | 
| -    for (Node* node = filter->firstChild(); node; node = node->nextSibling()) { | 
| +    for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { | 
| if (!node->isSVGElement()) | 
| continue; | 
|  | 
| @@ -167,6 +173,7 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderObject | 
| continue; | 
|  | 
| effectElement->setStandardAttributes(effect.get()); | 
| +        effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits(), sourceImageRect())); | 
| builder->add(effectElement->result(), effect); | 
| m_effects.append(effect); | 
| } | 
| @@ -183,8 +190,6 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| { | 
| m_hasCustomShaderFilter = false; | 
| m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); | 
| -    if (m_hasFilterThatMovesPixels) | 
| -        m_outsets = operations.outsets(); | 
|  | 
| // Keep the old effects on the stack until we've created the new effects. | 
| // New FECustomFilters can reuse cached resources from old FECustomFilters. | 
| @@ -199,7 +204,7 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| case FilterOperation::REFERENCE: { | 
| ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation); | 
| effect = buildReferenceFilter(renderer, previousEffect, referenceOperation); | 
| -            referenceOperation->setFilterEffect(effect); | 
| +            referenceOperation->setFilterEffect(effect, this); | 
| break; | 
| } | 
| case FilterOperation::GRAYSCALE: { | 
| @@ -351,11 +356,11 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| } | 
|  | 
| if (effect) { | 
| -            // Unlike SVG, filters applied here should not clip to their primitive subregions. | 
| -            effect->setClipsToBounds(false); | 
| effect->setOperatingColorSpace(ColorSpaceDeviceRGB); | 
|  | 
| if (filterOperation->getOperationType() != FilterOperation::REFERENCE) { | 
| +                // Unlike SVG, filters applied here should not clip to their primitive subregions. | 
| +                effect->setClipsToBounds(false); | 
| effect->inputEffects().append(previousEffect); | 
| m_effects.append(effect); | 
| } | 
| @@ -367,8 +372,6 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& | 
| if (!m_effects.size()) | 
| return false; | 
|  | 
| -    setMaxEffectRects(m_sourceDrawingRegion); | 
| - | 
| return true; | 
| } | 
|  | 
| @@ -419,15 +422,14 @@ LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const Layout | 
| return filterBoxRect; | 
| } | 
| // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect". | 
| -    LayoutRect rectForRepaint = dirtyRect; | 
| -    if (hasFilterThatMovesPixels()) { | 
| -        // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and | 
| -        // need to find out what is the rectangle that might influence the result inside that dirty rect. | 
| -        rectForRepaint.move(-m_outsets.right(), -m_outsets.bottom()); | 
| -        rectForRepaint.expand(m_outsets.left() + m_outsets.right(), m_outsets.top() + m_outsets.bottom()); | 
| -    } | 
| +    FloatRect rectForRepaint = dirtyRect; | 
| +    rectForRepaint.move(-filterBoxRect.location().x(), -filterBoxRect.location().y()); | 
| +    float inf = std::numeric_limits<float>::infinity(); | 
| +    FloatRect clipRect = FloatRect(FloatPoint(-inf, -inf), FloatSize(inf, inf)); | 
| +    rectForRepaint = lastEffect()->getSourceRect(rectForRepaint, clipRect); | 
| +    rectForRepaint.move(filterBoxRect.location().x(), filterBoxRect.location().y()); | 
| rectForRepaint.intersect(filterBoxRect); | 
| -    return rectForRepaint; | 
| +    return LayoutRect(rectForRepaint); | 
| } | 
|  | 
| bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect) | 
| @@ -438,13 +440,19 @@ bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, c | 
|  | 
| FilterEffectRenderer* filter = renderLayer->filterRenderer(); | 
| LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect); | 
| -    m_paintOffset = filterSourceRect.location(); | 
|  | 
| if (filterSourceRect.isEmpty()) { | 
| // The dirty rect is not in view, just bail out. | 
| m_haveFilterEffect = false; | 
| return false; | 
| } | 
| + | 
| +    AffineTransform absoluteTransform; | 
| +    absoluteTransform.translate(filterBoxRect.x(), filterBoxRect.y()); | 
| +    filter->setAbsoluteTransform(absoluteTransform); | 
| +    filter->setAbsoluteFilterRegion(filterSourceRect); | 
| +    filter->setFilterRegion(absoluteTransform.inverse().mapRect(filterSourceRect)); | 
| +    filter->lastEffect()->determineFilterPrimitiveSubregion(); | 
|  | 
| bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect); | 
| if (filter->hasFilterThatMovesPixels()) { | 
| @@ -466,7 +474,7 @@ GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* | 
| filter->allocateBackingStoreIfNeeded(); | 
| // Paint into the context that represents the SourceGraphic of the filter. | 
| GraphicsContext* sourceGraphicsContext = filter->inputContext(); | 
| -    if (!sourceGraphicsContext || !isFilterSizeValid(filter->filterRegion())) { | 
| +    if (!sourceGraphicsContext || !isFilterSizeValid(filter->absoluteFilterRegion())) { | 
| // Disable the filters and continue. | 
| m_haveFilterEffect = false; | 
| return oldContext; | 
| @@ -476,7 +484,10 @@ GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* | 
|  | 
| // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer. | 
| sourceGraphicsContext->save(); | 
| -    sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y()); | 
| +    // FIXME: can we just use sourceImageRect for everything, and get rid of | 
| +    // m_repaintRect? | 
| +    FloatPoint offset = filter->sourceImageRect().location(); | 
| +    sourceGraphicsContext->translate(-offset.x(), -offset.y()); | 
| sourceGraphicsContext->clearRect(m_repaintRect); | 
| sourceGraphicsContext->clip(m_repaintRect); | 
|  | 
| @@ -492,10 +503,7 @@ GraphicsContext* FilterEffectRendererHelper::applyFilterEffect() | 
| filter->apply(); | 
|  | 
| // Get the filtered output and draw it in place. | 
| -    LayoutRect destRect = filter->outputRect(); | 
| -    destRect.move(m_paintOffset.x(), m_paintOffset.y()); | 
| - | 
| -    m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver); | 
| +    m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), filter->outputRect(), CompositeSourceOver); | 
|  | 
| filter->clearIntermediateResults(); | 
|  | 
|  |