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