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 #if ENABLE(SVG)
24 #include "RenderSVGResourceContainer.h"
25 #include "SVGDocumentExtensions.h"
26 #include "SVGResources.h"
27 #include "SVGResourcesCycleSolver.h"
28
29 namespace WebCore {
30
SVGResourcesCache()31 SVGResourcesCache::SVGResourcesCache()
32 {
33 }
34
~SVGResourcesCache()35 SVGResourcesCache::~SVGResourcesCache()
36 {
37 deleteAllValues(m_cache);
38 }
39
addResourcesFromRenderObject(RenderObject * object,const RenderStyle * style)40 void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style)
41 {
42 ASSERT(object);
43 ASSERT(style);
44 ASSERT(!m_cache.contains(object));
45
46 const SVGRenderStyle* svgStyle = style->svgStyle();
47 ASSERT(svgStyle);
48
49 // Build a list of all resources associated with the passed RenderObject
50 SVGResources* resources = new SVGResources;
51 if (!resources->buildCachedResources(object, svgStyle)) {
52 delete resources;
53 return;
54 }
55
56 // Put object in cache.
57 m_cache.set(object, resources);
58
59 // Run cycle-detection _afterwards_, so self-references can be caught as well.
60 SVGResourcesCycleSolver solver(object, resources);
61 solver.resolveCycles();
62
63 // Walk resources and register the render object at each resources.
64 HashSet<RenderSVGResourceContainer*> resourceSet;
65 resources->buildSetOfResources(resourceSet);
66
67 HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
68 for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
69 (*it)->addClient(object);
70 }
71
removeResourcesFromRenderObject(RenderObject * object)72 void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object)
73 {
74 if (!m_cache.contains(object))
75 return;
76
77 SVGResources* resources = m_cache.get(object);
78
79 // Walk resources and register the render object at each resources.
80 HashSet<RenderSVGResourceContainer*> resourceSet;
81 resources->buildSetOfResources(resourceSet);
82
83 HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
84 for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
85 (*it)->removeClient(object);
86
87 delete m_cache.take(object);
88 }
89
resourcesCacheFromRenderObject(RenderObject * renderer)90 static inline SVGResourcesCache* resourcesCacheFromRenderObject(RenderObject* renderer)
91 {
92 Document* document = renderer->document();
93 ASSERT(document);
94
95 SVGDocumentExtensions* extensions = document->accessSVGExtensions();
96 ASSERT(extensions);
97
98 SVGResourcesCache* cache = extensions->resourcesCache();
99 ASSERT(cache);
100
101 return cache;
102 }
103
cachedResourcesForRenderObject(RenderObject * renderer)104 SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(RenderObject* renderer)
105 {
106 ASSERT(renderer);
107 SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
108 if (!cache->m_cache.contains(renderer))
109 return 0;
110
111 return cache->m_cache.get(renderer);
112 }
113
clientLayoutChanged(RenderObject * object)114 void SVGResourcesCache::clientLayoutChanged(RenderObject* object)
115 {
116 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
117 if (!resources)
118 return;
119
120 resources->removeClientFromCache(object);
121 }
122
clientStyleChanged(RenderObject * renderer,StyleDifference diff,const RenderStyle * newStyle)123 void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle)
124 {
125 ASSERT(renderer);
126 if (diff == StyleDifferenceEqual)
127 return;
128
129 // In this case the proper SVGFE*Element will imply whether the modifided CSS properties implies a relayout or repaint.
130 if (renderer->isSVGResourceFilterPrimitive() && diff == StyleDifferenceRepaint)
131 return;
132
133 clientUpdatedFromElement(renderer, newStyle);
134 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
135 }
136
clientUpdatedFromElement(RenderObject * renderer,const RenderStyle * newStyle)137 void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle)
138 {
139 ASSERT(renderer);
140 ASSERT(renderer->parent());
141
142 SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
143 cache->removeResourcesFromRenderObject(renderer);
144 cache->addResourcesFromRenderObject(renderer, newStyle);
145 }
146
clientDestroyed(RenderObject * renderer)147 void SVGResourcesCache::clientDestroyed(RenderObject* renderer)
148 {
149 ASSERT(renderer);
150 SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
151 cache->removeResourcesFromRenderObject(renderer);
152 }
153
resourceDestroyed(RenderSVGResourceContainer * resource)154 void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource)
155 {
156 ASSERT(resource);
157 SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource);
158
159 // The resource itself may have clients, that need to be notified.
160 cache->removeResourcesFromRenderObject(resource);
161
162 HashMap<RenderObject*, SVGResources*>::iterator end = cache->m_cache.end();
163 for (HashMap<RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it)
164 it->second->resourceDestroyed(resource);
165 }
166
167 }
168
169 #endif
170