| 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, |
| 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 |