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" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 return; | 31 return; |
32 // Replaces resource if already present, to handle potential id changes. | 32 // Replaces resource if already present, to handle potential id changes. |
33 m_resources.set(id, resource); | 33 m_resources.set(id, resource); |
34 | 34 |
35 SVGPendingElements* pendingElements = m_pendingResources.take(id); | 35 SVGPendingElements* pendingElements = m_pendingResources.take(id); |
36 if (!pendingElements) | 36 if (!pendingElements) |
37 return; | 37 return; |
38 // Update cached resources of pending clients. | 38 // Update cached resources of pending clients. |
39 for (Element* clientElement : *pendingElements) { | 39 for (Element* clientElement : *pendingElements) { |
40 DCHECK(clientElement->hasPendingResources()); | 40 DCHECK(clientElement->hasPendingResources()); |
41 clearHasPendingResourcesIfPossible(clientElement); | 41 clearHasPendingResourcesIfPossible(*clientElement); |
42 | 42 |
43 LayoutObject* layoutObject = clientElement->layoutObject(); | 43 LayoutObject* layoutObject = clientElement->layoutObject(); |
44 if (!layoutObject) | 44 if (!layoutObject) |
45 continue; | 45 continue; |
46 DCHECK(layoutObject->isSVG()); | 46 DCHECK(layoutObject->isSVG()); |
47 | 47 |
48 StyleDifference diff; | 48 StyleDifference diff; |
49 diff.setNeedsFullLayout(); | 49 diff.setNeedsFullLayout(); |
50 SVGResourcesCache::clientStyleChanged(layoutObject, diff, | 50 SVGResourcesCache::clientStyleChanged(layoutObject, diff, |
51 layoutObject->styleRef()); | 51 layoutObject->styleRef()); |
52 layoutObject->setNeedsLayoutAndFullPaintInvalidation( | 52 layoutObject->setNeedsLayoutAndFullPaintInvalidation( |
53 LayoutInvalidationReason::SvgResourceInvalidated); | 53 LayoutInvalidationReason::SvgResourceInvalidated); |
54 } | 54 } |
55 } | 55 } |
56 | 56 |
57 void SVGTreeScopeResources::removeResource(const AtomicString& id) { | 57 void SVGTreeScopeResources::removeResource(const AtomicString& id) { |
58 if (id.isEmpty()) | 58 if (id.isEmpty()) |
59 return; | 59 return; |
60 m_resources.erase(id); | 60 m_resources.erase(id); |
61 } | 61 } |
62 | 62 |
63 LayoutSVGResourceContainer* SVGTreeScopeResources::resourceById( | 63 LayoutSVGResourceContainer* SVGTreeScopeResources::resourceById( |
64 const AtomicString& id) const { | 64 const AtomicString& id) const { |
65 if (id.isEmpty()) | 65 if (id.isEmpty()) |
66 return nullptr; | 66 return nullptr; |
67 return m_resources.get(id); | 67 return m_resources.get(id); |
68 } | 68 } |
69 | 69 |
70 void SVGTreeScopeResources::addPendingResource(const AtomicString& id, | 70 void SVGTreeScopeResources::addPendingResource(const AtomicString& id, |
71 Element* element) { | 71 Element& element) { |
72 DCHECK(element); | 72 DCHECK(element.isConnected()); |
73 DCHECK(element->isConnected()); | |
74 | 73 |
75 if (id.isEmpty()) | 74 if (id.isEmpty()) |
76 return; | 75 return; |
77 | 76 auto result = m_pendingResources.insert(id, nullptr); |
78 HeapHashMap<AtomicString, Member<SVGPendingElements>>::AddResult result = | |
79 m_pendingResources.insert(id, nullptr); | |
80 if (result.isNewEntry) | 77 if (result.isNewEntry) |
81 result.storedValue->value = new SVGPendingElements; | 78 result.storedValue->value = new SVGPendingElements; |
82 result.storedValue->value->insert(element); | 79 result.storedValue->value->insert(&element); |
83 | 80 |
84 element->setHasPendingResources(); | 81 element.setHasPendingResources(); |
85 } | 82 } |
86 | 83 |
87 bool SVGTreeScopeResources::hasPendingResource(const AtomicString& id) const { | 84 bool SVGTreeScopeResources::isElementPendingResource( |
85 Element& element, | |
86 const AtomicString& id) const { | |
88 if (id.isEmpty()) | 87 if (id.isEmpty()) |
89 return false; | 88 return false; |
90 return m_pendingResources.contains(id); | 89 const SVGPendingElements* pendingElements = m_pendingResources.get(id); |
90 return pendingElements && pendingElements->contains(&element); | |
91 } | 91 } |
92 | 92 |
93 bool SVGTreeScopeResources::isElementPendingResources(Element* element) const { | 93 void SVGTreeScopeResources::clearHasPendingResourcesIfPossible( |
94 Element& element) { | |
94 // This algorithm takes time proportional to the number of pending resources | 95 // This algorithm takes time proportional to the number of pending resources |
95 // and need not. | 96 // and need not. |
96 // If performance becomes an issue we can keep a counted set of elements and | 97 // If performance becomes an issue we can keep a counted set of elements and |
97 // answer the question efficiently. | 98 // answer the question efficiently. |
98 DCHECK(element); | |
99 | |
100 for (const auto& entry : m_pendingResources) { | 99 for (const auto& entry : m_pendingResources) { |
101 SVGPendingElements* elements = entry.value.get(); | 100 SVGPendingElements* elements = entry.value.get(); |
102 DCHECK(elements); | 101 DCHECK(elements); |
103 if (elements->contains(element)) | 102 if (elements->contains(&element)) |
104 return true; | 103 return; |
105 } | 104 } |
106 return false; | 105 element.clearHasPendingResources(); |
107 } | |
108 | |
109 bool SVGTreeScopeResources::isElementPendingResource( | |
110 Element* element, | |
111 const AtomicString& id) const { | |
112 DCHECK(element); | |
113 if (!hasPendingResource(id)) | |
114 return false; | |
115 return m_pendingResources.get(id)->contains(element); | |
116 } | |
117 | |
118 void SVGTreeScopeResources::clearHasPendingResourcesIfPossible( | |
119 Element* element) { | |
120 if (!isElementPendingResources(element)) | |
121 element->clearHasPendingResources(); | |
122 } | 106 } |
123 | 107 |
124 void SVGTreeScopeResources::removeElementFromPendingResources( | 108 void SVGTreeScopeResources::removeElementFromPendingResources( |
125 Element* element) { | 109 Element& element) { |
126 DCHECK(element); | 110 if (m_pendingResources.isEmpty() || !element.hasPendingResources()) |
111 return; | |
112 // Remove the element from pending resources. | |
113 Vector<AtomicString> toBeRemoved; | |
114 for (const auto& entry : m_pendingResources) { | |
115 SVGPendingElements* elements = entry.value.get(); | |
116 DCHECK(elements); | |
117 DCHECK(!elements->isEmpty()); | |
127 | 118 |
128 // Remove the element from pending resources. | 119 elements->erase(&element); |
129 if (!m_pendingResources.isEmpty() && element->hasPendingResources()) { | 120 if (elements->isEmpty()) |
130 Vector<AtomicString> toBeRemoved; | 121 toBeRemoved.push_back(entry.key); |
131 for (const auto& entry : m_pendingResources) { | 122 } |
132 SVGPendingElements* elements = entry.value.get(); | 123 m_pendingResources.removeAll(toBeRemoved); |
Stephen Chennney
2017/02/23 17:00:50
From memory this has to come after the clearHasPen
fs
2017/02/23 17:10:45
This structure is on the GC-heap, so if there're a
| |
133 DCHECK(elements); | |
134 DCHECK(!elements->isEmpty()); | |
135 | 124 |
136 elements->erase(element); | 125 clearHasPendingResourcesIfPossible(element); |
137 if (elements->isEmpty()) | |
138 toBeRemoved.push_back(entry.key); | |
139 } | |
140 | |
141 clearHasPendingResourcesIfPossible(element); | |
142 | |
143 // We use the removePendingResource function here because it deals with set | |
144 // lifetime correctly. | |
145 for (const AtomicString& id : toBeRemoved) | |
146 removePendingResource(id); | |
147 } | |
148 } | |
149 | |
150 SVGTreeScopeResources::SVGPendingElements* | |
151 SVGTreeScopeResources::removePendingResource(const AtomicString& id) { | |
152 DCHECK(m_pendingResources.contains(id)); | |
153 return m_pendingResources.take(id); | |
154 } | 126 } |
155 | 127 |
156 void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) { | 128 void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) { |
157 if (id.isEmpty()) | 129 if (id.isEmpty()) |
158 return; | 130 return; |
159 // Get pending elements for this id. | 131 // Get pending elements for this id. |
160 SVGPendingElements* pendingElements = m_pendingResources.take(id); | 132 SVGPendingElements* pendingElements = m_pendingResources.take(id); |
161 if (!pendingElements) | 133 if (!pendingElements) |
162 return; | 134 return; |
163 // Rebuild pending resources for each client of a pending resource that is | 135 // Rebuild pending resources for each client of a pending resource that is |
164 // being removed. | 136 // being removed. |
165 for (Element* clientElement : *pendingElements) { | 137 for (Element* clientElement : *pendingElements) { |
166 DCHECK(clientElement->hasPendingResources()); | 138 DCHECK(clientElement->hasPendingResources()); |
167 if (!clientElement->hasPendingResources()) | 139 if (!clientElement->hasPendingResources()) |
168 continue; | 140 continue; |
169 // TODO(fs): Ideally we'd always resolve pending resources async instead of | 141 // TODO(fs): Ideally we'd always resolve pending resources async instead of |
170 // inside insertedInto and svgAttributeChanged. For now we only do it for | 142 // inside insertedInto and svgAttributeChanged. For now we only do it for |
171 // <use> since that would stamp out DOM. | 143 // <use> since that would stamp out DOM. |
172 if (isSVGUseElement(clientElement)) | 144 if (isSVGUseElement(clientElement)) |
173 toSVGUseElement(clientElement)->invalidateShadowTree(); | 145 toSVGUseElement(clientElement)->invalidateShadowTree(); |
174 else | 146 else |
175 clientElement->buildPendingResource(); | 147 clientElement->buildPendingResource(); |
176 | 148 |
177 clearHasPendingResourcesIfPossible(clientElement); | 149 clearHasPendingResourcesIfPossible(*clientElement); |
178 } | 150 } |
179 } | 151 } |
180 | 152 |
181 DEFINE_TRACE(SVGTreeScopeResources) { | 153 DEFINE_TRACE(SVGTreeScopeResources) { |
182 visitor->trace(m_pendingResources); | 154 visitor->trace(m_pendingResources); |
183 } | 155 } |
184 } | 156 } |
OLD | NEW |