Index: third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp |
diff --git a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp |
index 9241542c378224c90dbe0c2cd471410271bf0f9e..c00cffa87dc32d3a7ad32dd58c7cfefa6b132328 100644 |
--- a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp |
+++ b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp |
@@ -27,6 +27,10 @@ |
#include "core/paint/FilterEffectBuilder.h" |
#include "core/layout/svg/ReferenceFilterBuilder.h" |
+#include "core/paint/PaintLayer.h" |
+#include "core/svg/SVGFilterElement.h" |
+#include "core/svg/SVGLengthContext.h" |
+#include "core/svg/graphics/filters/SVGFilterBuilder.h" |
#include "platform/FloatConversion.h" |
#include "platform/LengthFunctions.h" |
#include "platform/graphics/ColorSpace.h" |
@@ -116,6 +120,18 @@ Vector<float> sepiaMatrix(double amount) |
return matrix; |
} |
+FloatRect computeReferenceBox(const Element& element, const FloatSize* zoomedReferenceBoxSize, float zoom) |
+{ |
+ FloatSize size; |
+ if (zoomedReferenceBoxSize) { |
+ size = *zoomedReferenceBoxSize; |
+ } else if (element.inShadowIncludingDocument() && element.layoutObject() && element.layoutObject()->enclosingLayer()) { |
+ size = FloatSize(element.layoutObject()->enclosingLayer()->physicalBoundingBoxIncludingReflectionAndStackingChildren(LayoutPoint()).size()); |
+ } |
+ size.scale(1.0f / zoom); |
+ return FloatRect(FloatPoint(), size); |
+} |
+ |
} // namespace |
FilterEffectBuilder::FilterEffectBuilder() |
@@ -131,7 +147,7 @@ DEFINE_TRACE(FilterEffectBuilder) |
visitor->trace(m_lastEffect); |
} |
-bool FilterEffectBuilder::build(Element* element, const FilterOperations& operations, float zoom, const FloatSize* referenceBoxSize, const SkPaint* fillPaint, const SkPaint* strokePaint) |
+bool FilterEffectBuilder::build(Element* element, const FilterOperations& operations, float zoom, const FloatSize* zoomedReferenceBoxSize, const SkPaint* fillPaint, const SkPaint* strokePaint) |
{ |
// Create a parent filter for shorthand filters. These have already been scaled by the CSS code for page zoom, so scale is 1.0 here. |
Filter* parentFilter = Filter::create(1.0f); |
@@ -141,7 +157,7 @@ bool FilterEffectBuilder::build(Element* element, const FilterOperations& operat |
FilterOperation* filterOperation = operations.operations().at(i).get(); |
switch (filterOperation->type()) { |
case FilterOperation::REFERENCE: { |
- Filter* referenceFilter = ReferenceFilterBuilder::build(zoom, element, previousEffect, toReferenceFilterOperation(*filterOperation), referenceBoxSize, fillPaint, strokePaint); |
+ Filter* referenceFilter = buildReferenceFilter(toReferenceFilterOperation(*filterOperation), zoomedReferenceBoxSize, fillPaint, strokePaint, *element, previousEffect, zoom); |
if (referenceFilter) |
effect = referenceFilter->lastEffect(); |
break; |
@@ -260,5 +276,49 @@ bool FilterEffectBuilder::build(Element* element, const FilterOperations& operat |
return true; |
} |
+Filter* FilterEffectBuilder::buildReferenceFilter( |
+ const ReferenceFilterOperation& referenceOperation, |
+ const FloatSize* zoomedReferenceBoxSize, |
+ const SkPaint* fillPaint, |
+ const SkPaint* strokePaint, |
+ Element& element, |
+ FilterEffect* previousEffect, |
+ float zoom) |
+{ |
+ SVGFilterElement* filterElement = ReferenceFilterBuilder::resolveFilterReference(referenceOperation, element); |
+ if (!filterElement) |
+ return nullptr; |
+ |
+ const FloatRect referenceBox = computeReferenceBox(element, zoomedReferenceBoxSize, zoom); |
+ return buildReferenceFilter(*filterElement, referenceBox, fillPaint, strokePaint, previousEffect, zoom); |
+} |
+ |
+Filter* FilterEffectBuilder::buildReferenceFilter( |
+ SVGFilterElement& filterElement, |
+ const FloatRect& referenceBox, |
+ const SkPaint* fillPaint, |
+ const SkPaint* strokePaint, |
+ FilterEffect* previousEffect, |
+ float zoom, |
+ SVGFilterGraphNodeMap* nodeMap) |
+{ |
+ FloatRect filterRegion = SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement, filterElement.filterUnits()->currentValue()->enumValue(), referenceBox); |
+ // TODO(fs): We rely on the presence of a node map here to opt-in to the |
+ // check for an empty filter region. The reason for this is that we lack a |
+ // viewport to resolve against for HTML content. This is crbug.com/512453. |
+ if (nodeMap && filterRegion.isEmpty()) |
+ return nullptr; |
+ |
+ bool primitiveBoundingBoxMode = filterElement.primitiveUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; |
+ Filter::UnitScaling unitScaling = primitiveBoundingBoxMode ? Filter::BoundingBox : Filter::UserSpace; |
+ Filter* result = Filter::create(referenceBox, filterRegion, zoom, unitScaling); |
+ if (!previousEffect) |
+ previousEffect = result->getSourceGraphic(); |
+ SVGFilterBuilder builder(previousEffect, nodeMap, fillPaint, strokePaint); |
+ builder.buildGraph(result, filterElement, referenceBox); |
+ result->setLastEffect(builder.lastEffect()); |
+ return result; |
+} |
+ |
} // namespace blink |