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::setCurrentTextPosition(const SVGCharacterData& data) |
59 { | 56 { |
60 if (m_inPathLayout) | 57 bool hasX = !SVGTextLayoutAttributes::isEmptyValue(data.x); |
61 return; | 58 if (hasX) |
| 59 m_textPosition.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_textPosition.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_textPosition.setY(m_textPosition.y() + glyphAdvance); |
81 } else { | 89 else |
82 m_x = x + glyphAdvance; | 90 m_textPosition.setX(m_textPosition.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_textPosition.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 setCurrentTextPosition(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, |
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(); | 442 m_textPosition = position; |
456 y = point.y(); | |
457 | 443 |
458 // For vertical text on path, the actual angle has to be rotated 90
degrees anti-clockwise, not the orientation angle! | 444 // For vertical text on path, the actual angle has to be rotated 90
degrees anti-clockwise, not the orientation angle! |
459 if (m_isVerticalText) | 445 if (m_isVerticalText) |
460 angle -= 90; | 446 angle -= 90; |
461 } else { | 447 } else { |
462 // Apply all previously calculated shift values. | 448 position = m_textPosition; |
463 if (m_isVerticalText) | 449 position += baselineShift; |
464 x += baselineShift; | |
465 else | |
466 y -= baselineShift; | |
467 | |
468 x += m_dx; | |
469 y += m_dy; | |
470 } | 450 } |
471 | 451 |
| 452 if (!SVGTextLayoutAttributes::isEmptyValue(data.rotate)) |
| 453 angle += data.rotate; |
| 454 |
472 // Determine whether we have to start a new fragment. | 455 // Determine whether we have to start a new fragment. |
473 bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPa
thLayout || angle || angle != lastAngle | 456 bool shouldStartNewFragment = needsFragmentPerGlyph || hasRelativePositi
on |
474 || applySpacingToNextCharacter || m_textLengthSpacingInEffect; | 457 || angle || angle != lastAngle || applySpacingToNextCharacter; |
475 | 458 |
476 // If we already started a fragment, close it now. | 459 // If we already started a fragment, close it now. |
477 if (didStartTextFragment && shouldStartNewFragment) { | 460 if (didStartTextFragment && shouldStartNewFragment) { |
478 applySpacingToNextCharacter = false; | 461 applySpacingToNextCharacter = false; |
479 recordTextFragment(textBox); | 462 recordTextFragment(textBox); |
480 } | 463 } |
481 | 464 |
482 // Eventually start a new fragment, if not yet done. | 465 // Eventually start a new fragment, if not yet done. |
483 if (!didStartTextFragment || shouldStartNewFragment) { | 466 if (!didStartTextFragment || shouldStartNewFragment) { |
484 ASSERT(!m_currentTextFragment.characterOffset); | 467 ASSERT(!m_currentTextFragment.characterOffset); |
485 ASSERT(!m_currentTextFragment.length); | 468 ASSERT(!m_currentTextFragment.length); |
486 | 469 |
487 didStartTextFragment = true; | 470 didStartTextFragment = true; |
488 m_currentTextFragment.characterOffset = m_visualMetricsIterator.char
acterOffset(); | 471 m_currentTextFragment.characterOffset = m_visualMetricsIterator.char
acterOffset(); |
489 m_currentTextFragment.metricsListOffset = m_visualMetricsIterator.me
tricsListOffset(); | 472 m_currentTextFragment.metricsListOffset = m_visualMetricsIterator.me
tricsListOffset(); |
490 m_currentTextFragment.x = x; | 473 m_currentTextFragment.x = position.x(); |
491 m_currentTextFragment.y = y; | 474 m_currentTextFragment.y = position.y(); |
492 | 475 |
493 // Build fragment transformation. | 476 // Build fragment transformation. |
494 if (angle) | 477 if (angle) |
495 m_currentTextFragment.transform.rotate(angle); | 478 m_currentTextFragment.transform.rotate(angle); |
496 | 479 |
497 if (textPathShiftX || textPathShiftY) | 480 if (textPathShift.x() || textPathShift.y()) |
498 m_currentTextFragment.transform.translate(textPathShiftX, textPa
thShiftY); | 481 m_currentTextFragment.transform.translate(textPathShift.x(), tex
tPathShift.y()); |
499 | 482 |
500 // In vertical text, always rotate by 90 degrees regardless of fontO
rientation. | 483 // For vertical text, always rotate by 90 degrees regardless of font
Orientation. |
501 // Shaping engine takes care of the necessary orientation. | 484 // The shaping engine takes care of the necessary orientation. |
502 if (m_isVerticalText) | 485 if (m_isVerticalText) |
503 m_currentTextFragment.transform.rotate(90); | 486 m_currentTextFragment.transform.rotate(90); |
504 | 487 |
505 m_currentTextFragment.isVertical = m_isVerticalText; | 488 m_currentTextFragment.isVertical = m_isVerticalText; |
506 m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathSca
ling != 1; | 489 m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathSca
ling != 1; |
507 if (m_currentTextFragment.isTextOnPath) | 490 if (m_currentTextFragment.isTextOnPath) |
508 m_currentTextFragment.lengthAdjustScale = m_textPathScaling; | 491 m_currentTextFragment.lengthAdjustScale = m_textPathScaling; |
509 } | 492 } |
510 | 493 |
511 // Update current text position, after processing of the current charact
er finished. | 494 // Advance current text position after processing of the current charact
er finished. |
512 if (m_inPathLayout) { | 495 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 | 496 |
519 float xNew = x - m_dx; | 497 // Apply CSS 'letter-spacing' and 'word-spacing' to the next character,
if needed. |
520 float yNew = y - m_dy; | 498 if (!m_inPathLayout && spacing) |
521 | 499 applySpacingToNextCharacter = true; |
522 if (m_isVerticalText) | |
523 xNew -= baselineShift; | |
524 else | |
525 yNew += baselineShift; | |
526 | |
527 updateCurrentTextPosition(xNew, yNew, glyphAdvance + spacing); | |
528 } | |
529 | 500 |
530 advanceToNextLogicalCharacter(logicalMetrics); | 501 advanceToNextLogicalCharacter(logicalMetrics); |
531 m_visualMetricsIterator.next(); | 502 m_visualMetricsIterator.next(); |
532 lastAngle = angle; | 503 lastAngle = angle; |
533 } | 504 } |
534 | 505 |
535 if (!didStartTextFragment) | 506 if (!didStartTextFragment) |
536 return; | 507 return; |
537 | 508 |
538 // Close last open fragment, if needed. | 509 // Close last open fragment, if needed. |
539 recordTextFragment(textBox); | 510 recordTextFragment(textBox); |
540 } | 511 } |
541 | 512 |
542 } // namespace blink | 513 } // namespace blink |
OLD | NEW |