Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / rendering / svg / SVGResourcesCache.cpp
1 /*
2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "SVGResourcesCache.h"
22
23 #include "RenderSVGResourceContainer.h"
24 #include "SVGResources.h"
25 #include "SVGResourcesCycleSolver.h"
26
27 namespace WebCore {
28
29 SVGResourcesCache::SVGResourcesCache() = default;
30
31 SVGResourcesCache::~SVGResourcesCache() = default;
32
33 void SVGResourcesCache::addResourcesFromRenderer(RenderElement& renderer, const RenderStyle& style)
34 {
35     ASSERT(!m_cache.contains(&renderer));
36
37     // Build a list of all resources associated with the passed RenderObject
38     auto newResources = std::make_unique<SVGResources>();
39     if (!newResources->buildCachedResources(renderer, style))
40         return;
41
42     // Put object in cache.
43     SVGResources& resources = *m_cache.add(&renderer, WTFMove(newResources)).iterator->value;
44
45     // Run cycle-detection _afterwards_, so self-references can be caught as well.
46     SVGResourcesCycleSolver solver(renderer, resources);
47     solver.resolveCycles();
48
49     // Walk resources and register the render object at each resources.
50     HashSet<RenderSVGResourceContainer*> resourceSet;
51     resources.buildSetOfResources(resourceSet);
52
53     for (auto* resourceContainer : resourceSet)
54         resourceContainer->addClient(renderer);
55 }
56
57 void SVGResourcesCache::removeResourcesFromRenderer(RenderElement& renderer)
58 {
59     std::unique_ptr<SVGResources> resources = m_cache.take(&renderer);
60     if (!resources)
61         return;
62
63     // Walk resources and register the render object at each resources.
64     HashSet<RenderSVGResourceContainer*> resourceSet;
65     resources->buildSetOfResources(resourceSet);
66
67     for (auto* resourceContainer : resourceSet)
68         resourceContainer->removeClient(renderer);
69 }
70
71 static inline SVGResourcesCache& resourcesCacheFromRenderer(const RenderElement& renderer)
72 {
73     return renderer.document().accessSVGExtensions().resourcesCache();
74 }
75
76 SVGResources* SVGResourcesCache::cachedResourcesForRenderer(const RenderElement& renderer)
77 {
78     return resourcesCacheFromRenderer(renderer).m_cache.get(&renderer);
79 }
80
81 void SVGResourcesCache::clientLayoutChanged(RenderElement& renderer)
82 {
83     auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer);
84     if (!resources)
85         return;
86
87     // Invalidate the resources if either the RenderElement itself changed,
88     // or we have filter resources, which could depend on the layout of children.
89     if (renderer.selfNeedsLayout())
90         resources->removeClientFromCache(renderer);
91 }
92
93 static inline bool rendererCanHaveResources(RenderObject& renderer)
94 {
95     return renderer.node() && renderer.node()->isSVGElement() && !renderer.isSVGInlineText();
96 }
97
98 void SVGResourcesCache::clientStyleChanged(RenderElement& renderer, StyleDifference diff, const RenderStyle& newStyle)
99 {
100     if (diff == StyleDifferenceEqual || !renderer.parent())
101         return;
102
103     // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint.
104     if (renderer.isSVGResourceFilterPrimitive() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrBorderOrOutline))
105         return;
106
107     // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer.
108     // FIXME: Avoid passing in a useless StyleDifference, but instead compare oldStyle/newStyle to see which resources changed
109     // to be able to selectively rebuild individual resources, instead of all of them.
110     if (rendererCanHaveResources(renderer)) {
111         auto& cache = resourcesCacheFromRenderer(renderer);
112         cache.removeResourcesFromRenderer(renderer);
113         cache.addResourcesFromRenderer(renderer, newStyle);
114     }
115
116     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
117
118     if (renderer.element() && !renderer.element()->isSVGElement())
119         renderer.element()->invalidateStyleAndLayerComposition();
120 }
121
122 void SVGResourcesCache::clientWasAddedToTree(RenderObject& renderer)
123 {
124     if (renderer.isAnonymous())
125         return;
126
127     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
128
129     if (!rendererCanHaveResources(renderer))
130         return;
131     RenderElement& elementRenderer = downcast<RenderElement>(renderer);
132     resourcesCacheFromRenderer(elementRenderer).addResourcesFromRenderer(elementRenderer, elementRenderer.style());
133 }
134
135 void SVGResourcesCache::clientWillBeRemovedFromTree(RenderObject& renderer)
136 {
137     if (renderer.isAnonymous())
138         return;
139
140     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
141
142     if (!rendererCanHaveResources(renderer))
143         return;
144     RenderElement& elementRenderer = downcast<RenderElement>(renderer);
145     resourcesCacheFromRenderer(elementRenderer).removeResourcesFromRenderer(elementRenderer);
146 }
147
148 void SVGResourcesCache::clientDestroyed(RenderElement& renderer)
149 {
150     if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer))
151         resources->removeClientFromCache(renderer);
152
153     resourcesCacheFromRenderer(renderer).removeResourcesFromRenderer(renderer);
154 }
155
156 void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer& resource)
157 {
158     auto& cache = resourcesCacheFromRenderer(resource);
159
160     // The resource itself may have clients, that need to be notified.
161     cache.removeResourcesFromRenderer(resource);
162
163     for (auto& it : cache.m_cache) {
164         it.value->resourceDestroyed(resource);
165
166         // Mark users of destroyed resources as pending resolution based on the id of the old resource.
167         Element& resourceElement = resource.element();
168         Element* clientElement = it.key->element();
169         clientElement->document().accessSVGExtensions().addPendingResource(resourceElement.getIdAttribute(), clientElement);
170     }
171 }
172
173 }