Chromium Code Reviews| 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 20 matching lines...) Expand all Loading... | |
| 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(Vector<SVGTextLayoutAttributes*>& layou tAttributes) |
| 37 : m_layoutAttributes(layoutAttributes) | 37 : m_layoutAttributes(layoutAttributes) |
| 38 , m_layoutAttributesPosition(0) | 38 , m_layoutAttributesPosition(0) |
| 39 , m_logicalCharacterOffset(0) | 39 , m_logicalCharacterOffset(0) |
| 40 , m_logicalMetricsListOffset(0) | 40 , m_logicalMetricsListOffset(0) |
| 41 , m_x(0) | |
| 42 , m_y(0) | |
| 43 , m_dx(0) | |
| 44 , m_dy(0) | |
| 45 , m_isVerticalText(false) | 41 , m_isVerticalText(false) |
| 46 , m_inPathLayout(false) | 42 , m_inPathLayout(false) |
| 47 , m_textLengthSpacingInEffect(false) | 43 , m_textLengthSpacingInEffect(false) |
| 48 , m_textPath(nullptr) | 44 , m_textPath(nullptr) |
| 49 , m_textPathCurrentOffset(0) | 45 , m_textPathCurrentOffset(0) |
| 46 , m_textPathDisplacement(0) | |
| 50 , m_textPathSpacing(0) | 47 , m_textPathSpacing(0) |
| 51 , m_textPathScaling(1) | 48 , m_textPathScaling(1) |
| 52 { | 49 { |
| 53 ASSERT(!m_layoutAttributes.isEmpty()); | 50 ASSERT(!m_layoutAttributes.isEmpty()); |
| 54 } | 51 } |
| 55 | 52 |
| 56 SVGTextLayoutEngine::~SVGTextLayoutEngine() = default; | 53 SVGTextLayoutEngine::~SVGTextLayoutEngine() = default; |
| 57 | 54 |
| 58 void SVGTextLayoutEngine::updateCharacterPositionIfNeeded(float& x, float& y) | 55 bool SVGTextLayoutEngine::setCurrentTextPositionIfNeeded(const SVGCharacterData& data) |
| 59 { | 56 { |
| 60 if (m_inPathLayout) | 57 bool hasX = !SVGTextLayoutAttributes::isEmptyValue(data.x); |
| 61 return; | 58 if (hasX) |
| 59 m_ctp.setX(data.x); | |
| 62 | 60 |
| 63 // Replace characters x/y position, with the current text position plus any | 61 bool hasY = !SVGTextLayoutAttributes::isEmptyValue(data.y); |
| 64 // relative adjustments, if it doesn't specify an absolute position itself. | 62 if (hasY) |
| 65 if (SVGTextLayoutAttributes::isEmptyValue(x)) | 63 m_ctp.setY(data.y); |
| 66 x = m_x + m_dx; | |
| 67 | 64 |
| 68 if (SVGTextLayoutAttributes::isEmptyValue(y)) | 65 // If there's an absolute x/y position available, it marks the beginning of |
| 69 y = m_y + m_dy; | 66 // a new position along the path. |
| 70 | 67 if (m_inPathLayout) { |
| 71 m_dx = 0; | 68 // TODO(fs): If a new chunk (== absolute position) is defined while in |
| 72 m_dy = 0; | 69 // path layout mode, alignment should be based on that chunk and not |
| 70 // the path as a whole. (Re: the addition of m_textPathStartOffset | |
| 71 // below.) | |
| 72 if (m_isVerticalText) { | |
| 73 if (hasY) | |
| 74 m_textPathCurrentOffset = data.y + m_textPathStartOffset; | |
| 75 } else { | |
| 76 if (hasX) | |
| 77 m_textPathCurrentOffset = data.x + m_textPathStartOffset; | |
| 78 } | |
| 79 } | |
| 80 return hasX || hasY; | |
| 73 } | 81 } |
| 74 | 82 |
| 75 void SVGTextLayoutEngine::updateCurrentTextPosition(float x, float y, float glyp hAdvance) | 83 void SVGTextLayoutEngine::advanceCurrentTextPosition(float glyphAdvance) |
| 76 { | 84 { |
| 77 // Update current text position after processing the character. | 85 // TODO(fs): m_textPathCurrentOffset should preferably also be updated |
| 78 if (m_isVerticalText) { | 86 // here, but that requires a bit more untangling yet. |
| 79 m_x = x; | 87 if (m_isVerticalText) |
| 80 m_y = y + glyphAdvance; | 88 m_ctp.setY(m_ctp.y() + glyphAdvance); |
| 81 } else { | 89 else |
| 82 m_x = x + glyphAdvance; | 90 m_ctp.setX(m_ctp.x() + glyphAdvance); |
| 83 m_y = y; | |
| 84 } | |
| 85 } | 91 } |
| 86 | 92 |
| 87 void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(float dx, fl oat dy) | 93 bool SVGTextLayoutEngine::applyRelativePositionAdjustmentsIfNeeded(const SVGChar acterData& data) |
| 88 { | 94 { |
| 89 // Update relative positioning information. | 95 FloatPoint delta; |
| 90 if (SVGTextLayoutAttributes::isEmptyValue(dx) && SVGTextLayoutAttributes::is EmptyValue(dy)) | 96 bool hasDx = !SVGTextLayoutAttributes::isEmptyValue(data.dx); |
| 91 return; | 97 if (hasDx) |
| 98 delta.setX(data.dx); | |
| 92 | 99 |
| 93 if (SVGTextLayoutAttributes::isEmptyValue(dx)) | 100 bool hasDy = !SVGTextLayoutAttributes::isEmptyValue(data.dy); |
| 94 dx = 0; | 101 if (hasDy) |
| 95 if (SVGTextLayoutAttributes::isEmptyValue(dy)) | 102 delta.setY(data.dy); |
| 96 dy = 0; | 103 |
| 104 // Apply dx/dy value adjustments to current text position, if needed. | |
| 105 m_ctp.moveBy(delta); | |
| 97 | 106 |
| 98 if (m_inPathLayout) { | 107 if (m_inPathLayout) { |
| 99 if (m_isVerticalText) { | 108 if (m_isVerticalText) |
| 100 m_dx += dx; | 109 delta = delta.transposedPoint(); |
| 101 m_dy = dy; | |
| 102 } else { | |
| 103 m_dx = dx; | |
| 104 m_dy += dy; | |
| 105 } | |
| 106 | 110 |
| 107 return; | 111 m_textPathCurrentOffset += delta.x(); |
| 112 m_textPathDisplacement += delta.y(); | |
| 108 } | 113 } |
| 109 | 114 return hasDx || hasDy; |
| 110 m_dx = dx; | |
| 111 m_dy = dy; | |
| 112 } | 115 } |
| 113 | 116 |
| 114 void SVGTextLayoutEngine::computeCurrentFragmentMetrics(SVGInlineTextBox* textBo x) | 117 void SVGTextLayoutEngine::computeCurrentFragmentMetrics(SVGInlineTextBox* textBo x) |
| 115 { | 118 { |
| 116 LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText(textBox->ge tLineLayoutItem()); | 119 LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText(textBox->ge tLineLayoutItem()); |
| 117 TextRun run = textBox->constructTextRun(textLineLayout.styleRef(), m_current TextFragment); | 120 TextRun run = textBox->constructTextRun(textLineLayout.styleRef(), m_current TextFragment); |
| 118 | 121 |
| 119 float scalingFactor = textLineLayout.scalingFactor(); | 122 float scalingFactor = textLineLayout.scalingFactor(); |
| 120 ASSERT(scalingFactor); | 123 ASSERT(scalingFactor); |
| 121 const Font& scaledFont = textLineLayout.scaledFont(); | 124 const Font& scaledFont = textLineLayout.scaledFont(); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 // Find the start of the current text box in the metrics list. | 341 // Find the start of the current text box in the metrics list. |
| 339 m_visualMetricsIterator.advanceToTextStart(textLineLayout, textBox->start()) ; | 342 m_visualMetricsIterator.advanceToTextStart(textLineLayout, textBox->start()) ; |
| 340 | 343 |
| 341 const Font& font = style.font(); | 344 const Font& font = style.font(); |
| 342 | 345 |
| 343 SVGTextLayoutEngineSpacing spacingLayout(font, style.effectiveZoom()); | 346 SVGTextLayoutEngineSpacing spacingLayout(font, style.effectiveZoom()); |
| 344 SVGTextLayoutEngineBaseline baselineLayout(font, style.effectiveZoom()); | 347 SVGTextLayoutEngineBaseline baselineLayout(font, style.effectiveZoom()); |
| 345 | 348 |
| 346 bool didStartTextFragment = false; | 349 bool didStartTextFragment = false; |
| 347 bool applySpacingToNextCharacter = false; | 350 bool applySpacingToNextCharacter = false; |
| 351 bool needsFragmentPerGlyph = m_isVerticalText || m_inPathLayout || m_textLen gthSpacingInEffect; | |
| 348 | 352 |
| 349 float lastAngle = 0; | 353 float lastAngle = 0; |
| 350 float baselineShift = baselineLayout.calculateBaselineShift(style); | 354 float baselineShiftValue = baselineLayout.calculateBaselineShift(style); |
| 351 baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVertical Text, textLineLayout); | 355 baselineShiftValue -= baselineLayout.calculateAlignmentBaselineShift(m_isVer ticalText, textLineLayout); |
| 356 FloatPoint baselineShift; | |
| 357 if (m_isVerticalText) | |
| 358 baselineShift.setX(baselineShiftValue); | |
| 359 else | |
| 360 baselineShift.setY(-baselineShiftValue); | |
| 352 | 361 |
| 353 // Main layout algorithm. | 362 // Main layout algorithm. |
| 354 const unsigned boxEndOffset = textBox->start() + textBox->len(); | 363 const unsigned boxEndOffset = textBox->start() + textBox->len(); |
| 355 while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.charact erOffset() < boxEndOffset) { | 364 while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.charact erOffset() < boxEndOffset) { |
| 356 const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics(); | 365 const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics(); |
| 357 if (visualMetrics.isEmpty()) { | 366 if (visualMetrics.isEmpty()) { |
| 358 m_visualMetricsIterator.next(); | 367 m_visualMetricsIterator.next(); |
| 359 continue; | 368 continue; |
| 360 } | 369 } |
| 361 | 370 |
| 362 SVGTextLayoutAttributes* logicalAttributes = nullptr; | 371 SVGTextLayoutAttributes* logicalAttributes = nullptr; |
| 363 if (!currentLogicalCharacterAttributes(logicalAttributes)) | 372 if (!currentLogicalCharacterAttributes(logicalAttributes)) |
| 364 break; | 373 break; |
| 365 | 374 |
| 366 ASSERT(logicalAttributes); | 375 ASSERT(logicalAttributes); |
| 367 SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics); | 376 SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics); |
| 368 if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics)) | 377 if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics)) |
| 369 break; | 378 break; |
| 370 | 379 |
| 371 SVGCharacterDataMap& characterDataMap = logicalAttributes->characterData Map(); | 380 SVGCharacterDataMap& characterDataMap = logicalAttributes->characterData Map(); |
| 372 SVGCharacterData data; | 381 SVGCharacterData data; |
| 373 SVGCharacterDataMap::iterator it = characterDataMap.find(m_logicalCharac terOffset + 1); | 382 SVGCharacterDataMap::iterator it = characterDataMap.find(m_logicalCharac terOffset + 1); |
| 374 if (it != characterDataMap.end()) | 383 if (it != characterDataMap.end()) |
| 375 data = it->value; | 384 data = it->value; |
| 376 | 385 |
| 377 float x = data.x; | 386 // TODO(fs): Use the return value to eliminate the additional |
| 378 float y = data.y; | 387 // hash-lookup below when determining if this text box should be tagged |
| 388 // as starting a new text chunk. | |
| 389 setCurrentTextPositionIfNeeded(data); | |
| 379 | 390 |
| 380 // When we've advanced to the box start offset, determine using the orig inal x/y values, | 391 // When we've advanced to the box start offset, determine using the orig inal x/y values, |
|
pdr.
2016/04/14 01:05:51
This code is sandwiched between setCurrentTextPosi
fs
2016/04/14 08:56:42
As I tried to note in the TODO above, I intend for
| |
| 381 // whether this character starts a new text chunk, before doing any furt her processing. | 392 // whether this character starts a new text chunk, before doing any furt her processing. |
| 382 if (m_visualMetricsIterator.characterOffset() == textBox->start()) | 393 if (m_visualMetricsIterator.characterOffset() == textBox->start()) |
| 383 textBox->setStartsNewTextChunk(logicalAttributes->context()->charact erStartsNewTextChunk(m_logicalCharacterOffset)); | 394 textBox->setStartsNewTextChunk(logicalAttributes->context()->charact erStartsNewTextChunk(m_logicalCharacterOffset)); |
| 384 | 395 |
| 385 float angle = SVGTextLayoutAttributes::isEmptyValue(data.rotate) ? 0 : d ata.rotate; | 396 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data ); |
| 386 | 397 |
| 387 // Calculate glyph orientation angle. | 398 // Determine the orientation of the current glyph. |
| 388 // Font::width() calculates the resolved FontOrientation for each charac ter, | 399 // Font::width() calculates the resolved FontOrientation for each charac ter, |
| 389 // but is not exposed today to avoid the API complexity. | 400 // but that value is not exposed today to avoid the API complexity. |
| 390 UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIte rator.characterOffset()); | 401 UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIte rator.characterOffset()); |
| 391 FontOrientation fontOrientation = font.getFontDescription().orientation( ); | 402 FontOrientation fontOrientation = font.getFontDescription().orientation( ); |
| 392 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien tation, currentCharacter); | 403 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien tation, currentCharacter); |
| 393 | 404 |
| 394 // Calculate glyph advance. | 405 // Calculate glyph advance. |
| 395 // Shaping engine takes care of x/y orientation shifts for different fon tOrientation values. | 406 // The shaping engine takes care of x/y orientation shifts for different fontOrientation values. |
| 396 float glyphAdvance = visualMetrics.advance(fontOrientation); | 407 float glyphAdvance = visualMetrics.advance(fontOrientation); |
| 397 | 408 |
| 398 // Assign current text position to x/y values, if needed. | 409 // Calculate CSS 'letter-spacing' and 'word-spacing' for the character, if needed. |
| 399 updateCharacterPositionIfNeeded(x, y); | |
| 400 | |
| 401 // Apply dx/dy value adjustments to current text position, if needed. | |
| 402 updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy); | |
| 403 | |
| 404 // Calculate CSS 'letter-spacing' and 'word-spacing' for next character, if needed. | |
| 405 float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); | 410 float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); |
| 406 | 411 |
| 407 float textPathShiftX = 0; | 412 FloatPoint textPathShift; |
| 408 float textPathShiftY = 0; | 413 float angle = 0; |
| 414 FloatPoint position; | |
| 409 if (m_inPathLayout) { | 415 if (m_inPathLayout) { |
| 410 float scaledGlyphAdvance = glyphAdvance * m_textPathScaling; | 416 float scaledGlyphAdvance = glyphAdvance * m_textPathScaling; |
| 411 if (m_isVerticalText) { | 417 // Setup translations that move to the glyph midpoint. |
| 412 // If there's an absolute y position available, it marks the beg inning of a new position along the path. | 418 textPathShift.set(-scaledGlyphAdvance / 2, m_textPathDisplacement); |
| 413 if (!SVGTextLayoutAttributes::isEmptyValue(y)) | 419 if (m_isVerticalText) |
| 414 m_textPathCurrentOffset = y + m_textPathStartOffset; | 420 textPathShift = textPathShift.transposedPoint(); |
| 415 | 421 textPathShift += baselineShift; |
| 416 m_textPathCurrentOffset += m_dy; | |
| 417 m_dy = 0; | |
| 418 | |
| 419 // Apply dx/dy correction and setup translations that move to th e glyph midpoint. | |
| 420 textPathShiftX += m_dx + baselineShift; | |
| 421 textPathShiftY -= scaledGlyphAdvance / 2; | |
| 422 } else { | |
| 423 // If there's an absolute x position available, it marks the beg inning of a new position along the path. | |
| 424 if (!SVGTextLayoutAttributes::isEmptyValue(x)) | |
| 425 m_textPathCurrentOffset = x + m_textPathStartOffset; | |
| 426 | |
| 427 m_textPathCurrentOffset += m_dx; | |
| 428 m_dx = 0; | |
| 429 | |
| 430 // Apply dx/dy correction and setup translations that move to th e glyph midpoint. | |
| 431 textPathShiftX -= scaledGlyphAdvance / 2; | |
| 432 textPathShiftY += m_dy - baselineShift; | |
| 433 } | |
| 434 | 422 |
| 435 // Calculate current offset along path. | 423 // Calculate current offset along path. |
| 436 float textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2; | 424 float textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2; |
| 437 | 425 |
| 438 // Move to next character. | 426 // Move to next character. |
| 439 m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing + spacing * m_textPathScaling; | 427 m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing + spacing * m_textPathScaling; |
| 440 | 428 |
| 441 FloatPoint point; | 429 PathPositionMapper::PositionType positionType = m_textPath->pointAnd NormalAtLength(textPathOffset, position, angle); |
| 442 PathPositionMapper::PositionType positionType = m_textPath->pointAnd NormalAtLength(textPathOffset, point, angle); | |
| 443 | 430 |
| 444 // Skip character, if we're before the path. | 431 // Skip character, if we're before the path. |
| 445 if (positionType == PathPositionMapper::BeforePath) { | 432 if (positionType == PathPositionMapper::BeforePath) { |
| 446 advanceToNextLogicalCharacter(logicalMetrics); | 433 advanceToNextLogicalCharacter(logicalMetrics); |
| 447 m_visualMetricsIterator.next(); | 434 m_visualMetricsIterator.next(); |
| 448 continue; | 435 continue; |
| 449 } | 436 } |
| 450 | 437 |
| 451 // Stop processing if the next character lies behind the path. | 438 // Stop processing if the next character lies behind the path. |
| 452 if (positionType == PathPositionMapper::AfterPath) | 439 if (positionType == PathPositionMapper::AfterPath) |
| 453 break; | 440 break; |
| 454 | 441 |
| 455 x = point.x(); | |
| 456 y = point.y(); | |
| 457 | |
| 458 // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle! | 442 // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle! |
| 459 if (m_isVerticalText) | 443 if (m_isVerticalText) |
| 460 angle -= 90; | 444 angle -= 90; |
| 461 } else { | 445 } else { |
| 462 // Apply all previously calculated shift values. | 446 position = m_ctp; |
| 463 if (m_isVerticalText) | 447 position += baselineShift; |
| 464 x += baselineShift; | |
| 465 else | |
| 466 y -= baselineShift; | |
| 467 | |
| 468 x += m_dx; | |
| 469 y += m_dy; | |
| 470 } | 448 } |
| 471 | 449 |
| 450 if (!SVGTextLayoutAttributes::isEmptyValue(data.rotate)) | |
| 451 angle += data.rotate; | |
| 452 | |
| 472 // Determine whether we have to start a new fragment. | 453 // Determine whether we have to start a new fragment. |
| 473 bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPa thLayout || angle || angle != lastAngle | 454 bool shouldStartNewFragment = needsFragmentPerGlyph || hasRelativePositi on |
| 474 || applySpacingToNextCharacter || m_textLengthSpacingInEffect; | 455 || angle || angle != lastAngle || applySpacingToNextCharacter; |
| 475 | 456 |
| 476 // If we already started a fragment, close it now. | 457 // If we already started a fragment, close it now. |
| 477 if (didStartTextFragment && shouldStartNewFragment) { | 458 if (didStartTextFragment && shouldStartNewFragment) { |
| 478 applySpacingToNextCharacter = false; | 459 applySpacingToNextCharacter = false; |
| 479 recordTextFragment(textBox); | 460 recordTextFragment(textBox); |
| 480 } | 461 } |
| 481 | 462 |
| 482 // Eventually start a new fragment, if not yet done. | 463 // Eventually start a new fragment, if not yet done. |
| 483 if (!didStartTextFragment || shouldStartNewFragment) { | 464 if (!didStartTextFragment || shouldStartNewFragment) { |
| 484 ASSERT(!m_currentTextFragment.characterOffset); | 465 ASSERT(!m_currentTextFragment.characterOffset); |
| 485 ASSERT(!m_currentTextFragment.length); | 466 ASSERT(!m_currentTextFragment.length); |
| 486 | 467 |
| 487 didStartTextFragment = true; | 468 didStartTextFragment = true; |
| 488 m_currentTextFragment.characterOffset = m_visualMetricsIterator.char acterOffset(); | 469 m_currentTextFragment.characterOffset = m_visualMetricsIterator.char acterOffset(); |
| 489 m_currentTextFragment.metricsListOffset = m_visualMetricsIterator.me tricsListOffset(); | 470 m_currentTextFragment.metricsListOffset = m_visualMetricsIterator.me tricsListOffset(); |
| 490 m_currentTextFragment.x = x; | 471 m_currentTextFragment.x = position.x(); |
| 491 m_currentTextFragment.y = y; | 472 m_currentTextFragment.y = position.y(); |
| 492 | 473 |
| 493 // Build fragment transformation. | 474 // Build fragment transformation. |
| 494 if (angle) | 475 if (angle) |
| 495 m_currentTextFragment.transform.rotate(angle); | 476 m_currentTextFragment.transform.rotate(angle); |
| 496 | 477 |
| 497 if (textPathShiftX || textPathShiftY) | 478 if (textPathShift.x() || textPathShift.y()) |
| 498 m_currentTextFragment.transform.translate(textPathShiftX, textPa thShiftY); | 479 m_currentTextFragment.transform.translate(textPathShift.x(), tex tPathShift.y()); |
| 499 | 480 |
| 500 // In vertical text, always rotate by 90 degrees regardless of fontO rientation. | 481 // For vertical text, always rotate by 90 degrees regardless of font Orientation. |
| 501 // Shaping engine takes care of the necessary orientation. | 482 // The shaping engine takes care of the necessary orientation. |
| 502 if (m_isVerticalText) | 483 if (m_isVerticalText) |
| 503 m_currentTextFragment.transform.rotate(90); | 484 m_currentTextFragment.transform.rotate(90); |
| 504 | 485 |
| 505 m_currentTextFragment.isVertical = m_isVerticalText; | 486 m_currentTextFragment.isVertical = m_isVerticalText; |
| 506 m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathSca ling != 1; | 487 m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathSca ling != 1; |
| 507 if (m_currentTextFragment.isTextOnPath) | 488 if (m_currentTextFragment.isTextOnPath) |
| 508 m_currentTextFragment.lengthAdjustScale = m_textPathScaling; | 489 m_currentTextFragment.lengthAdjustScale = m_textPathScaling; |
| 509 } | 490 } |
| 510 | 491 |
| 511 // Update current text position, after processing of the current charact er finished. | 492 // Advance current text position after processing of the current charact er finished. |
| 512 if (m_inPathLayout) { | 493 advanceCurrentTextPosition(glyphAdvance + spacing); |
| 513 updateCurrentTextPosition(x, y, glyphAdvance); | |
| 514 } else { | |
| 515 // Apply CSS 'kerning', 'letter-spacing' and 'word-spacing' to next character, if needed. | |
| 516 if (spacing) | |
| 517 applySpacingToNextCharacter = true; | |
| 518 | 494 |
| 519 float xNew = x - m_dx; | 495 // Apply CSS 'letter-spacing' and 'word-spacing' to the next character, if needed. |
| 520 float yNew = y - m_dy; | 496 if (!m_inPathLayout && spacing) |
| 521 | 497 applySpacingToNextCharacter = true; |
| 522 if (m_isVerticalText) | |
| 523 xNew -= baselineShift; | |
| 524 else | |
| 525 yNew += baselineShift; | |
| 526 | |
| 527 updateCurrentTextPosition(xNew, yNew, glyphAdvance + spacing); | |
| 528 } | |
| 529 | 498 |
| 530 advanceToNextLogicalCharacter(logicalMetrics); | 499 advanceToNextLogicalCharacter(logicalMetrics); |
| 531 m_visualMetricsIterator.next(); | 500 m_visualMetricsIterator.next(); |
| 532 lastAngle = angle; | 501 lastAngle = angle; |
| 533 } | 502 } |
| 534 | 503 |
| 535 if (!didStartTextFragment) | 504 if (!didStartTextFragment) |
| 536 return; | 505 return; |
| 537 | 506 |
| 538 // Close last open fragment, if needed. | 507 // Close last open fragment, if needed. |
| 539 recordTextFragment(textBox); | 508 recordTextFragment(textBox); |
| 540 } | 509 } |
| 541 | 510 |
| 542 } // namespace blink | 511 } // namespace blink |
| OLD | NEW |