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