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") { ...@@ -114,8 +114,6 @@ blink_core_sources("loader") {
"progress_tracker.h", "progress_tracker.h",
"resource/css_style_sheet_resource.cc", "resource/css_style_sheet_resource.cc",
"resource/css_style_sheet_resource.h", "resource/css_style_sheet_resource.h",
"resource/document_resource.cc",
"resource/document_resource.h",
"resource/font_resource.cc", "resource/font_resource.cc",
"resource/font_resource.h", "resource/font_resource.h",
"resource/image_resource.cc", "resource/image_resource.cc",
......
...@@ -5,12 +5,39 @@ ...@@ -5,12 +5,39 @@
#include "third_party/blink/renderer/core/loader/resource/text_resource.h" #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/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/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink { 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, TextResource::TextResource(const ResourceRequest& resource_request,
ResourceType type, ResourceType type,
const ResourceLoaderOptions& options, const ResourceLoaderOptions& options,
......
...@@ -10,11 +10,21 @@ ...@@ -10,11 +10,21 @@
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #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/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.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 { namespace blink {
class CORE_EXPORT TextResource : public Resource { class CORE_EXPORT TextResource : public Resource {
public: 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 // Returns the decoded data in text form. The data has to be available at
// call time. // call time.
String DecodedText() const; String DecodedText() const;
...@@ -23,19 +33,25 @@ class CORE_EXPORT TextResource : public Resource { ...@@ -23,19 +33,25 @@ class CORE_EXPORT TextResource : public Resource {
void SetEncodingForTest(const String& encoding) { SetEncoding(encoding); } void SetEncodingForTest(const String& encoding) { SetEncoding(encoding); }
protected: bool HasData() const { return Data(); }
TextResource(const ResourceRequest&,
ResourceType,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&);
~TextResource() override;
protected:
void SetEncoding(const String&) override; void SetEncoding(const String&) override;
private: private:
std::unique_ptr<TextResourceDecoder> decoder_; 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 } // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_TEXT_RESOURCE_H_ #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_TEXT_RESOURCE_H_
...@@ -111,6 +111,8 @@ blink_core_sources("svg") { ...@@ -111,6 +111,8 @@ blink_core_sources("svg") {
"svg_enumeration.h", "svg_enumeration.h",
"svg_enumeration_map.cc", "svg_enumeration_map.cc",
"svg_enumeration_map.h", "svg_enumeration_map.h",
"svg_external_document_cache.cc",
"svg_external_document_cache.h",
"svg_fe_blend_element.cc", "svg_fe_blend_element.cc",
"svg_fe_blend_element.h", "svg_fe_blend_element.h",
"svg_fe_color_matrix_element.cc", "svg_fe_color_matrix_element.cc",
......
...@@ -20,84 +20,115 @@ ...@@ -20,84 +20,115 @@
Boston, MA 02110-1301, USA. 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/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/document_init.h"
#include "third_party/blink/renderer/core/dom/xml_document.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/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 { namespace blink {
DocumentResource* DocumentResource::FetchSVGDocument( namespace {
FetchParameters& params,
const Document& context_document, bool MimeTypeAllowed(const ResourceResponse& response) {
ResourceClient* client) { AtomicString mime_type = response.MimeType();
DCHECK_EQ(params.GetResourceRequest().GetMode(), if (response.IsHTTP())
network::mojom::RequestMode::kSameOrigin); mime_type = response.HttpContentType();
params.SetRequestContext(mojom::RequestContextType::IMAGE); return mime_type == "image/svg+xml" || mime_type == "text/xml" ||
params.SetRequestDestination(network::mojom::RequestDestination::kImage); mime_type == "application/xml" || mime_type == "application/xhtml+xml";
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;
} }
DocumentResource::DocumentResource( } // namespace
const ResourceRequest& request,
ResourceType type, void SVGExternalDocumentCache::Entry::AddClient(Client* client) {
const ResourceLoaderOptions& options, if (!GetResource()->IsLoaded()) {
const TextResourceDecoderOptions& decoder_options) clients_.insert(client);
: TextResource(request, type, options, decoder_options) { return;
// FIXME: We'll support more types to support HTMLImports. }
DCHECK_EQ(type, ResourceType::kSVGDocument); 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(document_);
visitor->Trace(context_document_); visitor->Trace(context_document_);
Resource::Trace(visitor); visitor->Trace(clients_);
} }
void DocumentResource::NotifyFinished() { const char SVGExternalDocumentCache::kSupplementName[] =
if (Data() && MimeTypeAllowed()) { "SVGExternalDocumentCache";
// We don't need to create a new frame because the new document belongs to
// the parent UseElement. SVGExternalDocumentCache* SVGExternalDocumentCache::From(Document& document) {
document_ = CreateDocument(GetResponse().CurrentRequestUrl()); SVGExternalDocumentCache* cache =
document_->SetContent(DecodedText()); Supplement<Document>::From<SVGExternalDocumentCache>(document);
if (!cache) {
cache = MakeGarbageCollected<SVGExternalDocumentCache>(document);
Supplement<Document>::ProvideTo(document, cache);
} }
Resource::NotifyFinished(); return cache;
} }
bool DocumentResource::MimeTypeAllowed() const { SVGExternalDocumentCache::SVGExternalDocumentCache(Document& document)
DCHECK_EQ(GetType(), ResourceType::kSVGDocument); : Supplement<Document>(document) {}
AtomicString mime_type = GetResponse().MimeType();
if (GetResponse().IsHTTP()) SVGExternalDocumentCache::Entry* SVGExternalDocumentCache::Get(
mime_type = HttpContentType(); Client* client,
return mime_type == "image/svg+xml" || mime_type == "text/xml" || const KURL& url,
mime_type == "application/xml" || mime_type == "application/xhtml+xml"; 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) { void SVGExternalDocumentCache::Trace(Visitor* visitor) {
switch (GetType()) { Supplement<Document>::Trace(visitor);
case ResourceType::kSVGDocument: visitor->Trace(entries_);
return XMLDocument::CreateSVG(
DocumentInit::Create().WithURL(url).WithContextDocument(
context_document_));
default:
// FIXME: We'll add more types to support HTMLImports.
NOTREACHED();
return nullptr;
}
} }
} // namespace blink } // namespace blink
...@@ -20,69 +20,68 @@ ...@@ -20,69 +20,68 @@
Boston, MA 02110-1301, USA. Boston, MA 02110-1301, USA.
*/ */
#ifndef 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_LOADER_RESOURCE_DOCUMENT_RESOURCE_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
#include <memory> #include "services/network/public/mojom/content_security_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
#include "third_party/blink/renderer/platform/heap/handle.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.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.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/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink { namespace blink {
class Document; 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: public:
static DocumentResource* FetchSVGDocument(FetchParameters&, static const char kSupplementName[];
const Document& context_document, static SVGExternalDocumentCache* From(Document&);
ResourceClient*); explicit SVGExternalDocumentCache(Document&);
DocumentResource(const ResourceRequest&,
ResourceType,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&);
~DocumentResource() override;
void Trace(Visitor*) override; 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: public:
SVGDocumentResourceFactory() explicit Entry(Document* context_document)
: ResourceFactory(ResourceType::kSVGDocument, : context_document_(context_document) {}
TextResourceDecoderOptions::kXMLContent) {} ~Entry() override = default;
void Trace(Visitor*) override;
Resource* Create( Document* GetDocument();
const ResourceRequest& request, const KURL& Url() const { return GetResource()->Url(); }
const ResourceLoaderOptions& options,
const TextResourceDecoderOptions& decoder_options) const override { private:
return MakeGarbageCollected<DocumentResource>( friend class SVGExternalDocumentCache;
request, ResourceType::kSVGDocument, options, decoder_options); 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; Entry* Get(Client*,
Document* CreateDocument(const KURL&); const KURL&,
const AtomicString& initiator_name,
Member<Document> document_; network::mojom::blink::CSPDisposition =
WeakMember<Document> context_document_; network::mojom::blink::CSPDisposition::CHECK);
};
template <> private:
struct DowncastTraits<DocumentResource> { HeapHashMap<WeakMember<Resource>, WeakMember<Entry>> entries_;
static bool AllowFrom(const Resource& resource) {
return resource.GetType() == ResourceType::kSVGDocument;
}
}; };
} // namespace blink } // 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 @@ ...@@ -9,12 +9,9 @@
#include "third_party/blink/renderer/core/dom/id_target_observer.h" #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/dom/tree_scope.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.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/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_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h" #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
namespace blink { namespace blink {
...@@ -132,35 +129,24 @@ void LocalSVGResource::Trace(Visitor* visitor) { ...@@ -132,35 +129,24 @@ void LocalSVGResource::Trace(Visitor* visitor) {
ExternalSVGResource::ExternalSVGResource(const KURL& url) : url_(url) {} ExternalSVGResource::ExternalSVGResource(const KURL& url) : url_(url) {}
void ExternalSVGResource::Load(const Document& document) { void ExternalSVGResource::Load(Document& document) {
if (resource_document_) if (cache_entry_)
return; return;
ResourceLoaderOptions options; cache_entry_ = SVGExternalDocumentCache::From(document)->Get(
options.initiator_info.name = fetch_initiator_type_names::kCSS; this, url_, 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);
target_ = ResolveTarget(); target_ = ResolveTarget();
} }
void ExternalSVGResource::LoadWithoutCSP(const Document& document) { void ExternalSVGResource::LoadWithoutCSP(Document& document) {
if (resource_document_) if (cache_entry_)
return; return;
ResourceLoaderOptions options; cache_entry_ = SVGExternalDocumentCache::From(document)->Get(
options.initiator_info.name = fetch_initiator_type_names::kCSS; this, url_, fetch_initiator_type_names::kCSS,
FetchParameters params(ResourceRequest(url_), options);
params.SetContentSecurityCheck(
network::mojom::blink::CSPDisposition::DO_NOT_CHECK); network::mojom::blink::CSPDisposition::DO_NOT_CHECK);
params.MutableResourceRequest().SetMode(
network::mojom::blink::RequestMode::kSameOrigin);
resource_document_ =
DocumentResource::FetchSVGDocument(params, document, this);
target_ = ResolveTarget(); target_ = ResolveTarget();
} }
void ExternalSVGResource::NotifyFinished(Resource*) { void ExternalSVGResource::NotifyFinished(Document*) {
Element* new_target = ResolveTarget(); Element* new_target = ResolveTarget();
if (new_target == target_) if (new_target == target_)
return; return;
...@@ -168,16 +154,12 @@ void ExternalSVGResource::NotifyFinished(Resource*) { ...@@ -168,16 +154,12 @@ void ExternalSVGResource::NotifyFinished(Resource*) {
NotifyElementChanged(); NotifyElementChanged();
} }
String ExternalSVGResource::DebugName() const {
return "ExternalSVGResource";
}
Element* ExternalSVGResource::ResolveTarget() { Element* ExternalSVGResource::ResolveTarget() {
if (!resource_document_) if (!cache_entry_)
return nullptr; return nullptr;
if (!url_.HasFragmentIdentifier()) if (!url_.HasFragmentIdentifier())
return nullptr; return nullptr;
Document* external_document = resource_document_->GetDocument(); Document* external_document = cache_entry_->GetDocument();
if (!external_document) if (!external_document)
return nullptr; return nullptr;
AtomicString decoded_fragment(DecodeURLEscapeSequences( AtomicString decoded_fragment(DecodeURLEscapeSequences(
...@@ -186,9 +168,9 @@ Element* ExternalSVGResource::ResolveTarget() { ...@@ -186,9 +168,9 @@ Element* ExternalSVGResource::ResolveTarget() {
} }
void ExternalSVGResource::Trace(Visitor* visitor) { void ExternalSVGResource::Trace(Visitor* visitor) {
visitor->Trace(resource_document_); visitor->Trace(cache_entry_);
SVGResource::Trace(visitor); SVGResource::Trace(visitor);
ResourceClient::Trace(visitor); SVGExternalDocumentCache::Client::Trace(visitor);
} }
} // namespace blink } // namespace blink
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
#include "base/macros.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/core/svg/svg_resource_client.h"
#include "third_party/blink/renderer/platform/heap/handle.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/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h" #include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h"
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
namespace blink { namespace blink {
class Document; class Document;
class DocumentResource;
class Element; class Element;
class IdTargetObserver; class IdTargetObserver;
class LayoutSVGResourceContainer; class LayoutSVGResourceContainer;
...@@ -63,8 +62,8 @@ class SVGResource : public GarbageCollected<SVGResource> { ...@@ -63,8 +62,8 @@ class SVGResource : public GarbageCollected<SVGResource> {
public: public:
virtual ~SVGResource(); virtual ~SVGResource();
virtual void Load(const Document&) {} virtual void Load(Document&) {}
virtual void LoadWithoutCSP(const Document&) {} virtual void LoadWithoutCSP(Document&) {}
Element* Target() const { return target_; } Element* Target() const { return target_; }
LayoutSVGResourceContainer* ResourceContainer() const; LayoutSVGResourceContainer* ResourceContainer() const;
...@@ -111,26 +110,26 @@ class LocalSVGResource final : public SVGResource { ...@@ -111,26 +110,26 @@ class LocalSVGResource final : public SVGResource {
}; };
// External resource reference (see 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); USING_GARBAGE_COLLECTED_MIXIN(ExternalSVGResource);
public: public:
explicit ExternalSVGResource(const KURL&); explicit ExternalSVGResource(const KURL&);
void Load(const Document&) override; void Load(Document&) override;
void LoadWithoutCSP(const Document&) override; void LoadWithoutCSP(Document&) override;
void Trace(Visitor*) override; void Trace(Visitor*) override;
private: private:
Element* ResolveTarget(); Element* ResolveTarget();
// ResourceClient implementation // SVGExternalDocumentCache::Client implementation
String DebugName() const override; void NotifyFinished(Document*) override;
void NotifyFinished(Resource*) override;
Member<SVGExternalDocumentCache::Entry> cache_entry_;
KURL url_; KURL url_;
Member<DocumentResource> resource_document_;
}; };
} // namespace blink } // namespace blink
......
...@@ -90,11 +90,8 @@ SVGUseElement::SVGUseElement(Document& document) ...@@ -90,11 +90,8 @@ SVGUseElement::SVGUseElement(Document& document)
SVGUseElement::~SVGUseElement() = default; SVGUseElement::~SVGUseElement() = default;
void SVGUseElement::Dispose() {
ClearResource();
}
void SVGUseElement::Trace(Visitor* visitor) { void SVGUseElement::Trace(Visitor* visitor) {
visitor->Trace(cache_entry_);
visitor->Trace(x_); visitor->Trace(x_);
visitor->Trace(y_); visitor->Trace(y_);
visitor->Trace(width_); visitor->Trace(width_);
...@@ -102,7 +99,7 @@ void SVGUseElement::Trace(Visitor* visitor) { ...@@ -102,7 +99,7 @@ void SVGUseElement::Trace(Visitor* visitor) {
visitor->Trace(target_id_observer_); visitor->Trace(target_id_observer_);
SVGGraphicsElement::Trace(visitor); SVGGraphicsElement::Trace(visitor);
SVGURIReference::Trace(visitor); SVGURIReference::Trace(visitor);
ResourceClient::Trace(visitor); SVGExternalDocumentCache::Client::Trace(visitor);
} }
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
...@@ -196,19 +193,15 @@ void SVGUseElement::UpdateTargetReference() { ...@@ -196,19 +193,15 @@ void SVGUseElement::UpdateTargetReference() {
element_url_ = GetDocument().CompleteURL(url_string); element_url_ = GetDocument().CompleteURL(url_string);
element_url_is_local_ = url_string.StartsWith('#'); element_url_is_local_ = url_string.StartsWith('#');
if (!IsStructurallyExternal() || !GetDocument().IsActive()) { if (!IsStructurallyExternal() || !GetDocument().IsActive()) {
ClearResource(); cache_entry_ = nullptr;
return; return;
} }
if (!element_url_.HasFragmentIdentifier() || if (!element_url_.HasFragmentIdentifier() ||
(GetResource() && (cache_entry_ &&
EqualIgnoringFragmentIdentifier(element_url_, GetResource()->Url()))) EqualIgnoringFragmentIdentifier(element_url_, cache_entry_->Url()))) {
return; 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(); auto* context_document = &GetDocument();
if (GetDocument().ImportsController()) { if (GetDocument().ImportsController()) {
// For @imports from HTML imported Documents, we use the // For @imports from HTML imported Documents, we use the
...@@ -216,12 +209,13 @@ void SVGUseElement::UpdateTargetReference() { ...@@ -216,12 +209,13 @@ void SVGUseElement::UpdateTargetReference() {
// main Document's origin, while using the element document for // main Document's origin, while using the element document for
// CompleteURL() to use imported Documents' base URLs. // CompleteURL() to use imported Documents' base URLs.
if (!GetDocument().ContextDocument()) { if (!GetDocument().ContextDocument()) {
ClearResource(); cache_entry_ = nullptr;
return; return;
} }
context_document = GetDocument().ContextDocument(); 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) { void SVGUseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
...@@ -319,11 +313,9 @@ Element* SVGUseElement::ResolveTargetElement() { ...@@ -319,11 +313,9 @@ Element* SVGUseElement::ResolveTargetElement() {
WrapWeakPersistent(this))); WrapWeakPersistent(this)));
} }
} }
if (!ResourceIsValid()) if (!cache_entry_ || !cache_entry_->GetDocument())
return nullptr; return nullptr;
return To<DocumentResource>(GetResource()) return cache_entry_->GetDocument()->getElementById(element_identifier);
->GetDocument()
->getElementById(element_identifier);
} }
SVGElement* SVGUseElement::InstanceRoot() const { SVGElement* SVGUseElement::InstanceRoot() const {
...@@ -594,15 +586,14 @@ void SVGUseElement::DispatchPendingEvent() { ...@@ -594,15 +586,14 @@ void SVGUseElement::DispatchPendingEvent() {
DispatchEvent(*Event::Create(event_type_names::kLoad)); DispatchEvent(*Event::Create(event_type_names::kLoad));
} }
void SVGUseElement::NotifyFinished(Resource* resource) { void SVGUseElement::NotifyFinished(Document* external_document) {
DCHECK_EQ(GetResource(), resource);
if (!isConnected()) if (!isConnected())
return; return;
InvalidateShadowTree(); InvalidateShadowTree();
if (!ResourceIsValid()) { if (!external_document) {
DispatchEvent(*Event::Create(event_type_names::kError)); DispatchEvent(*Event::Create(event_type_names::kError));
} else if (!resource->WasCanceled()) { } else {
if (have_fired_load_event_) if (have_fired_load_event_)
return; return;
if (!IsStructurallyExternal()) if (!IsStructurallyExternal())
...@@ -616,21 +607,4 @@ void SVGUseElement::NotifyFinished(Resource* resource) { ...@@ -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 } // namespace blink
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/core/core_export.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_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_geometry_element.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h" #include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
#include "third_party/blink/renderer/core/svg/svg_uri_reference.h" #include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
...@@ -35,10 +35,9 @@ namespace blink { ...@@ -35,10 +35,9 @@ namespace blink {
class SVGUseElement final : public SVGGraphicsElement, class SVGUseElement final : public SVGGraphicsElement,
public SVGURIReference, public SVGURIReference,
public ResourceClient { public SVGExternalDocumentCache::Client {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(SVGUseElement); USING_GARBAGE_COLLECTED_MIXIN(SVGUseElement);
USING_PRE_FINALIZER(SVGUseElement, Dispose);
public: public:
explicit SVGUseElement(Document&); explicit SVGUseElement(Document&);
...@@ -65,8 +64,6 @@ class SVGUseElement final : public SVGGraphicsElement, ...@@ -65,8 +64,6 @@ class SVGUseElement final : public SVGGraphicsElement,
void Trace(Visitor*) override; void Trace(Visitor*) override;
private: private:
void Dispose();
FloatRect GetBBox() override; FloatRect GetBBox() override;
void CollectStyleForPresentationAttribute( void CollectStyleForPresentationAttribute(
...@@ -107,11 +104,11 @@ class SVGUseElement final : public SVGGraphicsElement, ...@@ -107,11 +104,11 @@ class SVGUseElement final : public SVGGraphicsElement,
bool HasCycleUseReferencing(const ContainerNode& target_instance, bool HasCycleUseReferencing(const ContainerNode& target_instance,
const SVGElement& new_target) const; const SVGElement& new_target) const;
bool ResourceIsValid() const; void NotifyFinished(Document*) override;
void NotifyFinished(Resource*) override;
String DebugName() const override { return "SVGUseElement"; }
void UpdateTargetReference(); void UpdateTargetReference();
Member<SVGExternalDocumentCache::Entry> cache_entry_;
Member<SVGAnimatedLength> x_; Member<SVGAnimatedLength> x_;
Member<SVGAnimatedLength> y_; Member<SVGAnimatedLength> y_;
Member<SVGAnimatedLength> width_; 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