blob: 7f591d7ce8c9453bf6d966fb1e22f5ff3890f294 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
#include "base/macros.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
class Document;
class Element;
class IdTargetObserver;
class LayoutSVGResourceContainer;
class QualifiedName;
class SVGFilterPrimitiveStandardAttributes;
class SVGResourceClient;
class SVGResourceDocumentContent;
class TreeScope;
// A class tracking a reference to an SVG resource (an element that constitutes
// a paint server, mask, clip-path, filter et.c.)
//
// Elements can be referenced using CSS, for example like:
//
// filter: url(#baz); ("local")
//
// or
//
// filter: url(foo.com/bar.svg#baz); ("external")
//
// SVGResource provide a mechanism to persistently reference an element in such
// cases - regardless of if the element reside in the same document (read: tree
// scope) or in an external (resource) document. Loading events related to the
// external documents case are handled by the SVGResource.
//
// For same document references, changes that could affect the 'id' lookup will
// be tracked, to handle elements being added, removed or having their 'id'
// mutated. (This does not apply for the external document case because it's
// assumed they will not mutate after load, due to scripts not being run etc.)
//
// SVGResources are created, and managed, either by SVGTreeScopeResources
// (local) or CSSURIValue (external), and have SVGResourceClients as a means to
// deliver change notifications. Clients that are interested in change
// notifications hence need to register a SVGResourceClient with the
// SVGResource. Most commonly this registration would take place when the
// computed style changes.
//
// The element is bound either when the SVGResource is created (for local
// resources) or after the referenced resource has completed loading (for
// external resources.)
//
// As content is mutated, clients will get notified via the SVGResource.
//
// <event> -> SVG...Element -> SVGResource -> SVGResourceClient(0..N)
//
class SVGResource : public GarbageCollected<SVGResource> {
public:
virtual ~SVGResource();
virtual void Load(Document&) {}
virtual void LoadWithoutCSP(Document&) {}
Element* Target() const { return target_; }
// Returns the target's LayoutObject (if target exists and is attached to the
// layout tree). Also perform cycle-checking, and may thus return nullptr if
// this SVGResourceClient -> SVGResource reference would start a cycle.
LayoutSVGResourceContainer* ResourceContainer(SVGResourceClient&) const;
// Same as the above, minus the cycle-checking.
LayoutSVGResourceContainer* ResourceContainerNoCycleCheck() const;
// Run cycle-checking for this SVGResourceClient -> SVGResource
// reference. Used internally by the cycle-checking, and shouldn't be called
// directly in general.
bool FindCycle(SVGResourceClient&) const;
void AddClient(SVGResourceClient&);
void RemoveClient(SVGResourceClient&);
virtual void Trace(Visitor*) const;
protected:
SVGResource();
void InvalidateCycleCache();
void NotifyContentChanged();
Member<Element> target_;
enum CycleState {
kNeedCheck,
kPerformingCheck,
kHasCycle,
kNoCycle,
};
struct ClientEntry {
int count = 0;
CycleState cached_cycle_check = kNeedCheck;
};
mutable HeapHashMap<Member<SVGResourceClient>, ClientEntry> clients_;
private:
DISALLOW_COPY_AND_ASSIGN(SVGResource);
};
// Local resource reference (see SVGResource.)
class LocalSVGResource final : public SVGResource {
public:
LocalSVGResource(TreeScope&, const AtomicString& id);
void Unregister();
using SVGResource::NotifyContentChanged;
void NotifyFilterPrimitiveChanged(
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute);
void Trace(Visitor*) const override;
private:
void TargetChanged(const AtomicString& id);
Member<TreeScope> tree_scope_;
Member<IdTargetObserver> id_observer_;
};
// External resource reference (see SVGResource.)
class ExternalSVGResource final : public SVGResource, public ResourceClient {
public:
explicit ExternalSVGResource(const KURL&);
void Load(Document&) override;
void LoadWithoutCSP(Document&) override;
void Trace(Visitor*) const override;
private:
Element* ResolveTarget();
// ResourceClient implementation
void NotifyFinished(Resource*) override;
String DebugName() const override;
Member<SVGResourceDocumentContent> document_content_;
KURL url_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_