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 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 { | 327 { |
328 ++m_logicalMetricsListOffset; | 328 ++m_logicalMetricsListOffset; |
329 m_logicalCharacterOffset += logicalMetrics.length(); | 329 m_logicalCharacterOffset += logicalMetrics.length(); |
330 } | 330 } |
331 | 331 |
332 void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, cons
t LayoutSVGInlineText& text, const ComputedStyle& style) | 332 void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, cons
t LayoutSVGInlineText& text, const ComputedStyle& style) |
333 { | 333 { |
334 if (m_inPathLayout && !m_textPathCalculator) | 334 if (m_inPathLayout && !m_textPathCalculator) |
335 return; | 335 return; |
336 | 336 |
337 const SVGComputedStyle& svgStyle = style.svgStyle(); | |
338 | |
339 // Find the start of the current text box in the metrics list. | 337 // Find the start of the current text box in the metrics list. |
340 m_visualMetricsIterator.advanceToTextStart(&text, textBox->start()); | 338 m_visualMetricsIterator.advanceToTextStart(&text, textBox->start()); |
341 | 339 |
342 const Font& font = style.font(); | 340 const Font& font = style.font(); |
343 | 341 |
344 SVGTextLayoutEngineSpacing spacingLayout(font, style.effectiveZoom()); | 342 SVGTextLayoutEngineSpacing spacingLayout(font, style.effectiveZoom()); |
345 SVGTextLayoutEngineBaseline baselineLayout(font, style.effectiveZoom()); | 343 SVGTextLayoutEngineBaseline baselineLayout(font, style.effectiveZoom()); |
346 | 344 |
347 bool didStartTextFragment = false; | 345 bool didStartTextFragment = false; |
348 bool applySpacingToNextCharacter = false; | 346 bool applySpacingToNextCharacter = false; |
(...skipping 30 matching lines...) Expand all Loading... |
379 float y = data.y; | 377 float y = data.y; |
380 | 378 |
381 // When we've advanced to the box start offset, determine using the orig
inal x/y values, | 379 // When we've advanced to the box start offset, determine using the orig
inal x/y values, |
382 // whether this character starts a new text chunk, before doing any furt
her processing. | 380 // whether this character starts a new text chunk, before doing any furt
her processing. |
383 if (m_visualMetricsIterator.characterOffset() == textBox->start()) | 381 if (m_visualMetricsIterator.characterOffset() == textBox->start()) |
384 textBox->setStartsNewTextChunk(logicalAttributes->context()->charact
erStartsNewTextChunk(m_logicalCharacterOffset)); | 382 textBox->setStartsNewTextChunk(logicalAttributes->context()->charact
erStartsNewTextChunk(m_logicalCharacterOffset)); |
385 | 383 |
386 float angle = SVGTextLayoutAttributes::isEmptyValue(data.rotate) ? 0 : d
ata.rotate; | 384 float angle = SVGTextLayoutAttributes::isEmptyValue(data.rotate) ? 0 : d
ata.rotate; |
387 | 385 |
388 // Calculate glyph orientation angle. | 386 // Calculate glyph orientation angle. |
| 387 // Font::width() calculates the resolved FontOrientation for each charac
ter, |
| 388 // but is not exposed today to avoid the API complexity. |
389 UChar32 currentCharacter = text.codepointAt(m_visualMetricsIterator.char
acterOffset()); | 389 UChar32 currentCharacter = text.codepointAt(m_visualMetricsIterator.char
acterOffset()); |
390 float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m
_isVerticalText, svgStyle, currentCharacter); | 390 FontOrientation fontOrientation = font.fontDescription().orientation(); |
| 391 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien
tation, currentCharacter); |
391 | 392 |
392 // Calculate glyph advance & x/y orientation shifts. | 393 // Calculate glyph advance. |
393 float xOrientationShift = 0; | 394 // Shaping engine takes care of x/y orientation shifts for different fon
tOrientation values. |
394 float yOrientationShift = 0; | 395 float glyphAdvance = visualMetrics.advance(fontOrientation); |
395 float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(
m_isVerticalText, visualMetrics, orientationAngle, xOrientationShift, yOrientati
onShift); | |
396 | 396 |
397 // Assign current text position to x/y values, if needed. | 397 // Assign current text position to x/y values, if needed. |
398 updateCharacterPositionIfNeeded(x, y); | 398 updateCharacterPositionIfNeeded(x, y); |
399 | 399 |
400 // Apply dx/dy value adjustments to current text position, if needed. | 400 // Apply dx/dy value adjustments to current text position, if needed. |
401 updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy); | 401 updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy); |
402 | 402 |
403 // Calculate CSS 'letter-spacing' and 'word-spacing' for next character,
if needed. | 403 // Calculate CSS 'letter-spacing' and 'word-spacing' for next character,
if needed. |
404 float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); | 404 float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); |
405 | 405 |
406 float textPathOffset = 0; | 406 float textPathOffset = 0; |
| 407 float textPathShiftX = 0; |
| 408 float textPathShiftY = 0; |
407 if (m_inPathLayout) { | 409 if (m_inPathLayout) { |
408 float scaledGlyphAdvance = glyphAdvance * m_textPathScaling; | 410 float scaledGlyphAdvance = glyphAdvance * m_textPathScaling; |
409 if (m_isVerticalText) { | 411 if (m_isVerticalText) { |
410 // If there's an absolute y position available, it marks the beg
inning of a new position along the path. | 412 // If there's an absolute y position available, it marks the beg
inning of a new position along the path. |
411 if (!SVGTextLayoutAttributes::isEmptyValue(y)) | 413 if (!SVGTextLayoutAttributes::isEmptyValue(y)) |
412 m_textPathCurrentOffset = y + m_textPathStartOffset; | 414 m_textPathCurrentOffset = y + m_textPathStartOffset; |
413 | 415 |
414 m_textPathCurrentOffset += m_dy; | 416 m_textPathCurrentOffset += m_dy; |
415 m_dy = 0; | 417 m_dy = 0; |
416 | 418 |
417 // Apply dx/dy correction and setup translations that move to th
e glyph midpoint. | 419 // Apply dx/dy correction and setup translations that move to th
e glyph midpoint. |
418 xOrientationShift += m_dx + baselineShift; | 420 textPathShiftX += m_dx + baselineShift; |
419 yOrientationShift -= scaledGlyphAdvance / 2; | 421 textPathShiftY -= scaledGlyphAdvance / 2; |
420 } else { | 422 } else { |
421 // If there's an absolute x position available, it marks the beg
inning of a new position along the path. | 423 // If there's an absolute x position available, it marks the beg
inning of a new position along the path. |
422 if (!SVGTextLayoutAttributes::isEmptyValue(x)) | 424 if (!SVGTextLayoutAttributes::isEmptyValue(x)) |
423 m_textPathCurrentOffset = x + m_textPathStartOffset; | 425 m_textPathCurrentOffset = x + m_textPathStartOffset; |
424 | 426 |
425 m_textPathCurrentOffset += m_dx; | 427 m_textPathCurrentOffset += m_dx; |
426 m_dx = 0; | 428 m_dx = 0; |
427 | 429 |
428 // Apply dx/dy correction and setup translations that move to th
e glyph midpoint. | 430 // Apply dx/dy correction and setup translations that move to th
e glyph midpoint. |
429 xOrientationShift -= scaledGlyphAdvance / 2; | 431 textPathShiftX -= scaledGlyphAdvance / 2; |
430 yOrientationShift += m_dy - baselineShift; | 432 textPathShiftY += m_dy - baselineShift; |
431 } | 433 } |
432 | 434 |
433 // Calculate current offset along path. | 435 // Calculate current offset along path. |
434 textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2; | 436 textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2; |
435 | 437 |
436 // Move to next character. | 438 // Move to next character. |
437 m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing +
spacing * m_textPathScaling; | 439 m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing +
spacing * m_textPathScaling; |
438 | 440 |
439 // Skip character, if we're before the path. | 441 // Skip character, if we're before the path. |
440 if (textPathOffset < 0) { | 442 if (textPathOffset < 0) { |
(...skipping 21 matching lines...) Expand all Loading... |
462 x += baselineShift; | 464 x += baselineShift; |
463 else | 465 else |
464 y -= baselineShift; | 466 y -= baselineShift; |
465 | 467 |
466 x += m_dx; | 468 x += m_dx; |
467 y += m_dy; | 469 y += m_dy; |
468 } | 470 } |
469 | 471 |
470 // Determine whether we have to start a new fragment. | 472 // Determine whether we have to start a new fragment. |
471 bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPa
thLayout || angle || angle != lastAngle | 473 bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPa
thLayout || angle || angle != lastAngle |
472 || orientationAngle || applySpacingToNextCharacter || m_textLengthSp
acingInEffect; | 474 || applySpacingToNextCharacter || m_textLengthSpacingInEffect; |
473 | 475 |
474 // If we already started a fragment, close it now. | 476 // If we already started a fragment, close it now. |
475 if (didStartTextFragment && shouldStartNewFragment) { | 477 if (didStartTextFragment && shouldStartNewFragment) { |
476 applySpacingToNextCharacter = false; | 478 applySpacingToNextCharacter = false; |
477 recordTextFragment(textBox); | 479 recordTextFragment(textBox); |
478 } | 480 } |
479 | 481 |
480 // Eventually start a new fragment, if not yet done. | 482 // Eventually start a new fragment, if not yet done. |
481 if (!didStartTextFragment || shouldStartNewFragment) { | 483 if (!didStartTextFragment || shouldStartNewFragment) { |
482 ASSERT(!m_currentTextFragment.characterOffset); | 484 ASSERT(!m_currentTextFragment.characterOffset); |
483 ASSERT(!m_currentTextFragment.length); | 485 ASSERT(!m_currentTextFragment.length); |
484 | 486 |
485 didStartTextFragment = true; | 487 didStartTextFragment = true; |
486 m_currentTextFragment.characterOffset = m_visualMetricsIterator.char
acterOffset(); | 488 m_currentTextFragment.characterOffset = m_visualMetricsIterator.char
acterOffset(); |
487 m_currentTextFragment.metricsListOffset = m_visualMetricsIterator.me
tricsListOffset(); | 489 m_currentTextFragment.metricsListOffset = m_visualMetricsIterator.me
tricsListOffset(); |
488 m_currentTextFragment.x = x; | 490 m_currentTextFragment.x = x; |
489 m_currentTextFragment.y = y; | 491 m_currentTextFragment.y = y; |
490 | 492 |
491 // Build fragment transformation. | 493 // Build fragment transformation. |
492 if (angle) | 494 if (angle) |
493 m_currentTextFragment.transform.rotate(angle); | 495 m_currentTextFragment.transform.rotate(angle); |
494 | 496 |
495 if (xOrientationShift || yOrientationShift) | 497 if (textPathShiftX || textPathShiftY) |
496 m_currentTextFragment.transform.translate(xOrientationShift, yOr
ientationShift); | 498 m_currentTextFragment.transform.translate(textPathShiftX, textPa
thShiftY); |
497 | 499 |
498 if (orientationAngle) | 500 // In vertical text, always rotate by 90 degrees regardless of fontO
rientation. |
499 m_currentTextFragment.transform.rotate(orientationAngle); | 501 // Shaping engine takes care of the necessary orientation. |
| 502 if (m_isVerticalText) |
| 503 m_currentTextFragment.transform.rotate(90); |
500 | 504 |
501 m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathSca
ling != 1; | 505 m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathSca
ling != 1; |
502 if (m_currentTextFragment.isTextOnPath) { | 506 if (m_currentTextFragment.isTextOnPath) { |
503 if (m_isVerticalText) | 507 if (m_isVerticalText) |
504 m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(
1, m_textPathScaling); | 508 m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(
1, m_textPathScaling); |
505 else | 509 else |
506 m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(
m_textPathScaling, 1); | 510 m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(
m_textPathScaling, 1); |
507 } | 511 } |
508 } | 512 } |
509 | 513 |
(...skipping 22 matching lines...) Expand all Loading... |
532 } | 536 } |
533 | 537 |
534 if (!didStartTextFragment) | 538 if (!didStartTextFragment) |
535 return; | 539 return; |
536 | 540 |
537 // Close last open fragment, if needed. | 541 // Close last open fragment, if needed. |
538 recordTextFragment(textBox); | 542 recordTextFragment(textBox); |
539 } | 543 } |
540 | 544 |
541 } | 545 } |
OLD | NEW |