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 |