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