summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc707
1 files changed, 142 insertions, 565 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
index 988c1c9b70c..31f880fb4ad 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -19,41 +19,25 @@
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include <memory>
-#include <utility>
-
+#include "base/ranges/algorithm.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h"
#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
#include "third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h"
-#include "third_party/blink/renderer/core/svg/svg_pattern_element.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
-#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
-#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
-#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter_effect.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/graphics/filters/source_graphic.h"
-#if DCHECK_IS_ON()
-#include <stdio.h>
-#endif
-
namespace blink {
-SVGResources::SVGResources() : linked_resource_(nullptr) {}
-
SVGElementResourceClient* SVGResources::GetClient(const LayoutObject& object) {
return To<SVGElement>(object.GetNode())->GetSVGResourceClient();
}
@@ -79,451 +63,6 @@ FloatRect SVGResources::ReferenceBoxForEffects(
return obb_layout_object->ObjectBoundingBox();
}
-static HashSet<AtomicString>& ClipperFilterMaskerTags() {
- DEFINE_STATIC_LOCAL(
- HashSet<AtomicString>, tag_list,
- ({
- // "container elements":
- // http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
- // "graphics elements" :
- // http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
- svg_names::kATag.LocalName(), svg_names::kCircleTag.LocalName(),
- svg_names::kEllipseTag.LocalName(), svg_names::kGTag.LocalName(),
- svg_names::kImageTag.LocalName(), svg_names::kLineTag.LocalName(),
- svg_names::kMarkerTag.LocalName(), svg_names::kMaskTag.LocalName(),
- svg_names::kPathTag.LocalName(), svg_names::kPolygonTag.LocalName(),
- svg_names::kPolylineTag.LocalName(), svg_names::kRectTag.LocalName(),
- svg_names::kSVGTag.LocalName(), svg_names::kTextTag.LocalName(),
- svg_names::kUseTag.LocalName(),
- // Not listed in the definitions is the clipPath element, the SVG spec
- // says though:
- // The "clipPath" element or any of its children can specify property
- // "clip-path".
- // So we have to add kClipPathTag here, otherwhise clip-path on
- // clipPath will fail. (Already mailed SVG WG, waiting for a solution)
- svg_names::kClipPathTag.LocalName(),
- // Not listed in the definitions are the text content elements, though
- // filter/clipper/masker on tspan/text/.. is allowed.
- // (Already mailed SVG WG, waiting for a solution)
- svg_names::kTextPathTag.LocalName(), svg_names::kTSpanTag.LocalName(),
- // Not listed in the definitions is the foreignObject element, but
- // clip-path is a supported attribute.
- svg_names::kForeignObjectTag.LocalName(),
- // Elements that we ignore, as it doesn't make any sense.
- // defs, pattern, switch (FIXME: Mail SVG WG about these)
- // symbol (is converted to a svg element, when referenced by use, we
- // can safely ignore it.)
- }));
- return tag_list;
-}
-
-bool SVGResources::SupportsMarkers(const SVGElement& element) {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list,
- ({
- svg_names::kLineTag.LocalName(),
- svg_names::kPathTag.LocalName(),
- svg_names::kPolygonTag.LocalName(),
- svg_names::kPolylineTag.LocalName(),
- }));
- return tag_list.Contains(element.localName());
-}
-
-static HashSet<AtomicString>& FillAndStrokeTags() {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list,
- ({
- svg_names::kCircleTag.LocalName(),
- svg_names::kEllipseTag.LocalName(),
- svg_names::kLineTag.LocalName(),
- svg_names::kPathTag.LocalName(),
- svg_names::kPolygonTag.LocalName(),
- svg_names::kPolylineTag.LocalName(),
- svg_names::kRectTag.LocalName(),
- svg_names::kTextTag.LocalName(),
- svg_names::kTextPathTag.LocalName(),
- svg_names::kTSpanTag.LocalName(),
- }));
- return tag_list;
-}
-
-bool SVGResources::HasResourceData() const {
- return clipper_filter_masker_data_ || marker_data_ || fill_stroke_data_ ||
- linked_resource_;
-}
-
-static inline SVGResources& EnsureResources(
- std::unique_ptr<SVGResources>& resources) {
- if (!resources)
- resources = std::make_unique<SVGResources>();
-
- return *resources.get();
-}
-
-std::unique_ptr<SVGResources> SVGResources::BuildResources(
- const LayoutObject& object,
- const ComputedStyle& computed_style) {
- Node* node = object.GetNode();
- DCHECK(node);
- SECURITY_DCHECK(node->IsSVGElement());
-
- auto& element = To<SVGElement>(*node);
-
- const AtomicString& tag_name = element.localName();
- DCHECK(!tag_name.IsNull());
-
- const SVGComputedStyle& style = computed_style.SvgStyle();
-
- std::unique_ptr<SVGResources> resources;
- if (ClipperFilterMaskerTags().Contains(tag_name)) {
- if (computed_style.ClipPath() && !object.IsSVGRoot()) {
- if (LayoutSVGResourceClipper* clipper =
- GetSVGResourceAsType(computed_style.ClipPath())) {
- EnsureResources(resources).SetClipper(clipper);
- }
- }
-
- if (computed_style.HasFilter() && !object.IsSVGRoot()) {
- if (LayoutSVGResourceFilter* filter =
- GetFilterResourceForSVG(computed_style)) {
- EnsureResources(resources).SetFilter(filter);
- }
- }
-
- if (auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
- style.MaskerResource())) {
- EnsureResources(resources).SetMasker(masker);
- }
- }
-
- if (style.HasMarkers() && SupportsMarkers(element)) {
- if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
- style.MarkerStartResource())) {
- EnsureResources(resources).SetMarkerStart(marker);
- }
- if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
- style.MarkerMidResource())) {
- EnsureResources(resources).SetMarkerMid(marker);
- }
- if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
- style.MarkerEndResource())) {
- EnsureResources(resources).SetMarkerEnd(marker);
- }
- }
-
- if (FillAndStrokeTags().Contains(tag_name)) {
- if (auto* paint_resource =
- GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
- style.FillPaint().Resource())) {
- EnsureResources(resources).SetFill(paint_resource);
- }
-
- if (auto* paint_resource =
- GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
- style.StrokePaint().Resource())) {
- EnsureResources(resources).SetStroke(paint_resource);
- }
- }
-
- if (auto* pattern = DynamicTo<SVGPatternElement>(element)) {
- const SVGPatternElement* directly_referenced_pattern =
- pattern->ReferencedElement();
- if (directly_referenced_pattern) {
- EnsureResources(resources).SetLinkedResource(
- DynamicTo<LayoutSVGResourceContainer>(
- directly_referenced_pattern->GetLayoutObject()));
- }
- }
-
- return (!resources || !resources->HasResourceData()) ? nullptr
- : std::move(resources);
-}
-
-void SVGResources::ResourceDestroyed(LayoutSVGResourceContainer* resource) {
- DCHECK(resource);
- if (!HasResourceData())
- return;
-
- if (linked_resource_ == resource) {
- DCHECK(!clipper_filter_masker_data_);
- DCHECK(!marker_data_);
- DCHECK(!fill_stroke_data_);
- linked_resource_->RemoveAllClientsFromCache();
- linked_resource_ = nullptr;
- return;
- }
-
- switch (resource->ResourceType()) {
- case kMaskerResourceType:
- if (!clipper_filter_masker_data_)
- break;
- if (clipper_filter_masker_data_->masker == resource)
- clipper_filter_masker_data_->masker = nullptr;
- break;
- case kMarkerResourceType:
- if (!marker_data_)
- break;
- if (marker_data_->marker_start == resource)
- marker_data_->marker_start = nullptr;
- if (marker_data_->marker_mid == resource)
- marker_data_->marker_mid = nullptr;
- if (marker_data_->marker_end == resource)
- marker_data_->marker_end = nullptr;
- break;
- case kPatternResourceType:
- case kLinearGradientResourceType:
- case kRadialGradientResourceType:
- if (!fill_stroke_data_)
- break;
- if (fill_stroke_data_->fill == resource)
- fill_stroke_data_->fill = nullptr;
- if (fill_stroke_data_->stroke == resource)
- fill_stroke_data_->stroke = nullptr;
- break;
- case kFilterResourceType:
- if (!clipper_filter_masker_data_)
- break;
- if (clipper_filter_masker_data_->filter == resource)
- clipper_filter_masker_data_->filter = nullptr;
- break;
- case kClipperResourceType:
- if (!clipper_filter_masker_data_)
- break;
- if (clipper_filter_masker_data_->clipper == resource)
- clipper_filter_masker_data_->clipper = nullptr;
- break;
- default:
- NOTREACHED();
- }
-}
-
-void SVGResources::ClearReferencesTo(LayoutSVGResourceContainer* resource) {
- DCHECK(resource);
- if (linked_resource_ == resource) {
- DCHECK(!clipper_filter_masker_data_);
- DCHECK(!marker_data_);
- DCHECK(!fill_stroke_data_);
- linked_resource_ = nullptr;
- return;
- }
-
- switch (resource->ResourceType()) {
- case kMaskerResourceType:
- DCHECK(clipper_filter_masker_data_);
- DCHECK_EQ(clipper_filter_masker_data_->masker, resource);
- clipper_filter_masker_data_->masker = nullptr;
- break;
- case kMarkerResourceType:
- DCHECK(marker_data_);
- DCHECK(resource == MarkerStart() || resource == MarkerMid() ||
- resource == MarkerEnd());
- if (marker_data_->marker_start == resource)
- marker_data_->marker_start = nullptr;
- if (marker_data_->marker_mid == resource)
- marker_data_->marker_mid = nullptr;
- if (marker_data_->marker_end == resource)
- marker_data_->marker_end = nullptr;
- break;
- case kPatternResourceType:
- case kLinearGradientResourceType:
- case kRadialGradientResourceType:
- DCHECK(fill_stroke_data_);
- DCHECK(resource == Fill() || resource == Stroke());
- if (fill_stroke_data_->fill == resource)
- fill_stroke_data_->fill = nullptr;
- if (fill_stroke_data_->stroke == resource)
- fill_stroke_data_->stroke = nullptr;
- break;
- case kFilterResourceType:
- DCHECK(clipper_filter_masker_data_);
- DCHECK_EQ(clipper_filter_masker_data_->filter, resource);
- clipper_filter_masker_data_->filter = nullptr;
- break;
- case kClipperResourceType:
- DCHECK(clipper_filter_masker_data_);
- DCHECK_EQ(clipper_filter_masker_data_->clipper, resource);
- clipper_filter_masker_data_->clipper = nullptr;
- break;
- default:
- NOTREACHED();
- }
-}
-
-void SVGResources::BuildSetOfResources(
- HashSet<LayoutSVGResourceContainer*>& set) {
- if (!HasResourceData())
- return;
-
- if (linked_resource_) {
- DCHECK(!clipper_filter_masker_data_);
- DCHECK(!marker_data_);
- DCHECK(!fill_stroke_data_);
- set.insert(linked_resource_);
- return;
- }
-
- if (clipper_filter_masker_data_) {
- if (clipper_filter_masker_data_->clipper)
- set.insert(clipper_filter_masker_data_->clipper);
- if (clipper_filter_masker_data_->filter)
- set.insert(clipper_filter_masker_data_->filter);
- if (clipper_filter_masker_data_->masker)
- set.insert(clipper_filter_masker_data_->masker);
- }
-
- if (marker_data_) {
- if (marker_data_->marker_start)
- set.insert(marker_data_->marker_start);
- if (marker_data_->marker_mid)
- set.insert(marker_data_->marker_mid);
- if (marker_data_->marker_end)
- set.insert(marker_data_->marker_end);
- }
-
- if (fill_stroke_data_) {
- if (fill_stroke_data_->fill)
- set.insert(fill_stroke_data_->fill);
- if (fill_stroke_data_->stroke)
- set.insert(fill_stroke_data_->stroke);
- }
-}
-
-void SVGResources::SetClipper(LayoutSVGResourceClipper* clipper) {
- DCHECK(clipper);
- DCHECK_EQ(clipper->ResourceType(), kClipperResourceType);
-
- if (!clipper_filter_masker_data_)
- clipper_filter_masker_data_ = std::make_unique<ClipperFilterMaskerData>();
-
- clipper_filter_masker_data_->clipper = clipper;
-}
-
-void SVGResources::SetFilter(LayoutSVGResourceFilter* filter) {
- DCHECK(filter);
- DCHECK_EQ(filter->ResourceType(), kFilterResourceType);
-
- if (!clipper_filter_masker_data_)
- clipper_filter_masker_data_ = std::make_unique<ClipperFilterMaskerData>();
-
- clipper_filter_masker_data_->filter = filter;
-}
-
-void SVGResources::SetMarkerStart(LayoutSVGResourceMarker* marker_start) {
- DCHECK(marker_start);
- DCHECK_EQ(marker_start->ResourceType(), kMarkerResourceType);
-
- if (!marker_data_)
- marker_data_ = std::make_unique<MarkerData>();
-
- marker_data_->marker_start = marker_start;
-}
-
-void SVGResources::SetMarkerMid(LayoutSVGResourceMarker* marker_mid) {
- DCHECK(marker_mid);
- DCHECK_EQ(marker_mid->ResourceType(), kMarkerResourceType);
-
- if (!marker_data_)
- marker_data_ = std::make_unique<MarkerData>();
-
- marker_data_->marker_mid = marker_mid;
-}
-
-void SVGResources::SetMarkerEnd(LayoutSVGResourceMarker* marker_end) {
- DCHECK(marker_end);
- DCHECK_EQ(marker_end->ResourceType(), kMarkerResourceType);
-
- if (!marker_data_)
- marker_data_ = std::make_unique<MarkerData>();
-
- marker_data_->marker_end = marker_end;
-}
-
-void SVGResources::SetMasker(LayoutSVGResourceMasker* masker) {
- DCHECK(masker);
- DCHECK_EQ(masker->ResourceType(), kMaskerResourceType);
-
- if (!clipper_filter_masker_data_)
- clipper_filter_masker_data_ = std::make_unique<ClipperFilterMaskerData>();
-
- clipper_filter_masker_data_->masker = masker;
-}
-
-void SVGResources::SetFill(LayoutSVGResourcePaintServer* fill) {
- DCHECK(fill);
-
- if (!fill_stroke_data_)
- fill_stroke_data_ = std::make_unique<FillStrokeData>();
-
- fill_stroke_data_->fill = fill;
-}
-
-void SVGResources::SetStroke(LayoutSVGResourcePaintServer* stroke) {
- DCHECK(stroke);
-
- if (!fill_stroke_data_)
- fill_stroke_data_ = std::make_unique<FillStrokeData>();
-
- fill_stroke_data_->stroke = stroke;
-}
-
-void SVGResources::SetLinkedResource(
- LayoutSVGResourceContainer* linked_resource) {
- if (!linked_resource)
- return;
-
- linked_resource_ = linked_resource;
-}
-
-#if DCHECK_IS_ON()
-void SVGResources::Dump(const LayoutObject* object) {
- DCHECK(object);
- DCHECK(object->GetNode());
-
- fprintf(stderr, "-> this=%p, SVGResources(layoutObject=%p, node=%p)\n", this,
- object, object->GetNode());
- fprintf(stderr, " | DOM Tree:\n");
- fprintf(stderr, "%s",
- object->GetNode()->ToTreeStringForThis().Utf8().c_str());
-
- fprintf(stderr, "\n | List of resources:\n");
- if (clipper_filter_masker_data_) {
- if (LayoutSVGResourceClipper* clipper =
- clipper_filter_masker_data_->clipper)
- fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper,
- clipper->GetElement());
- if (LayoutSVGResourceFilter* filter = clipper_filter_masker_data_->filter)
- fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter,
- filter->GetElement());
- if (LayoutSVGResourceMasker* masker = clipper_filter_masker_data_->masker)
- fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker,
- masker->GetElement());
- }
-
- if (marker_data_) {
- if (LayoutSVGResourceMarker* marker_start = marker_data_->marker_start)
- fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", marker_start,
- marker_start->GetElement());
- if (LayoutSVGResourceMarker* marker_mid = marker_data_->marker_mid)
- fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", marker_mid,
- marker_mid->GetElement());
- if (LayoutSVGResourceMarker* marker_end = marker_data_->marker_end)
- fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", marker_end,
- marker_end->GetElement());
- }
-
- if (fill_stroke_data_) {
- if (LayoutSVGResourcePaintServer* fill = fill_stroke_data_->fill)
- fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill,
- fill->GetElement());
- if (LayoutSVGResourcePaintServer* stroke = fill_stroke_data_->stroke)
- fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke,
- stroke->GetElement());
- }
-
- if (linked_resource_)
- fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", linked_resource_,
- linked_resource_->GetElement());
-}
-#endif
-
void SVGResources::UpdateClipPathFilterMask(SVGElement& element,
const ComputedStyle* old_style,
const ComputedStyle& style) {
@@ -543,7 +82,7 @@ void SVGResources::UpdateClipPathFilterMask(SVGElement& element,
layout_object->SetNeedsPaintPropertyUpdate();
client.MarkFilterDataDirty();
}
- if (StyleSVGResource* masker_resource = style.SvgStyle().MaskerResource())
+ if (StyleSVGResource* masker_resource = style.MaskerResource())
masker_resource->AddClient(element.EnsureSVGResourceClient());
if (had_client)
ClearClipPathFilterMask(element, old_style);
@@ -563,7 +102,7 @@ void SVGResources::ClearClipPathFilterMask(SVGElement& element,
style->Filter().RemoveClient(*client);
client->InvalidateFilterData();
}
- if (StyleSVGResource* masker_resource = style->SvgStyle().MaskerResource())
+ if (StyleSVGResource* masker_resource = style->MaskerResource())
masker_resource->RemoveClient(*client);
}
@@ -571,10 +110,9 @@ void SVGResources::UpdatePaints(SVGElement& element,
const ComputedStyle* old_style,
const ComputedStyle& style) {
const bool had_client = element.GetSVGResourceClient();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- if (StyleSVGResource* paint_resource = svg_style.FillPaint().Resource())
+ if (StyleSVGResource* paint_resource = style.FillPaint().Resource())
paint_resource->AddClient(element.EnsureSVGResourceClient());
- if (StyleSVGResource* paint_resource = svg_style.StrokePaint().Resource())
+ if (StyleSVGResource* paint_resource = style.StrokePaint().Resource())
paint_resource->AddClient(element.EnsureSVGResourceClient());
if (had_client)
ClearPaints(element, old_style);
@@ -587,10 +125,9 @@ void SVGResources::ClearPaints(SVGElement& element,
SVGResourceClient* client = element.GetSVGResourceClient();
if (!client)
return;
- const SVGComputedStyle& old_svg_style = style->SvgStyle();
- if (StyleSVGResource* paint_resource = old_svg_style.FillPaint().Resource())
+ if (StyleSVGResource* paint_resource = style->FillPaint().Resource())
paint_resource->RemoveClient(*client);
- if (StyleSVGResource* paint_resource = old_svg_style.StrokePaint().Resource())
+ if (StyleSVGResource* paint_resource = style->StrokePaint().Resource())
paint_resource->RemoveClient(*client);
}
@@ -598,12 +135,11 @@ void SVGResources::UpdateMarkers(SVGElement& element,
const ComputedStyle* old_style,
const ComputedStyle& style) {
const bool had_client = element.GetSVGResourceClient();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- if (StyleSVGResource* marker_resource = svg_style.MarkerStartResource())
+ if (StyleSVGResource* marker_resource = style.MarkerStartResource())
marker_resource->AddClient(element.EnsureSVGResourceClient());
- if (StyleSVGResource* marker_resource = svg_style.MarkerMidResource())
+ if (StyleSVGResource* marker_resource = style.MarkerMidResource())
marker_resource->AddClient(element.EnsureSVGResourceClient());
- if (StyleSVGResource* marker_resource = svg_style.MarkerEndResource())
+ if (StyleSVGResource* marker_resource = style.MarkerEndResource())
marker_resource->AddClient(element.EnsureSVGResourceClient());
if (had_client)
ClearMarkers(element, old_style);
@@ -616,58 +152,93 @@ void SVGResources::ClearMarkers(SVGElement& element,
SVGResourceClient* client = element.GetSVGResourceClient();
if (!client)
return;
- const SVGComputedStyle& old_svg_style = style->SvgStyle();
- if (StyleSVGResource* marker_resource = old_svg_style.MarkerStartResource())
+ if (StyleSVGResource* marker_resource = style->MarkerStartResource())
marker_resource->RemoveClient(*client);
- if (StyleSVGResource* marker_resource = old_svg_style.MarkerMidResource())
+ if (StyleSVGResource* marker_resource = style->MarkerMidResource())
marker_resource->RemoveClient(*client);
- if (StyleSVGResource* marker_resource = old_svg_style.MarkerEndResource())
+ if (StyleSVGResource* marker_resource = style->MarkerEndResource())
marker_resource->RemoveClient(*client);
}
-sk_sp<PaintFilter> FilterData::BuildPaintFilter() {
- return paint_filter_builder::Build(last_effect_, kInterpolationSpaceSRGB);
-}
+class SVGElementResourceClient::FilterData final
+ : public GarbageCollected<SVGElementResourceClient::FilterData> {
+ public:
+ FilterData(FilterEffect* last_effect, SVGFilterGraphNodeMap* node_map)
+ : last_effect_(last_effect), node_map_(node_map) {}
-bool FilterData::Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
- const QualifiedName& attribute) {
- if (FilterEffect* effect = node_map_->EffectForElement(primitive)) {
- if (!primitive.SetFilterEffectAttribute(effect, attribute))
- return false; // No change
- node_map_->InvalidateDependentEffects(effect);
+ sk_sp<PaintFilter> BuildPaintFilter() {
+ return paint_filter_builder::Build(last_effect_, kInterpolationSpaceSRGB);
}
- return true;
-}
-void FilterData::Trace(Visitor* visitor) const {
- visitor->Trace(last_effect_);
- visitor->Trace(node_map_);
-}
+ // Perform a finegrained invalidation of the filter chain for the
+ // specified filter primitive and attribute. Returns false if no
+ // further invalidation is required, otherwise true.
+ bool Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
+ const QualifiedName& attribute) {
+ if (FilterEffect* effect = node_map_->EffectForElement(primitive)) {
+ if (!primitive.SetFilterEffectAttribute(effect, attribute))
+ return false; // No change
+ node_map_->InvalidateDependentEffects(effect);
+ }
+ return true;
+ }
-void FilterData::Dispose() {
- node_map_ = nullptr;
- if (last_effect_)
- last_effect_->DisposeImageFiltersRecursive();
- last_effect_ = nullptr;
-}
+ void Dispose() {
+ node_map_ = nullptr;
+ if (last_effect_)
+ last_effect_->DisposeImageFiltersRecursive();
+ last_effect_ = nullptr;
+ }
+
+ void Trace(Visitor* visitor) const {
+ visitor->Trace(last_effect_);
+ visitor->Trace(node_map_);
+ }
+
+ private:
+ Member<FilterEffect> last_effect_;
+ Member<SVGFilterGraphNodeMap> node_map_;
+};
SVGElementResourceClient::SVGElementResourceClient(SVGElement* element)
: element_(element), filter_data_dirty_(false) {}
-void SVGElementResourceClient::ResourceContentChanged(
- InvalidationModeMask invalidation_mask) {
+namespace {
+
+template <typename ContainerType>
+bool ContainsResource(const ContainerType* container, SVGResource* resource) {
+ return container && container->Resource() == resource;
+}
+
+bool ContainsResource(const FilterOperations& operations,
+ SVGResource* resource) {
+ return base::ranges::any_of(
+ operations.Operations(), [resource](const FilterOperation* operation) {
+ return ContainsResource(DynamicTo<ReferenceFilterOperation>(operation),
+ resource);
+ });
+}
+
+} // namespace
+
+void SVGElementResourceClient::ResourceContentChanged(SVGResource* resource) {
LayoutObject* layout_object = element_->GetLayoutObject();
if (!layout_object)
return;
- if (layout_object->IsSVGResourceContainer()) {
- To<LayoutSVGResourceContainer>(layout_object)->RemoveAllClientsFromCache();
- return;
- }
- if (invalidation_mask & SVGResourceClient::kFilterCacheInvalidation)
+ const ComputedStyle& style = layout_object->StyleRef();
+ if (style.HasFilter() && ContainsResource(style.Filter(), resource)) {
InvalidateFilterData();
+ layout_object->SetShouldDoFullPaintInvalidation();
+ }
+
+ if (auto* container = DynamicTo<LayoutSVGResourceContainer>(layout_object)) {
+ container->RemoveAllClientsFromCache();
+ return;
+ }
- if (invalidation_mask & SVGResourceClient::kPaintInvalidation) {
+ if (ContainsResource(style.FillPaint().Resource(), resource) ||
+ ContainsResource(style.StrokePaint().Resource(), resource)) {
// Since LayoutSVGInlineTexts don't have SVGResources (they use their
// parent's), they will not be notified of changes to paint servers. So
// if the client is one that could have a LayoutSVGInlineText use a
@@ -677,48 +248,34 @@ void SVGElementResourceClient::ResourceContentChanged(
PaintInvalidationReason::kSVGResource);
}
- if (invalidation_mask & SVGResourceClient::kClipCacheInvalidation)
+ bool needs_layout = false;
+ if (ContainsResource(style.MarkerStartResource(), resource) ||
+ ContainsResource(style.MarkerMidResource(), resource) ||
+ ContainsResource(style.MarkerEndResource(), resource)) {
+ needs_layout = true;
+ layout_object->SetNeedsBoundariesUpdate();
+ }
+
+ const auto* clip_reference =
+ DynamicTo<ReferenceClipPathOperation>(style.ClipPath());
+ if (ContainsResource(clip_reference, resource)) {
+ // TODO(fs): "Downgrade" to non-subtree?
+ layout_object->SetSubtreeShouldDoFullPaintInvalidation();
layout_object->InvalidateClipPathCache();
+ }
- // Invalidate paint properties to update effects if any.
- if (invalidation_mask & SVGResourceClient::kPaintPropertiesInvalidation)
+ if (ContainsResource(style.MaskerResource(), resource)) {
+ // TODO(fs): "Downgrade" to non-subtree?
+ layout_object->SetSubtreeShouldDoFullPaintInvalidation();
layout_object->SetNeedsPaintPropertyUpdate();
+ }
- if (invalidation_mask & SVGResourceClient::kBoundariesInvalidation)
- layout_object->SetNeedsBoundariesUpdate();
-
- bool needs_layout =
- invalidation_mask & SVGResourceClient::kLayoutInvalidation;
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
*layout_object, needs_layout);
}
-void SVGElementResourceClient::ResourceElementChanged() {
- LayoutObject* layout_object = element_->GetLayoutObject();
- if (!layout_object)
- return;
- // TODO(fs): If the resource element (for a filter) doesn't actually change
- // we don't need to perform the associated invalidations.
- InvalidateFilterData();
- if (layout_object->Parent()) {
- SVGResourcesCache::UpdateResources(*layout_object);
- LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
- *layout_object, true);
- }
-}
-
-void SVGElementResourceClient::ResourceDestroyed(
- LayoutSVGResourceContainer* resource) {
- LayoutObject* layout_object = element_->GetLayoutObject();
- if (!layout_object)
- return;
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(*layout_object);
- if (resources)
- resources->ResourceDestroyed(resource);
-}
-
void SVGElementResourceClient::FilterPrimitiveChanged(
+ SVGResource* resource,
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) {
if (filter_data_ && !filter_data_->Invalidate(primitive, attribute))
@@ -730,7 +287,8 @@ void SVGElementResourceClient::FilterPrimitiveChanged(
MarkFilterDataDirty();
}
-static FilterData* CreateFilterDataWithNodeMap(
+SVGElementResourceClient::FilterData*
+SVGElementResourceClient::CreateFilterDataWithNodeMap(
FilterEffectBuilder& builder,
const ReferenceFilterOperation& reference_filter) {
auto* node_map = MakeGarbageCollected<SVGFilterGraphNodeMap>();
@@ -751,19 +309,35 @@ void SVGElementResourceClient::UpdateFilterData(
if (!operations.IsEmpty() && !filter_data_dirty_ &&
reference_box == operations.ReferenceBox())
return;
- if (!filter_data_ && GetFilterResourceForSVG(object.StyleRef())) {
- FilterEffectBuilder builder(reference_box, 1);
- filter_data_ = CreateFilterDataWithNodeMap(
- builder,
- To<ReferenceFilterOperation>(*object.StyleRef().Filter().at(0)));
- }
- operations.Clear();
- if (filter_data_) {
- operations.AppendReferenceFilter(filter_data_->BuildPaintFilter());
+ const ComputedStyle& style = object.StyleRef();
+ FilterEffectBuilder builder(reference_box, 1);
+ builder.SetShorthandScale(1 / style.EffectiveZoom());
+ const FilterOperations& filter = style.Filter();
+ // If the filter is a single 'url(...)' reference we can optimize some
+ // mutations to the referenced filter chain by tracking the filter
+ // dependencies and only perform partial invalidations of the filter chain.
+ const bool is_single_reference_filter =
+ filter.size() == 1 && IsA<ReferenceFilterOperation>(*filter.at(0));
+ if (is_single_reference_filter) {
+ if (!filter_data_) {
+ filter_data_ = CreateFilterDataWithNodeMap(
+ builder, To<ReferenceFilterOperation>(*filter.at(0)));
+ }
+ operations.Clear();
+ if (filter_data_) {
+ operations.AppendReferenceFilter(filter_data_->BuildPaintFilter());
+ } else {
+ // Filter construction failed. Create a filter chain that yields
+ // transparent black.
+ operations.AppendOpacityFilter(0);
+ }
} else {
- // Filter construction failed. Create a filter chain that yields
- // transparent black.
- operations.AppendOpacityFilter(0);
+ // Drop any existing filter data since the filter is no longer
+ // cacheable.
+ if (FilterData* filter_data = filter_data_.Release())
+ filter_data->Dispose();
+
+ operations = builder.BuildFilterOperations(filter);
}
operations.SetReferenceBox(reference_box);
filter_data_dirty_ = false;
@@ -794,34 +368,37 @@ void SVGElementResourceClient::Trace(Visitor* visitor) const {
}
SVGResourceInvalidator::SVGResourceInvalidator(LayoutObject& object)
- : resources_(SVGResourcesCache::CachedResourcesForLayoutObject(object)),
- object_(object) {}
+ : object_(object) {}
void SVGResourceInvalidator::InvalidateEffects() {
- if (!resources_)
- return;
- if (resources_->Filter())
- SVGResources::GetClient(object_)->InvalidateFilterData();
- if (resources_->Clipper()) {
+ const ComputedStyle& style = object_.StyleRef();
+ if (style.HasFilter()) {
+ if (SVGElementResourceClient* client = SVGResources::GetClient(object_))
+ client->InvalidateFilterData();
+ }
+ if (style.HasClipPath()) {
object_.SetShouldDoFullPaintInvalidation();
object_.InvalidateClipPathCache();
}
- if (resources_->Masker()) {
+ if (style.MaskerResource()) {
object_.SetShouldDoFullPaintInvalidation();
object_.SetNeedsPaintPropertyUpdate();
}
}
void SVGResourceInvalidator::InvalidatePaints() {
- if (!resources_)
+ SVGElementResourceClient* client = SVGResources::GetClient(object_);
+ if (!client)
return;
bool needs_invalidation = false;
- SVGElementResourceClient* client = SVGResources::GetClient(object_);
- if (LayoutSVGResourcePaintServer* fill = resources_->Fill()) {
+ const ComputedStyle& style = object_.StyleRef();
+ if (auto* fill = GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ *client, style.FillPaint().Resource())) {
fill->RemoveClientFromCache(*client);
needs_invalidation = true;
}
- if (LayoutSVGResourcePaintServer* stroke = resources_->Stroke()) {
+ if (auto* stroke = GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ *client, style.StrokePaint().Resource())) {
stroke->RemoveClientFromCache(*client);
needs_invalidation = true;
}