Commit d24c3eae authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Refactor <filter> invalidation to use the DOM structure

This changes the path used for invalidation of filter effects (SVGFE*)
from the layout tree to the DOM tree. This is done to allow invalidation
to work when the filter is not part of the layout tree. That change
will be done in a follow-up.

Also add casting helpers for SVGFilterPrimitiveStandardAttributes and
use it where applicable.

Bug: 773811
Change-Id: I275534e59eb285c0cab805f6c09d00b1f725e4f4
Reviewed-on: https://chromium-review.googlesource.com/719837Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Philip Rogers <pdr@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#509478}
parent 08beed78
......@@ -9,7 +9,7 @@
{
"object": "LayoutSVGRect rect",
"rect": [0, 0, 110, 110],
"reason": "style change"
"reason": "full"
}
]
}
......@@ -17,7 +17,7 @@
"objectPaintInvalidations": [
{
"object": "LayoutSVGRect rect",
"reason": "style change"
"reason": "full"
}
]
}
......
......@@ -14,7 +14,7 @@
{
"object": "LayoutSVGRect rect",
"rect": [0, 0, 110, 110],
"reason": "style change"
"reason": "full"
}
]
}
......@@ -30,7 +30,7 @@
},
{
"object": "LayoutSVGRect rect",
"reason": "style change"
"reason": "full"
}
]
}
......
......@@ -119,10 +119,9 @@ SVGUnitTypes::SVGUnitType LayoutSVGResourceFilter::PrimitiveUnits() const {
}
void LayoutSVGResourceFilter::PrimitiveAttributeChanged(
LayoutObject* object,
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) {
SVGFilterPrimitiveStandardAttributes* primitive =
static_cast<SVGFilterPrimitiveStandardAttributes*>(object->GetNode());
LayoutObject* object = primitive.GetLayoutObject();
for (auto& filter : filter_) {
FilterData* filter_data = filter.value.Get();
......@@ -135,7 +134,7 @@ void LayoutSVGResourceFilter::PrimitiveAttributeChanged(
continue;
// Since all effects shares the same attribute value, all
// or none of them will be changed.
if (!primitive->SetFilterEffectAttribute(effect, attribute))
if (!primitive.SetFilterEffectAttribute(effect, attribute))
return;
node_map->InvalidateDependentEffects(effect);
......
......@@ -32,6 +32,7 @@ namespace blink {
class FilterEffect;
class SVGFilterElement;
class SVGFilterGraphNodeMap;
class SVGFilterPrimitiveStandardAttributes;
class FilterData final : public GarbageCollected<FilterData> {
public:
......@@ -87,7 +88,8 @@ class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
SVGUnitTypes::SVGUnitType FilterUnits() const;
SVGUnitTypes::SVGUnitType PrimitiveUnits() const;
void PrimitiveAttributeChanged(LayoutObject*, const QualifiedName&);
void PrimitiveAttributeChanged(SVGFilterPrimitiveStandardAttributes&,
const QualifiedName&);
static const LayoutSVGResourceType kResourceType = kFilterResourceType;
LayoutSVGResourceType ResourceType() const override { return kResourceType; }
......
......@@ -27,6 +27,8 @@
#include "core/layout/svg/LayoutSVGResourceFilterPrimitive.h"
#include "core/svg/SVGFilterPrimitiveStandardAttributes.h"
namespace blink {
void LayoutSVGResourceFilterPrimitive::StyleDidChange(
......@@ -34,32 +36,27 @@ void LayoutSVGResourceFilterPrimitive::StyleDidChange(
const ComputedStyle* old_style) {
LayoutSVGHiddenContainer::StyleDidChange(diff, old_style);
LayoutObject* filter = Parent();
if (!filter)
return;
DCHECK(filter->IsSVGResourceFilter());
if (!old_style)
return;
const SVGComputedStyle& new_style = this->StyleRef().SvgStyle();
DCHECK(GetElement());
if (IsSVGFEFloodElement(*GetElement()) ||
IsSVGFEDropShadowElement(*GetElement())) {
SVGFilterPrimitiveStandardAttributes& element =
ToSVGFilterPrimitiveStandardAttributes(*GetElement());
const SVGComputedStyle& new_style = this->StyleRef().SvgStyle();
if (IsSVGFEFloodElement(element) || IsSVGFEDropShadowElement(element)) {
if (new_style.FloodColor() != old_style->SvgStyle().FloodColor())
ToLayoutSVGResourceFilter(filter)->PrimitiveAttributeChanged(
this, SVGNames::flood_colorAttr);
element.PrimitiveAttributeChanged(SVGNames::flood_colorAttr);
if (new_style.FloodOpacity() != old_style->SvgStyle().FloodOpacity())
ToLayoutSVGResourceFilter(filter)->PrimitiveAttributeChanged(
this, SVGNames::flood_opacityAttr);
} else if (IsSVGFEDiffuseLightingElement(*GetElement()) ||
IsSVGFESpecularLightingElement(*GetElement())) {
element.PrimitiveAttributeChanged(SVGNames::flood_opacityAttr);
} else if (IsSVGFEDiffuseLightingElement(element) ||
IsSVGFESpecularLightingElement(element)) {
if (new_style.LightingColor() != old_style->SvgStyle().LightingColor())
ToLayoutSVGResourceFilter(filter)->PrimitiveAttributeChanged(
this, SVGNames::lighting_colorAttr);
element.PrimitiveAttributeChanged(SVGNames::lighting_colorAttr);
}
if (new_style.ColorInterpolationFilters() !=
old_style->SvgStyle().ColorInterpolationFilters())
ToLayoutSVGResourceFilter(filter)->PrimitiveAttributeChanged(
this, SVGNames::color_interpolation_filtersAttr);
old_style->SvgStyle().ColorInterpolationFilters()) {
element.PrimitiveAttributeChanged(
SVGNames::color_interpolation_filtersAttr);
}
}
} // namespace blink
......@@ -27,7 +27,7 @@
#ifndef LayoutSVGResourceFilterPrimitive_h
#define LayoutSVGResourceFilterPrimitive_h
#include "core/layout/svg/LayoutSVGResourceFilter.h"
#include "core/layout/svg/LayoutSVGHiddenContainer.h"
namespace blink {
......@@ -50,14 +50,6 @@ class LayoutSVGResourceFilterPrimitive final : public LayoutSVGHiddenContainer {
return type == kLayoutObjectSVGResourceFilterPrimitive ||
LayoutSVGHiddenContainer::IsOfType(type);
}
inline void PrimitiveAttributeChanged(const QualifiedName& attribute) {
LayoutObject* filter = Parent();
if (!filter || !filter->IsSVGResourceFilter())
return;
ToLayoutSVGResourceFilter(filter)->PrimitiveAttributeChanged(this,
attribute);
}
};
} // namespace blink
......
......@@ -99,8 +99,7 @@ void SVGComponentTransferFunctionElement::SvgAttributeChanged(
attr_name == SVGNames::exponentAttr ||
attr_name == SVGNames::offsetAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
InvalidateFilterPrimitiveParent(this);
InvalidateFilterPrimitiveParent(*this);
return;
}
......
......@@ -41,7 +41,7 @@ void SVGFEMergeNodeElement::SvgAttributeChanged(
const QualifiedName& attr_name) {
if (attr_name == SVGNames::inAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
InvalidateFilterPrimitiveParent(this);
InvalidateFilterPrimitiveParent(*this);
return;
}
......
......@@ -96,17 +96,27 @@ void SVGFilterElement::SvgAttributeChanged(const QualifiedName& attr_name) {
if (is_xywh || attr_name == SVGNames::filterUnitsAttr ||
attr_name == SVGNames::primitiveUnitsAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
LayoutSVGResourceContainer* layout_object =
ToLayoutSVGResourceContainer(this->GetLayoutObject());
if (layout_object)
layout_object->InvalidateCacheAndMarkForLayout();
InvalidateFilterChain();
return;
}
SVGElement::SvgAttributeChanged(attr_name);
}
void SVGFilterElement::PrimitiveAttributeChanged(
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) {
if (LayoutObject* layout_object = GetLayoutObject()) {
ToLayoutSVGResourceFilter(layout_object)
->PrimitiveAttributeChanged(primitive, attribute);
}
}
void SVGFilterElement::InvalidateFilterChain() {
if (LayoutObject* layout_object = GetLayoutObject())
ToLayoutSVGResourceFilter(layout_object)->RemoveAllClientsFromCache();
}
void SVGFilterElement::ChildrenChanged(const ChildrenChange& change) {
SVGElement::ChildrenChanged(change);
......
......@@ -33,6 +33,8 @@
namespace blink {
class SVGFilterPrimitiveStandardAttributes;
class CORE_EXPORT SVGFilterElement final : public SVGElement,
public SVGURIReference {
DEFINE_WRAPPERTYPEINFO();
......@@ -55,6 +57,13 @@ class CORE_EXPORT SVGFilterElement final : public SVGElement,
return primitive_units_.Get();
}
// Fine-grained invalidation of a specific property on a specific primitive.
void PrimitiveAttributeChanged(SVGFilterPrimitiveStandardAttributes&,
const QualifiedName&);
// Invalidate the entire filter chain.
void InvalidateFilterChain();
private:
explicit SVGFilterElement(Document&);
......
......@@ -21,8 +21,8 @@
#include "core/svg/SVGFilterPrimitiveStandardAttributes.h"
#include "core/layout/svg/LayoutSVGResourceContainer.h"
#include "core/layout/svg/LayoutSVGResourceFilterPrimitive.h"
#include "core/svg/SVGFilterElement.h"
#include "core/svg/SVGLength.h"
#include "core/svg/graphics/filters/SVGFilterBuilder.h"
#include "core/svg_names.h"
......@@ -175,32 +175,24 @@ bool SVGFilterPrimitiveStandardAttributes::LayoutObjectIsNeeded(
}
void SVGFilterPrimitiveStandardAttributes::Invalidate() {
if (LayoutObject* primitive_layout_object = GetLayoutObject())
MarkForLayoutAndParentResourceInvalidation(primitive_layout_object);
if (SVGFilterElement* filter = ToSVGFilterElementOrNull(parentElement()))
filter->InvalidateFilterChain();
}
void SVGFilterPrimitiveStandardAttributes::PrimitiveAttributeChanged(
const QualifiedName& attribute) {
if (LayoutObject* primitive_layout_object = GetLayoutObject())
static_cast<LayoutSVGResourceFilterPrimitive*>(primitive_layout_object)
->PrimitiveAttributeChanged(attribute);
if (SVGFilterElement* filter = ToSVGFilterElementOrNull(parentElement()))
filter->PrimitiveAttributeChanged(*this, attribute);
}
void InvalidateFilterPrimitiveParent(SVGElement* element) {
if (!element)
void InvalidateFilterPrimitiveParent(SVGElement& element) {
Element* parent = element.parentElement();
if (!parent || !parent->IsSVGElement())
return;
ContainerNode* parent = element->parentNode();
if (!parent)
SVGElement& svgparent = ToSVGElement(*parent);
if (!IsSVGFilterPrimitiveStandardAttributes(svgparent))
return;
LayoutObject* layout_object = parent->GetLayoutObject();
if (!layout_object || !layout_object->IsSVGResourceFilterPrimitive())
return;
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
layout_object, false);
ToSVGFilterPrimitiveStandardAttributes(svgparent).Invalidate();
}
} // namespace blink
......@@ -57,15 +57,15 @@ class SVGFilterPrimitiveStandardAttributes : public SVGElement {
DECLARE_VIRTUAL_TRACE();
void PrimitiveAttributeChanged(const QualifiedName&);
void Invalidate();
protected:
SVGFilterPrimitiveStandardAttributes(const QualifiedName&, Document&);
void SvgAttributeChanged(const QualifiedName&) override;
void ChildrenChanged(const ChildrenChange&) override;
void Invalidate();
void PrimitiveAttributeChanged(const QualifiedName&);
private:
bool IsFilterEffect() const final { return true; }
......@@ -79,7 +79,14 @@ class SVGFilterPrimitiveStandardAttributes : public SVGElement {
Member<SVGAnimatedString> result_;
};
void InvalidateFilterPrimitiveParent(SVGElement*);
void InvalidateFilterPrimitiveParent(SVGElement&);
inline bool IsSVGFilterPrimitiveStandardAttributes(const SVGElement& element) {
return element.IsFilterEffect();
}
DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(
SVGFilterPrimitiveStandardAttributes);
} // namespace blink
......
......@@ -177,26 +177,25 @@ void SVGFilterBuilder::BuildGraph(Filter* filter,
if (!element->IsFilterEffect())
continue;
SVGFilterPrimitiveStandardAttributes* effect_element =
static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
FilterEffect* effect = effect_element->Build(this, filter);
SVGFilterPrimitiveStandardAttributes& effect_element =
ToSVGFilterPrimitiveStandardAttributes(*element);
FilterEffect* effect = effect_element.Build(this, filter);
if (!effect)
continue;
if (node_map_)
node_map_->AddPrimitive(effect_element->GetLayoutObject(), effect);
node_map_->AddPrimitive(effect_element.GetLayoutObject(), effect);
effect_element->SetStandardAttributes(effect, primitive_units,
reference_box);
effect_element.SetStandardAttributes(effect, primitive_units,
reference_box);
EColorInterpolation color_interpolation = ColorInterpolationForElement(
*effect_element, filter_color_interpolation);
effect_element, filter_color_interpolation);
effect->SetOperatingInterpolationSpace(
ResolveInterpolationSpace(color_interpolation));
if (effect_element->TaintsOrigin(effect->InputsTaintOrigin()))
if (effect_element.TaintsOrigin(effect->InputsTaintOrigin()))
effect->SetOriginTainted();
Add(AtomicString(effect_element->result()->CurrentValue()->Value()),
effect);
Add(AtomicString(effect_element.result()->CurrentValue()->Value()), effect);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment