| Index: third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
|
| diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
|
| index 2dddc1bee94d4365a630291d6d36bc96f5516dd7..adc9fe6908f8b9db06a5f46b64bf55a87c60eb6e 100644
|
| --- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
|
| +++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
|
| @@ -13,7 +13,8 @@
|
|
|
| namespace blink {
|
|
|
| -SVGTreeScopeResources::SVGTreeScopeResources(TreeScope* treeScope) {
|
| +SVGTreeScopeResources::SVGTreeScopeResources(TreeScope* treeScope)
|
| + : m_treeScope(treeScope) {
|
| // Whenever an object of SVGTreeScopeResources is created, to keep the code
|
| // behave as before,
|
| // the document should also have an instance of SVGDocumentExtensions created.
|
| @@ -23,41 +24,97 @@ SVGTreeScopeResources::SVGTreeScopeResources(TreeScope* treeScope) {
|
|
|
| SVGTreeScopeResources::~SVGTreeScopeResources() = default;
|
|
|
| +static LayoutSVGResourceContainer* lookupResource(TreeScope& treeScope,
|
| + const AtomicString& id) {
|
| + Element* element = treeScope.getElementById(id);
|
| + if (!element)
|
| + return nullptr;
|
| + LayoutObject* layoutObject = element->layoutObject();
|
| + if (!layoutObject || !layoutObject->isSVGResourceContainer())
|
| + return nullptr;
|
| + return toLayoutSVGResourceContainer(layoutObject);
|
| +}
|
| +
|
| void SVGTreeScopeResources::updateResource(
|
| const AtomicString& id,
|
| LayoutSVGResourceContainer* resource) {
|
| DCHECK(resource);
|
| - if (id.isEmpty())
|
| + if (resource->isRegistered() || id.isEmpty())
|
| return;
|
| - // Replaces resource if already present, to handle potential id changes.
|
| - m_resources.set(id, resource);
|
| + // Lookup the current resource. (Could differ from what's in the map if an
|
| + // element was just added/removed.)
|
| + LayoutSVGResourceContainer* currentResource =
|
| + lookupResource(*m_treeScope, id);
|
| + // Lookup the currently registered resource.
|
| + auto it = m_resources.find(id);
|
| + if (it != m_resources.end()) {
|
| + // Is the local map up-to-date already?
|
| + if (it->value == currentResource)
|
| + return;
|
| + unregisterResource(it);
|
| + }
|
| + if (currentResource)
|
| + registerResource(id, currentResource);
|
| +}
|
|
|
| - SVGPendingElements* pendingElements = m_pendingResources.take(id);
|
| - if (!pendingElements)
|
| +void SVGTreeScopeResources::updateResource(
|
| + const AtomicString& oldId,
|
| + const AtomicString& newId,
|
| + LayoutSVGResourceContainer* resource) {
|
| + removeResource(oldId, resource);
|
| + updateResource(newId, resource);
|
| +}
|
| +
|
| +void SVGTreeScopeResources::removeResource(
|
| + const AtomicString& id,
|
| + LayoutSVGResourceContainer* resource) {
|
| + DCHECK(resource);
|
| + if (!resource->isRegistered() || id.isEmpty())
|
| return;
|
| - // Update cached resources of pending clients.
|
| - for (Element* clientElement : *pendingElements) {
|
| - DCHECK(clientElement->hasPendingResources());
|
| - clearHasPendingResourcesIfPossible(*clientElement);
|
| + auto it = m_resources.find(id);
|
| + // If this is not the currently registered resource for this id, then do
|
| + // nothing.
|
| + if (it == m_resources.end() || it->value != resource)
|
| + return;
|
| + unregisterResource(it);
|
| + // If the layout tree is being torn down, then don't attempt to update the
|
| + // map, since that layout object is likely to be stale already.
|
| + if (resource->documentBeingDestroyed())
|
| + return;
|
| + // Another resource could now be current. Perform a lookup and potentially
|
| + // update the map.
|
| + LayoutSVGResourceContainer* currentResource =
|
| + lookupResource(*m_treeScope, id);
|
| + if (!currentResource)
|
| + return;
|
| + // Since this is a removal, don't allow re-adding the resource.
|
| + if (currentResource == resource)
|
| + return;
|
| + registerResource(id, currentResource);
|
| +}
|
|
|
| - LayoutObject* layoutObject = clientElement->layoutObject();
|
| - if (!layoutObject)
|
| - continue;
|
| - DCHECK(layoutObject->isSVG());
|
| +void SVGTreeScopeResources::registerResource(
|
| + const AtomicString& id,
|
| + LayoutSVGResourceContainer* resource) {
|
| + DCHECK(!id.isEmpty());
|
| + DCHECK(resource);
|
| + DCHECK(!resource->isRegistered());
|
|
|
| - StyleDifference diff;
|
| - diff.setNeedsFullLayout();
|
| - SVGResourcesCache::clientStyleChanged(layoutObject, diff,
|
| - layoutObject->styleRef());
|
| - layoutObject->setNeedsLayoutAndFullPaintInvalidation(
|
| - LayoutInvalidationReason::SvgResourceInvalidated);
|
| - }
|
| + m_resources.set(id, resource);
|
| + resource->setRegistered(true);
|
| +
|
| + notifyPendingClients(id);
|
| }
|
|
|
| -void SVGTreeScopeResources::removeResource(const AtomicString& id) {
|
| - if (id.isEmpty())
|
| - return;
|
| - m_resources.erase(id);
|
| +void SVGTreeScopeResources::unregisterResource(ResourceMap::iterator it) {
|
| + LayoutSVGResourceContainer* resource = it->value;
|
| + DCHECK(resource);
|
| + DCHECK(resource->isRegistered());
|
| +
|
| + resource->detachAllClients(it->key);
|
| +
|
| + resource->setRegistered(false);
|
| + m_resources.remove(it);
|
| }
|
|
|
| LayoutSVGResourceContainer* SVGTreeScopeResources::resourceById(
|
| @@ -125,6 +182,30 @@ void SVGTreeScopeResources::removeElementFromPendingResources(
|
| clearHasPendingResourcesIfPossible(element);
|
| }
|
|
|
| +void SVGTreeScopeResources::notifyPendingClients(const AtomicString& id) {
|
| + DCHECK(!id.isEmpty());
|
| + SVGPendingElements* pendingElements = m_pendingResources.take(id);
|
| + if (!pendingElements)
|
| + return;
|
| + // Update cached resources of pending clients.
|
| + for (Element* clientElement : *pendingElements) {
|
| + DCHECK(clientElement->hasPendingResources());
|
| + clearHasPendingResourcesIfPossible(*clientElement);
|
| +
|
| + LayoutObject* layoutObject = clientElement->layoutObject();
|
| + if (!layoutObject)
|
| + continue;
|
| + DCHECK(layoutObject->isSVG());
|
| +
|
| + StyleDifference diff;
|
| + diff.setNeedsFullLayout();
|
| + SVGResourcesCache::clientStyleChanged(layoutObject, diff,
|
| + layoutObject->styleRef());
|
| + layoutObject->setNeedsLayoutAndFullPaintInvalidation(
|
| + LayoutInvalidationReason::SvgResourceInvalidated);
|
| + }
|
| +}
|
| +
|
| void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) {
|
| if (id.isEmpty())
|
| return;
|
| @@ -152,5 +233,6 @@ void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) {
|
|
|
| DEFINE_TRACE(SVGTreeScopeResources) {
|
| visitor->trace(m_pendingResources);
|
| + visitor->trace(m_treeScope);
|
| }
|
| }
|
|
|