OLD | NEW |
1 /** | 1 /** |
2 * Copyright (C) 2007 Rob Buis <buis@kde.org> | 2 * Copyright (C) 2007 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) Research In Motion Limited 2010. All rights reserved. | 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
12 * | 12 * |
13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
17 * | 17 * |
18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
22 */ | 22 */ |
23 | 23 |
24 #ifndef SVGRenderSupport_h | 24 #ifndef SVGRenderSupport_h |
25 #define SVGRenderSupport_h | 25 #define SVGRenderSupport_h |
26 | 26 |
27 #include "core/rendering/PaintInfo.h" | 27 #include "core/rendering/PaintInfo.h" |
| 28 #include "core/rendering/svg/RenderSVGRoot.h" |
| 29 #include "core/rendering/svg/RenderSVGShape.h" |
| 30 #include "core/rendering/svg/RenderSVGText.h" |
| 31 #include "core/rendering/svg/RenderSVGViewportContainer.h" |
| 32 #include "core/rendering/svg/SVGResources.h" |
| 33 #include "core/rendering/svg/SVGResourcesCache.h" |
28 | 34 |
29 namespace WebCore { | 35 namespace WebCore { |
30 | 36 |
31 class FloatPoint; | 37 class FloatPoint; |
32 class FloatRect; | 38 class FloatRect; |
33 class ImageBuffer; | 39 class ImageBuffer; |
34 class LayoutRect; | 40 class LayoutRect; |
35 class RenderBoxModelObject; | 41 class RenderBoxModelObject; |
36 class RenderGeometryMap; | 42 class RenderGeometryMap; |
37 class RenderLayerModelObject; | 43 class RenderLayerModelObject; |
38 class RenderObject; | 44 class RenderObject; |
39 class RenderStyle; | 45 class RenderStyle; |
40 class RenderSVGRoot; | 46 class RenderSVGRoot; |
41 class TransformState; | 47 class TransformState; |
42 | 48 |
43 namespace SVGRenderSupport { | 49 class SVGRenderSupport { |
44 // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container | 50 public: |
45 void layoutChildren(RenderObject*, bool selfNeedsLayout); | 51 // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Contai
ner |
| 52 template <typename RenderObjectType> |
| 53 static void layoutChildren(RenderObjectType*, bool selfNeedsLayout); |
46 | 54 |
47 // Layout resources used by this node. | 55 // Layout resources used by this node. |
48 void layoutResourcesIfNeeded(const RenderObject*); | 56 static void layoutResourcesIfNeeded(const RenderObject*); |
49 | 57 |
50 // Helper function determining wheter overflow is hidden | 58 // Helper function determining wheter overflow is hidden |
51 bool isOverflowHidden(const RenderObject*); | 59 static bool isOverflowHidden(const RenderObject*); |
52 | 60 |
53 // Calculates the repaintRect in combination with filter, clipper and masker in
local coordinates. | 61 // Calculates the repaintRect in combination with filter, clipper and masker
in local coordinates. |
54 void intersectRepaintRectWithResources(const RenderObject*, FloatRect&); | 62 static void intersectRepaintRectWithResources(const RenderObject*, FloatRect
&); |
55 | 63 |
56 // Determines whether a container needs to be laid out because it's filtered and
a child is being laid out. | 64 // Determines whether a container needs to be laid out because it's filtered
and a child is being laid out. |
57 bool filtersForceContainerLayout(RenderObject*); | 65 static bool filtersForceContainerLayout(RenderObject*); |
58 | 66 |
59 // Determines whether the passed point lies in a clipping area | 67 // Determines whether the passed point lies in a clipping area |
60 bool pointInClippingArea(RenderObject*, const FloatPoint&); | 68 static bool pointInClippingArea(RenderObject*, const FloatPoint&); |
61 | 69 |
62 void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& obj
ectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, Floa
tRect& repaintBoundingBox); | 70 template <typename RenderObjectType> |
63 bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const Aff
ineTransform& localTransform, const PaintInfo&); | 71 static void computeContainerBoundingBoxes(const RenderObjectType* container,
FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBo
undingBox, FloatRect& repaintBoundingBox); |
64 | 72 |
65 // Important functions used by nearly all SVG renderers centralizing coordinate
transformations / repaint rect calculations | 73 static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect
, const AffineTransform& localTransform, const PaintInfo&); |
66 LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const RenderLayerM
odelObject* repaintContainer); | |
67 void computeFloatRectForRepaint(const RenderObject*, const RenderLayerModelObjec
t* repaintContainer, FloatRect&, bool fixed); | |
68 void mapLocalToContainer(const RenderObject*, const RenderLayerModelObject* repa
intContainer, TransformState&, bool* wasFixed = 0); | |
69 const RenderObject* pushMappingToContainer(const RenderObject*, const RenderLaye
rModelObject* ancestorToStopAt, RenderGeometryMap&); | |
70 bool checkForSVGRepaintDuringLayout(RenderObject*); | |
71 | 74 |
72 // Shared between SVG renderers and resources. | 75 // Important functions used by nearly all SVG renderers centralizing coordin
ate transformations / repaint rect calculations |
73 void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const Rende
rObject*); | 76 static LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const R
enderLayerModelObject* repaintContainer); |
74 void applyStrokeStyleToStrokeData(StrokeData*, const RenderStyle*, const RenderO
bject*); | 77 static void computeFloatRectForRepaint(const RenderObject*, const RenderLaye
rModelObject* repaintContainer, FloatRect&, bool fixed); |
| 78 static void mapLocalToContainer(const RenderObject*, const RenderLayerModelO
bject* repaintContainer, TransformState&, bool* wasFixed = 0); |
| 79 static const RenderObject* pushMappingToContainer(const RenderObject*, const
RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&); |
| 80 static bool checkForSVGRepaintDuringLayout(RenderObject*); |
75 | 81 |
76 // Determines if any ancestor's transform has changed. | 82 // Shared between SVG renderers and resources. |
77 bool transformToRootChanged(RenderObject*); | 83 static void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*,
const RenderObject*); |
| 84 static void applyStrokeStyleToStrokeData(StrokeData*, const RenderStyle*, co
nst RenderObject*); |
78 | 85 |
79 // FIXME: These methods do not belong here. | 86 // Determines if any ancestor's transform has changed. |
80 const RenderSVGRoot* findTreeRootObject(const RenderObject*); | 87 static bool transformToRootChanged(RenderObject*); |
81 | 88 |
82 // Helper method for determining if a RenderObject marked as text (isText()== tr
ue) | 89 // FIXME: These methods do not belong here. |
83 // can/will be rendered as part of a <text>. | 90 static const RenderSVGRoot* findTreeRootObject(const RenderObject*); |
84 bool isRenderableTextNode(const RenderObject*); | |
85 | 91 |
86 } // namespace SVGRenderSupport | 92 // Helper method for determining if a RenderObject marked as text (isText()=
= true) |
| 93 // can/will be rendered as part of a <text>. |
| 94 static bool isRenderableTextNode(const RenderObject*); |
| 95 |
| 96 private: |
| 97 static void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& obje
ctBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox); |
| 98 static void invalidateResourcesOfChildren(RenderObject* start); |
| 99 static bool layoutSizeOfNearestViewportChanged(const RenderObject* start); |
| 100 }; |
| 101 |
| 102 template <typename RenderObjectType> |
| 103 void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObjectType* con
tainer, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& s
trokeBoundingBox, FloatRect& repaintBoundingBox) |
| 104 { |
| 105 objectBoundingBox = FloatRect(); |
| 106 objectBoundingBoxValid = false; |
| 107 strokeBoundingBox = FloatRect(); |
| 108 |
| 109 // When computing the strokeBoundingBox, we use the repaintRects of the cont
ainer's children so that the container's stroke includes |
| 110 // the resources applied to the children (such as clips and filters). This a
llows filters applied to containers to correctly bound |
| 111 // the children, and also improves inlining of SVG content, as the stroke bo
und is used in that situation also. |
| 112 for (RenderObject* current = container->firstChild(); current; current = cur
rent->nextSibling()) { |
| 113 if (current->isSVGHiddenContainer()) |
| 114 continue; |
| 115 |
| 116 const AffineTransform& transform = current->localToParentTransform(); |
| 117 updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, curre
nt, |
| 118 transform.mapRect(current->objectBoundingBox())); |
| 119 strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoo
rdinates())); |
| 120 } |
| 121 |
| 122 repaintBoundingBox = strokeBoundingBox; |
| 123 } |
| 124 |
| 125 template <typename RenderObjectType> |
| 126 void SVGRenderSupport::layoutChildren(RenderObjectType* start, bool selfNeedsLay
out) |
| 127 { |
| 128 bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); |
| 129 bool transformChanged = transformToRootChanged(start); |
| 130 HashSet<RenderObject*> notlayoutedObjects; |
| 131 |
| 132 for (RenderObject* child = start->firstChild(); child; child = child->nextSi
bling()) { |
| 133 bool needsLayout = selfNeedsLayout; |
| 134 bool childEverHadLayout = child->everHadLayout(); |
| 135 |
| 136 if (transformChanged) { |
| 137 // If the transform changed we need to update the text metrics (note
: this also happens for layoutSizeChanged=true). |
| 138 if (child->isSVGText()) |
| 139 toRenderSVGText(child)->setNeedsTextMetricsUpdate(); |
| 140 needsLayout = true; |
| 141 } |
| 142 |
| 143 if (layoutSizeChanged) { |
| 144 // When selfNeedsLayout is false and the layout size changed, we hav
e to check whether this child uses relative lengths |
| 145 if (SVGElement* element = child->node()->isSVGElement() ? toSVGEleme
nt(child->node()) : 0) { |
| 146 if (element->hasRelativeLengths()) { |
| 147 // When the layout size changed and when using relative valu
es tell the RenderSVGShape to update its shape object |
| 148 if (child->isSVGShape()) { |
| 149 toRenderSVGShape(child)->setNeedsShapeUpdate(); |
| 150 } else if (child->isSVGText()) { |
| 151 toRenderSVGText(child)->setNeedsTextMetricsUpdate(); |
| 152 toRenderSVGText(child)->setNeedsPositioningValuesUpdate(
); |
| 153 } |
| 154 |
| 155 needsLayout = true; |
| 156 } |
| 157 } |
| 158 } |
| 159 |
| 160 SubtreeLayoutScope layoutScope(*child); |
| 161 // Resource containers are nasty: they can invalidate clients outside th
e current SubtreeLayoutScope. |
| 162 // Since they only care about viewport size changes (to resolve their re
lative lengths), we trigger |
| 163 // their invalidation directly from SVGSVGElement::svgAttributeChange()
or at a higher |
| 164 // SubtreeLayoutScope (in RenderView::layout()). |
| 165 if (needsLayout && !child->isSVGResourceContainer()) |
| 166 layoutScope.setNeedsLayout(child); |
| 167 |
| 168 layoutResourcesIfNeeded(child); |
| 169 |
| 170 if (child->needsLayout()) { |
| 171 child->layout(); |
| 172 // Renderers are responsible for repainting themselves when changing
, except |
| 173 // for the initial paint to avoid potential double-painting caused b
y non-sensical "old" bounds. |
| 174 // We could handle this in the individual objects, but for now it's
easier to have |
| 175 // parent containers call repaint(). (RenderBlock::layout* has simi
lar logic.) |
| 176 if (!childEverHadLayout && !RuntimeEnabledFeatures::repaintAfterLayo
utEnabled()) |
| 177 child->repaint(); |
| 178 } else if (layoutSizeChanged) { |
| 179 notlayoutedObjects.add(child); |
| 180 } |
| 181 } |
| 182 |
| 183 if (!layoutSizeChanged) { |
| 184 ASSERT(notlayoutedObjects.isEmpty()); |
| 185 return; |
| 186 } |
| 187 |
| 188 // If the layout size changed, invalidate all resources of all children that
didn't go through the layout() code path. |
| 189 HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); |
| 190 for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it !=
end; ++it) |
| 191 invalidateResourcesOfChildren(*it); |
| 192 } |
| 193 |
| 194 // Update a bounding box taking into account the validity of the other bounding
box. |
| 195 inline void SVGRenderSupport::updateObjectBoundingBox(FloatRect& objectBoundingB
ox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBo
x) |
| 196 { |
| 197 bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isO
bjectBoundingBoxValid() : true; |
| 198 if (!otherValid) |
| 199 return; |
| 200 |
| 201 if (!objectBoundingBoxValid) { |
| 202 objectBoundingBox = otherBoundingBox; |
| 203 objectBoundingBoxValid = true; |
| 204 return; |
| 205 } |
| 206 |
| 207 objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox); |
| 208 } |
| 209 |
| 210 inline void SVGRenderSupport::invalidateResourcesOfChildren(RenderObject* start) |
| 211 { |
| 212 ASSERT(!start->needsLayout()); |
| 213 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObj
ect(start)) |
| 214 resources->removeClientFromCache(start, false); |
| 215 |
| 216 for (RenderObject* child = start->slowFirstChild(); child; child = child->ne
xtSibling()) |
| 217 invalidateResourcesOfChildren(child); |
| 218 } |
| 219 |
| 220 inline bool SVGRenderSupport::layoutSizeOfNearestViewportChanged(const RenderObj
ect* start) |
| 221 { |
| 222 while (start && !start->isSVGRoot() && !start->isSVGViewportContainer()) |
| 223 start = start->parent(); |
| 224 |
| 225 ASSERT(start); |
| 226 ASSERT(start->isSVGRoot() || start->isSVGViewportContainer()); |
| 227 if (start->isSVGViewportContainer()) |
| 228 return toRenderSVGViewportContainer(start)->isLayoutSizeChanged(); |
| 229 |
| 230 return toRenderSVGRoot(start)->isLayoutSizeChanged(); |
| 231 } |
87 | 232 |
88 } // namespace WebCore | 233 } // namespace WebCore |
89 | 234 |
90 #endif // SVGRenderSupport_h | 235 #endif // SVGRenderSupport_h |
OLD | NEW |