Commit 43db8c36 authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Transition ReferenceClipPathOperation to SVGResource

This CL replaces the use of SVGElementProxy in
ReferenceClipPathOperation with SVGResource. The main change between the
two is when the element reference is resolved ("when used" versus
"when computed".)

This also, by extension, adds infrastructure for invalidation and other
things required to make SVGResource work.

Bug: 769774
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: Ia43f76256a251a15c4dc100461cff9bf728eb188
Reviewed-on: https://chromium-review.googlesource.com/951613
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541771}
parent a4a4697b
<!DOCTYPE html>
<div style="width: 100px; height: 100px; background-color: green"></div>
<!DOCTYPE html>
<div style="clip-path: url(#c)"></div>
<svg height="0">
<clipPath id="c" clipPathUnits="objectBoundingBox">
<rect width="0.5" height="1"/>
</clipPath>
</svg>
<script>
let div = document.querySelector('div');
div.attachShadow({ mode: 'open' });
div.shadowRoot.innerHTML = '<div style="width: 100px; height: 100px; background-color: green; clip-path: inherit; border-right: 100px solid red"></div>';
</script>
......@@ -32,6 +32,8 @@ class CSSURIValue : public CSSValue {
String CustomCSSText() const;
bool IsLocal(const Document&) const;
AtomicString FragmentIdentifier() const;
bool Equals(const CSSURIValue&) const;
void TraceAfterDispatch(blink::Visitor*);
......@@ -42,7 +44,6 @@ class CSSURIValue : public CSSValue {
const AtomicString& absolute_url);
KURL AbsoluteUrl() const;
AtomicString FragmentIdentifier() const;
AtomicString relative_url_;
bool is_local_;
......
......@@ -28,6 +28,7 @@
#include "core/css/CSSImageValue.h"
#include "core/css/CSSURIValue.h"
#include "core/dom/Document.h"
#include "core/dom/TreeScope.h"
#include "core/style/ComputedStyle.h"
#include "core/style/ContentData.h"
#include "core/style/CursorData.h"
......@@ -39,6 +40,7 @@
#include "core/style/StyleImage.h"
#include "core/style/StylePendingImage.h"
#include "core/svg/SVGElementProxy.h"
#include "core/svg/SVGTreeScopeResources.h"
#include "platform/Length.h"
#include "platform/loader/fetch/FetchParameters.h"
#include "platform/loader/fetch/ResourceFetcher.h"
......@@ -100,6 +102,16 @@ SVGElementProxy& ElementStyleResources::CachedOrPendingFromValue(
return value.EnsureElementProxy(*document_);
}
SVGResource* ElementStyleResources::GetSVGResourceFromValue(
TreeScope& tree_scope,
const CSSURIValue& value) const {
if (!value.IsLocal(*document_))
return nullptr;
SVGTreeScopeResources& tree_scope_resources =
tree_scope.EnsureSVGTreeScopedResources();
return tree_scope_resources.ResourceForId(value.FragmentIdentifier());
}
void ElementStyleResources::LoadPendingSVGDocuments(
ComputedStyle* computed_style) {
if (!computed_style->HasFilter())
......
......@@ -44,8 +44,10 @@ class CSSValue;
class ComputedStyle;
class Document;
class SVGElementProxy;
class SVGResource;
class StyleImage;
class StylePendingImage;
class TreeScope;
// Holds information about resources, requested by stylesheets.
// Lifetime: per-element style resolve.
......@@ -59,6 +61,7 @@ class ElementStyleResources {
StyleImage* CachedOrPendingFromValue(CSSPropertyID, const CSSImageValue&);
StyleImage* SetOrPendingFromValue(CSSPropertyID, const CSSImageSetValue&);
SVGElementProxy& CachedOrPendingFromValue(const CSSURIValue&);
SVGResource* GetSVGResourceFromValue(TreeScope&, const CSSURIValue&) const;
void LoadPendingResources(ComputedStyle*);
......
......@@ -135,10 +135,11 @@ scoped_refptr<ClipPathOperation> StyleBuilderConverter::ConvertClipPath(
return ShapeClipPathOperation::Create(BasicShapeForValue(state, value));
if (value.IsURIValue()) {
const CSSURIValue& url_value = ToCSSURIValue(value);
SVGElementProxy& element_proxy =
state.GetElementStyleResources().CachedOrPendingFromValue(url_value);
SVGResource* resource =
state.GetElementStyleResources().GetSVGResourceFromValue(
state.GetTreeScope(), url_value);
// TODO(fs): Doesn't work with external SVG references (crbug.com/109212.)
return ReferenceClipPathOperation::Create(url_value.Value(), element_proxy);
return ReferenceClipPathOperation::Create(url_value.Value(), resource);
}
DCHECK(value.IsIdentifierValue() &&
ToCSSIdentifierValue(value).GetValueID() == CSSValueNone);
......
......@@ -78,6 +78,10 @@ StyleResolverState::~StyleResolverState() {
animation_update_.Clear();
}
TreeScope& StyleResolverState::GetTreeScope() const {
return GetElement() ? GetElement()->GetTreeScope() : GetDocument();
}
void StyleResolverState::SetStyle(scoped_refptr<ComputedStyle> style) {
// FIXME: Improve RAII of StyleResolverState to remove this function.
style_ = std::move(style);
......
......@@ -66,6 +66,7 @@ class CORE_EXPORT StyleResolverState {
Document& GetDocument() const { return *document_; }
// These are all just pass-through methods to ElementResolveContext.
Element* GetElement() const { return element_context_.GetElement(); }
TreeScope& GetTreeScope() const;
const ContainerNode* ParentNode() const {
return element_context_.ParentNode();
}
......
......@@ -8,6 +8,7 @@
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Document.h"
#include "core/style/ComputedStyle.h"
#include "platform/MemoryCoordinator.h"
#include "platform/fonts/FontCache.h"
#include "platform/wtf/PtrUtil.h"
#include "public/platform/Platform.h"
......
......@@ -68,6 +68,8 @@ SVGElementProxySet* LayoutSVGResourceContainer::ElementProxySet() {
}
void LayoutSVGResourceContainer::NotifyContentChanged() {
if (SVGResource* resource = ResourceForContainer(*this))
resource->NotifyContentChanged();
if (SVGElementProxySet* proxy_set = ElementProxySet())
proxy_set->NotifyContentChanged(GetElement()->GetTreeScope());
}
......@@ -89,7 +91,7 @@ void LayoutSVGResourceContainer::StyleDidChange(
// resource.
if (SVGResource* resource = ResourceForContainer(*this)) {
if (resource->Target() == GetElement())
resource->NotifyResourceClients();
resource->NotifyPendingClients();
}
}
......@@ -113,8 +115,10 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
InvalidationModeMask invalidation_mask) {
if (is_invalidating_)
return;
SVGResource* resource = ResourceForContainer(*this);
SVGElementProxySet* proxy_set = ElementProxySet();
if (clients_.IsEmpty() && (!proxy_set || proxy_set->IsEmpty()))
if (clients_.IsEmpty() && (!proxy_set || proxy_set->IsEmpty()) &&
(!resource || !resource->HasClients()))
return;
// Remove modes for which invalidations have already been
// performed. If no modes remain we are done.
......@@ -142,7 +146,7 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
MarkForLayoutAndParentResourceInvalidation(*client, needs_layout);
}
// Invalidate clients registered via an SVGElementProxy.
// Invalidate clients registered via an SVGElementProxy/SVGResource.
NotifyContentChanged();
is_invalidating_ = false;
......
......@@ -51,15 +51,12 @@ LayoutSVGResourceClipper* ResolveElementReference(
return resources ? resources->Clipper() : nullptr;
}
// TODO(fs): Doesn't work with external SVG references (crbug.com/109212.)
Node* target_node = layout_object.GetNode();
if (!target_node)
SVGResource* resource = reference_clip_path_operation.Resource();
LayoutSVGResourceContainer* container =
resource ? resource->ResourceContainer() : nullptr;
if (!container || container->ResourceType() != kClipperResourceType)
return nullptr;
SVGElement* element =
reference_clip_path_operation.FindElement(target_node->GetTreeScope());
if (!IsSVGClipPathElement(element) || !element->GetLayoutObject())
return nullptr;
return ToLayoutSVGResourceClipper(
ToLayoutSVGResourceContainer(element->GetLayoutObject()));
return ToLayoutSVGResourceClipper(container);
}
} // namespace
......
......@@ -186,7 +186,7 @@ PaintLayer::~PaintLayer() {
style.Filter().RemoveClient(rare_data_->resource_info);
if (IsReferenceClipPath(style.ClipPath())) {
ToReferenceClipPathOperation(style.ClipPath())
->RemoveClient(rare_data_->resource_info);
->RemoveClient(*rare_data_->resource_info);
}
rare_data_->resource_info->ClearLayer();
}
......@@ -2325,17 +2325,13 @@ bool PaintLayer::HitTestClippedOutByClipPath(
return !clip_path->GetPath(float_reference_box).Contains(point);
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
Node* target_node = GetLayoutObject().GetNode();
if (!target_node)
SVGResource* resource =
ToReferenceClipPathOperation(*clip_path_operation).Resource();
LayoutSVGResourceContainer* container =
resource ? resource->ResourceContainer() : nullptr;
if (!container || container->ResourceType() != kClipperResourceType)
return false;
const ReferenceClipPathOperation& reference_clip_path_operation =
ToReferenceClipPathOperation(*clip_path_operation);
SVGElement* element =
reference_clip_path_operation.FindElement(target_node->GetTreeScope());
if (!IsSVGClipPathElement(element) || !element->GetLayoutObject())
return false;
LayoutSVGResourceClipper* clipper = ToLayoutSVGResourceClipper(
ToLayoutSVGResourceContainer(element->GetLayoutObject()));
auto* clipper = ToLayoutSVGResourceClipper(container);
// If the clipPath is using "userspace on use" units, then the origin of
// the coordinate system is the top-left of the reference box, so adjust
// the point accordingly.
......@@ -2931,15 +2927,11 @@ void PaintLayer::UpdateClipPath(const ComputedStyle* old_style,
const bool had_resource_info = ResourceInfo();
if (IsReferenceClipPath(new_clip_operation)) {
ToReferenceClipPathOperation(new_clip_operation)
->AddClient(&EnsureResourceInfo(),
GetLayoutObject()
.GetDocument()
.GetTaskRunner(TaskType::kUnspecedLoading)
.get());
->AddClient(EnsureResourceInfo());
}
if (had_resource_info && IsReferenceClipPath(old_clip_operation)) {
ToReferenceClipPathOperation(old_clip_operation)
->RemoveClient(ResourceInfo());
->RemoveClient(*ResourceInfo());
}
}
......
......@@ -6,26 +6,25 @@
namespace blink {
void ReferenceClipPathOperation::AddClient(
SVGResourceClient* client,
base::SingleThreadTaskRunner* task_runner) {
element_proxy_->AddClient(client, task_runner);
void ReferenceClipPathOperation::AddClient(SVGResourceClient& client) {
if (resource_)
resource_->AddClient(client);
}
void ReferenceClipPathOperation::RemoveClient(SVGResourceClient* client) {
element_proxy_->RemoveClient(client);
void ReferenceClipPathOperation::RemoveClient(SVGResourceClient& client) {
if (resource_)
resource_->RemoveClient(client);
}
SVGElement* ReferenceClipPathOperation::FindElement(
TreeScope& tree_scope) const {
return element_proxy_->FindElement(tree_scope);
SVGResource* ReferenceClipPathOperation::Resource() const {
return resource_;
}
bool ReferenceClipPathOperation::operator==(const ClipPathOperation& o) const {
if (!IsSameType(o))
return false;
const ReferenceClipPathOperation& other = ToReferenceClipPathOperation(o);
return element_proxy_ == other.element_proxy_ && url_ == other.url_;
return resource_ == other.resource_ && url_ == other.url_;
}
} // namespace blink
......@@ -32,7 +32,7 @@
#include <memory>
#include "core/style/BasicShapes.h"
#include "core/svg/SVGElementProxy.h"
#include "core/svg/SVGResource.h"
#include "platform/graphics/Path.h"
#include "platform/wtf/PtrUtil.h"
#include "platform/wtf/RefCounted.h"
......@@ -40,9 +40,7 @@
namespace blink {
class SVGElement;
class SVGResourceClient;
class TreeScope;
class ClipPathOperation : public RefCounted<ClipPathOperation> {
public:
......@@ -66,25 +64,24 @@ class ReferenceClipPathOperation final : public ClipPathOperation {
public:
static scoped_refptr<ReferenceClipPathOperation> Create(
const String& url,
SVGElementProxy& element_proxy) {
return base::AdoptRef(new ReferenceClipPathOperation(url, element_proxy));
SVGResource* resource) {
return base::AdoptRef(new ReferenceClipPathOperation(url, resource));
}
void AddClient(SVGResourceClient*, base::SingleThreadTaskRunner*);
void RemoveClient(SVGResourceClient*);
SVGElement* FindElement(TreeScope&) const;
void AddClient(SVGResourceClient&);
void RemoveClient(SVGResourceClient&);
SVGResource* Resource() const;
const String& Url() const { return url_; }
private:
bool operator==(const ClipPathOperation&) const override;
OperationType GetType() const override { return REFERENCE; }
ReferenceClipPathOperation(const String& url, SVGElementProxy& element_proxy)
: element_proxy_(&element_proxy), url_(url) {}
ReferenceClipPathOperation(const String& url, SVGResource* resource)
: resource_(resource), url_(url) {}
Persistent<SVGElementProxy> element_proxy_;
Persistent<SVGResource> resource_;
String url_;
};
......
......@@ -23,8 +23,8 @@
#include "core/svg/SVGFilterElement.h"
#include "core/frame/UseCounter.h"
#include "core/layout/svg/LayoutSVGResourceFilter.h"
#include "core/svg/SVGElementProxy.h"
namespace blink {
......
......@@ -11,6 +11,7 @@
#include "core/layout/svg/SVGResources.h"
#include "core/layout/svg/SVGResourcesCache.h"
#include "core/svg/SVGElement.h"
#include "core/svg/SVGResourceClient.h"
#include "core/svg/SVGURIReference.h"
namespace blink {
......@@ -27,9 +28,18 @@ void SVGResource::Trace(Visitor* visitor) {
visitor->Trace(tree_scope_);
visitor->Trace(target_);
visitor->Trace(id_observer_);
visitor->Trace(clients_);
visitor->Trace(pending_clients_);
}
void SVGResource::AddClient(SVGResourceClient& client) {
clients_.insert(&client);
}
void SVGResource::RemoveClient(SVGResourceClient& client) {
clients_.erase(&client);
}
void SVGResource::AddWatch(SVGElement& element) {
pending_clients_.insert(&element);
element.SetHasPendingResources();
......@@ -41,14 +51,15 @@ void SVGResource::RemoveWatch(SVGElement& element) {
bool SVGResource::IsEmpty() const {
LayoutSVGResourceContainer* container = ResourceContainer();
return (!container || !container->HasClients()) && pending_clients_.IsEmpty();
return !HasClients() && (!container || !container->HasClients()) &&
pending_clients_.IsEmpty();
}
void SVGResource::Unregister() {
SVGURIReference::UnobserveTarget(id_observer_);
}
void SVGResource::NotifyResourceClients() {
void SVGResource::NotifyPendingClients() {
HeapHashSet<Member<SVGElement>> pending_clients;
pending_clients.swap(pending_clients_);
......@@ -58,6 +69,22 @@ void SVGResource::NotifyResourceClients() {
}
}
void SVGResource::NotifyContentChanged() {
HeapVector<Member<SVGResourceClient>> clients;
CopyToVector(clients_, clients);
for (SVGResourceClient* client : clients)
client->ResourceContentChanged();
}
void SVGResource::NotifyElementChanged() {
HeapVector<Member<SVGResourceClient>> clients;
CopyToVector(clients_, clients);
for (SVGResourceClient* client : clients)
client->ResourceElementChanged();
}
LayoutSVGResourceContainer* SVGResource::ResourceContainer() const {
if (!target_)
return nullptr;
......@@ -76,7 +103,8 @@ void SVGResource::TargetChanged(const AtomicString& id) {
if (LayoutSVGResourceContainer* old_resource = ResourceContainer())
old_resource->MakeClientsPending(*this);
target_ = new_target;
NotifyResourceClients();
NotifyElementChanged();
NotifyPendingClients();
}
} // namespace blink
......@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "platform/heap/Handle.h"
#include "platform/wtf/HashCountedSet.h"
#include "platform/wtf/HashSet.h"
namespace blink {
......@@ -15,6 +16,7 @@ class Element;
class IdTargetObserver;
class LayoutSVGResourceContainer;
class SVGElement;
class SVGResourceClient;
class TreeScope;
// A class tracking a reference to an SVG resource (an element that constitutes
......@@ -26,6 +28,11 @@ class SVGResource : public GarbageCollected<SVGResource> {
Element* Target() const { return target_; }
LayoutSVGResourceContainer* ResourceContainer() const;
void AddClient(SVGResourceClient&);
void RemoveClient(SVGResourceClient&);
bool HasClients() const { return !clients_.IsEmpty(); }
void AddWatch(SVGElement&);
void RemoveWatch(SVGElement&);
......@@ -35,14 +42,17 @@ class SVGResource : public GarbageCollected<SVGResource> {
void Trace(Visitor*);
void NotifyResourceClients();
void NotifyPendingClients();
void NotifyContentChanged();
private:
void TargetChanged(const AtomicString& id);
void NotifyElementChanged();
Member<TreeScope> tree_scope_;
Member<Element> target_;
Member<IdTargetObserver> id_observer_;
HeapHashCountedSet<Member<SVGResourceClient>> clients_;
HeapHashSet<Member<SVGElement>> pending_clients_;
DISALLOW_COPY_AND_ASSIGN(SVGResource);
......
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