| 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 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 m_currentTextFragment.characterOffset; | 148 m_currentTextFragment.characterOffset; |
| 149 | 149 |
| 150 // Figure out fragment metrics. | 150 // Figure out fragment metrics. |
| 151 computeCurrentFragmentMetrics(textBox); | 151 computeCurrentFragmentMetrics(textBox); |
| 152 | 152 |
| 153 textBox->textFragments().append(m_currentTextFragment); | 153 textBox->textFragments().append(m_currentTextFragment); |
| 154 m_currentTextFragment = SVGTextFragment(); | 154 m_currentTextFragment = SVGTextFragment(); |
| 155 } | 155 } |
| 156 | 156 |
| 157 void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) { | 157 void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) { |
| 158 // Build text chunks for all <textPath> children, using the line layout algori
thm. | 158 // Build text chunks for all <textPath> children, using the line layout |
| 159 // This is needeed as text-anchor is just an additional startOffset for text p
aths. | 159 // algorithm. This is needeed as text-anchor is just an additional startOffset |
| 160 // for text paths. |
| 160 SVGTextLayoutEngine lineLayout(m_descendantTextNodes); | 161 SVGTextLayoutEngine lineLayout(m_descendantTextNodes); |
| 161 lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; | 162 lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; |
| 162 lineLayout.layoutCharactersInTextBoxes(flowBox); | 163 lineLayout.layoutCharactersInTextBoxes(flowBox); |
| 163 | 164 |
| 164 m_inPathLayout = true; | 165 m_inPathLayout = true; |
| 165 LineLayoutSVGTextPath textPath = | 166 LineLayoutSVGTextPath textPath = |
| 166 LineLayoutSVGTextPath(flowBox->getLineLayoutItem()); | 167 LineLayoutSVGTextPath(flowBox->getLineLayoutItem()); |
| 167 | 168 |
| 168 m_textPath = textPath.layoutPath(); | 169 m_textPath = textPath.layoutPath(); |
| 169 if (!m_textPath) | 170 if (!m_textPath) |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 | 271 |
| 271 if (isTextPath) | 272 if (isTextPath) |
| 272 endTextPathLayout(); | 273 endTextPathLayout(); |
| 273 } | 274 } |
| 274 } | 275 } |
| 275 } | 276 } |
| 276 | 277 |
| 277 void SVGTextLayoutEngine::finishLayout() { | 278 void SVGTextLayoutEngine::finishLayout() { |
| 278 m_visualMetricsIterator = SVGInlineTextMetricsIterator(); | 279 m_visualMetricsIterator = SVGInlineTextMetricsIterator(); |
| 279 | 280 |
| 280 // After all text fragments are stored in their correpsonding SVGInlineTextBox
es, we can layout individual text chunks. | 281 // After all text fragments are stored in their correpsonding |
| 281 // Chunk layouting is only performed for line layout boxes, not for path layou
t, where it has already been done. | 282 // SVGInlineTextBoxes, we can layout individual text chunks. |
| 283 // Chunk layouting is only performed for line layout boxes, not for path |
| 284 // layout, where it has already been done. |
| 282 SVGTextChunkBuilder chunkLayoutBuilder; | 285 SVGTextChunkBuilder chunkLayoutBuilder; |
| 283 chunkLayoutBuilder.processTextChunks(m_lineLayoutBoxes); | 286 chunkLayoutBuilder.processTextChunks(m_lineLayoutBoxes); |
| 284 | 287 |
| 285 m_lineLayoutBoxes.clear(); | 288 m_lineLayoutBoxes.clear(); |
| 286 } | 289 } |
| 287 | 290 |
| 288 const LayoutSVGInlineText* SVGTextLayoutEngine::nextLogicalTextNode() { | 291 const LayoutSVGInlineText* SVGTextLayoutEngine::nextLogicalTextNode() { |
| 289 ASSERT(m_currentLogicalTextNodeIndex < m_descendantTextNodes.size()); | 292 ASSERT(m_currentLogicalTextNodeIndex < m_descendantTextNodes.size()); |
| 290 ++m_currentLogicalTextNodeIndex; | 293 ++m_currentLogicalTextNodeIndex; |
| 291 if (m_currentLogicalTextNodeIndex == m_descendantTextNodes.size()) | 294 if (m_currentLogicalTextNodeIndex == m_descendantTextNodes.size()) |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 break; | 391 break; |
| 389 | 392 |
| 390 const SVGCharacterData data = | 393 const SVGCharacterData data = |
| 391 logicalTextNode->characterDataMap().get(m_logicalCharacterOffset + 1); | 394 logicalTextNode->characterDataMap().get(m_logicalCharacterOffset + 1); |
| 392 | 395 |
| 393 // TODO(fs): Use the return value to eliminate the additional | 396 // TODO(fs): Use the return value to eliminate the additional |
| 394 // hash-lookup below when determining if this text box should be tagged | 397 // hash-lookup below when determining if this text box should be tagged |
| 395 // as starting a new text chunk. | 398 // as starting a new text chunk. |
| 396 setCurrentTextPosition(data); | 399 setCurrentTextPosition(data); |
| 397 | 400 |
| 398 // When we've advanced to the box start offset, determine using the original
x/y values, | 401 // When we've advanced to the box start offset, determine using the original |
| 399 // whether this character starts a new text chunk, before doing any further
processing. | 402 // x/y values, whether this character starts a new text chunk, before doing |
| 403 // any further processing. |
| 400 if (m_visualMetricsIterator.characterOffset() == textBox->start()) | 404 if (m_visualMetricsIterator.characterOffset() == textBox->start()) |
| 401 textBox->setStartsNewTextChunk( | 405 textBox->setStartsNewTextChunk( |
| 402 logicalTextNode->characterStartsNewTextChunk( | 406 logicalTextNode->characterStartsNewTextChunk( |
| 403 m_logicalCharacterOffset)); | 407 m_logicalCharacterOffset)); |
| 404 | 408 |
| 405 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data); | 409 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data); |
| 406 | 410 |
| 407 // Determine the orientation of the current glyph. | 411 // Determine the orientation of the current glyph. |
| 408 // Font::width() calculates the resolved FontOrientation for each character, | 412 // Font::width() calculates the resolved FontOrientation for each character, |
| 409 // but that value is not exposed today to avoid the API complexity. | 413 // but that value is not exposed today to avoid the API complexity. |
| 410 UChar32 currentCharacter = | 414 UChar32 currentCharacter = |
| 411 textLineLayout.codepointAt(m_visualMetricsIterator.characterOffset()); | 415 textLineLayout.codepointAt(m_visualMetricsIterator.characterOffset()); |
| 412 FontOrientation fontOrientation = font.getFontDescription().orientation(); | 416 FontOrientation fontOrientation = font.getFontDescription().orientation(); |
| 413 fontOrientation = adjustOrientationForCharacterInMixedVertical( | 417 fontOrientation = adjustOrientationForCharacterInMixedVertical( |
| 414 fontOrientation, currentCharacter); | 418 fontOrientation, currentCharacter); |
| 415 | 419 |
| 416 // Calculate glyph advance. | 420 // Calculate glyph advance. The shaping engine takes care of x/y orientation |
| 417 // The shaping engine takes care of x/y orientation shifts for different fon
tOrientation values. | 421 // shifts for different fontOrientation values. |
| 418 float glyphAdvance = visualMetrics.advance(fontOrientation); | 422 float glyphAdvance = visualMetrics.advance(fontOrientation); |
| 419 | 423 |
| 420 // Calculate CSS 'letter-spacing' and 'word-spacing' for the character, if n
eeded. | 424 // Calculate CSS 'letter-spacing' and 'word-spacing' for the character, if |
| 425 // needed. |
| 421 float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); | 426 float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); |
| 422 | 427 |
| 423 FloatPoint textPathShift; | 428 FloatPoint textPathShift; |
| 424 float angle = 0; | 429 float angle = 0; |
| 425 FloatPoint position; | 430 FloatPoint position; |
| 426 if (m_inPathLayout) { | 431 if (m_inPathLayout) { |
| 427 float scaledGlyphAdvance = glyphAdvance * m_textPathScaling; | 432 float scaledGlyphAdvance = glyphAdvance * m_textPathScaling; |
| 428 // Setup translations that move to the glyph midpoint. | 433 // Setup translations that move to the glyph midpoint. |
| 429 textPathShift.set(-scaledGlyphAdvance / 2, m_textPathDisplacement); | 434 textPathShift.set(-scaledGlyphAdvance / 2, m_textPathDisplacement); |
| 430 if (m_isVerticalText) | 435 if (m_isVerticalText) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 447 m_visualMetricsIterator.next(); | 452 m_visualMetricsIterator.next(); |
| 448 continue; | 453 continue; |
| 449 } | 454 } |
| 450 | 455 |
| 451 // Stop processing if the next character lies behind the path. | 456 // Stop processing if the next character lies behind the path. |
| 452 if (positionType == PathPositionMapper::AfterPath) | 457 if (positionType == PathPositionMapper::AfterPath) |
| 453 break; | 458 break; |
| 454 | 459 |
| 455 m_textPosition = position; | 460 m_textPosition = position; |
| 456 | 461 |
| 457 // For vertical text on path, the actual angle has to be rotated 90 degree
s anti-clockwise, not the orientation angle! | 462 // For vertical text on path, the actual angle has to be rotated 90 |
| 463 // degrees anti-clockwise, not the orientation angle! |
| 458 if (m_isVerticalText) | 464 if (m_isVerticalText) |
| 459 angle -= 90; | 465 angle -= 90; |
| 460 } else { | 466 } else { |
| 461 position = m_textPosition; | 467 position = m_textPosition; |
| 462 position += baselineShift; | 468 position += baselineShift; |
| 463 } | 469 } |
| 464 | 470 |
| 465 if (data.hasRotate()) | 471 if (data.hasRotate()) |
| 466 angle += data.rotate; | 472 angle += data.rotate; |
| 467 | 473 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 490 m_currentTextFragment.y = position.y(); | 496 m_currentTextFragment.y = position.y(); |
| 491 | 497 |
| 492 // Build fragment transformation. | 498 // Build fragment transformation. |
| 493 if (angle) | 499 if (angle) |
| 494 m_currentTextFragment.transform.rotate(angle); | 500 m_currentTextFragment.transform.rotate(angle); |
| 495 | 501 |
| 496 if (textPathShift.x() || textPathShift.y()) | 502 if (textPathShift.x() || textPathShift.y()) |
| 497 m_currentTextFragment.transform.translate(textPathShift.x(), | 503 m_currentTextFragment.transform.translate(textPathShift.x(), |
| 498 textPathShift.y()); | 504 textPathShift.y()); |
| 499 | 505 |
| 500 // For vertical text, always rotate by 90 degrees regardless of fontOrient
ation. | 506 // For vertical text, always rotate by 90 degrees regardless of |
| 507 // fontOrientation. |
| 501 // The shaping engine takes care of the necessary orientation. | 508 // The shaping engine takes care of the necessary orientation. |
| 502 if (m_isVerticalText) | 509 if (m_isVerticalText) |
| 503 m_currentTextFragment.transform.rotate(90); | 510 m_currentTextFragment.transform.rotate(90); |
| 504 | 511 |
| 505 m_currentTextFragment.isVertical = m_isVerticalText; | 512 m_currentTextFragment.isVertical = m_isVerticalText; |
| 506 m_currentTextFragment.isTextOnPath = | 513 m_currentTextFragment.isTextOnPath = |
| 507 m_inPathLayout && m_textPathScaling != 1; | 514 m_inPathLayout && m_textPathScaling != 1; |
| 508 if (m_currentTextFragment.isTextOnPath) | 515 if (m_currentTextFragment.isTextOnPath) |
| 509 m_currentTextFragment.lengthAdjustScale = m_textPathScaling; | 516 m_currentTextFragment.lengthAdjustScale = m_textPathScaling; |
| 510 } | 517 } |
| 511 | 518 |
| 512 // Advance current text position after processing of the current character f
inished. | 519 // Advance current text position after processing of the current character |
| 520 // finished. |
| 513 advanceCurrentTextPosition(glyphAdvance + spacing); | 521 advanceCurrentTextPosition(glyphAdvance + spacing); |
| 514 | 522 |
| 515 // Apply CSS 'letter-spacing' and 'word-spacing' to the next character, if n
eeded. | 523 // Apply CSS 'letter-spacing' and 'word-spacing' to the next character, if |
| 524 // needed. |
| 516 if (!m_inPathLayout && spacing) | 525 if (!m_inPathLayout && spacing) |
| 517 applySpacingToNextCharacter = true; | 526 applySpacingToNextCharacter = true; |
| 518 | 527 |
| 519 advanceToNextLogicalCharacter(logicalMetrics); | 528 advanceToNextLogicalCharacter(logicalMetrics); |
| 520 m_visualMetricsIterator.next(); | 529 m_visualMetricsIterator.next(); |
| 521 lastAngle = angle; | 530 lastAngle = angle; |
| 522 } | 531 } |
| 523 | 532 |
| 524 if (!didStartTextFragment) | 533 if (!didStartTextFragment) |
| 525 return; | 534 return; |
| 526 | 535 |
| 527 // Close last open fragment, if needed. | 536 // Close last open fragment, if needed. |
| 528 recordTextFragment(textBox); | 537 recordTextFragment(textBox); |
| 529 } | 538 } |
| 530 | 539 |
| 531 } // namespace blink | 540 } // namespace blink |
| OLD | NEW |