blob: 7f72216c701bceacb0e8464492da22c4326b0400 [file] [log] [blame]
darin@apple.com640fa302008-02-15 05:03:55 +00001/*
rwlbuis@webkit.org32a5f4c2008-07-09 20:36:45 +00002 * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
krit@webkit.org5fcb8982011-01-08 20:54:58 +00003 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 * Copyright (C) 2009 Google, Inc. All rights reserved.
6 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
krit@webkit.org6e426162010-02-26 18:02:26 +00007 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
oliverb3a02bf2007-10-12 11:36:01 +00008 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
ddkilzercd662e62007-11-03 13:35:52 +000021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
oliverb3a02bf2007-10-12 11:36:01 +000023 */
24
25#include "config.h"
oliverf69ac652007-10-12 13:37:01 +000026#include "SVGRenderSupport.h"
27
zimmermann@webkit.orge62f8ac2010-04-24 12:47:00 +000028#include "NodeRenderStyle.h"
akling@apple.comdce4d532014-01-05 11:45:54 +000029#include "RenderElement.h"
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +000030#include "RenderGeometryMap.h"
akling@apple.comdce4d532014-01-05 11:45:54 +000031#include "RenderIterator.h"
eric@webkit.orgb35848a2010-06-10 08:33:22 +000032#include "RenderLayer.h"
cdumez@apple.com2601e052014-10-10 18:02:32 +000033#include "RenderSVGImage.h"
krit@webkit.org6e426162010-02-26 18:02:26 +000034#include "RenderSVGResourceClipper.h"
krit@webkit.org5703bb22010-04-20 12:52:54 +000035#include "RenderSVGResourceFilter.h"
krit@webkit.org39cab222010-03-28 16:01:18 +000036#include "RenderSVGResourceMarker.h"
krit@webkit.org0b226d62010-02-18 23:12:30 +000037#include "RenderSVGResourceMasker.h"
zimmermann@webkit.org853c6482010-07-06 07:28:44 +000038#include "RenderSVGRoot.h"
commit-queue@webkit.org80066802012-02-22 20:31:11 +000039#include "RenderSVGText.h"
cdumez@apple.com2601e052014-10-10 18:02:32 +000040#include "RenderSVGTransformableContainer.h"
krit@webkit.orgef8159d2012-02-08 19:19:03 +000041#include "RenderSVGViewportContainer.h"
zimmermann@webkit.orgb984a402010-07-29 13:50:51 +000042#include "SVGResources.h"
commit-queue@webkit.orgb22ae9f2011-11-15 01:43:16 +000043#include "SVGResourcesCache.h"
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000044#include "TransformState.h"
oliverb3a02bf2007-10-12 11:36:01 +000045
46namespace WebCore {
47
akling@apple.com559147c2013-11-09 11:32:57 +000048FloatRect SVGRenderSupport::repaintRectForRendererInLocalCoordinatesExcludingSVGShadow(const RenderElement& renderer)
timothy_horton@apple.com314822f2012-11-08 02:58:21 +000049{
50 // FIXME: Add support for RenderSVGBlock.
51
cdumez@apple.com2601e052014-10-10 18:02:32 +000052 if (is<RenderSVGModelObject>(renderer))
53 return downcast<RenderSVGModelObject>(renderer).repaintRectInLocalCoordinatesExcludingSVGShadow();
timothy_horton@apple.com314822f2012-11-08 02:58:21 +000054
akling@apple.com559147c2013-11-09 11:32:57 +000055 return renderer.repaintRectInLocalCoordinates();
timothy_horton@apple.com314822f2012-11-08 02:58:21 +000056}
57
akling@apple.com559147c2013-11-09 11:32:57 +000058LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer)
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000059{
60 // Return early for any cases where we don't actually paint
akling@apple.com559147c2013-11-09 11:32:57 +000061 if (renderer.style().visibility() != VISIBLE && !renderer.enclosingLayer()->hasVisibleContent())
leviw@chromium.org4da729d2011-08-15 19:07:58 +000062 return LayoutRect();
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000063
64 // Pass our local paint rect to computeRectForRepaint() which will
65 // map to parent coords and recurse up the parent chain.
akling@apple.com559147c2013-11-09 11:32:57 +000066 FloatRect repaintRect = repaintRectForRendererInLocalCoordinatesExcludingSVGShadow(renderer);
67 const SVGRenderStyle& svgStyle = renderer.style().svgStyle();
akling@apple.com148c2872013-11-02 05:01:08 +000068 if (const ShadowData* shadow = svgStyle.shadow())
timothy_horton@apple.com314822f2012-11-08 02:58:21 +000069 shadow->adjustRectForShadow(repaintRect);
zalan@apple.com6d4f9592015-10-07 21:14:16 +000070 return enclosingLayoutRect(renderer.computeFloatRectForRepaint(repaintRect, repaintContainer));
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000071}
72
zalan@apple.com6d4f9592015-10-07 21:14:16 +000073FloatRect SVGRenderSupport::computeFloatRectForRepaint(const RenderElement& renderer, const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed)
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000074{
zalan@apple.com6d4f9592015-10-07 21:14:16 +000075 FloatRect adjustedRect = repaintRect;
akling@apple.com559147c2013-11-09 11:32:57 +000076 const SVGRenderStyle& svgStyle = renderer.style().svgStyle();
akling@apple.com148c2872013-11-02 05:01:08 +000077 if (const ShadowData* shadow = svgStyle.shadow())
zalan@apple.com6d4f9592015-10-07 21:14:16 +000078 shadow->adjustRectForShadow(adjustedRect);
79 adjustedRect.inflate(renderer.style().outlineWidth());
zimmermann@webkit.org08fae322010-02-11 20:53:39 +000080
zimmermann@webkit.org80d89632011-11-29 09:40:51 +000081 // Translate to coords in our parent renderer, and then call computeFloatRectForRepaint() on our parent.
zalan@apple.com6d4f9592015-10-07 21:14:16 +000082 adjustedRect = renderer.localToParentTransform().mapRect(adjustedRect);
83 return renderer.parent()->computeFloatRectForRepaint(adjustedRect, repaintContainer, fixed);
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000084}
85
commit-queue@webkit.org0ab25222015-02-16 23:19:23 +000086const RenderElement& SVGRenderSupport::localToParentTransform(const RenderElement& renderer, AffineTransform &transform)
eric@webkit.orgabec5ee2009-05-05 08:14:44 +000087{
akling@apple.com559147c2013-11-09 11:32:57 +000088 ASSERT(renderer.parent());
89 auto& parent = *renderer.parent();
leviw@chromium.org248a7152012-08-16 18:00:34 +000090
commit-queue@webkit.org0ab25222015-02-16 23:19:23 +000091 // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform
92 // to map an element from SVG viewport coordinates to CSS box coordinates.
93 if (is<RenderSVGRoot>(parent))
94 transform = downcast<RenderSVGRoot>(parent).localToBorderBoxTransform() * renderer.localToParentTransform();
95 else
96 transform = renderer.localToParentTransform();
97
98 return parent;
99}
100
101void SVGRenderSupport::mapLocalToContainer(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed)
102{
103 AffineTransform transform;
104 auto& parent = localToParentTransform(renderer, transform);
105
106 transformState.applyTransform(transform);
commit-queue@webkit.org5849cae2014-02-28 16:35:27 +0000107
leviw@chromium.org63f73872012-10-11 23:47:28 +0000108 MapCoordinatesFlags mode = UseTransforms;
akling@apple.com559147c2013-11-09 11:32:57 +0000109 parent.mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
eric@webkit.orgabec5ee2009-05-05 08:14:44 +0000110}
111
akling@apple.com559147c2013-11-09 11:32:57 +0000112const RenderElement* SVGRenderSupport::pushMappingToContainer(const RenderElement& renderer, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap)
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000113{
akling@apple.com559147c2013-11-09 11:32:57 +0000114 ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != &renderer);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000115
commit-queue@webkit.org0ab25222015-02-16 23:19:23 +0000116 AffineTransform transform;
117 auto& parent = localToParentTransform(renderer, transform);
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000118
commit-queue@webkit.org0ab25222015-02-16 23:19:23 +0000119 geometryMap.push(&renderer, transform);
akling@apple.com559147c2013-11-09 11:32:57 +0000120 return &parent;
simon.fraser@apple.comca41ec62012-05-25 21:42:32 +0000121}
122
akling@apple.com559147c2013-11-09 11:32:57 +0000123bool SVGRenderSupport::checkForSVGRepaintDuringLayout(const RenderElement& renderer)
pdr@google.com8e74d212012-11-07 19:26:57 +0000124{
akling@apple.com559147c2013-11-09 11:32:57 +0000125 if (!renderer.checkForRepaintDuringLayout())
pdr@google.com8e74d212012-11-07 19:26:57 +0000126 return false;
127 // When a parent container is transformed in SVG, all children will be painted automatically
128 // so we are able to skip redundant repaint checks.
akling@apple.com559147c2013-11-09 11:32:57 +0000129 auto parent = renderer.parent();
cdumez@apple.com2601e052014-10-10 18:02:32 +0000130 return !(is<RenderSVGContainer>(parent) && downcast<RenderSVGContainer>(*parent).didTransformToRootUpdate());
pdr@google.com8e74d212012-11-07 19:26:57 +0000131}
132
commit-queue@webkit.org8b29eba2012-03-26 14:36:59 +0000133// Update a bounding box taking into account the validity of the other bounding box.
134static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox)
eric@webkit.org39ad3582009-04-16 17:09:59 +0000135{
cdumez@apple.com2601e052014-10-10 18:02:32 +0000136 bool otherValid = is<RenderSVGContainer>(*other) ? downcast<RenderSVGContainer>(*other).isObjectBoundingBoxValid() : true;
commit-queue@webkit.org8b29eba2012-03-26 14:36:59 +0000137 if (!otherValid)
138 return;
commit-queue@webkit.orgce5c1202012-01-18 03:16:47 +0000139
commit-queue@webkit.org8b29eba2012-03-26 14:36:59 +0000140 if (!objectBoundingBoxValid) {
141 objectBoundingBox = otherBoundingBox;
142 objectBoundingBoxValid = true;
143 return;
144 }
145
146 objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox);
147}
148
akling@apple.com559147c2013-11-09 11:32:57 +0000149void SVGRenderSupport::computeContainerBoundingBoxes(const RenderElement& container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox)
commit-queue@webkit.org8b29eba2012-03-26 14:36:59 +0000150{
schenney@chromium.org73c43072012-06-15 15:37:12 +0000151 objectBoundingBox = FloatRect();
152 objectBoundingBoxValid = false;
153 strokeBoundingBox = FloatRect();
154
155 // When computing the strokeBoundingBox, we use the repaintRects of the container's children so that the container's stroke includes
156 // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound
157 // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also.
akling@apple.com559147c2013-11-09 11:32:57 +0000158 for (RenderObject* current = container.firstChild(); current; current = current->nextSibling()) {
zimmermann@webkit.org41e5b7d2010-09-01 07:15:17 +0000159 if (current->isSVGHiddenContainer())
160 continue;
161
commit-queue@webkit.org9a596852014-07-13 06:35:21 +0000162 // Don't include elements in the union that do not render.
cdumez@apple.come1628492014-10-18 00:21:40 +0000163 if (is<RenderSVGShape>(*current) && downcast<RenderSVGShape>(*current).isRenderingDisabled())
commit-queue@webkit.org9a596852014-07-13 06:35:21 +0000164 continue;
165
zimmermann@webkit.org53660b42010-09-01 12:32:29 +0000166 const AffineTransform& transform = current->localToParentTransform();
167 if (transform.isIdentity()) {
commit-queue@webkit.org8b29eba2012-03-26 14:36:59 +0000168 updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, current->objectBoundingBox());
schenney@chromium.org73c43072012-06-15 15:37:12 +0000169 strokeBoundingBox.unite(current->repaintRectInLocalCoordinates());
zimmermann@webkit.org53660b42010-09-01 12:32:29 +0000170 } else {
commit-queue@webkit.org8b29eba2012-03-26 14:36:59 +0000171 updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, transform.mapRect(current->objectBoundingBox()));
schenney@chromium.org73c43072012-06-15 15:37:12 +0000172 strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates()));
zimmermann@webkit.org49f8fa22010-07-01 09:47:01 +0000173 }
eric@webkit.org39ad3582009-04-16 17:09:59 +0000174 }
schenney@chromium.org73c43072012-06-15 15:37:12 +0000175
176 repaintBoundingBox = strokeBoundingBox;
zimmermann@webkit.org53660b42010-09-01 12:32:29 +0000177}
eric@webkit.org39ad3582009-04-16 17:09:59 +0000178
zimmermann@webkit.org53660b42010-09-01 12:32:29 +0000179bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
180{
181 if (localTransform.isIdentity())
182 return localRepaintRect.intersects(paintInfo.rect);
183
184 return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
eric@webkit.org39ad3582009-04-16 17:09:59 +0000185}
186
commit-queue@webkit.orgb3a3e3b2016-01-21 17:50:26 +0000187RenderSVGRoot* SVGRenderSupport::findTreeRootObject(RenderElement& start)
zimmermann@webkit.org853c6482010-07-06 07:28:44 +0000188{
commit-queue@webkit.orgb3a3e3b2016-01-21 17:50:26 +0000189 return lineageOfType<RenderSVGRoot>(start).first();
190}
191
192const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderElement& start)
193{
194 return lineageOfType<RenderSVGRoot>(start).first();
zimmermann@webkit.org853c6482010-07-06 07:28:44 +0000195}
196
akling@apple.com83ccacb2014-02-03 09:02:55 +0000197static inline void invalidateResourcesOfChildren(RenderElement& renderer)
zimmermann@webkit.orgcff31342010-08-13 10:03:22 +0000198{
akling@apple.com83ccacb2014-02-03 09:02:55 +0000199 ASSERT(!renderer.needsLayout());
akling@apple.com2e79f742014-09-05 19:25:57 +0000200 if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer))
akling@apple.com83ccacb2014-02-03 09:02:55 +0000201 resources->removeClientFromCache(renderer, false);
zimmermann@webkit.orgcff31342010-08-13 10:03:22 +0000202
akling@apple.com83ccacb2014-02-03 09:02:55 +0000203 for (auto& child : childrenOfType<RenderElement>(renderer))
204 invalidateResourcesOfChildren(child);
zimmermann@webkit.orgcff31342010-08-13 10:03:22 +0000205}
206
akling@apple.com559147c2013-11-09 11:32:57 +0000207static inline bool layoutSizeOfNearestViewportChanged(const RenderElement& renderer)
krit@webkit.orgef8159d2012-02-08 19:19:03 +0000208{
akling@apple.com559147c2013-11-09 11:32:57 +0000209 const RenderElement* start = &renderer;
cdumez@apple.com2601e052014-10-10 18:02:32 +0000210 while (start && !is<RenderSVGRoot>(*start) && !is<RenderSVGViewportContainer>(*start))
krit@webkit.orgef8159d2012-02-08 19:19:03 +0000211 start = start->parent();
212
213 ASSERT(start);
cdumez@apple.com2601e052014-10-10 18:02:32 +0000214 if (is<RenderSVGViewportContainer>(*start))
215 return downcast<RenderSVGViewportContainer>(*start).isLayoutSizeChanged();
krit@webkit.orgef8159d2012-02-08 19:19:03 +0000216
cdumez@apple.com2601e052014-10-10 18:02:32 +0000217 return downcast<RenderSVGRoot>(*start).isLayoutSizeChanged();
krit@webkit.orgef8159d2012-02-08 19:19:03 +0000218}
219
akling@apple.com559147c2013-11-09 11:32:57 +0000220bool SVGRenderSupport::transformToRootChanged(RenderElement* ancestor)
commit-queue@webkit.org0827c372012-02-24 00:52:35 +0000221{
cdumez@apple.com2601e052014-10-10 18:02:32 +0000222 while (ancestor && !is<RenderSVGRoot>(*ancestor)) {
223 if (is<RenderSVGTransformableContainer>(*ancestor))
224 return downcast<RenderSVGTransformableContainer>(*ancestor).didTransformToRootUpdate();
225 if (is<RenderSVGViewportContainer>(*ancestor))
226 return downcast<RenderSVGViewportContainer>(*ancestor).didTransformToRootUpdate();
commit-queue@webkit.org0827c372012-02-24 00:52:35 +0000227 ancestor = ancestor->parent();
228 }
229
230 return false;
231}
232
commit-queue@webkit.orgb3a3e3b2016-01-21 17:50:26 +0000233void SVGRenderSupport::layoutDifferentRootIfNeeded(const RenderElement& renderer)
234{
235 if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) {
236 auto* svgRoot = SVGRenderSupport::findTreeRootObject(renderer);
237 ASSERT(svgRoot);
238 resources->layoutDifferentRootIfNeeded(svgRoot);
239 }
240}
241
akling@apple.com559147c2013-11-09 11:32:57 +0000242void SVGRenderSupport::layoutChildren(RenderElement& start, bool selfNeedsLayout)
zimmermann@webkit.orgd5d17b32010-01-14 03:05:30 +0000243{
krit@webkit.orgef8159d2012-02-08 19:19:03 +0000244 bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start);
akling@apple.com559147c2013-11-09 11:32:57 +0000245 bool transformChanged = transformToRootChanged(&start);
timothy_horton@apple.com6712c512012-12-12 01:15:00 +0000246 bool hasSVGShadow = rendererHasSVGShadow(start);
akling@apple.com559147c2013-11-09 11:32:57 +0000247 bool needsBoundariesUpdate = start.needsBoundariesUpdate();
darin@apple.com738e9f52014-03-13 17:51:59 +0000248 HashSet<RenderElement*> elementsThatDidNotReceiveLayout;
zimmermann@webkit.org853c6482010-07-06 07:28:44 +0000249
akling@apple.com559147c2013-11-09 11:32:57 +0000250 for (RenderObject* child = start.firstChild(); child; child = child->nextSibling()) {
zimmermann@webkit.orgd5d17b32010-01-14 03:05:30 +0000251 bool needsLayout = selfNeedsLayout;
eric@webkit.org31f20a92012-08-09 07:58:50 +0000252 bool childEverHadLayout = child->everHadLayout();
zimmermann@webkit.org853c6482010-07-06 07:28:44 +0000253
timothy_horton@apple.com6712c512012-12-12 01:15:00 +0000254 if (needsBoundariesUpdate && hasSVGShadow) {
255 // If we have a shadow, our shadow is baked into our children's cached boundaries,
256 // so they need to update.
257 child->setNeedsBoundariesUpdate();
258 needsLayout = true;
259 }
260
commit-queue@webkit.org0827c372012-02-24 00:52:35 +0000261 if (transformChanged) {
262 // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true).
cdumez@apple.comf3814492014-10-10 23:06:32 +0000263 if (is<RenderSVGText>(*child))
264 downcast<RenderSVGText>(*child).setNeedsTextMetricsUpdate();
commit-queue@webkit.org0827c372012-02-24 00:52:35 +0000265 needsLayout = true;
266 }
267
zimmermann@webkit.org853c6482010-07-06 07:28:44 +0000268 if (layoutSizeChanged) {
269 // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
cdumez@apple.comf3814492014-10-10 23:06:32 +0000270 if (SVGElement* element = is<SVGElement>(*child->node()) ? downcast<SVGElement>(child->node()) : nullptr) {
ch.dumez@sisa.samsung.com7dd31bf2013-08-22 21:58:09 +0000271 if (element->hasRelativeLengths()) {
reni@webkit.orgf0d767a2011-11-30 15:49:02 +0000272 // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object
cdumez@apple.comf3814492014-10-10 23:06:32 +0000273 if (is<RenderSVGShape>(*child))
274 downcast<RenderSVGShape>(*child).setNeedsShapeUpdate();
275 else if (is<RenderSVGText>(*child)) {
276 RenderSVGText& svgText = downcast<RenderSVGText>(*child);
277 svgText.setNeedsTextMetricsUpdate();
278 svgText.setNeedsPositioningValuesUpdate();
zimmermann@webkit.orgfec8f1d2012-05-16 07:21:07 +0000279 }
zimmermann@webkit.org853c6482010-07-06 07:28:44 +0000280
281 needsLayout = true;
282 }
zimmermann@webkit.orgd5d17b32010-01-14 03:05:30 +0000283 }
284 }
285
eric@webkit.org31f20a92012-08-09 07:58:50 +0000286 if (needsLayout)
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000287 child->setNeedsLayout(MarkOnlyThis);
eric@webkit.org31f20a92012-08-09 07:58:50 +0000288
289 if (child->needsLayout()) {
commit-queue@webkit.orgb3a3e3b2016-01-21 17:50:26 +0000290 layoutDifferentRootIfNeeded(downcast<RenderElement>(*child));
cdumez@apple.comf3814492014-10-10 23:06:32 +0000291 downcast<RenderElement>(*child).layout();
eric@webkit.org31f20a92012-08-09 07:58:50 +0000292 // Renderers are responsible for repainting themselves when changing, except
293 // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds.
294 // We could handle this in the individual objects, but for now it's easier to have
295 // parent containers call repaint(). (RenderBlock::layout* has similar logic.)
296 if (!childEverHadLayout)
297 child->repaint();
cdumez@apple.comf3814492014-10-10 23:06:32 +0000298 } else if (layoutSizeChanged && is<RenderElement>(*child))
299 elementsThatDidNotReceiveLayout.add(downcast<RenderElement>(child));
zimmermann@webkit.orgd5d17b32010-01-14 03:05:30 +0000300
zimmermann@webkit.orgd5d17b32010-01-14 03:05:30 +0000301 ASSERT(!child->needsLayout());
302 }
zimmermann@webkit.orgcff31342010-08-13 10:03:22 +0000303
304 if (!layoutSizeChanged) {
darin@apple.com738e9f52014-03-13 17:51:59 +0000305 ASSERT(elementsThatDidNotReceiveLayout.isEmpty());
zimmermann@webkit.orgcff31342010-08-13 10:03:22 +0000306 return;
307 }
308
309 // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path.
darin@apple.com738e9f52014-03-13 17:51:59 +0000310 for (auto* element : elementsThatDidNotReceiveLayout)
311 invalidateResourcesOfChildren(*element);
zimmermann@webkit.orgd5d17b32010-01-14 03:05:30 +0000312}
313
akling@apple.com559147c2013-11-09 11:32:57 +0000314bool SVGRenderSupport::isOverflowHidden(const RenderElement& renderer)
zimmermann@webkit.org43b8cc92010-02-08 14:26:33 +0000315{
zimmermann@webkit.org1ef0ade2010-02-09 16:08:18 +0000316 // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000317 ASSERT(!renderer.isDocumentElementRenderer());
zimmermann@webkit.org1ef0ade2010-02-09 16:08:18 +0000318
commit-queue@webkit.orgd5054f12014-05-09 19:05:33 +0000319 return renderer.style().overflowX() == OHIDDEN || renderer.style().overflowX() == OSCROLL;
zimmermann@webkit.org43b8cc92010-02-08 14:26:33 +0000320}
321
akling@apple.com559147c2013-11-09 11:32:57 +0000322bool SVGRenderSupport::rendererHasSVGShadow(const RenderObject& renderer)
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000323{
324 // FIXME: Add support for RenderSVGBlock.
325
cdumez@apple.com2601e052014-10-10 18:02:32 +0000326 if (is<RenderSVGModelObject>(renderer))
327 return downcast<RenderSVGModelObject>(renderer).hasSVGShadow();
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000328
cdumez@apple.com2601e052014-10-10 18:02:32 +0000329 if (is<RenderSVGRoot>(renderer))
330 return downcast<RenderSVGRoot>(renderer).hasSVGShadow();
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000331
332 return false;
333}
334
akling@apple.com559147c2013-11-09 11:32:57 +0000335void SVGRenderSupport::setRendererHasSVGShadow(RenderObject& renderer, bool hasShadow)
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000336{
337 // FIXME: Add support for RenderSVGBlock.
338
cdumez@apple.com2601e052014-10-10 18:02:32 +0000339 if (is<RenderSVGModelObject>(renderer)) {
340 downcast<RenderSVGModelObject>(renderer).setHasSVGShadow(hasShadow);
akling@apple.com559147c2013-11-09 11:32:57 +0000341 return;
342 }
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000343
cdumez@apple.com2601e052014-10-10 18:02:32 +0000344 if (is<RenderSVGRoot>(renderer))
345 downcast<RenderSVGRoot>(renderer).setHasSVGShadow(hasShadow);
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000346}
347
akling@apple.com559147c2013-11-09 11:32:57 +0000348void SVGRenderSupport::intersectRepaintRectWithShadows(const RenderElement& renderer, FloatRect& repaintRect)
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000349{
350 // Since -webkit-svg-shadow enables shadow drawing for its children, but its children
351 // don't inherit the shadow in their SVGRenderStyle, we need to search our parents for
352 // shadows in order to correctly compute our repaint rect.
353
akling@apple.com559147c2013-11-09 11:32:57 +0000354 auto currentObject = &renderer;
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000355
356 AffineTransform localToRootTransform;
357
akling@apple.com559147c2013-11-09 11:32:57 +0000358 while (currentObject && rendererHasSVGShadow(*currentObject)) {
akling@apple.com827be9c2013-10-29 02:58:43 +0000359 const RenderStyle& style = currentObject->style();
akling@apple.com148c2872013-11-02 05:01:08 +0000360 const SVGRenderStyle& svgStyle = style.svgStyle();
361 if (const ShadowData* shadow = svgStyle.shadow())
362 shadow->adjustRectForShadow(repaintRect);
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000363
364 repaintRect = currentObject->localToParentTransform().mapRect(repaintRect);
365 localToRootTransform *= currentObject->localToParentTransform();
366
367 currentObject = currentObject->parent();
368 };
369
370 if (localToRootTransform.isIdentity())
371 return;
372
commit-queue@webkit.org759ff2e2015-12-01 20:26:05 +0000373 AffineTransform rootToLocalTransform = localToRootTransform.inverse().valueOr(AffineTransform());
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000374 repaintRect = rootToLocalTransform.mapRect(repaintRect);
375}
376
akling@apple.comf67100c2013-10-24 18:41:42 +0000377void SVGRenderSupport::intersectRepaintRectWithResources(const RenderElement& renderer, FloatRect& repaintRect)
eric@webkit.org55e39b22009-04-28 19:37:32 +0000378{
akling@apple.com2e79f742014-09-05 19:25:57 +0000379 auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer);
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000380 if (!resources)
zimmermann@webkit.orgb984a402010-07-29 13:50:51 +0000381 return;
zimmermann@webkit.orgb984a402010-07-29 13:50:51 +0000382
zimmermann@webkit.orgb984a402010-07-29 13:50:51 +0000383 if (RenderSVGResourceFilter* filter = resources->filter())
384 repaintRect = filter->resourceBoundingBox(renderer);
eric@webkit.org55e39b22009-04-28 19:37:32 +0000385
zimmermann@webkit.orgb984a402010-07-29 13:50:51 +0000386 if (RenderSVGResourceClipper* clipper = resources->clipper())
387 repaintRect.intersect(clipper->resourceBoundingBox(renderer));
388
389 if (RenderSVGResourceMasker* masker = resources->masker())
390 repaintRect.intersect(masker->resourceBoundingBox(renderer));
krit@webkit.org4dc21c12009-12-30 08:10:44 +0000391}
392
akling@apple.com559147c2013-11-09 11:32:57 +0000393bool SVGRenderSupport::filtersForceContainerLayout(const RenderElement& renderer)
commit-queue@webkit.org17807a92011-11-11 23:40:57 +0000394{
395 // If any of this container's children need to be laid out, and a filter is applied
396 // to the container, we need to repaint the entire container.
akling@apple.com559147c2013-11-09 11:32:57 +0000397 if (!renderer.normalChildNeedsLayout())
commit-queue@webkit.org17807a92011-11-11 23:40:57 +0000398 return false;
399
akling@apple.com2e79f742014-09-05 19:25:57 +0000400 auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer);
commit-queue@webkit.org17807a92011-11-11 23:40:57 +0000401 if (!resources || !resources->filter())
402 return false;
403
404 return true;
405}
406
akling@apple.com559147c2013-11-09 11:32:57 +0000407bool SVGRenderSupport::pointInClippingArea(const RenderElement& renderer, const FloatPoint& point)
krit@webkit.org21317bb2010-06-06 12:26:45 +0000408{
krit@webkit.org21317bb2010-06-06 12:26:45 +0000409 // We just take clippers into account to determine if a point is on the node. The Specification may
410 // change later and we also need to check maskers.
akling@apple.com2e79f742014-09-05 19:25:57 +0000411 auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer);
zimmermann@webkit.orgb984a402010-07-29 13:50:51 +0000412 if (!resources)
413 return true;
414
415 if (RenderSVGResourceClipper* clipper = resources->clipper())
akling@apple.com559147c2013-11-09 11:32:57 +0000416 return clipper->hitTestClipContent(renderer.objectBoundingBox(), point);
krit@webkit.org21317bb2010-06-06 12:26:45 +0000417
418 return true;
419}
420
akling@apple.com88c9a522013-10-29 17:17:22 +0000421void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle& style, const RenderElement& renderer)
zimmermann@webkit.org555112d2010-04-24 11:42:46 +0000422{
zimmermann@webkit.org51cbd132010-08-06 11:21:20 +0000423 ASSERT(context);
akling@apple.com88c9a522013-10-29 17:17:22 +0000424 ASSERT(renderer.element());
425 ASSERT(renderer.element()->isSVGElement());
zimmermann@webkit.org555112d2010-04-24 11:42:46 +0000426
akling@apple.com148c2872013-11-02 05:01:08 +0000427 const SVGRenderStyle& svgStyle = style.svgStyle();
zimmermann@webkit.org51cbd132010-08-06 11:21:20 +0000428
cdumez@apple.com7487b352014-09-23 00:55:05 +0000429 SVGLengthContext lengthContext(downcast<SVGElement>(renderer.element()));
krit@webkit.org3b6d18c2014-08-18 18:18:16 +0000430 context->setStrokeThickness(lengthContext.valueForLength(svgStyle.strokeWidth()));
akling@apple.com148c2872013-11-02 05:01:08 +0000431 context->setLineCap(svgStyle.capStyle());
432 context->setLineJoin(svgStyle.joinStyle());
433 if (svgStyle.joinStyle() == MiterJoin)
434 context->setMiterLimit(svgStyle.strokeMiterLimit());
zimmermann@webkit.org51cbd132010-08-06 11:21:20 +0000435
akling@apple.com148c2872013-11-02 05:01:08 +0000436 const Vector<SVGLength>& dashes = svgStyle.strokeDashArray();
eric@webkit.org24ac4062010-04-26 10:05:10 +0000437 if (dashes.isEmpty())
438 context->setStrokeStyle(SolidStroke);
zimmermann@webkit.org51cbd132010-08-06 11:21:20 +0000439 else {
440 DashArray dashArray;
akling@apple.com88c9a522013-10-29 17:17:22 +0000441 dashArray.reserveInitialCapacity(dashes.size());
darin@apple.com738e9f52014-03-13 17:51:59 +0000442 for (auto& dash : dashes)
443 dashArray.uncheckedAppend(dash.value(lengthContext));
zimmermann@webkit.org51cbd132010-08-06 11:21:20 +0000444
krit@webkit.org3b6d18c2014-08-18 18:18:16 +0000445 context->setLineDash(dashArray, lengthContext.valueForLength(svgStyle.strokeDashOffset()));
zimmermann@webkit.org51cbd132010-08-06 11:21:20 +0000446 }
zimmermann@webkit.org555112d2010-04-24 11:42:46 +0000447}
448
akling@apple.com559147c2013-11-09 11:32:57 +0000449void SVGRenderSupport::childAdded(RenderElement& parent, RenderObject& child)
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000450{
451 SVGRenderSupport::setRendererHasSVGShadow(child, SVGRenderSupport::rendererHasSVGShadow(parent) || SVGRenderSupport::rendererHasSVGShadow(child));
452}
453
commit-queue@webkit.orgb668ca22014-02-18 17:10:37 +0000454void SVGRenderSupport::styleChanged(RenderElement& renderer, const RenderStyle* oldStyle)
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000455{
akling@apple.com559147c2013-11-09 11:32:57 +0000456 auto parent = renderer.parent();
457 SVGRenderSupport::setRendererHasSVGShadow(renderer, (parent && SVGRenderSupport::rendererHasSVGShadow(*parent)) || renderer.style().svgStyle().shadow());
commit-queue@webkit.orgb668ca22014-02-18 17:10:37 +0000458
459#if ENABLE(CSS_COMPOSITING)
460 if (renderer.element() && renderer.element()->isSVGElement() && (!oldStyle || renderer.style().hasBlendMode() != oldStyle->hasBlendMode()))
461 SVGRenderSupport::updateMaskedAncestorShouldIsolateBlending(renderer);
462#else
463 UNUSED_PARAM(oldStyle);
464#endif
timothy_horton@apple.com314822f2012-11-08 02:58:21 +0000465}
466
commit-queue@webkit.orgb668ca22014-02-18 17:10:37 +0000467#if ENABLE(CSS_COMPOSITING)
468bool SVGRenderSupport::isolatesBlending(const RenderStyle& style)
469{
dino@apple.comd75816f2015-08-19 20:22:50 +0000470 return style.svgStyle().isolatesBlending() || style.hasFilter() || style.hasBlendMode() || style.opacity() < 1.0f;
commit-queue@webkit.orgb668ca22014-02-18 17:10:37 +0000471}
472
473void SVGRenderSupport::updateMaskedAncestorShouldIsolateBlending(const RenderElement& renderer)
474{
475 ASSERT(renderer.element());
476 ASSERT(renderer.element()->isSVGElement());
477
478 bool maskedAncestorShouldIsolateBlending = renderer.style().hasBlendMode();
darin@apple.com738e9f52014-03-13 17:51:59 +0000479 for (auto* ancestor = renderer.element()->parentElement(); ancestor && ancestor->isSVGElement(); ancestor = ancestor->parentElement()) {
cdumez@apple.com7487b352014-09-23 00:55:05 +0000480 if (!downcast<SVGElement>(*ancestor).isSVGGraphicsElement() || !isolatesBlending(*ancestor->computedStyle()))
commit-queue@webkit.orgb668ca22014-02-18 17:10:37 +0000481 continue;
482
483 if (ancestor->computedStyle()->svgStyle().hasMasker())
cdumez@apple.com11b68052014-09-25 17:25:43 +0000484 downcast<SVGGraphicsElement>(*ancestor).setShouldIsolateBlending(maskedAncestorShouldIsolateBlending);
commit-queue@webkit.orgb668ca22014-02-18 17:10:37 +0000485
486 return;
487 }
488}
489#endif
krit@webkit.org6e426162010-02-26 18:02:26 +0000490}