Replace WTF::move with WTFMove
[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 "HTMLNames.h"
24 #include "RenderSVGResourceContainer.h"
25 #include "SVGResources.h"
26 #include "SVGResourcesCycleSolver.h"
27
28 namespace WebCore {
29
30 SVGResourcesCache::SVGResourcesCache()
31 {
32 }
33
34 SVGResourcesCache::~SVGResourcesCache()
35 {
36 }
37
38 void SVGResourcesCache::addResourcesFromRenderer(RenderElement& renderer, const RenderStyle& style)
39 {
40     ASSERT(!m_cache.contains(&renderer));
41
42     // Build a list of all resources associated with the passed RenderObject
43     auto newResources = std::make_unique<SVGResources>();
44     if (!newResources->buildCachedResources(renderer, style))
45         return;
46
47     // Put object in cache.
48     SVGResources& resources = *m_cache.add(&renderer, WTFMove(newResources)).iterator->value;
49
50     // Run cycle-detection _afterwards_, so self-references can be caught as well.
51     SVGResourcesCycleSolver solver(renderer, resources);
52     solver.resolveCycles();
53
54     // Walk resources and register the render object at each resources.
55     HashSet<RenderSVGResourceContainer*> resourceSet;
56     resources.buildSetOfResources(resourceSet);
57
58     for (auto* resourceContainer : resourceSet)
59         resourceContainer->addClient(renderer);
60 }
61
62 void SVGResourcesCache::removeResourcesFromRenderer(RenderElement& renderer)
63 {
64     std::unique_ptr<SVGResources> resources = m_cache.take(&renderer);
65     if (!resources)
66         return;
67
68     // Walk resources and register the render object at each resources.
69     HashSet<RenderSVGResourceContainer*> resourceSet;
70     resources->buildSetOfResources(resourceSet);
71
72     for (auto* resourceContainer : resourceSet)
73         resourceContainer->removeClient(renderer);
74 }
75
76 static inline SVGResourcesCache& resourcesCacheFromRenderer(const RenderElement& renderer)
77 {
78     return renderer.document().accessSVGExtensions().resourcesCache();
79 }
80
81 SVGResources* SVGResourcesCache::cachedResourcesForRenderer(const RenderElement& renderer)
82 {
83     return resourcesCacheFromRenderer(renderer).m_cache.get(&renderer);
84 }
85
86 void SVGResourcesCache::clientLayoutChanged(RenderElement& renderer)
87 {
88     auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer);
89     if (!resources)
90         return;
91
92     // Invalidate the resources if either the RenderElement itself changed,
93     // or we have filter resources, which could depend on the layout of children.
94     if (renderer.selfNeedsLayout())
95         resources->removeClientFromCache(renderer);
96 }
97
98 static inline bool rendererCanHaveResources(RenderObject& renderer)
99 {
100     return renderer.node() && renderer.node()->isSVGElement() && !renderer.isSVGInlineText();
101 }
102
103 void SVGResourcesCache::clientStyleChanged(RenderElement& renderer, StyleDifference diff, const RenderStyle& newStyle)
104 {
105     if (diff == StyleDifferenceEqual || !renderer.parent())
106         return;
107
108     // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint.
109     if (renderer.isSVGResourceFilterPrimitive() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrBorderOrOutline))
110         return;
111
112     // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer.
113     // FIXME: Avoid passing in a useless StyleDifference, but instead compare oldStyle/newStyle to see which resources changed
114     // to be able to selectively rebuild individual resources, instead of all of them.
115     if (rendererCanHaveResources(renderer)) {
116         auto& cache = resourcesCacheFromRenderer(renderer);
117         cache.removeResourcesFromRenderer(renderer);
118         cache.addResourcesFromRenderer(renderer, newStyle);
119     }
120
121     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
122
123     if (renderer.element() && !renderer.element()->isSVGElement())
124         renderer.element()->setNeedsStyleRecalc(SyntheticStyleChange);
125 }
126
127 void SVGResourcesCache::clientWasAddedToTree(RenderObject& renderer)
128 {
129     if (renderer.isAnonymous())
130         return;
131
132     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
133
134     if (!rendererCanHaveResources(renderer))
135         return;
136     RenderElement& elementRenderer = downcast<RenderElement>(renderer);
137     resourcesCacheFromRenderer(elementRenderer).addResourcesFromRenderer(elementRenderer, elementRenderer.style());
138 }
139
140 void SVGResourcesCache::clientWillBeRemovedFromTree(RenderObject& renderer)
141 {
142     if (renderer.isAnonymous())
143         return;
144
145     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
146
147     if (!rendererCanHaveResources(renderer))
148         return;
149     RenderElement& elementRenderer = downcast<RenderElement>(renderer);
150     resourcesCacheFromRenderer(elementRenderer).removeResourcesFromRenderer(elementRenderer);
151 }
152
153 void SVGResourcesCache::clientDestroyed(RenderElement& renderer)
154 {
155     if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer))
156         resources->removeClientFromCache(renderer);
157
158     resourcesCacheFromRenderer(renderer).removeResourcesFromRenderer(renderer);
159 }
160
161 void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer& resource)
162 {
163     auto& cache = resourcesCacheFromRenderer(resource);
164
165     // The resource itself may have clients, that need to be notified.
166     cache.removeResourcesFromRenderer(resource);
167
168     for (auto& it : cache.m_cache) {
169         it.value->resourceDestroyed(resource);
170
171         // Mark users of destroyed resources as pending resolution based on the id of the old resource.
172         Element& resourceElement = resource.element();
173         Element* clientElement = it.key->element();
174         clientElement->document().accessSVGExtensions().addPendingResource(resourceElement.getIdAttribute(), clientElement);
175     }
176 }
177
178 }