summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc62
1 files changed, 58 insertions, 4 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
index ce06ebc5c63..da7fd935d74 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
@@ -22,6 +22,7 @@
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
+#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
@@ -83,12 +84,66 @@ void LayoutSVGResourceContainer::StyleDidChange(
resource->NotifyResourceAttached(*this);
}
+bool LayoutSVGResourceContainer::FindCycle(
+ SVGResourcesCycleSolver& solver) const {
+ if (solver.IsKnownAcyclic(this))
+ return false;
+ SVGResourcesCycleSolver::Scope scope(solver);
+ if (!scope.Enter(this) || FindCycleFromSelf(solver))
+ return true;
+ solver.AddAcyclicSubgraph(this);
+ return false;
+}
+
+bool LayoutSVGResourceContainer::FindCycleInResources(
+ SVGResourcesCycleSolver& solver,
+ const LayoutObject& layout_object) const {
+ SVGResources* resources =
+ SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
+ if (!resources)
+ return false;
+ // Fetch all the referenced resources.
+ HashSet<LayoutSVGResourceContainer*> local_resources;
+ resources->BuildSetOfResources(local_resources);
+ // This performs a depth-first search for a back-edge in all the
+ // (potentially disjoint) graphs formed by the referenced resources.
+ for (auto* local_resource : local_resources) {
+ if (local_resource->FindCycle(solver))
+ return true;
+ }
+ return false;
+}
+
+bool LayoutSVGResourceContainer::FindCycleFromSelf(
+ SVGResourcesCycleSolver& solver) const {
+ if (FindCycleInResources(solver, *this))
+ return true;
+ return FindCycleInDescendants(solver);
+}
+
+bool LayoutSVGResourceContainer::FindCycleInDescendants(
+ SVGResourcesCycleSolver& solver) const {
+ LayoutObject* node = FirstChild();
+ while (node) {
+ // Skip subtrees which are themselves resources. (They will be
+ // processed - if needed - when they are actually referenced.)
+ if (node->IsSVGResourceContainer()) {
+ node = node->NextInPreOrderAfterChildren(this);
+ continue;
+ }
+ if (FindCycleInResources(solver, *node))
+ return true;
+ node = node->NextInPreOrder(this);
+ }
+ return false;
+}
+
void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
InvalidationModeMask invalidation_mask) {
if (is_invalidating_)
return;
LocalSVGResource* resource = ResourceForContainer(*this);
- if (!resource || !resource->HasClients())
+ if (!resource)
return;
// Remove modes for which invalidations have already been
// performed. If no modes remain we are done.
@@ -100,8 +155,7 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
is_invalidating_ = true;
// Invalidate clients registered via an SVGResource.
- if (resource)
- resource->NotifyContentChanged(invalidation_mask);
+ resource->NotifyContentChanged(invalidation_mask);
is_invalidating_ = false;
}
@@ -154,7 +208,7 @@ static inline void RemoveFromCacheAndInvalidateDependencies(
if (SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object)) {
- SVGResourceClient* client = element->GetSVGResourceClient();
+ SVGElementResourceClient* client = element->GetSVGResourceClient();
if (InvalidationModeMask invalidation_mask =
resources->RemoveClientFromCacheAffectingObjectBounds(*client)) {
LayoutSVGResourceContainer::MarkClientForInvalidation(object,