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