ed7272313769cba41019018cb7fb582bcb8b9235
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGResourceContainer.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
22 #if ENABLE(SVG)
23 #include "RenderSVGResourceContainer.h"
24
25 #include "RenderLayer.h"
26 #include "RenderSVGRoot.h"
27 #include "RenderView.h"
28 #include "SVGGraphicsElement.h"
29 #include "SVGRenderingContext.h"
30 #include "SVGResourcesCache.h"
31 #include <wtf/StackStats.h>
32
33 namespace WebCore {
34
35 static inline SVGDocumentExtensions& svgExtensionsFromElement(SVGElement& element)
36 {
37     // FIXME: accessSVGExtensions() should return a reference.
38     return *element.document().accessSVGExtensions();
39 }
40
41 RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement& element)
42     : RenderSVGHiddenContainer(element)
43     , m_id(element.getIdAttribute())
44     , m_registered(false)
45     , m_isInvalidating(false)
46 {
47 }
48
49 RenderSVGResourceContainer::~RenderSVGResourceContainer()
50 {
51     if (m_registered)
52         svgExtensionsFromElement(element()).removeResource(m_id);
53 }
54
55 void RenderSVGResourceContainer::layout()
56 {
57     StackStats::LayoutCheckPoint layoutCheckPoint;
58     // Invalidate all resources if our layout changed.
59     if (everHadLayout() && selfNeedsLayout())
60         RenderSVGRoot::addResourceForClientInvalidation(this);
61
62     RenderSVGHiddenContainer::layout();
63 }
64
65 void RenderSVGResourceContainer::willBeDestroyed()
66 {
67     SVGResourcesCache::resourceDestroyed(this);
68     RenderSVGHiddenContainer::willBeDestroyed();
69 }
70
71 void RenderSVGResourceContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
72 {
73     RenderSVGHiddenContainer::styleDidChange(diff, oldStyle);
74
75     if (!m_registered) {
76         m_registered = true;
77         registerResource();
78     }
79 }
80
81 void RenderSVGResourceContainer::idChanged()
82 {
83     // Invalidate all our current clients.
84     removeAllClientsFromCache();
85
86     // Remove old id, that is guaranteed to be present in cache.
87     svgExtensionsFromElement(element()).removeResource(m_id);
88     m_id = element().getIdAttribute();
89
90     registerResource();
91 }
92
93 void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode)
94 {
95     if ((m_clients.isEmpty() && m_clientLayers.isEmpty()) || m_isInvalidating)
96         return;
97
98     m_isInvalidating = true;
99     bool needsLayout = mode == LayoutAndBoundariesInvalidation;
100     bool markForInvalidation = mode != ParentOnlyInvalidation;
101
102     HashSet<RenderObject*>::iterator end = m_clients.end();
103     for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) {
104         RenderObject* client = *it;
105         if (client->isSVGResourceContainer()) {
106             client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation);
107             continue;
108         }
109
110         if (markForInvalidation)
111             markClientForInvalidation(client, mode);
112
113         RenderSVGResource::markForLayoutAndParentResourceInvalidation(client, needsLayout);
114     }
115
116     markAllClientLayersForInvalidation();
117
118     m_isInvalidating = false;
119 }
120
121 void RenderSVGResourceContainer::markAllClientLayersForInvalidation()
122 {
123 #if ENABLE(CSS_FILTERS)
124     HashSet<RenderLayer*>::iterator layerEnd = m_clientLayers.end();
125     for (HashSet<RenderLayer*>::iterator it = m_clientLayers.begin(); it != layerEnd; ++it)
126         (*it)->filterNeedsRepaint();
127 #endif
128 }
129
130 void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode)
131 {
132     ASSERT(client);
133     ASSERT(!m_clients.isEmpty());
134
135     switch (mode) {
136     case LayoutAndBoundariesInvalidation:
137     case BoundariesInvalidation:
138         client->setNeedsBoundariesUpdate();
139         break;
140     case RepaintInvalidation:
141         if (!client->documentBeingDestroyed())
142             client->repaint();
143         break;
144     case ParentOnlyInvalidation:
145         break;
146     }
147 }
148
149 void RenderSVGResourceContainer::addClient(RenderObject* client)
150 {
151     ASSERT(client);
152     m_clients.add(client);
153 }
154
155 void RenderSVGResourceContainer::removeClient(RenderObject* client)
156 {
157     ASSERT(client);
158     removeClientFromCache(client, false);
159     m_clients.remove(client);
160 }
161
162 void RenderSVGResourceContainer::addClientRenderLayer(RenderLayer* client)
163 {
164     ASSERT(client);
165     m_clientLayers.add(client);
166 }
167
168 void RenderSVGResourceContainer::removeClientRenderLayer(RenderLayer* client)
169 {
170     ASSERT(client);
171     m_clientLayers.remove(client);
172 }
173
174 void RenderSVGResourceContainer::registerResource()
175 {
176     SVGDocumentExtensions& extensions = svgExtensionsFromElement(element());
177     if (!extensions.hasPendingResource(m_id)) {
178         extensions.addResource(m_id, this);
179         return;
180     }
181
182     OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients = extensions.removePendingResource(m_id);
183
184     // Cache us with the new id.
185     extensions.addResource(m_id, this);
186
187     // Update cached resources of pending clients.
188     const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
189     for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
190         ASSERT((*it)->hasPendingResources());
191         extensions.clearHasPendingResourcesIfPossible(*it);
192         RenderObject* renderer = (*it)->renderer();
193         if (!renderer)
194             continue;
195         SVGResourcesCache::clientStyleChanged(renderer, StyleDifferenceLayout, renderer->style());
196         renderer->setNeedsLayout();
197     }
198 }
199
200 bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform)
201 {
202     ASSERT_UNUSED(object, object);
203 #if USE(CG)
204     UNUSED_PARAM(resourceTransform);
205     return false;
206 #else
207     // This method should only be called for RenderObjects that deal with text rendering. Cmp. RenderObject.h's is*() methods.
208     ASSERT(object->isSVGText() || object->isSVGTextPath() || object->isSVGInline());
209
210     // In text drawing, the scaling part of the graphics context CTM is removed, compare SVGInlineTextBox::paintTextWithShadows.
211     // So, we use that scaling factor here, too, and then push it down to pattern or gradient space
212     // in order to keep the pattern or gradient correctly scaled.
213     float scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(object);
214     if (scalingFactor == 1)
215         return false;
216     resourceTransform.scale(scalingFactor);
217     return true;
218 #endif
219 }
220
221 // FIXME: This does not belong here.
222 AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
223 {
224     if (!object->isSVGShape())
225         return resourceTransform;
226
227     SVGGraphicsElement* element = toSVGGraphicsElement(object->node());
228     AffineTransform transform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate);
229     transform *= resourceTransform;
230     return transform;
231 }
232
233 }
234
235 #endif