OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006 Apple Computer, Inc. | 2 * Copyright (C) 2006 Apple Computer, Inc. |
3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> | 3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> |
4 * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> | 4 * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> |
5 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> | 5 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> |
6 * Copyright (C) 2008 Rob Buis <buis@kde.org> | 6 * Copyright (C) 2008 Rob Buis <buis@kde.org> |
7 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> | 7 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> |
8 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. | 8 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. |
9 * Copyright (C) 2012 Google Inc. | 9 * Copyright (C) 2012 Google Inc. |
10 * | 10 * |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 #include "SVGURIReference.h" | 50 #include "SVGURIReference.h" |
51 #include "SimpleFontData.h" | 51 #include "SimpleFontData.h" |
52 #include "TransformState.h" | 52 #include "TransformState.h" |
53 #include "VisiblePosition.h" | 53 #include "VisiblePosition.h" |
54 | 54 |
55 namespace WebCore { | 55 namespace WebCore { |
56 | 56 |
57 RenderSVGText::RenderSVGText(SVGTextElement* node) | 57 RenderSVGText::RenderSVGText(SVGTextElement* node) |
58 : RenderSVGBlock(node) | 58 : RenderSVGBlock(node) |
59 , m_needsReordering(false) | 59 , m_needsReordering(false) |
60 , m_needsPositioningValuesUpdate(true) | 60 , m_needsPositioningValuesUpdate(false) |
61 , m_needsTransformUpdate(true) | 61 , m_needsTransformUpdate(true) |
62 , m_needsTextMetricsUpdate(true) | 62 , m_needsTextMetricsUpdate(false) |
63 { | 63 { |
64 } | 64 } |
65 | 65 |
| 66 RenderSVGText::~RenderSVGText() |
| 67 { |
| 68 ASSERT(m_layoutAttributes.isEmpty()); |
| 69 } |
| 70 |
66 bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const | 71 bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const |
67 { | 72 { |
68 return child->isInline(); | 73 return child->isInline(); |
69 } | 74 } |
70 | 75 |
71 RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start) | 76 RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start) |
72 { | 77 { |
73 ASSERT(start); | 78 ASSERT(start); |
74 while (start && !start->isSVGText()) | 79 while (start && !start->isSVGText()) |
75 start = start->parent(); | 80 start = start->parent(); |
(...skipping 27 matching lines...) Expand all Loading... |
103 void RenderSVGText::computeFloatRectForRepaint(RenderBoxModelObject* repaintCont
ainer, FloatRect& repaintRect, bool fixed) const | 108 void RenderSVGText::computeFloatRectForRepaint(RenderBoxModelObject* repaintCont
ainer, FloatRect& repaintRect, bool fixed) const |
104 { | 109 { |
105 SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaint
Rect, fixed); | 110 SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaint
Rect, fixed); |
106 } | 111 } |
107 | 112 |
108 void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer,
bool /* fixed */, bool /* useTransforms */, TransformState& transformState, Appl
yContainerFlipOrNot, bool* wasFixed) const | 113 void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer,
bool /* fixed */, bool /* useTransforms */, TransformState& transformState, Appl
yContainerFlipOrNot, bool* wasFixed) const |
109 { | 114 { |
110 SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState
, wasFixed); | 115 SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState
, wasFixed); |
111 } | 116 } |
112 | 117 |
113 static inline void recursiveUpdateLayoutAttributes(RenderObject* start, SVGTextL
ayoutAttributesBuilder& builder) | 118 static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLay
outAttributes*>& attributes) |
114 { | 119 { |
115 if (start->isSVGInlineText()) { | 120 for (RenderObject* descendant = text; descendant; descendant = descendant->n
extInPreOrder(text)) { |
116 builder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(start
)); | 121 if (descendant->isSVGInlineText()) |
117 return; | 122 attributes.append(toRenderSVGInlineText(descendant)->layoutAttribute
s()); |
118 } | 123 } |
119 | |
120 for (RenderObject* child = start->firstChild(); child; child = child->nextSi
bling()) | |
121 recursiveUpdateLayoutAttributes(child, builder); | |
122 } | |
123 | |
124 void RenderSVGText::layoutAttributesChanged(RenderObject* child) | |
125 { | |
126 ASSERT(child); | |
127 if (m_needsPositioningValuesUpdate) | |
128 return; | |
129 FontCachePurgePreventer fontCachePurgePreventer; | |
130 recursiveUpdateLayoutAttributes(child, m_layoutAttributesBuilder); | |
131 rebuildLayoutAttributes(); | |
132 } | 124 } |
133 | 125 |
134 static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGI
nlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previou
s, SVGTextLayoutAttributes*& next) | 126 static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGI
nlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previou
s, SVGTextLayoutAttributes*& next) |
135 { | 127 { |
136 ASSERT(start); | 128 ASSERT(start); |
137 ASSERT(locateElement); | 129 ASSERT(locateElement); |
| 130 // FIXME: Make this iterative. |
138 for (RenderObject* child = start->firstChild(); child; child = child->nextSi
bling()) { | 131 for (RenderObject* child = start->firstChild(); child; child = child->nextSi
bling()) { |
139 if (child->isSVGInlineText()) { | 132 if (child->isSVGInlineText()) { |
140 RenderSVGInlineText* text = toRenderSVGInlineText(child); | 133 RenderSVGInlineText* text = toRenderSVGInlineText(child); |
141 if (locateElement != text) { | 134 if (locateElement != text) { |
142 if (stopAfterNext) { | 135 if (stopAfterNext) { |
143 next = text->layoutAttributes(); | 136 next = text->layoutAttributes(); |
144 return true; | 137 return true; |
145 } | 138 } |
146 | 139 |
147 previous = text->layoutAttributes(); | 140 previous = text->layoutAttributes(); |
148 continue; | 141 continue; |
149 } | 142 } |
150 | 143 |
151 stopAfterNext = true; | 144 stopAfterNext = true; |
152 continue; | 145 continue; |
153 } | 146 } |
154 | 147 |
155 if (!child->isSVGInline()) | 148 if (!child->isSVGInline()) |
156 continue; | 149 continue; |
157 | 150 |
158 if (findPreviousAndNextAttributes(child, locateElement, stopAfterNext, p
revious, next)) | 151 if (findPreviousAndNextAttributes(child, locateElement, stopAfterNext, p
revious, next)) |
159 return true; | 152 return true; |
160 } | 153 } |
161 | 154 |
162 return false; | 155 return false; |
163 } | 156 } |
164 | 157 |
165 void RenderSVGText::layoutAttributesWillBeDestroyed(RenderSVGInlineText* text, V
ector<SVGTextLayoutAttributes*>& affectedAttributes) | 158 inline bool RenderSVGText::shouldHandleSubtreeMutations() const |
| 159 { |
| 160 if (beingDestroyed() || !everHadLayout()) { |
| 161 ASSERT(m_layoutAttributes.isEmpty()); |
| 162 ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements()); |
| 163 return false; |
| 164 } |
| 165 return true; |
| 166 } |
| 167 |
| 168 void RenderSVGText::subtreeChildWasAdded(RenderObject* child) |
| 169 { |
| 170 ASSERT(child); |
| 171 if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) |
| 172 return; |
| 173 |
| 174 // The positioning elements cache doesn't include the new 'child' yet. Clear
the |
| 175 // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds i
t. |
| 176 m_layoutAttributesBuilder.clearTextPositioningElements(); |
| 177 |
| 178 // Detect changes in layout attributes and only measure those text parts tha
t have changed! |
| 179 Vector<SVGTextLayoutAttributes*> newLayoutAttributes; |
| 180 collectLayoutAttributes(this, newLayoutAttributes); |
| 181 if (newLayoutAttributes.isEmpty()) { |
| 182 ASSERT(m_layoutAttributes.isEmpty()); |
| 183 return; |
| 184 } |
| 185 |
| 186 // Compare m_layoutAttributes with newLayoutAttributes to figure out which a
ttribute got added. |
| 187 size_t size = newLayoutAttributes.size(); |
| 188 SVGTextLayoutAttributes* attributes = 0; |
| 189 for (size_t i = 0; i < size; ++i) { |
| 190 attributes = newLayoutAttributes[i]; |
| 191 if (m_layoutAttributes.find(attributes) == notFound) { |
| 192 // Every time this is invoked, there's only a single new entry in th
e newLayoutAttributes list, compared to the old in m_layoutAttributes. |
| 193 bool stopAfterNext = false; |
| 194 SVGTextLayoutAttributes* previous = 0; |
| 195 SVGTextLayoutAttributes* next = 0; |
| 196 ASSERT_UNUSED(child, attributes->context() == child); |
| 197 findPreviousAndNextAttributes(this, attributes->context(), stopAfter
Next, previous, next); |
| 198 |
| 199 if (previous) |
| 200 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(p
revious->context()); |
| 201 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attri
butes->context()); |
| 202 if (next) |
| 203 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(n
ext->context()); |
| 204 break; |
| 205 } |
| 206 } |
| 207 |
| 208 #ifndef NDEBUG |
| 209 // Verify that m_layoutAttributes only differs by a maximum of one entry. |
| 210 for (size_t i = 0; i < size; ++i) |
| 211 ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || ne
wLayoutAttributes[i] == attributes); |
| 212 #endif |
| 213 |
| 214 m_layoutAttributes = newLayoutAttributes; |
| 215 } |
| 216 |
| 217 static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector<
SVGTextLayoutAttributes*>& expectedLayoutAttributes) |
| 218 { |
| 219 #ifndef NDEBUG |
| 220 Vector<SVGTextLayoutAttributes*> newLayoutAttributes; |
| 221 collectLayoutAttributes(text, newLayoutAttributes); |
| 222 ASSERT(newLayoutAttributes == expectedLayoutAttributes); |
| 223 #else |
| 224 UNUSED_PARAM(text); |
| 225 UNUSED_PARAM(expectedLayoutAttributes); |
| 226 #endif |
| 227 } |
| 228 |
| 229 void RenderSVGText::willBeDestroyed() |
| 230 { |
| 231 m_layoutAttributes.clear(); |
| 232 m_layoutAttributesBuilder.clearTextPositioningElements(); |
| 233 |
| 234 RenderSVGBlock::willBeDestroyed(); |
| 235 } |
| 236 |
| 237 void RenderSVGText::subtreeChildWillBeRemoved(RenderSVGInlineText* text, Vector<
SVGTextLayoutAttributes*, 2>& affectedAttributes) |
166 { | 238 { |
167 ASSERT(text); | 239 ASSERT(text); |
168 if (m_needsPositioningValuesUpdate) | 240 if (!shouldHandleSubtreeMutations()) |
169 return; | 241 return; |
170 | 242 |
| 243 checkLayoutAttributesConsistency(this, m_layoutAttributes); |
| 244 |
| 245 // The positioning elements cache depends on the size of each text renderer
in the |
| 246 // subtree. If this changes, clear the cache. It's going to be rebuilt below
. |
| 247 m_layoutAttributesBuilder.clearTextPositioningElements(); |
| 248 if (m_layoutAttributes.isEmpty()) |
| 249 return; |
| 250 |
| 251 // This logic requires that the 'text' child is still inserted in the tree. |
171 bool stopAfterNext = false; | 252 bool stopAfterNext = false; |
172 SVGTextLayoutAttributes* previous = 0; | 253 SVGTextLayoutAttributes* previous = 0; |
173 SVGTextLayoutAttributes* next = 0; | 254 SVGTextLayoutAttributes* next = 0; |
174 findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next); | 255 if (!documentBeingDestroyed()) |
| 256 findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next)
; |
| 257 |
175 if (previous) | 258 if (previous) |
176 affectedAttributes.append(previous); | 259 affectedAttributes.append(previous); |
177 if (next) | 260 if (next) |
178 affectedAttributes.append(next); | 261 affectedAttributes.append(next); |
| 262 |
| 263 size_t position = m_layoutAttributes.find(text->layoutAttributes()); |
| 264 ASSERT(position != notFound); |
| 265 m_layoutAttributes.remove(position); |
179 } | 266 } |
180 | 267 |
181 void RenderSVGText::invalidateTextPositioningElements() | 268 void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*
, 2>& affectedAttributes) |
182 { | 269 { |
183 // Clear the text positioning elements. This should be called when either th
e children | 270 if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) { |
184 // of a DOM text element have changed, or the length of the text in any chil
d element | 271 ASSERT(affectedAttributes.isEmpty()); |
185 // has changed. Failure to clear may leave us with invalid elements, as othe
r code paths | 272 return; |
186 // do not always cause the position elements to be marked invalid before use
. | 273 } |
187 m_layoutAttributesBuilder.clearTextPositioningElements(); | 274 |
| 275 // This is called immediately after subtreeChildWillBeDestroyed, once the Re
nderSVGInlineText::willBeDestroyed() method |
| 276 // passes on to the base class, which removes us from the render tree. At th
is point we can update the layout attributes. |
| 277 unsigned size = affectedAttributes.size(); |
| 278 for (unsigned i = 0; i < size; ++i) |
| 279 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedA
ttributes[i]->context()); |
188 } | 280 } |
189 | 281 |
190 static inline void recursiveUpdateScaledFont(RenderObject* start) | 282 void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) |
191 { | 283 { |
192 for (RenderObject* child = start->firstChild(); child; child = child->nextSi
bling()) { | 284 ASSERT(text); |
193 if (child->isSVGInlineText()) { | 285 if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) |
194 toRenderSVGInlineText(child)->updateScaledFont(); | 286 return; |
195 continue; | |
196 } | |
197 | 287 |
198 recursiveUpdateScaledFont(child); | 288 checkLayoutAttributesConsistency(this, m_layoutAttributes); |
| 289 |
| 290 // Only update the metrics cache, but not the text positioning element cache |
| 291 // nor the layout attributes cached in the leaf #text renderers. |
| 292 FontCachePurgePreventer fontCachePurgePreventer; |
| 293 for (RenderObject* descendant = text; descendant; descendant = descendant->n
extInPreOrder(text)) { |
| 294 if (descendant->isSVGInlineText()) |
| 295 m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGI
nlineText(descendant)); |
199 } | 296 } |
200 } | 297 } |
201 | 298 |
| 299 void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text) |
| 300 { |
| 301 ASSERT(text); |
| 302 ASSERT(!beingDestroyed()); |
| 303 if (!everHadLayout()) { |
| 304 ASSERT(m_layoutAttributes.isEmpty()); |
| 305 ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements()); |
| 306 return; |
| 307 } |
| 308 |
| 309 // The positioning elements cache depends on the size of each text renderer
in the |
| 310 // subtree. If this changes, clear the cache. It's going to be rebuilt below
. |
| 311 m_layoutAttributesBuilder.clearTextPositioningElements(); |
| 312 |
| 313 checkLayoutAttributesConsistency(this, m_layoutAttributes); |
| 314 for (RenderObject* descendant = text; descendant; descendant = descendant->n
extInPreOrder(text)) { |
| 315 if (descendant->isSVGInlineText()) |
| 316 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRen
derSVGInlineText(descendant)); |
| 317 } |
| 318 } |
| 319 |
| 320 static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayout
AttributesBuilder* builder = 0) |
| 321 { |
| 322 for (RenderObject* descendant = start; descendant; descendant = descendant->
nextInPreOrder(start)) { |
| 323 if (!descendant->isSVGInlineText()) |
| 324 continue; |
| 325 RenderSVGInlineText* text = toRenderSVGInlineText(descendant); |
| 326 text->updateScaledFont(); |
| 327 if (builder) |
| 328 builder->rebuildMetricsForTextRenderer(text); |
| 329 } |
| 330 } |
| 331 |
202 void RenderSVGText::layout() | 332 void RenderSVGText::layout() |
203 { | 333 { |
204 ASSERT(needsLayout()); | 334 ASSERT(needsLayout()); |
205 LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); | 335 LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); |
206 | 336 |
207 bool updateCachedBoundariesInParents = false; | 337 bool updateCachedBoundariesInParents = false; |
208 if (m_needsTransformUpdate) { | 338 if (m_needsTransformUpdate) { |
209 SVGTextElement* text = static_cast<SVGTextElement*>(node()); | 339 SVGTextElement* text = static_cast<SVGTextElement*>(node()); |
210 m_localTransform = text->animatedLocalTransform(); | 340 m_localTransform = text->animatedLocalTransform(); |
211 m_needsTransformUpdate = false; | 341 m_needsTransformUpdate = false; |
212 updateCachedBoundariesInParents = true; | 342 updateCachedBoundariesInParents = true; |
213 } | 343 } |
214 | 344 |
215 // If the root layout size changed (eg. window size changes) or the position
ing values change | 345 if (!everHadLayout()) { |
216 // or the transform to the root context has changed then recompute the on-sc
reen font size. | 346 // When laying out initially, collect all layout attributes, build the c
haracter data map, |
217 if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->
isLayoutSizeChanged()) { | 347 // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineTex
t children in the subtree. |
218 recursiveUpdateScaledFont(this); | 348 ASSERT(m_layoutAttributes.isEmpty()); |
219 rebuildLayoutAttributes(true); | 349 collectLayoutAttributes(this, m_layoutAttributes); |
| 350 updateFontInAllDescendants(this); |
| 351 m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this); |
| 352 |
| 353 m_needsReordering = true; |
| 354 m_needsTextMetricsUpdate = false; |
| 355 m_needsPositioningValuesUpdate = false; |
220 updateCachedBoundariesInParents = true; | 356 updateCachedBoundariesInParents = true; |
221 m_needsTextMetricsUpdate = false; | 357 } else if (m_needsPositioningValuesUpdate) { |
222 } | 358 // When the x/y/dx/dy/rotate lists change, recompute the layout attribut
es, and eventually |
| 359 // update the on-screen font objects as well in all descendants. |
| 360 if (m_needsTextMetricsUpdate) { |
| 361 updateFontInAllDescendants(this); |
| 362 m_needsTextMetricsUpdate = false; |
| 363 } |
223 | 364 |
224 if (m_needsPositioningValuesUpdate) { | 365 m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this); |
225 // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder
for details). | |
226 m_layoutAttributesBuilder.buildLayoutAttributesForWholeTree(this); | |
227 m_needsReordering = true; | 366 m_needsReordering = true; |
228 m_needsPositioningValuesUpdate = false; | 367 m_needsPositioningValuesUpdate = false; |
229 updateCachedBoundariesInParents = true; | 368 updateCachedBoundariesInParents = true; |
| 369 } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(
this)->isLayoutSizeChanged()) { |
| 370 // If the root layout size changed (eg. window size changes) or the tran
sform to the root |
| 371 // context has changed then recompute the on-screen font size. |
| 372 updateFontInAllDescendants(this, &m_layoutAttributesBuilder); |
| 373 |
| 374 ASSERT(!m_needsReordering); |
| 375 ASSERT(!m_needsPositioningValuesUpdate); |
| 376 m_needsTextMetricsUpdate = false; |
| 377 updateCachedBoundariesInParents = true; |
230 } | 378 } |
231 | 379 |
| 380 checkLayoutAttributesConsistency(this, m_layoutAttributes); |
| 381 |
232 // Reduced version of RenderBlock::layoutBlock(), which only takes care of S
VG text. | 382 // Reduced version of RenderBlock::layoutBlock(), which only takes care of S
VG text. |
233 // All if branches that could cause early exit in RenderBlocks layoutBlock()
method are turned into assertions. | 383 // All if branches that could cause early exit in RenderBlocks layoutBlock()
method are turned into assertions. |
234 ASSERT(!isInline()); | 384 ASSERT(!isInline()); |
235 ASSERT(!simplifiedLayout()); | 385 ASSERT(!simplifiedLayout()); |
236 ASSERT(!scrollsOverflow()); | 386 ASSERT(!scrollsOverflow()); |
237 ASSERT(!hasControlClip()); | 387 ASSERT(!hasControlClip()); |
238 ASSERT(!hasColumns()); | 388 ASSERT(!hasColumns()); |
239 ASSERT(!positionedObjects()); | 389 ASSERT(!positionedObjects()); |
240 ASSERT(!m_overflow); | 390 ASSERT(!m_overflow); |
241 ASSERT(!isAnonymousBlock()); | 391 ASSERT(!isAnonymousBlock()); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 | 507 |
358 if (const ShadowData* textShadow = style()->textShadow()) | 508 if (const ShadowData* textShadow = style()->textShadow()) |
359 textShadow->adjustRectForShadow(repaintRect); | 509 textShadow->adjustRectForShadow(repaintRect); |
360 | 510 |
361 return repaintRect; | 511 return repaintRect; |
362 } | 512 } |
363 | 513 |
364 void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild) | 514 void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild) |
365 { | 515 { |
366 RenderSVGBlock::addChild(child, beforeChild); | 516 RenderSVGBlock::addChild(child, beforeChild); |
367 layoutAttributesChanged(child); | 517 subtreeChildWasAdded(child); |
| 518 } |
| 519 |
| 520 void RenderSVGText::removeChild(RenderObject* child) |
| 521 { |
| 522 if (!child->isSVGInlineText()) { |
| 523 RenderSVGBlock::removeChild(child); |
| 524 return; |
| 525 } |
| 526 |
| 527 RenderSVGInlineText* text = toRenderSVGInlineText(child); |
| 528 Vector<SVGTextLayoutAttributes*, 2> affectedAttributes; |
| 529 subtreeChildWillBeRemoved(text, affectedAttributes); |
| 530 RenderSVGBlock::removeChild(child); |
| 531 subtreeChildWasRemoved(affectedAttributes); |
368 } | 532 } |
369 | 533 |
370 // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style | 534 // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style |
371 // in a SVG text element context. | 535 // in a SVG text element context. |
372 RenderBlock* RenderSVGText::firstLineBlock() const | 536 RenderBlock* RenderSVGText::firstLineBlock() const |
373 { | 537 { |
374 return 0; | 538 return 0; |
375 } | 539 } |
376 | 540 |
377 // Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Styl
e | 541 // Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Styl
e |
378 // in a SVG text element context. | 542 // in a SVG text element context. |
379 void RenderSVGText::updateFirstLetter() | 543 void RenderSVGText::updateFirstLetter() |
380 { | 544 { |
381 } | 545 } |
382 | 546 |
383 static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<
SVGTextLayoutAttributes*>& attributes) | |
384 { | |
385 for (RenderObject* child = start->firstChild(); child; child = child->nextSi
bling()) { | |
386 if (child->isSVGInlineText()) { | |
387 attributes.append(toRenderSVGInlineText(child)->layoutAttributes()); | |
388 continue; | |
389 } | |
390 | |
391 recursiveCollectLayoutAttributes(child, attributes); | |
392 } | |
393 } | |
394 | |
395 void RenderSVGText::rebuildLayoutAttributes(bool performFullRebuild) | |
396 { | |
397 if (performFullRebuild) | |
398 m_layoutAttributes.clear(); | |
399 | |
400 if (m_layoutAttributes.isEmpty()) { | |
401 recursiveCollectLayoutAttributes(this, m_layoutAttributes); | |
402 if (m_layoutAttributes.isEmpty() || !performFullRebuild) | |
403 return; | |
404 | |
405 m_layoutAttributesBuilder.rebuildMetricsForWholeTree(this); | |
406 return; | |
407 } | |
408 | |
409 Vector<SVGTextLayoutAttributes*> affectedAttributes; | |
410 rebuildLayoutAttributes(affectedAttributes); | |
411 } | |
412 | |
413 void RenderSVGText::rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& af
fectedAttributes) | |
414 { | |
415 // Detect changes in layout attributes and only measure those text parts tha
t have changed! | |
416 Vector<SVGTextLayoutAttributes*> newLayoutAttributes; | |
417 recursiveCollectLayoutAttributes(this, newLayoutAttributes); | |
418 if (newLayoutAttributes.isEmpty()) { | |
419 m_layoutAttributes.clear(); | |
420 return; | |
421 } | |
422 | |
423 // Compare m_layoutAttributes with newLayoutAttributes to figure out which a
ttributes got added/removed. | |
424 size_t size = newLayoutAttributes.size(); | |
425 for (size_t i = 0; i < size; ++i) { | |
426 SVGTextLayoutAttributes* attributes = newLayoutAttributes[i]; | |
427 if (m_layoutAttributes.find(attributes) == notFound) | |
428 m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(attributes->
context()); | |
429 } | |
430 | |
431 size = affectedAttributes.size(); | |
432 for (size_t i = 0; i < size; ++i) | |
433 m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(affectedAttribut
es[i]->context()); | |
434 | |
435 m_layoutAttributes = newLayoutAttributes; | |
436 } | |
437 | |
438 } | 547 } |
439 | 548 |
440 #endif // ENABLE(SVG) | 549 #endif // ENABLE(SVG) |
OLD | NEW |