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