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