OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/svg/SVGTreeScopeResources.h" | 5 #include "core/svg/SVGTreeScopeResources.h" |
6 | 6 |
7 #include "core/dom/Element.h" | 7 #include "core/dom/Element.h" |
8 #include "core/dom/TreeScope.h" | 8 #include "core/dom/TreeScope.h" |
9 #include "core/layout/svg/LayoutSVGResourceContainer.h" | 9 #include "core/layout/svg/LayoutSVGResourceContainer.h" |
10 #include "core/layout/svg/SVGResourcesCache.h" | 10 #include "core/layout/svg/SVGResourcesCache.h" |
11 #include "core/svg/SVGUseElement.h" | 11 #include "core/svg/SVGUseElement.h" |
12 #include "wtf/text/AtomicString.h" | 12 #include "wtf/text/AtomicString.h" |
13 | 13 |
14 namespace blink { | 14 namespace blink { |
15 | 15 |
16 SVGTreeScopeResources::SVGTreeScopeResources(TreeScope* treeScope) { | 16 SVGTreeScopeResources::SVGTreeScopeResources(TreeScope* treeScope) |
17 : m_treeScope(treeScope) { | |
17 // Whenever an object of SVGTreeScopeResources is created, to keep the code | 18 // Whenever an object of SVGTreeScopeResources is created, to keep the code |
18 // behave as before, | 19 // behave as before, |
19 // the document should also have an instance of SVGDocumentExtensions created. | 20 // the document should also have an instance of SVGDocumentExtensions created. |
20 // Thus below line is added. | 21 // Thus below line is added. |
21 treeScope->document().accessSVGExtensions(); | 22 treeScope->document().accessSVGExtensions(); |
22 } | 23 } |
23 | 24 |
24 SVGTreeScopeResources::~SVGTreeScopeResources() = default; | 25 SVGTreeScopeResources::~SVGTreeScopeResources() = default; |
25 | 26 |
27 static LayoutSVGResourceContainer* lookupResource(TreeScope& treeScope, | |
pdr.
2017/02/27 23:06:30
Should this lookup ever fail? I am wondering if we
fs
2017/03/06 20:49:54
Besides the LayoutObject type-check, it's expected
| |
28 const AtomicString& id) { | |
29 Element* element = treeScope.getElementById(id); | |
30 if (!element) | |
31 return nullptr; | |
32 LayoutObject* layoutObject = element->layoutObject(); | |
33 if (!layoutObject || !layoutObject->isSVGResourceContainer()) | |
34 return nullptr; | |
35 return toLayoutSVGResourceContainer(layoutObject); | |
36 } | |
37 | |
26 void SVGTreeScopeResources::updateResource( | 38 void SVGTreeScopeResources::updateResource( |
27 const AtomicString& id, | 39 const AtomicString& id, |
28 LayoutSVGResourceContainer* resource) { | 40 LayoutSVGResourceContainer* resource) { |
29 DCHECK(resource); | 41 DCHECK(resource); |
30 if (id.isEmpty()) | 42 if (resource->isRegistered() || id.isEmpty()) |
31 return; | 43 return; |
32 // Replaces resource if already present, to handle potential id changes. | 44 // Lookup the current resource. (Could differ from what's in the map if an |
33 m_resources.set(id, resource); | 45 // element was just added/removed.) |
34 | 46 LayoutSVGResourceContainer* currentResource = |
35 SVGPendingElements* pendingElements = m_pendingResources.take(id); | 47 lookupResource(*m_treeScope, id); |
36 if (!pendingElements) | 48 // Lookup the currently registered resource. |
37 return; | 49 auto it = m_resources.find(id); |
38 // Update cached resources of pending clients. | 50 if (it != m_resources.end()) { |
39 for (Element* clientElement : *pendingElements) { | 51 // Is the local map up-to-date already? |
40 DCHECK(clientElement->hasPendingResources()); | 52 if (it->value == currentResource) |
41 clearHasPendingResourcesIfPossible(*clientElement); | 53 return; |
42 | 54 unregisterResource(it); |
43 LayoutObject* layoutObject = clientElement->layoutObject(); | |
44 if (!layoutObject) | |
45 continue; | |
46 DCHECK(layoutObject->isSVG()); | |
47 | |
48 StyleDifference diff; | |
49 diff.setNeedsFullLayout(); | |
50 SVGResourcesCache::clientStyleChanged(layoutObject, diff, | |
51 layoutObject->styleRef()); | |
52 layoutObject->setNeedsLayoutAndFullPaintInvalidation( | |
53 LayoutInvalidationReason::SvgResourceInvalidated); | |
54 } | 55 } |
56 if (currentResource) | |
57 registerResource(id, currentResource); | |
55 } | 58 } |
56 | 59 |
57 void SVGTreeScopeResources::removeResource(const AtomicString& id) { | 60 void SVGTreeScopeResources::updateResource( |
58 if (id.isEmpty()) | 61 const AtomicString& oldId, |
62 const AtomicString& newId, | |
63 LayoutSVGResourceContainer* resource) { | |
64 removeResource(oldId, resource); | |
65 updateResource(newId, resource); | |
66 } | |
67 | |
68 void SVGTreeScopeResources::removeResource( | |
69 const AtomicString& id, | |
70 LayoutSVGResourceContainer* resource) { | |
71 DCHECK(resource); | |
72 if (!resource->isRegistered() || id.isEmpty()) | |
59 return; | 73 return; |
60 m_resources.erase(id); | 74 auto it = m_resources.find(id); |
75 // If this is not the currently registered resource for this id, then do | |
76 // nothing. | |
77 if (it == m_resources.end() || it->value != resource) | |
78 return; | |
79 unregisterResource(it); | |
80 // If the layout tree is being torn down, then don't attempt to update the | |
81 // map, since that layout object is likely to be stale already. | |
82 if (resource->documentBeingDestroyed()) | |
83 return; | |
84 // Another resource could now be current. Perform a lookup and potentially | |
85 // update the map. | |
86 LayoutSVGResourceContainer* currentResource = | |
87 lookupResource(*m_treeScope, id); | |
88 if (!currentResource) | |
89 return; | |
90 // Since this is a removal, don't allow re-adding the resource. | |
91 if (currentResource == resource) | |
92 return; | |
93 registerResource(id, currentResource); | |
94 } | |
95 | |
96 void SVGTreeScopeResources::registerResource( | |
97 const AtomicString& id, | |
98 LayoutSVGResourceContainer* resource) { | |
99 DCHECK(!id.isEmpty()); | |
100 DCHECK(resource); | |
101 DCHECK(!resource->isRegistered()); | |
102 | |
103 m_resources.set(id, resource); | |
104 resource->setRegistered(true); | |
105 | |
106 notifyPendingClients(id); | |
107 } | |
108 | |
109 void SVGTreeScopeResources::unregisterResource(ResourceMap::iterator it) { | |
110 LayoutSVGResourceContainer* resource = it->value; | |
111 DCHECK(resource); | |
112 DCHECK(resource->isRegistered()); | |
113 | |
114 resource->detachAllClients(it->key); | |
115 | |
116 resource->setRegistered(false); | |
117 m_resources.remove(it); | |
61 } | 118 } |
62 | 119 |
63 LayoutSVGResourceContainer* SVGTreeScopeResources::resourceById( | 120 LayoutSVGResourceContainer* SVGTreeScopeResources::resourceById( |
64 const AtomicString& id) const { | 121 const AtomicString& id) const { |
65 if (id.isEmpty()) | 122 if (id.isEmpty()) |
66 return nullptr; | 123 return nullptr; |
67 return m_resources.at(id); | 124 return m_resources.at(id); |
68 } | 125 } |
69 | 126 |
70 void SVGTreeScopeResources::addPendingResource(const AtomicString& id, | 127 void SVGTreeScopeResources::addPendingResource(const AtomicString& id, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 | 175 |
119 elements->erase(&element); | 176 elements->erase(&element); |
120 if (elements->isEmpty()) | 177 if (elements->isEmpty()) |
121 toBeRemoved.push_back(entry.key); | 178 toBeRemoved.push_back(entry.key); |
122 } | 179 } |
123 m_pendingResources.removeAll(toBeRemoved); | 180 m_pendingResources.removeAll(toBeRemoved); |
124 | 181 |
125 clearHasPendingResourcesIfPossible(element); | 182 clearHasPendingResourcesIfPossible(element); |
126 } | 183 } |
127 | 184 |
185 void SVGTreeScopeResources::notifyPendingClients(const AtomicString& id) { | |
186 DCHECK(!id.isEmpty()); | |
187 SVGPendingElements* pendingElements = m_pendingResources.take(id); | |
188 if (!pendingElements) | |
189 return; | |
190 // Update cached resources of pending clients. | |
191 for (Element* clientElement : *pendingElements) { | |
192 DCHECK(clientElement->hasPendingResources()); | |
193 clearHasPendingResourcesIfPossible(*clientElement); | |
194 | |
195 LayoutObject* layoutObject = clientElement->layoutObject(); | |
196 if (!layoutObject) | |
197 continue; | |
198 DCHECK(layoutObject->isSVG()); | |
199 | |
200 StyleDifference diff; | |
201 diff.setNeedsFullLayout(); | |
202 SVGResourcesCache::clientStyleChanged(layoutObject, diff, | |
203 layoutObject->styleRef()); | |
204 layoutObject->setNeedsLayoutAndFullPaintInvalidation( | |
205 LayoutInvalidationReason::SvgResourceInvalidated); | |
206 } | |
207 } | |
208 | |
128 void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) { | 209 void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) { |
129 if (id.isEmpty()) | 210 if (id.isEmpty()) |
130 return; | 211 return; |
131 // Get pending elements for this id. | 212 // Get pending elements for this id. |
132 SVGPendingElements* pendingElements = m_pendingResources.take(id); | 213 SVGPendingElements* pendingElements = m_pendingResources.take(id); |
133 if (!pendingElements) | 214 if (!pendingElements) |
134 return; | 215 return; |
135 // Rebuild pending resources for each client of a pending resource that is | 216 // Rebuild pending resources for each client of a pending resource that is |
136 // being removed. | 217 // being removed. |
137 for (Element* clientElement : *pendingElements) { | 218 for (Element* clientElement : *pendingElements) { |
138 DCHECK(clientElement->hasPendingResources()); | 219 DCHECK(clientElement->hasPendingResources()); |
139 if (!clientElement->hasPendingResources()) | 220 if (!clientElement->hasPendingResources()) |
140 continue; | 221 continue; |
141 // TODO(fs): Ideally we'd always resolve pending resources async instead of | 222 // TODO(fs): Ideally we'd always resolve pending resources async instead of |
142 // inside insertedInto and svgAttributeChanged. For now we only do it for | 223 // inside insertedInto and svgAttributeChanged. For now we only do it for |
143 // <use> since that would stamp out DOM. | 224 // <use> since that would stamp out DOM. |
144 if (isSVGUseElement(clientElement)) | 225 if (isSVGUseElement(clientElement)) |
145 toSVGUseElement(clientElement)->invalidateShadowTree(); | 226 toSVGUseElement(clientElement)->invalidateShadowTree(); |
146 else | 227 else |
147 clientElement->buildPendingResource(); | 228 clientElement->buildPendingResource(); |
148 | 229 |
149 clearHasPendingResourcesIfPossible(*clientElement); | 230 clearHasPendingResourcesIfPossible(*clientElement); |
150 } | 231 } |
151 } | 232 } |
152 | 233 |
153 DEFINE_TRACE(SVGTreeScopeResources) { | 234 DEFINE_TRACE(SVGTreeScopeResources) { |
154 visitor->trace(m_pendingResources); | 235 visitor->trace(m_pendingResources); |
236 visitor->trace(m_treeScope); | |
155 } | 237 } |
156 } | 238 } |
OLD | NEW |