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 "RenderSVGShadowTreeRootContainer.h"
26 #include "SVGStyledTransformableElement.h"
27
28 namespace WebCore {
29
svgExtensionsFromNode(Node * node)30 static inline SVGDocumentExtensions* svgExtensionsFromNode(Node* node)
31 {
32 ASSERT(node);
33 ASSERT(node->document());
34 return node->document()->accessSVGExtensions();
35 }
36
RenderSVGResourceContainer(SVGStyledElement * node)37 RenderSVGResourceContainer::RenderSVGResourceContainer(SVGStyledElement* node)
38 : RenderSVGHiddenContainer(node)
39 , m_id(node->hasID() ? node->getIdAttribute() : nullAtom)
40 , m_registered(false)
41 {
42 }
43
~RenderSVGResourceContainer()44 RenderSVGResourceContainer::~RenderSVGResourceContainer()
45 {
46 if (m_registered)
47 svgExtensionsFromNode(node())->removeResource(m_id);
48 }
49
layout()50 void RenderSVGResourceContainer::layout()
51 {
52 // Invalidate all resources if our layout changed.
53 if (m_everHadLayout && selfNeedsLayout())
54 removeAllClientsFromCache();
55
56 RenderSVGHiddenContainer::layout();
57 }
58
destroy()59 void RenderSVGResourceContainer::destroy()
60 {
61 SVGResourcesCache::resourceDestroyed(this);
62 RenderSVGHiddenContainer::destroy();
63 }
64
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)65 void RenderSVGResourceContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
66 {
67 RenderSVGHiddenContainer::styleDidChange(diff, oldStyle);
68
69 if (!m_registered) {
70 m_registered = true;
71 registerResource();
72 }
73 }
74
idChanged()75 void RenderSVGResourceContainer::idChanged()
76 {
77 // Invalidate all our current clients.
78 removeAllClientsFromCache();
79
80 // Remove old id, that is guaranteed to be present in cache.
81 SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
82 extensions->removeResource(m_id);
83 m_id = static_cast<Element*>(node())->getIdAttribute();
84
85 registerResource();
86 }
87
markAllClientsForInvalidation(InvalidationMode mode)88 void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode)
89 {
90 if (m_clients.isEmpty())
91 return;
92
93 bool needsLayout = mode == LayoutAndBoundariesInvalidation;
94 bool markForInvalidation = mode != ParentOnlyInvalidation;
95
96 HashSet<RenderObject*>::iterator end = m_clients.end();
97 for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) {
98 RenderObject* client = *it;
99 if (client->isSVGResourceContainer()) {
100 client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation);
101 continue;
102 }
103
104 if (markForInvalidation)
105 markClientForInvalidation(client, mode);
106
107 if (needsLayout)
108 client->setNeedsLayout(true);
109
110 // Invalidate resources in ancestor chain, if needed.
111 RenderObject* current = client->parent();
112 while (current) {
113 if (current->isSVGResourceContainer()) {
114 current->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation);
115 break;
116 }
117
118 current = current->parent();
119 }
120 }
121 }
122
markClientForInvalidation(RenderObject * client,InvalidationMode mode)123 void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode)
124 {
125 ASSERT(client);
126 ASSERT(!m_clients.isEmpty());
127
128 switch (mode) {
129 case LayoutAndBoundariesInvalidation:
130 case BoundariesInvalidation:
131 client->setNeedsBoundariesUpdate();
132 break;
133 case RepaintInvalidation:
134 if (client->view())
135 client->repaint();
136 break;
137 case ParentOnlyInvalidation:
138 break;
139 }
140 }
141
addClient(RenderObject * client)142 void RenderSVGResourceContainer::addClient(RenderObject* client)
143 {
144 ASSERT(client);
145 m_clients.add(client);
146 }
147
removeClient(RenderObject * client)148 void RenderSVGResourceContainer::removeClient(RenderObject* client)
149 {
150 ASSERT(client);
151 m_clients.remove(client);
152 }
153
registerResource()154 void RenderSVGResourceContainer::registerResource()
155 {
156 SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
157 if (!extensions->isPendingResource(m_id)) {
158 extensions->addResource(m_id, this);
159 return;
160 }
161
162 OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id));
163
164 // Cache us with the new id.
165 extensions->addResource(m_id, this);
166
167 // Update cached resources of pending clients.
168 const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
169 for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
170 RenderObject* renderer = (*it)->renderer();
171 if (!renderer)
172 continue;
173 SVGResourcesCache::clientUpdatedFromElement(renderer, renderer->style());
174 renderer->setNeedsLayout(true);
175 }
176 }
177
178 // FIXME: This does not belong here.
transformOnNonScalingStroke(RenderObject * object,const AffineTransform & resourceTransform)179 AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
180 {
181 if (!object->isSVGPath())
182 return resourceTransform;
183
184 SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node());
185 AffineTransform transform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate);
186 transform *= resourceTransform;
187 return transform;
188 }
189
190 }
191
192 #endif
193