| 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 |