| 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 #include "core/paint/SVGTextPainter.h" | 43 #include "core/paint/SVGTextPainter.h" |
| 44 #include "core/style/ShadowList.h" | 44 #include "core/style/ShadowList.h" |
| 45 #include "core/svg/SVGTextElement.h" | 45 #include "core/svg/SVGTextElement.h" |
| 46 #include "platform/geometry/FloatQuad.h" | 46 #include "platform/geometry/FloatQuad.h" |
| 47 | 47 |
| 48 namespace blink { | 48 namespace blink { |
| 49 | 49 |
| 50 namespace { | 50 namespace { |
| 51 | 51 |
| 52 const LayoutSVGText* findTextRoot(const LayoutObject* start) { | 52 const LayoutSVGText* findTextRoot(const LayoutObject* start) { |
| 53 ASSERT(start); | 53 DCHECK(start); |
| 54 for (; start; start = start->parent()) { | 54 for (; start; start = start->parent()) { |
| 55 if (start->isSVGText()) | 55 if (start->isSVGText()) |
| 56 return toLayoutSVGText(start); | 56 return toLayoutSVGText(start); |
| 57 } | 57 } |
| 58 return nullptr; | 58 return nullptr; |
| 59 } | 59 } |
| 60 | 60 |
| 61 } // namespace | 61 } // namespace |
| 62 | 62 |
| 63 LayoutSVGText::LayoutSVGText(SVGTextElement* node) | 63 LayoutSVGText::LayoutSVGText(SVGTextElement* node) |
| 64 : LayoutSVGBlock(node), | 64 : LayoutSVGBlock(node), |
| 65 m_needsReordering(false), | 65 m_needsReordering(false), |
| 66 m_needsPositioningValuesUpdate(false), | 66 m_needsPositioningValuesUpdate(false), |
| 67 m_needsTransformUpdate(true), | 67 m_needsTransformUpdate(true), |
| 68 m_needsTextMetricsUpdate(false) {} | 68 m_needsTextMetricsUpdate(false) {} |
| 69 | 69 |
| 70 LayoutSVGText::~LayoutSVGText() { | 70 LayoutSVGText::~LayoutSVGText() { |
| 71 ASSERT(m_descendantTextNodes.isEmpty()); | 71 DCHECK(m_descendantTextNodes.isEmpty()); |
| 72 } | 72 } |
| 73 | 73 |
| 74 void LayoutSVGText::willBeDestroyed() { | 74 void LayoutSVGText::willBeDestroyed() { |
| 75 m_descendantTextNodes.clear(); | 75 m_descendantTextNodes.clear(); |
| 76 | 76 |
| 77 LayoutSVGBlock::willBeDestroyed(); | 77 LayoutSVGBlock::willBeDestroyed(); |
| 78 } | 78 } |
| 79 | 79 |
| 80 bool LayoutSVGText::isChildAllowed(LayoutObject* child, | 80 bool LayoutSVGText::isChildAllowed(LayoutObject* child, |
| 81 const ComputedStyle&) const { | 81 const ComputedStyle&) const { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 104 | 104 |
| 105 void LayoutSVGText::invalidatePositioningValues( | 105 void LayoutSVGText::invalidatePositioningValues( |
| 106 LayoutInvalidationReasonForTracing reason) { | 106 LayoutInvalidationReasonForTracing reason) { |
| 107 m_descendantTextNodes.clear(); | 107 m_descendantTextNodes.clear(); |
| 108 setNeedsPositioningValuesUpdate(); | 108 setNeedsPositioningValuesUpdate(); |
| 109 setNeedsLayoutAndFullPaintInvalidation(reason); | 109 setNeedsLayoutAndFullPaintInvalidation(reason); |
| 110 } | 110 } |
| 111 | 111 |
| 112 void LayoutSVGText::subtreeChildWasAdded() { | 112 void LayoutSVGText::subtreeChildWasAdded() { |
| 113 if (beingDestroyed() || !everHadLayout()) { | 113 if (beingDestroyed() || !everHadLayout()) { |
| 114 ASSERT(m_descendantTextNodes.isEmpty()); | 114 DCHECK(m_descendantTextNodes.isEmpty()); |
| 115 return; | 115 return; |
| 116 } | 116 } |
| 117 if (documentBeingDestroyed()) | 117 if (documentBeingDestroyed()) |
| 118 return; | 118 return; |
| 119 | 119 |
| 120 // The positioning elements cache depends on the size of each text | 120 // The positioning elements cache depends on the size of each text |
| 121 // layoutObject in the subtree. If this changes, clear the cache. It will be | 121 // layoutObject in the subtree. If this changes, clear the cache. It will be |
| 122 // rebuilt on the next layout. | 122 // rebuilt on the next layout. |
| 123 invalidatePositioningValues(LayoutInvalidationReason::ChildChanged); | 123 invalidatePositioningValues(LayoutInvalidationReason::ChildChanged); |
| 124 setNeedsTextMetricsUpdate(); | 124 setNeedsTextMetricsUpdate(); |
| 125 } | 125 } |
| 126 | 126 |
| 127 void LayoutSVGText::subtreeChildWillBeRemoved() { | 127 void LayoutSVGText::subtreeChildWillBeRemoved() { |
| 128 if (beingDestroyed() || !everHadLayout()) { | 128 if (beingDestroyed() || !everHadLayout()) { |
| 129 ASSERT(m_descendantTextNodes.isEmpty()); | 129 DCHECK(m_descendantTextNodes.isEmpty()); |
| 130 return; | 130 return; |
| 131 } | 131 } |
| 132 | 132 |
| 133 // The positioning elements cache depends on the size of each text | 133 // The positioning elements cache depends on the size of each text |
| 134 // layoutObject in the subtree. If this changes, clear the cache. It will be | 134 // layoutObject in the subtree. If this changes, clear the cache. It will be |
| 135 // rebuilt on the next layout. | 135 // rebuilt on the next layout. |
| 136 invalidatePositioningValues(LayoutInvalidationReason::ChildChanged); | 136 invalidatePositioningValues(LayoutInvalidationReason::ChildChanged); |
| 137 setNeedsTextMetricsUpdate(); | 137 setNeedsTextMetricsUpdate(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 void LayoutSVGText::subtreeTextDidChange() { | 140 void LayoutSVGText::subtreeTextDidChange() { |
| 141 ASSERT(!beingDestroyed()); | 141 DCHECK(!beingDestroyed()); |
| 142 if (!everHadLayout()) { | 142 if (!everHadLayout()) { |
| 143 ASSERT(m_descendantTextNodes.isEmpty()); | 143 DCHECK(m_descendantTextNodes.isEmpty()); |
| 144 return; | 144 return; |
| 145 } | 145 } |
| 146 | 146 |
| 147 // The positioning elements cache depends on the size of each text object in | 147 // The positioning elements cache depends on the size of each text object in |
| 148 // the subtree. If this changes, clear the cache and mark it for rebuilding | 148 // the subtree. If this changes, clear the cache and mark it for rebuilding |
| 149 // in the next layout. | 149 // in the next layout. |
| 150 invalidatePositioningValues(LayoutInvalidationReason::TextChanged); | 150 invalidatePositioningValues(LayoutInvalidationReason::TextChanged); |
| 151 setNeedsTextMetricsUpdate(); | 151 setNeedsTextMetricsUpdate(); |
| 152 } | 152 } |
| 153 | 153 |
| 154 static inline void updateFontAndMetrics(LayoutSVGText& textRoot) { | 154 static inline void updateFontAndMetrics(LayoutSVGText& textRoot) { |
| 155 bool lastCharacterWasWhiteSpace = true; | 155 bool lastCharacterWasWhiteSpace = true; |
| 156 for (LayoutObject* descendant = textRoot.firstChild(); descendant; | 156 for (LayoutObject* descendant = textRoot.firstChild(); descendant; |
| 157 descendant = descendant->nextInPreOrder(&textRoot)) { | 157 descendant = descendant->nextInPreOrder(&textRoot)) { |
| 158 if (!descendant->isSVGInlineText()) | 158 if (!descendant->isSVGInlineText()) |
| 159 continue; | 159 continue; |
| 160 LayoutSVGInlineText& text = toLayoutSVGInlineText(*descendant); | 160 LayoutSVGInlineText& text = toLayoutSVGInlineText(*descendant); |
| 161 text.updateScaledFont(); | 161 text.updateScaledFont(); |
| 162 text.updateMetricsList(lastCharacterWasWhiteSpace); | 162 text.updateMetricsList(lastCharacterWasWhiteSpace); |
| 163 } | 163 } |
| 164 } | 164 } |
| 165 | 165 |
| 166 static inline void checkDescendantTextNodeConsistency( | 166 static inline void checkDescendantTextNodeConsistency( |
| 167 LayoutSVGText& text, | 167 LayoutSVGText& text, |
| 168 Vector<LayoutSVGInlineText*>& expectedDescendantTextNodes) { | 168 Vector<LayoutSVGInlineText*>& expectedDescendantTextNodes) { |
| 169 #if DCHECK_IS_ON() | 169 #if DCHECK_IS_ON() |
| 170 Vector<LayoutSVGInlineText*> newDescendantTextNodes; | 170 Vector<LayoutSVGInlineText*> newDescendantTextNodes; |
| 171 collectDescendantTextNodes(text, newDescendantTextNodes); | 171 collectDescendantTextNodes(text, newDescendantTextNodes); |
| 172 ASSERT(newDescendantTextNodes == expectedDescendantTextNodes); | 172 DCHECK(newDescendantTextNodes == expectedDescendantTextNodes); |
| 173 #endif | 173 #endif |
| 174 } | 174 } |
| 175 | 175 |
| 176 void LayoutSVGText::layout() { | 176 void LayoutSVGText::layout() { |
| 177 ASSERT(needsLayout()); | 177 DCHECK(needsLayout()); |
| 178 // This flag is set and reset as needed only within this function. | 178 // This flag is set and reset as needed only within this function. |
| 179 ASSERT(!m_needsReordering); | 179 DCHECK(!m_needsReordering); |
| 180 LayoutAnalyzer::Scope analyzer(*this); | 180 LayoutAnalyzer::Scope analyzer(*this); |
| 181 | 181 |
| 182 bool updateParentBoundaries = false; | 182 bool updateParentBoundaries = false; |
| 183 if (m_needsTransformUpdate) { | 183 if (m_needsTransformUpdate) { |
| 184 m_localTransform = toSVGTextElement(node())->calculateTransform( | 184 m_localTransform = toSVGTextElement(node())->calculateTransform( |
| 185 SVGElement::IncludeMotionTransform); | 185 SVGElement::IncludeMotionTransform); |
| 186 m_needsTransformUpdate = false; | 186 m_needsTransformUpdate = false; |
| 187 updateParentBoundaries = true; | 187 updateParentBoundaries = true; |
| 188 } | 188 } |
| 189 | 189 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 216 m_needsPositioningValuesUpdate = false; | 216 m_needsPositioningValuesUpdate = false; |
| 217 m_needsReordering = true; | 217 m_needsReordering = true; |
| 218 updateParentBoundaries = true; | 218 updateParentBoundaries = true; |
| 219 } | 219 } |
| 220 | 220 |
| 221 checkDescendantTextNodeConsistency(*this, m_descendantTextNodes); | 221 checkDescendantTextNodeConsistency(*this, m_descendantTextNodes); |
| 222 | 222 |
| 223 // Reduced version of LayoutBlock::layoutBlock(), which only takes care of SVG | 223 // Reduced version of LayoutBlock::layoutBlock(), which only takes care of SVG |
| 224 // text. All if branches that could cause early exit in LayoutBlocks | 224 // text. All if branches that could cause early exit in LayoutBlocks |
| 225 // layoutBlock() method are turned into assertions. | 225 // layoutBlock() method are turned into assertions. |
| 226 ASSERT(!isInline()); | 226 DCHECK(!isInline()); |
| 227 ASSERT(!simplifiedLayout()); | 227 DCHECK(!simplifiedLayout()); |
| 228 ASSERT(!scrollsOverflow()); | 228 DCHECK(!scrollsOverflow()); |
| 229 ASSERT(!hasControlClip()); | 229 DCHECK(!hasControlClip()); |
| 230 ASSERT(!positionedObjects()); | 230 DCHECK(!positionedObjects()); |
| 231 ASSERT(!isAnonymousBlock()); | 231 DCHECK(!isAnonymousBlock()); |
| 232 | 232 |
| 233 if (!firstChild()) | 233 if (!firstChild()) |
| 234 setChildrenInline(true); | 234 setChildrenInline(true); |
| 235 | 235 |
| 236 // FIXME: We need to find a way to only layout the child boxes, if needed. | 236 // FIXME: We need to find a way to only layout the child boxes, if needed. |
| 237 FloatRect oldBoundaries = objectBoundingBox(); | 237 FloatRect oldBoundaries = objectBoundingBox(); |
| 238 ASSERT(childrenInline()); | 238 DCHECK(childrenInline()); |
| 239 | 239 |
| 240 rebuildFloatsFromIntruding(); | 240 rebuildFloatsFromIntruding(); |
| 241 | 241 |
| 242 LayoutUnit beforeEdge = borderBefore() + paddingBefore(); | 242 LayoutUnit beforeEdge = borderBefore() + paddingBefore(); |
| 243 LayoutUnit afterEdge = | 243 LayoutUnit afterEdge = |
| 244 borderAfter() + paddingAfter() + scrollbarLogicalHeight(); | 244 borderAfter() + paddingAfter() + scrollbarLogicalHeight(); |
| 245 setLogicalHeight(beforeEdge); | 245 setLogicalHeight(beforeEdge); |
| 246 | 246 |
| 247 LayoutState state(*this); | 247 LayoutState state(*this); |
| 248 layoutInlineChildren(true, afterEdge); | 248 layoutInlineChildren(true, afterEdge); |
| 249 | 249 |
| 250 m_needsReordering = false; | 250 m_needsReordering = false; |
| 251 | 251 |
| 252 FloatRect newBoundaries = objectBoundingBox(); | 252 FloatRect newBoundaries = objectBoundingBox(); |
| 253 if (!updateParentBoundaries) | 253 if (!updateParentBoundaries) |
| 254 updateParentBoundaries = oldBoundaries != newBoundaries; | 254 updateParentBoundaries = oldBoundaries != newBoundaries; |
| 255 | 255 |
| 256 m_overflow.reset(); | 256 m_overflow.reset(); |
| 257 addSelfVisualOverflow(LayoutRect(newBoundaries)); | 257 addSelfVisualOverflow(LayoutRect(newBoundaries)); |
| 258 addVisualEffectOverflow(); | 258 addVisualEffectOverflow(); |
| 259 | 259 |
| 260 // Invalidate all resources of this client if our layout changed. | 260 // Invalidate all resources of this client if our layout changed. |
| 261 if (everHadLayout() && selfNeedsLayout()) | 261 if (everHadLayout() && selfNeedsLayout()) |
| 262 SVGResourcesCache::clientLayoutChanged(this); | 262 SVGResourcesCache::clientLayoutChanged(this); |
| 263 | 263 |
| 264 // If our bounds changed, notify the parents. | 264 // If our bounds changed, notify the parents. |
| 265 if (updateParentBoundaries) | 265 if (updateParentBoundaries) |
| 266 LayoutSVGBlock::setNeedsBoundariesUpdate(); | 266 LayoutSVGBlock::setNeedsBoundariesUpdate(); |
| 267 | 267 |
| 268 ASSERT(!m_needsReordering); | 268 DCHECK(!m_needsReordering); |
| 269 ASSERT(!m_needsTransformUpdate); | 269 DCHECK(!m_needsTransformUpdate); |
| 270 ASSERT(!m_needsTextMetricsUpdate); | 270 DCHECK(!m_needsTextMetricsUpdate); |
| 271 ASSERT(!m_needsPositioningValuesUpdate); | 271 DCHECK(!m_needsPositioningValuesUpdate); |
| 272 clearNeedsLayout(); | 272 clearNeedsLayout(); |
| 273 } | 273 } |
| 274 | 274 |
| 275 RootInlineBox* LayoutSVGText::createRootInlineBox() { | 275 RootInlineBox* LayoutSVGText::createRootInlineBox() { |
| 276 RootInlineBox* box = new SVGRootInlineBox(LineLayoutItem(this)); | 276 RootInlineBox* box = new SVGRootInlineBox(LineLayoutItem(this)); |
| 277 box->setHasVirtualLogicalHeight(); | 277 box->setHasVirtualLogicalHeight(); |
| 278 return box; | 278 return box; |
| 279 } | 279 } |
| 280 | 280 |
| 281 bool LayoutSVGText::nodeAtFloatPoint(HitTestResult& result, | 281 bool LayoutSVGText::nodeAtFloatPoint(HitTestResult& result, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 const LayoutPoint& pointInContents) { | 324 const LayoutPoint& pointInContents) { |
| 325 RootInlineBox* rootBox = firstRootBox(); | 325 RootInlineBox* rootBox = firstRootBox(); |
| 326 if (!rootBox) | 326 if (!rootBox) |
| 327 return createPositionWithAffinity(0); | 327 return createPositionWithAffinity(0); |
| 328 | 328 |
| 329 LayoutPoint clippedPointInContents(pointInContents); | 329 LayoutPoint clippedPointInContents(pointInContents); |
| 330 clippedPointInContents.moveBy(-rootBox->location()); | 330 clippedPointInContents.moveBy(-rootBox->location()); |
| 331 clippedPointInContents.clampNegativeToZero(); | 331 clippedPointInContents.clampNegativeToZero(); |
| 332 clippedPointInContents.moveBy(rootBox->location()); | 332 clippedPointInContents.moveBy(rootBox->location()); |
| 333 | 333 |
| 334 ASSERT(!rootBox->nextRootBox()); | 334 DCHECK(!rootBox->nextRootBox()); |
| 335 ASSERT(childrenInline()); | 335 DCHECK(childrenInline()); |
| 336 | 336 |
| 337 InlineBox* closestBox = | 337 InlineBox* closestBox = |
| 338 toSVGRootInlineBox(rootBox)->closestLeafChildForPosition( | 338 toSVGRootInlineBox(rootBox)->closestLeafChildForPosition( |
| 339 clippedPointInContents); | 339 clippedPointInContents); |
| 340 if (!closestBox) | 340 if (!closestBox) |
| 341 return createPositionWithAffinity(0); | 341 return createPositionWithAffinity(0); |
| 342 | 342 |
| 343 return closestBox->getLineLayoutItem().positionForPoint( | 343 return closestBox->getLineLayoutItem().positionForPoint( |
| 344 LayoutPoint(clippedPointInContents.x(), closestBox->y())); | 344 LayoutPoint(clippedPointInContents.x(), closestBox->y())); |
| 345 } | 345 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 359 return FloatRect(box->frameRect()); | 359 return FloatRect(box->frameRect()); |
| 360 return FloatRect(); | 360 return FloatRect(); |
| 361 } | 361 } |
| 362 | 362 |
| 363 FloatRect LayoutSVGText::strokeBoundingBox() const { | 363 FloatRect LayoutSVGText::strokeBoundingBox() const { |
| 364 FloatRect strokeBoundaries = objectBoundingBox(); | 364 FloatRect strokeBoundaries = objectBoundingBox(); |
| 365 const SVGComputedStyle& svgStyle = style()->svgStyle(); | 365 const SVGComputedStyle& svgStyle = style()->svgStyle(); |
| 366 if (!svgStyle.hasStroke()) | 366 if (!svgStyle.hasStroke()) |
| 367 return strokeBoundaries; | 367 return strokeBoundaries; |
| 368 | 368 |
| 369 ASSERT(node()); | 369 DCHECK(node()); |
| 370 ASSERT(node()->isSVGElement()); | 370 DCHECK(node()->isSVGElement()); |
| 371 SVGLengthContext lengthContext(toSVGElement(node())); | 371 SVGLengthContext lengthContext(toSVGElement(node())); |
| 372 strokeBoundaries.inflate( | 372 strokeBoundaries.inflate( |
| 373 lengthContext.valueForLength(svgStyle.strokeWidth())); | 373 lengthContext.valueForLength(svgStyle.strokeWidth())); |
| 374 return strokeBoundaries; | 374 return strokeBoundaries; |
| 375 } | 375 } |
| 376 | 376 |
| 377 FloatRect LayoutSVGText::visualRectInLocalSVGCoordinates() const { | 377 FloatRect LayoutSVGText::visualRectInLocalSVGCoordinates() const { |
| 378 FloatRect visualRect = strokeBoundingBox(); | 378 FloatRect visualRect = strokeBoundingBox(); |
| 379 SVGLayoutSupport::adjustVisualRectWithResources(this, visualRect); | 379 SVGLayoutSupport::adjustVisualRectWithResources(this, visualRect); |
| 380 | 380 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 411 | 411 |
| 412 void LayoutSVGText::invalidateTreeIfNeeded( | 412 void LayoutSVGText::invalidateTreeIfNeeded( |
| 413 const PaintInvalidationState& paintInvalidationState) { | 413 const PaintInvalidationState& paintInvalidationState) { |
| 414 // TODO(wangxianzhu): Verify if the inherited | 414 // TODO(wangxianzhu): Verify if the inherited |
| 415 // LayoutBoxModelObject::invalidateTreeIfNeeded() | 415 // LayoutBoxModelObject::invalidateTreeIfNeeded() |
| 416 // is applicable here. If yes, remove this overriding method. | 416 // is applicable here. If yes, remove this overriding method. |
| 417 LayoutObject::invalidateTreeIfNeeded(paintInvalidationState); | 417 LayoutObject::invalidateTreeIfNeeded(paintInvalidationState); |
| 418 } | 418 } |
| 419 | 419 |
| 420 } // namespace blink | 420 } // namespace blink |
| OLD | NEW |