OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org> | 2 * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org> |
3 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> | 3 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> |
4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> | 4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
5 * Copyright (C) 2009 Google, Inc. All rights reserved. | 5 * Copyright (C) 2009 Google, Inc. All rights reserved. |
6 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> | 6 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> |
7 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 7 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
8 * | 8 * |
9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
11 * License as published by the Free Software Foundation; either | 11 * License as published by the Free Software Foundation; either |
12 * version 2 of the License, or (at your option) any later version. | 12 * version 2 of the License, or (at your option) any later version. |
13 * | 13 * |
14 * This library is distributed in the hope that it will be useful, | 14 * This library is distributed in the hope that it will be useful, |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 * Library General Public License for more details. | 17 * Library General Public License for more details. |
18 * | 18 * |
19 * You should have received a copy of the GNU Library General Public License | 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 | 20 * along with this library; see the file COPYING.LIB. If not, write to |
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
22 * Boston, MA 02110-1301, USA. | 22 * Boston, MA 02110-1301, USA. |
23 */ | 23 */ |
24 | 24 |
25 #include "config.h" | 25 #include "config.h" |
26 | |
27 #include "core/rendering/svg/SVGRenderSupport.h" | 26 #include "core/rendering/svg/SVGRenderSupport.h" |
28 | 27 |
29 #include "core/rendering/RenderGeometryMap.h" | 28 #include "core/rendering/RenderGeometryMap.h" |
30 #include "core/rendering/RenderLayer.h" | 29 #include "core/rendering/RenderLayer.h" |
31 #include "core/rendering/SubtreeLayoutScope.h" | 30 #include "core/rendering/SubtreeLayoutScope.h" |
32 #include "core/rendering/svg/RenderSVGInlineText.h" | 31 #include "core/rendering/svg/RenderSVGInlineText.h" |
33 #include "core/rendering/svg/RenderSVGResourceClipper.h" | 32 #include "core/rendering/svg/RenderSVGResourceClipper.h" |
34 #include "core/rendering/svg/RenderSVGResourceFilter.h" | 33 #include "core/rendering/svg/RenderSVGResourceFilter.h" |
35 #include "core/rendering/svg/RenderSVGResourceMasker.h" | 34 #include "core/rendering/svg/RenderSVGResourceMasker.h" |
36 #include "core/rendering/svg/RenderSVGRoot.h" | |
37 #include "core/rendering/svg/RenderSVGText.h" | |
38 #include "core/rendering/svg/RenderSVGViewportContainer.h" | |
39 #include "core/rendering/svg/SVGResources.h" | |
40 #include "core/rendering/svg/SVGResourcesCache.h" | |
41 #include "core/svg/SVGElement.h" | 35 #include "core/svg/SVGElement.h" |
42 #include "platform/geometry/TransformState.h" | 36 #include "platform/geometry/TransformState.h" |
43 | 37 |
44 namespace WebCore { | 38 namespace WebCore { |
45 | 39 |
46 LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderObject* o
bject, const RenderLayerModelObject* repaintContainer) | 40 LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderObject* o
bject, const RenderLayerModelObject* repaintContainer) |
47 { | 41 { |
48 // Return early for any cases where we don't actually paint | 42 // Return early for any cases where we don't actually paint |
49 if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->h
asVisibleContent()) | 43 if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->h
asVisibleContent()) |
50 return LayoutRect(); | 44 return LayoutRect(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) | 97 bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) |
104 { | 98 { |
105 if (!object->checkForRepaintDuringLayout()) | 99 if (!object->checkForRepaintDuringLayout()) |
106 return false; | 100 return false; |
107 // When a parent container is transformed in SVG, all children will be paint
ed automatically | 101 // When a parent container is transformed in SVG, all children will be paint
ed automatically |
108 // so we are able to skip redundant repaint checks. | 102 // so we are able to skip redundant repaint checks. |
109 RenderObject* parent = object->parent(); | 103 RenderObject* parent = object->parent(); |
110 return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)-
>didTransformToRootUpdate()); | 104 return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)-
>didTransformToRootUpdate()); |
111 } | 105 } |
112 | 106 |
113 // Update a bounding box taking into account the validity of the other bounding
box. | |
114 static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& o
bjectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) | |
115 { | |
116 bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isO
bjectBoundingBoxValid() : true; | |
117 if (!otherValid) | |
118 return; | |
119 | |
120 if (!objectBoundingBoxValid) { | |
121 objectBoundingBox = otherBoundingBox; | |
122 objectBoundingBoxValid = true; | |
123 return; | |
124 } | |
125 | |
126 objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox); | |
127 } | |
128 | |
129 void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* contain
er, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strok
eBoundingBox, FloatRect& repaintBoundingBox) | |
130 { | |
131 objectBoundingBox = FloatRect(); | |
132 objectBoundingBoxValid = false; | |
133 strokeBoundingBox = FloatRect(); | |
134 | |
135 // When computing the strokeBoundingBox, we use the repaintRects of the cont
ainer's children so that the container's stroke includes | |
136 // the resources applied to the children (such as clips and filters). This a
llows filters applied to containers to correctly bound | |
137 // the children, and also improves inlining of SVG content, as the stroke bo
und is used in that situation also. | |
138 for (RenderObject* current = container->slowFirstChild(); current; current =
current->nextSibling()) { | |
139 if (current->isSVGHiddenContainer()) | |
140 continue; | |
141 | |
142 const AffineTransform& transform = current->localToParentTransform(); | |
143 updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, curre
nt, | |
144 transform.mapRect(current->objectBoundingBox())); | |
145 strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoo
rdinates())); | |
146 } | |
147 | |
148 repaintBoundingBox = strokeBoundingBox; | |
149 } | |
150 | |
151 bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepa
intRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) | 107 bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepa
intRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) |
152 { | 108 { |
153 return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); | 109 return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); |
154 } | 110 } |
155 | 111 |
156 const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* st
art) | 112 const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* st
art) |
157 { | 113 { |
158 while (start && !start->isSVGRoot()) | 114 while (start && !start->isSVGRoot()) |
159 start = start->parent(); | 115 start = start->parent(); |
160 | 116 |
161 ASSERT(start); | 117 ASSERT(start); |
162 ASSERT(start->isSVGRoot()); | 118 ASSERT(start->isSVGRoot()); |
163 return toRenderSVGRoot(start); | 119 return toRenderSVGRoot(start); |
164 } | 120 } |
165 | 121 |
166 static inline void invalidateResourcesOfChildren(RenderObject* start) | |
167 { | |
168 ASSERT(!start->needsLayout()); | |
169 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObj
ect(start)) | |
170 resources->removeClientFromCache(start, false); | |
171 | |
172 for (RenderObject* child = start->slowFirstChild(); child; child = child->ne
xtSibling()) | |
173 invalidateResourcesOfChildren(child); | |
174 } | |
175 | |
176 static inline bool layoutSizeOfNearestViewportChanged(const RenderObject* start) | |
177 { | |
178 while (start && !start->isSVGRoot() && !start->isSVGViewportContainer()) | |
179 start = start->parent(); | |
180 | |
181 ASSERT(start); | |
182 ASSERT(start->isSVGRoot() || start->isSVGViewportContainer()); | |
183 if (start->isSVGViewportContainer()) | |
184 return toRenderSVGViewportContainer(start)->isLayoutSizeChanged(); | |
185 | |
186 return toRenderSVGRoot(start)->isLayoutSizeChanged(); | |
187 } | |
188 | |
189 bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor) | 122 bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor) |
190 { | 123 { |
191 while (ancestor && !ancestor->isSVGRoot()) { | 124 while (ancestor && !ancestor->isSVGRoot()) { |
192 if (ancestor->isSVGTransformableContainer()) | 125 if (ancestor->isSVGTransformableContainer()) |
193 return toRenderSVGContainer(ancestor)->didTransformToRootUpdate(); | 126 return toRenderSVGContainer(ancestor)->didTransformToRootUpdate(); |
194 if (ancestor->isSVGViewportContainer()) | 127 if (ancestor->isSVGViewportContainer()) |
195 return toRenderSVGViewportContainer(ancestor)->didTransformToRootUpd
ate(); | 128 return toRenderSVGViewportContainer(ancestor)->didTransformToRootUpd
ate(); |
196 ancestor = ancestor->parent(); | 129 ancestor = ancestor->parent(); |
197 } | 130 } |
198 | 131 |
199 return false; | 132 return false; |
200 } | 133 } |
201 | 134 |
202 void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) | |
203 { | |
204 bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); | |
205 bool transformChanged = transformToRootChanged(start); | |
206 HashSet<RenderObject*> notlayoutedObjects; | |
207 | |
208 for (RenderObject* child = start->slowFirstChild(); child; child = child->ne
xtSibling()) { | |
209 bool needsLayout = selfNeedsLayout; | |
210 bool childEverHadLayout = child->everHadLayout(); | |
211 | |
212 if (transformChanged) { | |
213 // If the transform changed we need to update the text metrics (note
: this also happens for layoutSizeChanged=true). | |
214 if (child->isSVGText()) | |
215 toRenderSVGText(child)->setNeedsTextMetricsUpdate(); | |
216 needsLayout = true; | |
217 } | |
218 | |
219 if (layoutSizeChanged) { | |
220 // When selfNeedsLayout is false and the layout size changed, we hav
e to check whether this child uses relative lengths | |
221 if (SVGElement* element = child->node()->isSVGElement() ? toSVGEleme
nt(child->node()) : 0) { | |
222 if (element->hasRelativeLengths()) { | |
223 // When the layout size changed and when using relative valu
es tell the RenderSVGShape to update its shape object | |
224 if (child->isSVGShape()) | |
225 toRenderSVGShape(child)->setNeedsShapeUpdate(); | |
226 else if (child->isSVGText()) { | |
227 toRenderSVGText(child)->setNeedsTextMetricsUpdate(); | |
228 toRenderSVGText(child)->setNeedsPositioningValuesUpdate(
); | |
229 } | |
230 | |
231 needsLayout = true; | |
232 } | |
233 } | |
234 } | |
235 | |
236 SubtreeLayoutScope layoutScope(*child); | |
237 // Resource containers are nasty: they can invalidate clients outside th
e current SubtreeLayoutScope. | |
238 // Since they only care about viewport size changes (to resolve their re
lative lengths), we trigger | |
239 // their invalidation directly from SVGSVGElement::svgAttributeChange()
or at a higher | |
240 // SubtreeLayoutScope (in RenderView::layout()). | |
241 if (needsLayout && !child->isSVGResourceContainer()) | |
242 layoutScope.setNeedsLayout(child); | |
243 | |
244 layoutResourcesIfNeeded(child); | |
245 | |
246 if (child->needsLayout()) { | |
247 child->layout(); | |
248 // Renderers are responsible for repainting themselves when changing
, except | |
249 // for the initial paint to avoid potential double-painting caused b
y non-sensical "old" bounds. | |
250 // We could handle this in the individual objects, but for now it's
easier to have | |
251 // parent containers call repaint(). (RenderBlock::layout* has simi
lar logic.) | |
252 if (!childEverHadLayout && !RuntimeEnabledFeatures::repaintAfterLayo
utEnabled()) | |
253 child->repaint(); | |
254 } else if (layoutSizeChanged) | |
255 notlayoutedObjects.add(child); | |
256 } | |
257 | |
258 if (!layoutSizeChanged) { | |
259 ASSERT(notlayoutedObjects.isEmpty()); | |
260 return; | |
261 } | |
262 | |
263 // If the layout size changed, invalidate all resources of all children that
didn't go through the layout() code path. | |
264 HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); | |
265 for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it !=
end; ++it) | |
266 invalidateResourcesOfChildren(*it); | |
267 } | |
268 | |
269 void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object) | 135 void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object) |
270 { | 136 { |
271 ASSERT(object); | 137 ASSERT(object); |
272 | 138 |
273 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(
object); | 139 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(
object); |
274 if (resources) | 140 if (resources) |
275 resources->layoutIfNeeded(); | 141 resources->layoutIfNeeded(); |
276 } | 142 } |
277 | 143 |
278 bool SVGRenderSupport::isOverflowHidden(const RenderObject* object) | 144 bool SVGRenderSupport::isOverflowHidden(const RenderObject* object) |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 } | 257 } |
392 | 258 |
393 bool SVGRenderSupport::isRenderableTextNode(const RenderObject* object) | 259 bool SVGRenderSupport::isRenderableTextNode(const RenderObject* object) |
394 { | 260 { |
395 ASSERT(object->isText()); | 261 ASSERT(object->isText()); |
396 // <br> is marked as text, but is not handled by the SVG rendering code-path
. | 262 // <br> is marked as text, but is not handled by the SVG rendering code-path
. |
397 return object->isSVGInlineText() && !toRenderSVGInlineText(object)->hasEmpty
Text(); | 263 return object->isSVGInlineText() && !toRenderSVGInlineText(object)->hasEmpty
Text(); |
398 } | 264 } |
399 | 265 |
400 } | 266 } |
OLD | NEW |