| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. |
| 3 * | 3 * |
| 4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
| 6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
| 7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
| 8 * | 8 * |
| 9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #include "core/layout/svg/SVGTextLayoutEngineBaseline.h" | 26 #include "core/layout/svg/SVGTextLayoutEngineBaseline.h" |
| 27 #include "core/layout/svg/SVGTextLayoutEngineSpacing.h" | 27 #include "core/layout/svg/SVGTextLayoutEngineSpacing.h" |
| 28 #include "core/layout/svg/line/SVGInlineFlowBox.h" | 28 #include "core/layout/svg/line/SVGInlineFlowBox.h" |
| 29 #include "core/layout/svg/line/SVGInlineTextBox.h" | 29 #include "core/layout/svg/line/SVGInlineTextBox.h" |
| 30 #include "core/svg/SVGElement.h" | 30 #include "core/svg/SVGElement.h" |
| 31 #include "core/svg/SVGLengthContext.h" | 31 #include "core/svg/SVGLengthContext.h" |
| 32 #include "core/svg/SVGTextContentElement.h" | 32 #include "core/svg/SVGTextContentElement.h" |
| 33 | 33 |
| 34 namespace blink { | 34 namespace blink { |
| 35 | 35 |
| 36 SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes*>& layou
tAttributes) | 36 SVGTextLayoutEngine::SVGTextLayoutEngine(const Vector<LayoutSVGInlineText*>& des
cendantTextNodes) |
| 37 : m_layoutAttributes(layoutAttributes) | 37 : m_descendantTextNodes(descendantTextNodes) |
| 38 , m_layoutAttributesPosition(0) | 38 , m_currentLogicalTextNodeIndex(0) |
| 39 , m_logicalCharacterOffset(0) | 39 , m_logicalCharacterOffset(0) |
| 40 , m_logicalMetricsListOffset(0) | 40 , m_logicalMetricsListOffset(0) |
| 41 , m_isVerticalText(false) | 41 , m_isVerticalText(false) |
| 42 , m_inPathLayout(false) | 42 , m_inPathLayout(false) |
| 43 , m_textLengthSpacingInEffect(false) | 43 , m_textLengthSpacingInEffect(false) |
| 44 , m_textPath(nullptr) | 44 , m_textPath(nullptr) |
| 45 , m_textPathCurrentOffset(0) | 45 , m_textPathCurrentOffset(0) |
| 46 , m_textPathDisplacement(0) | 46 , m_textPathDisplacement(0) |
| 47 , m_textPathSpacing(0) | 47 , m_textPathSpacing(0) |
| 48 , m_textPathScaling(1) | 48 , m_textPathScaling(1) |
| 49 { | 49 { |
| 50 ASSERT(!m_layoutAttributes.isEmpty()); | 50 ASSERT(!m_descendantTextNodes.isEmpty()); |
| 51 } | 51 } |
| 52 | 52 |
| 53 SVGTextLayoutEngine::~SVGTextLayoutEngine() = default; | 53 SVGTextLayoutEngine::~SVGTextLayoutEngine() = default; |
| 54 | 54 |
| 55 bool SVGTextLayoutEngine::setCurrentTextPosition(const SVGCharacterData& data) | 55 bool SVGTextLayoutEngine::setCurrentTextPosition(const SVGCharacterData& data) |
| 56 { | 56 { |
| 57 bool hasX = data.hasX(); | 57 bool hasX = data.hasX(); |
| 58 if (hasX) | 58 if (hasX) |
| 59 m_textPosition.setX(data.x); | 59 m_textPosition.setX(data.x); |
| 60 | 60 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 computeCurrentFragmentMetrics(textBox); | 149 computeCurrentFragmentMetrics(textBox); |
| 150 | 150 |
| 151 textBox->textFragments().append(m_currentTextFragment); | 151 textBox->textFragments().append(m_currentTextFragment); |
| 152 m_currentTextFragment = SVGTextFragment(); | 152 m_currentTextFragment = SVGTextFragment(); |
| 153 } | 153 } |
| 154 | 154 |
| 155 void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) | 155 void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) |
| 156 { | 156 { |
| 157 // Build text chunks for all <textPath> children, using the line layout algo
rithm. | 157 // Build text chunks for all <textPath> children, using the line layout algo
rithm. |
| 158 // This is needeed as text-anchor is just an additional startOffset for text
paths. | 158 // This is needeed as text-anchor is just an additional startOffset for text
paths. |
| 159 SVGTextLayoutEngine lineLayout(m_layoutAttributes); | 159 SVGTextLayoutEngine lineLayout(m_descendantTextNodes); |
| 160 lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; | 160 lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; |
| 161 lineLayout.layoutCharactersInTextBoxes(flowBox); | 161 lineLayout.layoutCharactersInTextBoxes(flowBox); |
| 162 | 162 |
| 163 m_inPathLayout = true; | 163 m_inPathLayout = true; |
| 164 LineLayoutSVGTextPath textPath = LineLayoutSVGTextPath(flowBox->getLineLayou
tItem()); | 164 LineLayoutSVGTextPath textPath = LineLayoutSVGTextPath(flowBox->getLineLayou
tItem()); |
| 165 | 165 |
| 166 m_textPath = textPath.layoutPath(); | 166 m_textPath = textPath.layoutPath(); |
| 167 if (!m_textPath) | 167 if (!m_textPath) |
| 168 return; | 168 return; |
| 169 m_textPathStartOffset = textPath.calculateStartOffset(m_textPath->length()); | 169 m_textPathStartOffset = textPath.calculateStartOffset(m_textPath->length()); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 m_visualMetricsIterator = SVGInlineTextMetricsIterator(); | 269 m_visualMetricsIterator = SVGInlineTextMetricsIterator(); |
| 270 | 270 |
| 271 // After all text fragments are stored in their correpsonding SVGInlineTextB
oxes, we can layout individual text chunks. | 271 // After all text fragments are stored in their correpsonding SVGInlineTextB
oxes, we can layout individual text chunks. |
| 272 // Chunk layouting is only performed for line layout boxes, not for path lay
out, where it has already been done. | 272 // Chunk layouting is only performed for line layout boxes, not for path lay
out, where it has already been done. |
| 273 SVGTextChunkBuilder chunkLayoutBuilder; | 273 SVGTextChunkBuilder chunkLayoutBuilder; |
| 274 chunkLayoutBuilder.processTextChunks(m_lineLayoutBoxes); | 274 chunkLayoutBuilder.processTextChunks(m_lineLayoutBoxes); |
| 275 | 275 |
| 276 m_lineLayoutBoxes.clear(); | 276 m_lineLayoutBoxes.clear(); |
| 277 } | 277 } |
| 278 | 278 |
| 279 const SVGTextLayoutAttributes* SVGTextLayoutEngine::nextLogicalAttributes() | 279 const LayoutSVGInlineText* SVGTextLayoutEngine::nextLogicalTextNode() |
| 280 { | 280 { |
| 281 ASSERT(m_layoutAttributesPosition < m_layoutAttributes.size()); | 281 ASSERT(m_currentLogicalTextNodeIndex < m_descendantTextNodes.size()); |
| 282 ++m_layoutAttributesPosition; | 282 ++m_currentLogicalTextNodeIndex; |
| 283 if (m_layoutAttributesPosition == m_layoutAttributes.size()) | 283 if (m_currentLogicalTextNodeIndex == m_descendantTextNodes.size()) |
| 284 return nullptr; | 284 return nullptr; |
| 285 | 285 |
| 286 m_logicalMetricsListOffset = 0; | 286 m_logicalMetricsListOffset = 0; |
| 287 m_logicalCharacterOffset = 0; | 287 m_logicalCharacterOffset = 0; |
| 288 return m_layoutAttributes[m_layoutAttributesPosition]; | 288 return m_descendantTextNodes[m_currentLogicalTextNodeIndex]; |
| 289 } | 289 } |
| 290 | 290 |
| 291 const SVGTextLayoutAttributes* SVGTextLayoutEngine::currentLogicalCharacterMetri
cs(SVGTextMetrics& logicalMetrics) | 291 const LayoutSVGInlineText* SVGTextLayoutEngine::currentLogicalCharacterMetrics(S
VGTextMetrics& logicalMetrics) |
| 292 { | 292 { |
| 293 // If we're consumed all layout attributes, there can be no more metrics. | 293 // If we're consumed all text nodes, there can be no more metrics. |
| 294 if (m_layoutAttributesPosition == m_layoutAttributes.size()) | 294 if (m_currentLogicalTextNodeIndex == m_descendantTextNodes.size()) |
| 295 return nullptr; | 295 return nullptr; |
| 296 | 296 |
| 297 const SVGTextLayoutAttributes* logicalAttributes = m_layoutAttributes[m_layo
utAttributesPosition]; | 297 const LayoutSVGInlineText* logicalTextNode = m_descendantTextNodes[m_current
LogicalTextNodeIndex]; |
| 298 // If we reached the end of the text node associated with the current set | 298 // If we reached the end of the text node associated with the current set |
| 299 // of layout attributes, try to move to the next text node/set of layout | 299 // of layout attributes, try to move to the next text node/set of layout |
| 300 // attributes. | 300 // attributes. |
| 301 ASSERT(m_logicalCharacterOffset <= logicalAttributes->context()->textLength(
)); | 301 ASSERT(m_logicalCharacterOffset <= logicalTextNode->textLength()); |
| 302 if (m_logicalCharacterOffset == logicalAttributes->context()->textLength())
{ | 302 if (m_logicalCharacterOffset == logicalTextNode->textLength()) { |
| 303 logicalAttributes = nextLogicalAttributes(); | 303 logicalTextNode = nextLogicalTextNode(); |
| 304 if (!logicalAttributes) | 304 if (!logicalTextNode) |
| 305 return nullptr; | 305 return nullptr; |
| 306 } | 306 } |
| 307 | 307 |
| 308 // We have set of layout attributes. Find the first non-collapsed text | 308 // We have set of layout attributes. Find the first non-collapsed text |
| 309 // metrics cell. | 309 // metrics cell. |
| 310 const Vector<SVGTextMetrics>* metricsList = &logicalAttributes->context()->m
etricsList(); | 310 const Vector<SVGTextMetrics>* metricsList = &logicalTextNode->metricsList(); |
| 311 unsigned metricsListSize = metricsList->size(); | 311 unsigned metricsListSize = metricsList->size(); |
| 312 while (true) { | 312 while (true) { |
| 313 // If we run out of metrics, move to the next set of layout attributes. | 313 // If we run out of metrics, move to the next set of layout attributes. |
| 314 if (m_logicalMetricsListOffset == metricsListSize) { | 314 if (m_logicalMetricsListOffset == metricsListSize) { |
| 315 logicalAttributes = nextLogicalAttributes(); | 315 logicalTextNode = nextLogicalTextNode(); |
| 316 if (!logicalAttributes) | 316 if (!logicalTextNode) |
| 317 return nullptr; | 317 return nullptr; |
| 318 | 318 |
| 319 metricsList = &logicalAttributes->context()->metricsList(); | 319 metricsList = &logicalTextNode->metricsList(); |
| 320 metricsListSize = metricsList->size(); | 320 metricsListSize = metricsList->size(); |
| 321 continue; | 321 continue; |
| 322 } | 322 } |
| 323 | 323 |
| 324 ASSERT(metricsListSize); | 324 ASSERT(metricsListSize); |
| 325 ASSERT(m_logicalMetricsListOffset < metricsListSize); | 325 ASSERT(m_logicalMetricsListOffset < metricsListSize); |
| 326 logicalMetrics = metricsList->at(m_logicalMetricsListOffset); | 326 logicalMetrics = metricsList->at(m_logicalMetricsListOffset); |
| 327 if (logicalMetrics.isEmpty() || (!logicalMetrics.width() && !logicalMetr
ics.height())) { | 327 if (logicalMetrics.isEmpty() || (!logicalMetrics.width() && !logicalMetr
ics.height())) { |
| 328 advanceToNextLogicalCharacter(logicalMetrics); | 328 advanceToNextLogicalCharacter(logicalMetrics); |
| 329 continue; | 329 continue; |
| 330 } | 330 } |
| 331 | 331 |
| 332 // Stop if we found the next valid logical text metrics object. | 332 // Stop if we found the next valid logical text metrics object. |
| 333 return logicalAttributes; | 333 return logicalTextNode; |
| 334 } | 334 } |
| 335 | 335 |
| 336 ASSERT_NOT_REACHED(); | 336 ASSERT_NOT_REACHED(); |
| 337 return nullptr; | 337 return nullptr; |
| 338 } | 338 } |
| 339 | 339 |
| 340 void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& lo
gicalMetrics) | 340 void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& lo
gicalMetrics) |
| 341 { | 341 { |
| 342 ++m_logicalMetricsListOffset; | 342 ++m_logicalMetricsListOffset; |
| 343 m_logicalCharacterOffset += logicalMetrics.length(); | 343 m_logicalCharacterOffset += logicalMetrics.length(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 372 // Main layout algorithm. | 372 // Main layout algorithm. |
| 373 const unsigned boxEndOffset = textBox->start() + textBox->len(); | 373 const unsigned boxEndOffset = textBox->start() + textBox->len(); |
| 374 while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.charact
erOffset() < boxEndOffset) { | 374 while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.charact
erOffset() < boxEndOffset) { |
| 375 const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics(); | 375 const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics(); |
| 376 if (visualMetrics.isEmpty()) { | 376 if (visualMetrics.isEmpty()) { |
| 377 m_visualMetricsIterator.next(); | 377 m_visualMetricsIterator.next(); |
| 378 continue; | 378 continue; |
| 379 } | 379 } |
| 380 | 380 |
| 381 SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics); | 381 SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics); |
| 382 const SVGTextLayoutAttributes* logicalAttributes = currentLogicalCharact
erMetrics(logicalMetrics); | 382 const LayoutSVGInlineText* logicalTextNode = currentLogicalCharacterMetr
ics(logicalMetrics); |
| 383 if (!logicalAttributes) | 383 if (!logicalTextNode) |
| 384 break; | 384 break; |
| 385 | 385 |
| 386 const SVGCharacterDataMap& characterDataMap = logicalAttributes->charact
erDataMap(); | 386 const SVGCharacterData data = logicalTextNode->characterDataMap().get(m_
logicalCharacterOffset + 1); |
| 387 SVGCharacterData data; | |
| 388 SVGCharacterDataMap::const_iterator it = characterDataMap.find(m_logical
CharacterOffset + 1); | |
| 389 if (it != characterDataMap.end()) | |
| 390 data = it->value; | |
| 391 | 387 |
| 392 // TODO(fs): Use the return value to eliminate the additional | 388 // TODO(fs): Use the return value to eliminate the additional |
| 393 // hash-lookup below when determining if this text box should be tagged | 389 // hash-lookup below when determining if this text box should be tagged |
| 394 // as starting a new text chunk. | 390 // as starting a new text chunk. |
| 395 setCurrentTextPosition(data); | 391 setCurrentTextPosition(data); |
| 396 | 392 |
| 397 // When we've advanced to the box start offset, determine using the orig
inal x/y values, | 393 // When we've advanced to the box start offset, determine using the orig
inal x/y values, |
| 398 // whether this character starts a new text chunk, before doing any furt
her processing. | 394 // whether this character starts a new text chunk, before doing any furt
her processing. |
| 399 if (m_visualMetricsIterator.characterOffset() == textBox->start()) | 395 if (m_visualMetricsIterator.characterOffset() == textBox->start()) |
| 400 textBox->setStartsNewTextChunk(logicalAttributes->context()->charact
erStartsNewTextChunk(m_logicalCharacterOffset)); | 396 textBox->setStartsNewTextChunk(logicalTextNode->characterStartsNewTe
xtChunk(m_logicalCharacterOffset)); |
| 401 | 397 |
| 402 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data
); | 398 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data
); |
| 403 | 399 |
| 404 // Determine the orientation of the current glyph. | 400 // Determine the orientation of the current glyph. |
| 405 // Font::width() calculates the resolved FontOrientation for each charac
ter, | 401 // Font::width() calculates the resolved FontOrientation for each charac
ter, |
| 406 // but that value is not exposed today to avoid the API complexity. | 402 // but that value is not exposed today to avoid the API complexity. |
| 407 UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIte
rator.characterOffset()); | 403 UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIte
rator.characterOffset()); |
| 408 FontOrientation fontOrientation = font.getFontDescription().orientation(
); | 404 FontOrientation fontOrientation = font.getFontDescription().orientation(
); |
| 409 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien
tation, currentCharacter); | 405 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien
tation, currentCharacter); |
| 410 | 406 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 } | 506 } |
| 511 | 507 |
| 512 if (!didStartTextFragment) | 508 if (!didStartTextFragment) |
| 513 return; | 509 return; |
| 514 | 510 |
| 515 // Close last open fragment, if needed. | 511 // Close last open fragment, if needed. |
| 516 recordTextFragment(textBox); | 512 recordTextFragment(textBox); |
| 517 } | 513 } |
| 518 | 514 |
| 519 } // namespace blink | 515 } // namespace blink |
| OLD | NEW |