Commit c1db0569 authored by Nate Chapin's avatar Nate Chapin Committed by Commit Bot

Use a separate caching layer for SVG external Documents

External SVG documents are loaded using the DocumentResource subclass
of Resource, which stores the external Document. As of
https://chromium.googlesource.com/chromium/src/+/099517c767c6ef8d66408c03004d9e3a12be5011,
that Document is created with a context Document. The MemoryCache
architecture allows the reuse of Resources across different Documents,
and it seems wrong for an external SVG Document to get used in a
different Document than the one that is considered its context Document.

This introduces a new registry for loading SVG external documents, and
makes DocumentResource an implementation detail of that registry. It
ensures that these resources are not kept in the MemoryCache, and
because the registry is per-Document, it ensures that the external
documents will not be shared across contexts.

Bug: 1029822
Change-Id: Ibcff651a2c22ec924ff92d01b0bb63ff17f399ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2128234
Commit-Queue: Nate Chapin <japhet@chromium.org>
Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Reviewed-by: default avatarFredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#760591}
parent 101683ca
......@@ -114,8 +114,6 @@ blink_core_sources("loader") {
"progress_tracker.h",
"resource/css_style_sheet_resource.cc",
"resource/css_style_sheet_resource.h",
"resource/document_resource.cc",
"resource/document_resource.h",
"resource/font_resource.cc",
"resource/font_resource.h",
"resource/image_resource.cc",
......
......@@ -5,12 +5,39 @@
#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
namespace {
class SVGDocumentResourceFactory : public ResourceFactory {
public:
SVGDocumentResourceFactory()
: ResourceFactory(ResourceType::kSVGDocument,
TextResourceDecoderOptions::kXMLContent) {}
Resource* Create(
const ResourceRequest& request,
const ResourceLoaderOptions& options,
const TextResourceDecoderOptions& decoder_options) const override {
return MakeGarbageCollected<TextResource>(
request, ResourceType::kSVGDocument, options, decoder_options);
}
};
} // namespace
TextResource* TextResource::FetchSVGDocument(FetchParameters& params,
ResourceFetcher* fetcher,
ResourceClient* client) {
return To<TextResource>(
fetcher->RequestResource(params, SVGDocumentResourceFactory(), client));
}
TextResource::TextResource(const ResourceRequest& resource_request,
ResourceType type,
const ResourceLoaderOptions& options,
......
......@@ -10,11 +10,21 @@
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
class CORE_EXPORT TextResource : public Resource {
public:
static TextResource* FetchSVGDocument(FetchParameters&,
ResourceFetcher*,
ResourceClient*);
TextResource(const ResourceRequest&,
ResourceType,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&);
~TextResource() override;
// Returns the decoded data in text form. The data has to be available at
// call time.
String DecodedText() const;
......@@ -23,19 +33,25 @@ class CORE_EXPORT TextResource : public Resource {
void SetEncodingForTest(const String& encoding) { SetEncoding(encoding); }
protected:
TextResource(const ResourceRequest&,
ResourceType,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&);
~TextResource() override;
bool HasData() const { return Data(); }
protected:
void SetEncoding(const String&) override;
private:
std::unique_ptr<TextResourceDecoder> decoder_;
};
template <>
struct DowncastTraits<TextResource> {
static bool AllowFrom(const Resource& resource) {
return resource.GetType() == ResourceType::kCSSStyleSheet ||
resource.GetType() == ResourceType::kScript ||
resource.GetType() == ResourceType::kXSLStyleSheet ||
resource.GetType() == ResourceType::kSVGDocument;
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_TEXT_RESOURCE_H_
......@@ -111,6 +111,8 @@ blink_core_sources("svg") {
"svg_enumeration.h",
"svg_enumeration_map.cc",
"svg_enumeration_map.h",
"svg_external_document_cache.cc",
"svg_external_document_cache.h",
"svg_fe_blend_element.cc",
"svg_fe_blend_element.h",
"svg_fe_color_matrix_element.cc",
......
......@@ -20,84 +20,115 @@
Boston, MA 02110-1301, USA.
*/
#include "third_party/blink/renderer/core/loader/resource/document_resource.h"
#include "third_party/blink/renderer/core/svg/svg_external_document_cache.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
#include "third_party/blink/renderer/core/dom/xml_document.h"
#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
DocumentResource* DocumentResource::FetchSVGDocument(
FetchParameters& params,
const Document& context_document,
ResourceClient* client) {
DCHECK_EQ(params.GetResourceRequest().GetMode(),
network::mojom::RequestMode::kSameOrigin);
params.SetRequestContext(mojom::RequestContextType::IMAGE);
params.SetRequestDestination(network::mojom::RequestDestination::kImage);
auto* resource =
To<DocumentResource>(context_document.Fetcher()->RequestResource(
params, SVGDocumentResourceFactory(), client));
if (!resource->document_ && !resource->context_document_)
resource->context_document_ = const_cast<Document*>(&context_document);
return resource;
namespace {
bool MimeTypeAllowed(const ResourceResponse& response) {
AtomicString mime_type = response.MimeType();
if (response.IsHTTP())
mime_type = response.HttpContentType();
return mime_type == "image/svg+xml" || mime_type == "text/xml" ||
mime_type == "application/xml" || mime_type == "application/xhtml+xml";
}
DocumentResource::DocumentResource(
const ResourceRequest& request,
ResourceType type,
const ResourceLoaderOptions& options,
const TextResourceDecoderOptions& decoder_options)
: TextResource(request, type, options, decoder_options) {
// FIXME: We'll support more types to support HTMLImports.
DCHECK_EQ(type, ResourceType::kSVGDocument);
} // namespace
void SVGExternalDocumentCache::Entry::AddClient(Client* client) {
if (!GetResource()->IsLoaded()) {
clients_.insert(client);
return;
}
context_document_->GetTaskRunner(TaskType::kInternalLoading)
->PostTask(
FROM_HERE,
WTF::Bind(&SVGExternalDocumentCache::Client::NotifyFinished,
WrapPersistent(client), WrapPersistent(document_.Get())));
}
void SVGExternalDocumentCache::Entry::NotifyFinished(Resource* resource) {
DCHECK_EQ(GetResource(), resource);
for (auto client : clients_) {
if (client)
client->NotifyFinished(GetDocument());
}
}
DocumentResource::~DocumentResource() = default;
Document* SVGExternalDocumentCache::Entry::GetDocument() {
const TextResource* resource = To<TextResource>(GetResource());
if (!document_ && resource->HasData() &&
MimeTypeAllowed(resource->GetResponse())) {
document_ = XMLDocument::CreateSVG(
DocumentInit::Create()
.WithURL(resource->GetResponse().CurrentRequestUrl())
.WithContextDocument(context_document_));
document_->SetContent(resource->DecodedText());
}
return document_.Get();
}
void DocumentResource::Trace(Visitor* visitor) {
void SVGExternalDocumentCache::Entry::Trace(Visitor* visitor) {
ResourceClient::Trace(visitor);
visitor->Trace(document_);
visitor->Trace(context_document_);
Resource::Trace(visitor);
visitor->Trace(clients_);
}
void DocumentResource::NotifyFinished() {
if (Data() && MimeTypeAllowed()) {
// We don't need to create a new frame because the new document belongs to
// the parent UseElement.
document_ = CreateDocument(GetResponse().CurrentRequestUrl());
document_->SetContent(DecodedText());
const char SVGExternalDocumentCache::kSupplementName[] =
"SVGExternalDocumentCache";
SVGExternalDocumentCache* SVGExternalDocumentCache::From(Document& document) {
SVGExternalDocumentCache* cache =
Supplement<Document>::From<SVGExternalDocumentCache>(document);
if (!cache) {
cache = MakeGarbageCollected<SVGExternalDocumentCache>(document);
Supplement<Document>::ProvideTo(document, cache);
}
Resource::NotifyFinished();
return cache;
}
bool DocumentResource::MimeTypeAllowed() const {
DCHECK_EQ(GetType(), ResourceType::kSVGDocument);
AtomicString mime_type = GetResponse().MimeType();
if (GetResponse().IsHTTP())
mime_type = HttpContentType();
return mime_type == "image/svg+xml" || mime_type == "text/xml" ||
mime_type == "application/xml" || mime_type == "application/xhtml+xml";
SVGExternalDocumentCache::SVGExternalDocumentCache(Document& document)
: Supplement<Document>(document) {}
SVGExternalDocumentCache::Entry* SVGExternalDocumentCache::Get(
Client* client,
const KURL& url,
const AtomicString& initiator_name,
network::mojom::blink::CSPDisposition csp_disposition) {
ResourceLoaderOptions options;
options.initiator_info.name = initiator_name;
FetchParameters params(ResourceRequest(url), options);
params.SetContentSecurityCheck(csp_disposition);
params.MutableResourceRequest().SetMode(
network::mojom::blink::RequestMode::kSameOrigin);
params.SetRequestContext(mojom::blink::RequestContextType::IMAGE);
params.SetRequestDestination(network::mojom::RequestDestination::kImage);
Document* context_document = GetSupplementable();
Entry* entry = MakeGarbageCollected<Entry>(context_document);
Resource* resource = TextResource::FetchSVGDocument(
params, context_document->Fetcher(), entry);
// TODO(fs): Handle revalidations that return a new/different resource without
// needing to throw away the old Entry.
if (resource && resource->IsCacheValidator())
entries_.erase(resource);
entry = entries_.insert(resource, entry).stored_value->value;
entry->AddClient(client);
return entry;
}
Document* DocumentResource::CreateDocument(const KURL& url) {
switch (GetType()) {
case ResourceType::kSVGDocument:
return XMLDocument::CreateSVG(
DocumentInit::Create().WithURL(url).WithContextDocument(
context_document_));
default:
// FIXME: We'll add more types to support HTMLImports.
NOTREACHED();
return nullptr;
}
void SVGExternalDocumentCache::Trace(Visitor* visitor) {
Supplement<Document>::Trace(visitor);
visitor->Trace(entries_);
}
} // namespace blink
......@@ -20,69 +20,68 @@
Boston, MA 02110-1301, USA.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_DOCUMENT_RESOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_DOCUMENT_RESOURCE_H_
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
#include <memory>
#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
class Document;
class FetchParameters;
class CORE_EXPORT DocumentResource final : public TextResource {
class SVGExternalDocumentCache
: public GarbageCollected<SVGExternalDocumentCache>,
public Supplement<Document> {
USING_GARBAGE_COLLECTED_MIXIN(SVGExternalDocumentCache);
public:
static DocumentResource* FetchSVGDocument(FetchParameters&,
const Document& context_document,
ResourceClient*);
DocumentResource(const ResourceRequest&,
ResourceType,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&);
~DocumentResource() override;
static const char kSupplementName[];
static SVGExternalDocumentCache* From(Document&);
explicit SVGExternalDocumentCache(Document&);
void Trace(Visitor*) override;
Document* GetDocument() const { return document_.Get(); }
class Client : public GarbageCollectedMixin {
public:
virtual void NotifyFinished(Document*) = 0;
};
void NotifyFinished() override;
class Entry final : public GarbageCollected<Entry>, public ResourceClient {
USING_GARBAGE_COLLECTED_MIXIN(Entry);
private:
class SVGDocumentResourceFactory : public ResourceFactory {
public:
SVGDocumentResourceFactory()
: ResourceFactory(ResourceType::kSVGDocument,
TextResourceDecoderOptions::kXMLContent) {}
Resource* Create(
const ResourceRequest& request,
const ResourceLoaderOptions& options,
const TextResourceDecoderOptions& decoder_options) const override {
return MakeGarbageCollected<DocumentResource>(
request, ResourceType::kSVGDocument, options, decoder_options);
}
explicit Entry(Document* context_document)
: context_document_(context_document) {}
~Entry() override = default;
void Trace(Visitor*) override;
Document* GetDocument();
const KURL& Url() const { return GetResource()->Url(); }
private:
friend class SVGExternalDocumentCache;
void AddClient(Client*);
// ResourceClient overrides;
void NotifyFinished(Resource*) override;
String DebugName() const override { return "SVGExternalDocumentCache"; }
Member<Document> document_;
Member<Document> context_document_;
HeapHashSet<WeakMember<Client>> clients_;
};
bool MimeTypeAllowed() const;
Document* CreateDocument(const KURL&);
Member<Document> document_;
WeakMember<Document> context_document_;
};
Entry* Get(Client*,
const KURL&,
const AtomicString& initiator_name,
network::mojom::blink::CSPDisposition =
network::mojom::blink::CSPDisposition::CHECK);
template <>
struct DowncastTraits<DocumentResource> {
static bool AllowFrom(const Resource& resource) {
return resource.GetType() == ResourceType::kSVGDocument;
}
private:
HeapHashMap<WeakMember<Resource>, WeakMember<Entry>> entries_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_DOCUMENT_RESOURCE_H_
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
......@@ -9,12 +9,9 @@
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/tree_scope.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/loader/resource/document_resource.h"
#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
namespace blink {
......@@ -132,35 +129,24 @@ void LocalSVGResource::Trace(Visitor* visitor) {
ExternalSVGResource::ExternalSVGResource(const KURL& url) : url_(url) {}
void ExternalSVGResource::Load(const Document& document) {
if (resource_document_)
void ExternalSVGResource::Load(Document& document) {
if (cache_entry_)
return;
ResourceLoaderOptions options;
options.initiator_info.name = fetch_initiator_type_names::kCSS;
FetchParameters params(ResourceRequest(url_), options);
params.MutableResourceRequest().SetMode(
network::mojom::blink::RequestMode::kSameOrigin);
resource_document_ =
DocumentResource::FetchSVGDocument(params, document, this);
cache_entry_ = SVGExternalDocumentCache::From(document)->Get(
this, url_, fetch_initiator_type_names::kCSS);
target_ = ResolveTarget();
}
void ExternalSVGResource::LoadWithoutCSP(const Document& document) {
if (resource_document_)
void ExternalSVGResource::LoadWithoutCSP(Document& document) {
if (cache_entry_)
return;
ResourceLoaderOptions options;
options.initiator_info.name = fetch_initiator_type_names::kCSS;
FetchParameters params(ResourceRequest(url_), options);
params.SetContentSecurityCheck(
cache_entry_ = SVGExternalDocumentCache::From(document)->Get(
this, url_, fetch_initiator_type_names::kCSS,
network::mojom::blink::CSPDisposition::DO_NOT_CHECK);
params.MutableResourceRequest().SetMode(
network::mojom::blink::RequestMode::kSameOrigin);
resource_document_ =
DocumentResource::FetchSVGDocument(params, document, this);
target_ = ResolveTarget();
}
void ExternalSVGResource::NotifyFinished(Resource*) {
void ExternalSVGResource::NotifyFinished(Document*) {
Element* new_target = ResolveTarget();
if (new_target == target_)
return;
......@@ -168,16 +154,12 @@ void ExternalSVGResource::NotifyFinished(Resource*) {
NotifyElementChanged();
}
String ExternalSVGResource::DebugName() const {
return "ExternalSVGResource";
}
Element* ExternalSVGResource::ResolveTarget() {
if (!resource_document_)
if (!cache_entry_)
return nullptr;
if (!url_.HasFragmentIdentifier())
return nullptr;
Document* external_document = resource_document_->GetDocument();
Document* external_document = cache_entry_->GetDocument();
if (!external_document)
return nullptr;
AtomicString decoded_fragment(DecodeURLEscapeSequences(
......@@ -186,9 +168,9 @@ Element* ExternalSVGResource::ResolveTarget() {
}
void ExternalSVGResource::Trace(Visitor* visitor) {
visitor->Trace(resource_document_);
visitor->Trace(cache_entry_);
SVGResource::Trace(visitor);
ResourceClient::Trace(visitor);
SVGExternalDocumentCache::Client::Trace(visitor);
}
} // namespace blink
......@@ -6,9 +6,9 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
#include "base/macros.h"
#include "third_party/blink/renderer/core/svg/svg_external_document_cache.h"
#include "third_party/blink/renderer/core/svg/svg_resource_client.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_counted_set.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
......@@ -17,7 +17,6 @@
namespace blink {
class Document;
class DocumentResource;
class Element;
class IdTargetObserver;
class LayoutSVGResourceContainer;
......@@ -63,8 +62,8 @@ class SVGResource : public GarbageCollected<SVGResource> {
public:
virtual ~SVGResource();
virtual void Load(const Document&) {}
virtual void LoadWithoutCSP(const Document&) {}
virtual void Load(Document&) {}
virtual void LoadWithoutCSP(Document&) {}
Element* Target() const { return target_; }
LayoutSVGResourceContainer* ResourceContainer() const;
......@@ -111,26 +110,26 @@ class LocalSVGResource final : public SVGResource {
};
// External resource reference (see SVGResource.)
class ExternalSVGResource final : public SVGResource, private ResourceClient {
class ExternalSVGResource final : public SVGResource,
private SVGExternalDocumentCache::Client {
USING_GARBAGE_COLLECTED_MIXIN(ExternalSVGResource);
public:
explicit ExternalSVGResource(const KURL&);
void Load(const Document&) override;
void LoadWithoutCSP(const Document&) override;
void Load(Document&) override;
void LoadWithoutCSP(Document&) override;
void Trace(Visitor*) override;
private:
Element* ResolveTarget();
// ResourceClient implementation
String DebugName() const override;
void NotifyFinished(Resource*) override;
// SVGExternalDocumentCache::Client implementation
void NotifyFinished(Document*) override;
Member<SVGExternalDocumentCache::Entry> cache_entry_;
KURL url_;
Member<DocumentResource> resource_document_;
};
} // namespace blink
......
......@@ -90,11 +90,8 @@ SVGUseElement::SVGUseElement(Document& document)
SVGUseElement::~SVGUseElement() = default;
void SVGUseElement::Dispose() {
ClearResource();
}
void SVGUseElement::Trace(Visitor* visitor) {
visitor->Trace(cache_entry_);
visitor->Trace(x_);
visitor->Trace(y_);
visitor->Trace(width_);
......@@ -102,7 +99,7 @@ void SVGUseElement::Trace(Visitor* visitor) {
visitor->Trace(target_id_observer_);
SVGGraphicsElement::Trace(visitor);
SVGURIReference::Trace(visitor);
ResourceClient::Trace(visitor);
SVGExternalDocumentCache::Client::Trace(visitor);
}
#if DCHECK_IS_ON()
......@@ -196,19 +193,15 @@ void SVGUseElement::UpdateTargetReference() {
element_url_ = GetDocument().CompleteURL(url_string);
element_url_is_local_ = url_string.StartsWith('#');
if (!IsStructurallyExternal() || !GetDocument().IsActive()) {
ClearResource();
cache_entry_ = nullptr;
return;
}
if (!element_url_.HasFragmentIdentifier() ||
(GetResource() &&
EqualIgnoringFragmentIdentifier(element_url_, GetResource()->Url())))
(cache_entry_ &&
EqualIgnoringFragmentIdentifier(element_url_, cache_entry_->Url()))) {
return;
}
ResourceLoaderOptions options;
options.initiator_info.name = localName();
FetchParameters params(ResourceRequest(element_url_), options);
params.MutableResourceRequest().SetMode(
network::mojom::RequestMode::kSameOrigin);
auto* context_document = &GetDocument();
if (GetDocument().ImportsController()) {
// For @imports from HTML imported Documents, we use the
......@@ -216,12 +209,13 @@ void SVGUseElement::UpdateTargetReference() {
// main Document's origin, while using the element document for
// CompleteURL() to use imported Documents' base URLs.
if (!GetDocument().ContextDocument()) {
ClearResource();
cache_entry_ = nullptr;
return;
}
context_document = GetDocument().ContextDocument();
}
DocumentResource::FetchSVGDocument(params, *context_document, this);
cache_entry_ = SVGExternalDocumentCache::From(*context_document)
->Get(this, element_url_, localName());
}
void SVGUseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
......@@ -319,11 +313,9 @@ Element* SVGUseElement::ResolveTargetElement() {
WrapWeakPersistent(this)));
}
}
if (!ResourceIsValid())
if (!cache_entry_ || !cache_entry_->GetDocument())
return nullptr;
return To<DocumentResource>(GetResource())
->GetDocument()
->getElementById(element_identifier);
return cache_entry_->GetDocument()->getElementById(element_identifier);
}
SVGElement* SVGUseElement::InstanceRoot() const {
......@@ -594,15 +586,14 @@ void SVGUseElement::DispatchPendingEvent() {
DispatchEvent(*Event::Create(event_type_names::kLoad));
}
void SVGUseElement::NotifyFinished(Resource* resource) {
DCHECK_EQ(GetResource(), resource);
void SVGUseElement::NotifyFinished(Document* external_document) {
if (!isConnected())
return;
InvalidateShadowTree();
if (!ResourceIsValid()) {
if (!external_document) {
DispatchEvent(*Event::Create(event_type_names::kError));
} else if (!resource->WasCanceled()) {
} else {
if (have_fired_load_event_)
return;
if (!IsStructurallyExternal())
......@@ -616,21 +607,4 @@ void SVGUseElement::NotifyFinished(Resource* resource) {
}
}
bool SVGUseElement::ResourceIsValid() const {
Resource* resource = GetResource();
if (!resource || resource->ErrorOccurred())
return false;
// If the resource has not yet finished loading but is revalidating, consider
// it to be valid if it actually carries a document. <use> elements that are
// in the process of "loading" the revalidated resource (performing the
// revalidation) will get a NotifyFinished() callback and invalidate as
// needed. <use> elements that have already finished loading (a potentially
// older version of the resource) will keep showing that until its shadow
// tree is invalidated.
// TODO(fs): Handle revalidations that return a new/different resource.
if (!resource->IsLoaded() && !resource->IsCacheValidator())
return false;
return To<DocumentResource>(resource)->GetDocument();
}
} // namespace blink
......@@ -24,8 +24,8 @@
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/loader/resource/document_resource.h"
#include "third_party/blink/renderer/core/svg/svg_animated_length.h"
#include "third_party/blink/renderer/core/svg/svg_external_document_cache.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
......@@ -35,10 +35,9 @@ namespace blink {
class SVGUseElement final : public SVGGraphicsElement,
public SVGURIReference,
public ResourceClient {
public SVGExternalDocumentCache::Client {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(SVGUseElement);
USING_PRE_FINALIZER(SVGUseElement, Dispose);
public:
explicit SVGUseElement(Document&);
......@@ -65,8 +64,6 @@ class SVGUseElement final : public SVGGraphicsElement,
void Trace(Visitor*) override;
private:
void Dispose();
FloatRect GetBBox() override;
void CollectStyleForPresentationAttribute(
......@@ -107,11 +104,11 @@ class SVGUseElement final : public SVGGraphicsElement,
bool HasCycleUseReferencing(const ContainerNode& target_instance,
const SVGElement& new_target) const;
bool ResourceIsValid() const;
void NotifyFinished(Resource*) override;
String DebugName() const override { return "SVGUseElement"; }
void NotifyFinished(Document*) override;
void UpdateTargetReference();
Member<SVGExternalDocumentCache::Entry> cache_entry_;
Member<SVGAnimatedLength> x_;
Member<SVGAnimatedLength> y_;
Member<SVGAnimatedLength> width_;
......
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