| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 Google Inc. All rights reserved. | 2 * Copyright (c) 2012 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. | 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
| 7 * met: | 7 * met: |
| 8 * | 8 * |
| 9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 { | 208 { |
| 209 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ()); | 209 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ()); |
| 210 return globalHarfBuzzRunCache; | 210 return globalHarfBuzzRunCache; |
| 211 } | 211 } |
| 212 | 212 |
| 213 static inline float harfBuzzPositionToFloat(hb_position_t value) | 213 static inline float harfBuzzPositionToFloat(hb_position_t value) |
| 214 { | 214 { |
| 215 return static_cast<float>(value) / (1 << 16); | 215 return static_cast<float>(value) / (1 << 16); |
| 216 } | 216 } |
| 217 | 217 |
| 218 static inline unsigned countGraphemesInCluster(const UChar* normalizedBuffer, un
signed normalizedBufferLength, uint16_t startIndex, uint16_t endIndex) | 218 static inline unsigned countGraphemesInCluster(const UChar* str, unsigned strLen
gth, uint16_t startIndex, uint16_t endIndex) |
| 219 { | 219 { |
| 220 if (startIndex > endIndex) { | 220 if (startIndex > endIndex) { |
| 221 uint16_t tempIndex = startIndex; | 221 uint16_t tempIndex = startIndex; |
| 222 startIndex = endIndex; | 222 startIndex = endIndex; |
| 223 endIndex = tempIndex; | 223 endIndex = tempIndex; |
| 224 } | 224 } |
| 225 uint16_t length = endIndex - startIndex; | 225 uint16_t length = endIndex - startIndex; |
| 226 ASSERT(static_cast<unsigned>(startIndex + length) <= normalizedBufferLength)
; | 226 ASSERT(static_cast<unsigned>(startIndex + length) <= strLength); |
| 227 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&normalizedBuf
fer[startIndex], length); | 227 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startInde
x], length); |
| 228 | 228 |
| 229 int cursorPos = cursorPosIterator->current(); | 229 int cursorPos = cursorPosIterator->current(); |
| 230 int numGraphemes = -1; | 230 int numGraphemes = -1; |
| 231 while (0 <= cursorPos) { | 231 while (0 <= cursorPos) { |
| 232 cursorPos = cursorPosIterator->next(); | 232 cursorPos = cursorPosIterator->next(); |
| 233 numGraphemes++; | 233 numGraphemes++; |
| 234 } | 234 } |
| 235 return numGraphemes < 0 ? 0 : numGraphemes; | 235 return numGraphemes < 0 ? 0 : numGraphemes; |
| 236 } | 236 } |
| 237 | 237 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 position += m_advances[glyphIndex]; | 339 position += m_advances[glyphIndex]; |
| 340 } else { | 340 } else { |
| 341 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex]
< offset) { | 341 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex]
< offset) { |
| 342 position += m_advances[glyphIndex]; | 342 position += m_advances[glyphIndex]; |
| 343 ++glyphIndex; | 343 ++glyphIndex; |
| 344 } | 344 } |
| 345 } | 345 } |
| 346 return position; | 346 return position; |
| 347 } | 347 } |
| 348 | 348 |
| 349 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest
ination, unsigned* destinationLength) | |
| 350 { | |
| 351 unsigned position = 0; | |
| 352 bool error = false; | |
| 353 const UChar* source; | |
| 354 String stringFor8BitRun; | |
| 355 if (run.is8Bit()) { | |
| 356 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru
n.length()); | |
| 357 source = stringFor8BitRun.characters16(); | |
| 358 } else { | |
| 359 source = run.characters16(); | |
| 360 } | |
| 361 | |
| 362 *destinationLength = 0; | |
| 363 while (position < length) { | |
| 364 UChar32 character; | |
| 365 U16_NEXT(source, position, length, character); | |
| 366 // Don't normalize tabs as they are not treated as spaces for word-end. | |
| 367 if (run.normalizeSpace() && Character::isNormalizedCanvasSpaceCharacter(
character)) | |
| 368 character = space; | |
| 369 else if (Character::treatAsSpace(character) && character != characterTab
ulation) | |
| 370 character = space; | |
| 371 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) | |
| 372 character = zeroWidthSpace; | |
| 373 | |
| 374 U16_APPEND(destination, *destinationLength, length, character, error); | |
| 375 ASSERT_UNUSED(error, !error); | |
| 376 } | |
| 377 } | |
| 378 | 349 |
| 379 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmph
asisOrNot forTextEmphasis, HashSet<const SimpleFontData*>* fallbackFonts, FloatR
ect* bounds) | 350 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmph
asisOrNot forTextEmphasis, HashSet<const SimpleFontData*>* fallbackFonts, FloatR
ect* bounds) |
| 380 : Shaper(font, run, forTextEmphasis, fallbackFonts, bounds) | 351 : Shaper(font, run, forTextEmphasis, fallbackFonts, bounds) |
| 381 , m_normalizedBufferLength(0) | |
| 382 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) | 352 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) |
| 383 , m_letterSpacing(font->fontDescription().letterSpacing()) | 353 , m_letterSpacing(font->fontDescription().letterSpacing()) |
| 384 , m_expansionOpportunityCount(0) | 354 , m_expansionOpportunityCount(0) |
| 385 , m_fromIndex(0) | 355 , m_fromIndex(0) |
| 386 , m_toIndex(m_run.length()) | 356 , m_toIndex(m_run.length()) |
| 387 { | 357 { |
| 388 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]); | |
| 389 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm
alizedBufferLength); | |
| 390 setExpansion(m_run.expansion()); | 358 setExpansion(m_run.expansion()); |
| 391 setFontFeatures(); | 359 setFontFeatures(); |
| 392 } | 360 } |
| 393 | 361 |
| 394 float HarfBuzzShaper::nextExpansionPerOpportunity() | 362 float HarfBuzzShaper::nextExpansionPerOpportunity() |
| 395 { | 363 { |
| 396 if (!m_expansionOpportunityCount) { | 364 if (!m_expansionOpportunityCount) { |
| 397 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha
per does not match to the one in expansionOpportunityCount() | 365 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha
per does not match to the one in expansionOpportunityCount() |
| 398 return 0; | 366 return 0; |
| 399 } | 367 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 410 // WebKit uses this to justify text. | 378 // WebKit uses this to justify text. |
| 411 void HarfBuzzShaper::setExpansion(float padding) | 379 void HarfBuzzShaper::setExpansion(float padding) |
| 412 { | 380 { |
| 413 m_expansion = padding; | 381 m_expansion = padding; |
| 414 if (!m_expansion) | 382 if (!m_expansion) |
| 415 return; | 383 return; |
| 416 | 384 |
| 417 // If we have padding to distribute, then we try to give an equal | 385 // If we have padding to distribute, then we try to give an equal |
| 418 // amount to each expansion opportunity. | 386 // amount to each expansion opportunity. |
| 419 bool isAfterExpansion = m_isAfterExpansion; | 387 bool isAfterExpansion = m_isAfterExpansion; |
| 420 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_normali
zedBuffer.get(), m_normalizedBufferLength, m_run.direction(), isAfterExpansion,
m_run.textJustify()); | 388 if (m_run.is8Bit()) |
| 389 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_run
.characters8(), m_run.length(), m_run.direction(), isAfterExpansion, m_run.textJ
ustify()); |
| 390 else |
| 391 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_run
.characters16(), m_run.length(), m_run.direction(), isAfterExpansion, m_run.text
Justify()); |
| 392 |
| 421 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) { | 393 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) { |
| 422 ASSERT(m_expansionOpportunityCount > 0); | 394 ASSERT(m_expansionOpportunityCount > 0); |
| 423 --m_expansionOpportunityCount; | 395 --m_expansionOpportunityCount; |
| 424 } | 396 } |
| 425 | 397 |
| 426 if (m_expansionOpportunityCount) | 398 if (m_expansionOpportunityCount) |
| 427 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; | 399 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; |
| 428 else | 400 else |
| 429 m_expansionPerOpportunity = 0; | 401 m_expansionPerOpportunity = 0; |
| 430 } | 402 } |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); | 502 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); |
| 531 feature.value = settings->at(i).value(); | 503 feature.value = settings->at(i).value(); |
| 532 feature.start = 0; | 504 feature.start = 0; |
| 533 feature.end = static_cast<unsigned>(-1); | 505 feature.end = static_cast<unsigned>(-1); |
| 534 m_features.append(feature); | 506 m_features.append(feature); |
| 535 } | 507 } |
| 536 } | 508 } |
| 537 | 509 |
| 538 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) | 510 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) |
| 539 { | 511 { |
| 540 if (!createHarfBuzzRuns()) | 512 if (m_run.is8Bit()) |
| 541 return false; | 513 return shapeInternal<LChar>(glyphBuffer); |
| 542 | 514 return shapeInternal<UChar>(glyphBuffer); |
| 543 m_totalWidth = 0; | |
| 544 if (!shapeHarfBuzzRuns()) | |
| 545 return false; | |
| 546 | |
| 547 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer)) | |
| 548 return false; | |
| 549 | |
| 550 return true; | |
| 551 } | 515 } |
| 552 | 516 |
| 553 static inline int handleMultipleUChar( | 517 static inline int handleMultipleUChar( |
| 554 UChar32 character, | 518 UChar32 character, |
| 555 unsigned clusterLength, | 519 unsigned clusterLength, |
| 556 const SimpleFontData* currentFontData, | 520 const SimpleFontData* currentFontData, |
| 557 const UChar* currentCharacterPosition, | 521 const UChar* currentCharacterPosition, |
| 558 const UChar* markCharactersEnd, | 522 const UChar* markCharactersEnd, |
| 559 const UChar* normalizedBufferEnd) | 523 const UChar* strEnd) |
| 560 { | 524 { |
| 561 if (U_GET_GC_MASK(character) & U_GC_M_MASK) { | 525 if (U_GET_GC_MASK(character) & U_GC_M_MASK) { |
| 562 int markLength = clusterLength; | 526 int markLength = clusterLength; |
| 563 while (markCharactersEnd < normalizedBufferEnd) { | 527 while (markCharactersEnd < strEnd) { |
| 564 UChar32 nextCharacter; | 528 UChar32 nextCharacter; |
| 565 int nextCharacterLength = 0; | 529 int nextCharacterLength = 0; |
| 566 U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd
- markCharactersEnd, nextCharacter); | 530 U16_NEXT(markCharactersEnd, nextCharacterLength, strEnd - markCharac
tersEnd, nextCharacter); |
| 567 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) | 531 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) |
| 568 break; | 532 break; |
| 569 markLength += nextCharacterLength; | 533 markLength += nextCharacterLength; |
| 570 markCharactersEnd += nextCharacterLength; | 534 markCharactersEnd += nextCharacterLength; |
| 571 } | 535 } |
| 572 | 536 |
| 573 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacte
rPosition, markCharactersEnd - currentCharacterPosition)) { | 537 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacte
rPosition, markCharactersEnd - currentCharacterPosition)) { |
| 574 return markLength; | 538 return markLength; |
| 575 } | 539 } |
| 576 } | 540 } |
| 577 return 0; | 541 return 0; |
| 578 } | 542 } |
| 579 | 543 |
| 580 struct CandidateRun { | 544 struct CandidateRun { |
| 581 UChar32 character; | 545 UChar32 character; |
| 582 unsigned start; | 546 unsigned start; |
| 583 unsigned end; | 547 unsigned end; |
| 584 const SimpleFontData* fontData; | 548 const SimpleFontData* fontData; |
| 585 UScriptCode script; | 549 UScriptCode script; |
| 586 }; | 550 }; |
| 587 | 551 |
| 588 static inline bool collectCandidateRuns(const UChar* normalizedBuffer, | 552 template<typename CharType> |
| 589 size_t bufferLength, const Font* font, Vector<CandidateRun>* runs, bool isSp
aceNormalize) | 553 bool collectCandidateRuns(const TextRun& textRun, |
| 554 const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize) |
| 590 { | 555 { |
| 591 const UChar* normalizedBufferEnd = normalizedBuffer + bufferLength; | 556 const CharType* str = textRun.characters16(); |
| 592 SurrogatePairAwareTextIterator iterator(normalizedBuffer, 0, bufferLength, b
ufferLength); | 557 const CharType* strEnd = str + textRun.length(); |
| 558 SurrogatePairAwareTextIterator iterator(str, 0, textRun.length(), textRun.le
ngth()); |
| 593 UChar32 character; | 559 UChar32 character; |
| 594 unsigned clusterLength = 0; | 560 unsigned clusterLength = 0; |
| 595 unsigned startIndexOfCurrentRun = 0; | 561 unsigned startIndexOfCurrentRun = 0; |
| 596 | 562 |
| 597 if (!iterator.consume(character, clusterLength)) | 563 if (!iterator.consume(character, clusterLength)) |
| 598 return false; | 564 return false; |
| 599 | 565 |
| 600 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character,
false, isSpaceNormalize).fontData; | 566 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character,
false, isSpaceNormalize).fontData; |
| 601 UErrorCode errorCode = U_ZERO_ERROR; | 567 UErrorCode errorCode = U_ZERO_ERROR; |
| 602 UScriptCode nextScript = uscript_getScript(character, &errorCode); | 568 UScriptCode nextScript = uscript_getScript(character, &errorCode); |
| 603 if (U_FAILURE(errorCode)) | 569 if (U_FAILURE(errorCode)) |
| 604 return false; | 570 return false; |
| 605 | 571 |
| 606 do { | 572 do { |
| 607 const UChar* currentCharacterPosition = iterator.characters(); | 573 const CharType* currentCharacterPosition = iterator.characters(); |
| 608 const SimpleFontData* currentFontData = nextFontData; | 574 const SimpleFontData* currentFontData = nextFontData; |
| 609 UScriptCode currentScript = nextScript; | 575 UScriptCode currentScript = nextScript; |
| 610 | 576 |
| 611 UChar32 lastCharacter = character; | 577 UChar32 lastCharacter = character; |
| 612 for (iterator.advance(clusterLength); iterator.consume(character, cluste
rLength); iterator.advance(clusterLength)) { | 578 for (iterator.advance(clusterLength); iterator.consume(character, cluste
rLength); iterator.advance(clusterLength)) { |
| 613 if (Character::treatAsZeroWidthSpace(character)) | 579 if (Character::treatAsZeroWidthSpace(character)) |
| 614 continue; | 580 continue; |
| 615 | 581 |
| 616 int length = handleMultipleUChar(character, clusterLength, currentFo
ntData, currentCharacterPosition, iterator.characters() + clusterLength, normali
zedBufferEnd); | 582 int length = handleMultipleUChar(character, clusterLength, currentFo
ntData, currentCharacterPosition, iterator.characters() + clusterLength, strEnd)
; |
| 617 if (length) { | 583 if (length) { |
| 618 clusterLength = length; | 584 clusterLength = length; |
| 619 continue; | 585 continue; |
| 620 } | 586 } |
| 621 | 587 |
| 622 nextFontData = font->glyphDataForCharacter(character, false, isSpace
Normalize).fontData; | 588 nextFontData = font->glyphDataForCharacter(character, false, isSpace
Normalize).fontData; |
| 623 nextScript = uscript_getScript(character, &errorCode); | 589 nextScript = uscript_getScript(character, &errorCode); |
| 624 if (U_FAILURE(errorCode)) | 590 if (U_FAILURE(errorCode)) |
| 625 return false; | 591 return false; |
| 626 if (lastCharacter == zeroWidthJoiner) | 592 if (lastCharacter == zeroWidthJoiner) |
| 627 currentFontData = nextFontData; | 593 currentFontData = nextFontData; |
| 628 if ((nextFontData != currentFontData) || ((currentScript != nextScri
pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre
ntScript)))) | 594 if ((nextFontData != currentFontData) || ((currentScript != nextScri
pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre
ntScript)))) |
| 629 break; | 595 break; |
| 630 currentCharacterPosition = iterator.characters(); | 596 currentCharacterPosition = iterator.characters(); |
| 631 lastCharacter = character; | 597 lastCharacter = character; |
| 632 } | 598 } |
| 633 | 599 |
| 634 CandidateRun run = { character, startIndexOfCurrentRun, iterator.current
Character(), currentFontData, currentScript }; | 600 CandidateRun run = { character, startIndexOfCurrentRun, iterator.current
Character(), currentFontData, currentScript }; |
| 635 runs->append(run); | 601 runs->append(run); |
| 636 | 602 |
| 637 startIndexOfCurrentRun = iterator.currentCharacter(); | 603 startIndexOfCurrentRun = iterator.currentCharacter(); |
| 638 } while (iterator.consume(character, clusterLength)); | 604 } while (iterator.consume(character, clusterLength)); |
| 639 | 605 |
| 640 return true; | 606 return true; |
| 641 } | 607 } |
| 642 | 608 |
| 609 template<> |
| 610 bool collectCandidateRuns<LChar>(const TextRun& textRun, |
| 611 const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize) |
| 612 { |
| 613 const LChar* str = textRun.characters8(); |
| 614 UChar32 character = *str; |
| 615 const SimpleFontData* fontData = font->glyphDataForCharacter(character, |
| 616 false, isSpaceNormalize).fontData; |
| 617 |
| 618 // For 8-bit runs we do not need to split based on script or check for |
| 619 // clusters as the entire run is guaranteed to be latin-1. |
| 620 CandidateRun run = { *str, 0, textRun.length(), fontData, USCRIPT_LATIN }; |
| 621 runs->append(run); |
| 622 return true; |
| 623 } |
| 624 |
| 643 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, | 625 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, |
| 644 CandidateRun& adjacentRun) | 626 CandidateRun& adjacentRun) |
| 645 { | 627 { |
| 646 for (int i = 0; i < length; i++) { | 628 for (int i = 0; i < length; i++) { |
| 647 if (scriptExtensions[i] == adjacentRun.script) | 629 if (scriptExtensions[i] == adjacentRun.script) |
| 648 return true; | 630 return true; |
| 649 } | 631 } |
| 650 return false; | 632 return false; |
| 651 } | 633 } |
| 652 | 634 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 | 704 |
| 723 i = std::max(i, nextResolvedRun); | 705 i = std::max(i, nextResolvedRun); |
| 724 } | 706 } |
| 725 return true; | 707 return true; |
| 726 } | 708 } |
| 727 | 709 |
| 728 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact
er length | 710 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact
er length |
| 729 // because most characters have break opportunities both before and after. | 711 // because most characters have break opportunities both before and after. |
| 730 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter() | 712 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter() |
| 731 { | 713 { |
| 732 ASSERT(m_normalizedBufferLength == 1); | 714 ASSERT(m_run.length() == 1); |
| 733 UChar32 character = m_normalizedBuffer[0]; | 715 UChar32 character = m_run[0]; |
| 734 if (!U16_IS_SINGLE(character)) | 716 if (!U16_IS_SINGLE(character)) |
| 735 return false; | 717 return false; |
| 736 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character, fa
lse, m_run.normalizeSpace()).fontData; | 718 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character, |
| 719 false, m_run.normalizeSpace()).fontData; |
| 737 UErrorCode errorCode = U_ZERO_ERROR; | 720 UErrorCode errorCode = U_ZERO_ERROR; |
| 738 UScriptCode script = uscript_getScript(character, &errorCode); | 721 UScriptCode script = uscript_getScript(character, &errorCode); |
| 739 if (U_FAILURE(errorCode)) | 722 if (U_FAILURE(errorCode)) |
| 740 return false; | 723 return false; |
| 741 addHarfBuzzRun(0, 1, fontData, script); | 724 addHarfBuzzRun(0, 1, fontData, script); |
| 742 return true; | 725 return true; |
| 743 } | 726 } |
| 744 | 727 |
| 728 template<typename CharType> |
| 729 bool HarfBuzzShaper::shapeInternal(GlyphBuffer* glyphBuffer) |
| 730 { |
| 731 if (!createHarfBuzzRuns<CharType>()) |
| 732 return false; |
| 733 |
| 734 m_totalWidth = 0; |
| 735 if (!shapeHarfBuzzRuns<CharType>()) |
| 736 return false; |
| 737 |
| 738 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer)) |
| 739 return false; |
| 740 |
| 741 return true; |
| 742 } |
| 743 |
| 744 template<typename CharType> |
| 745 bool HarfBuzzShaper::createHarfBuzzRuns() | 745 bool HarfBuzzShaper::createHarfBuzzRuns() |
| 746 { | 746 { |
| 747 if (m_normalizedBufferLength == 1) | 747 if (m_run.length() == 1) |
| 748 return createHarfBuzzRunsForSingleCharacter(); | 748 return createHarfBuzzRunsForSingleCharacter(); |
| 749 | 749 |
| 750 Vector<CandidateRun> candidateRuns; | 750 Vector<CandidateRun> candidateRuns; |
| 751 if (!collectCandidateRuns(m_normalizedBuffer.get(), | 751 if (!collectCandidateRuns<CharType>(m_run, m_font, &candidateRuns, |
| 752 m_normalizedBufferLength, m_font, &candidateRuns, m_run.normalizeSpace()
)) | 752 m_run.normalizeSpace())) |
| 753 return false; | 753 return false; |
| 754 | 754 |
| 755 if (!resolveCandidateRuns(candidateRuns)) | 755 if (!resolveCandidateRuns(candidateRuns)) |
| 756 return false; | 756 return false; |
| 757 | 757 |
| 758 size_t length = candidateRuns.size(); | 758 size_t length = candidateRuns.size(); |
| 759 for (size_t i = 0; i < length; ) { | 759 for (size_t i = 0; i < length; ) { |
| 760 CandidateRun& run = candidateRuns[i]; | 760 CandidateRun& run = candidateRuns[i]; |
| 761 CandidateRun lastMatchingRun = run; | 761 CandidateRun lastMatchingRun = run; |
| 762 for (i++; i < length; i++) { | 762 for (i++; i < length; i++) { |
| 763 if (candidateRuns[i].script != run.script | 763 if (candidateRuns[i].script != run.script |
| 764 || candidateRuns[i].fontData != run.fontData) | 764 || candidateRuns[i].fontData != run.fontData) |
| 765 break; | 765 break; |
| 766 lastMatchingRun = candidateRuns[i]; | 766 lastMatchingRun = candidateRuns[i]; |
| 767 } | 767 } |
| 768 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script)
; | 768 if (lastMatchingRun.end > run.start) |
| 769 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.scr
ipt); |
| 769 } | 770 } |
| 770 return !m_harfBuzzRuns.isEmpty(); | 771 return !m_harfBuzzRuns.isEmpty(); |
| 771 } | 772 } |
| 772 | 773 |
| 773 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built | 774 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built |
| 774 // without hb-icu. See http://crbug.com/356929 | 775 // without hb-icu. See http://crbug.com/356929 |
| 775 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) | 776 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) |
| 776 { | 777 { |
| 777 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) | 778 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) |
| 778 return HB_SCRIPT_INVALID; | 779 return HB_SCRIPT_INVALID; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 793 ASSERT(endCharacter > startCharacter); | 794 ASSERT(endCharacter > startCharacter); |
| 794 ASSERT(script != USCRIPT_INVALID_CODE); | 795 ASSERT(script != USCRIPT_INVALID_CODE); |
| 795 if (m_fallbackFonts) | 796 if (m_fallbackFonts) |
| 796 trackNonPrimaryFallbackFont(fontData); | 797 trackNonPrimaryFallbackFont(fontData); |
| 797 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, | 798 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, |
| 798 startCharacter, endCharacter - startCharacter, | 799 startCharacter, endCharacter - startCharacter, |
| 799 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription().
orientation(), fontData), | 800 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription().
orientation(), fontData), |
| 800 ICUScriptToHBScript(script))); | 801 ICUScriptToHBScript(script))); |
| 801 } | 802 } |
| 802 | 803 |
| 803 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir, | |
| 804 const String& localeString, const CachedShapingResults* cachedResults) | |
| 805 { | |
| 806 ASSERT(cachedResults); | |
| 807 return cachedResults->dir == dir | |
| 808 && cachedResults->font == *font | |
| 809 && !cachedResults->font.loadingCustomFonts() | |
| 810 && !font->loadingCustomFonts() | |
| 811 && cachedResults->locale == localeString; | |
| 812 } | |
| 813 | |
| 814 static const uint16_t* toUint16(const UChar* src) | 804 static const uint16_t* toUint16(const UChar* src) |
| 815 { | 805 { |
| 816 // FIXME: This relies on undefined behavior however it works on the | 806 // FIXME: This relies on undefined behavior however it works on the |
| 817 // current versions of all compilers we care about and avoids making | 807 // current versions of all compilers we care about and avoids making |
| 818 // a copy of the string. | 808 // a copy of the string. |
| 819 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s
ize as uint16_t"); | 809 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s
ize as uint16_t"); |
| 820 return reinterpret_cast<const uint16_t*>(src); | 810 return reinterpret_cast<const uint16_t*>(src); |
| 821 } | 811 } |
| 822 | 812 |
| 823 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, | 813 template<typename CharType> |
| 824 const FontDescription& fontDescription, const UChar* normalizedBuffer, | 814 inline const CharType* charactersForRun(const TextRun& textRun, |
| 815 unsigned startIndex) |
| 816 { |
| 817 return textRun.data16(startIndex); |
| 818 } |
| 819 |
| 820 template<> |
| 821 inline const LChar* charactersForRun<LChar>(const TextRun& textRun, |
| 822 unsigned startIndex) |
| 823 { |
| 824 return textRun.data8(startIndex); |
| 825 } |
| 826 |
| 827 template<typename CharType> |
| 828 inline const CharType* charactersForString(const String& string) |
| 829 { |
| 830 return string.characters16(); |
| 831 } |
| 832 |
| 833 template<> |
| 834 inline const LChar* charactersForString<LChar>(const String& string) |
| 835 { |
| 836 return string.characters8(); |
| 837 } |
| 838 |
| 839 template<typename CharType> |
| 840 inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, |
| 841 const CharType* characters, unsigned length) |
| 842 { |
| 843 hb_buffer_add_utf16(buffer, toUint16(characters), length, 0, length); |
| 844 } |
| 845 |
| 846 template<> |
| 847 inline void addToHarfBuzzBufferInternal<LChar>(hb_buffer_t* buffer, |
| 848 const LChar* characters, unsigned length) |
| 849 { |
| 850 // On linux we use the system version of harfbuzz so we cannot depend on |
| 851 // hb_buffer_add_latin1 being available as it was only added in 0.9.38. |
| 852 // FIXME: Remove this hack once all supported distros have HB >= 0.9.38. |
| 853 // https://crbug.com/462689 |
| 854 #if OS(LINUX) |
| 855 String converted = String::make16BitFrom8BitSource(characters, length); |
| 856 hb_buffer_add_utf16(buffer, toUint16(converted.characters16()), |
| 857 length, 0, length); |
| 858 #else |
| 859 hb_buffer_add_latin1(buffer, characters, length, 0, length); |
| 860 #endif |
| 861 } |
| 862 |
| 863 template<typename CharType> |
| 864 inline void addToHarfBuzzBuffer(hb_buffer_t* buffer, |
| 865 const FontDescription& fontDescription, const TextRun& textRun, |
| 825 unsigned startIndex, unsigned numCharacters) | 866 unsigned startIndex, unsigned numCharacters) |
| 826 { | 867 { |
| 827 if (fontDescription.variant() == FontVariantSmallCaps | 868 if (fontDescription.variant() == FontVariantSmallCaps |
| 828 && u_islower(normalizedBuffer[startIndex])) { | 869 && u_islower(textRun[startIndex])) { |
| 829 String upperText = String(normalizedBuffer + startIndex, numCharacters) | 870 String upperText = String(charactersForRun<CharType>( |
| 830 .upper(); | 871 textRun, startIndex), numCharacters).upper(); |
| 831 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call | 872 // If TextRun is 16 bit upperText should be 16 bit too. |
| 832 // makeUpper(). | 873 ASSERT(upperText.is8Bit() == textRun.is8Bit()); |
| 833 ASSERT(!upperText.is8Bit()); | 874 addToHarfBuzzBufferInternal<CharType>(buffer, |
| 834 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), | 875 charactersForString<CharType>(upperText), numCharacters); |
| 835 numCharacters, 0, numCharacters); | |
| 836 } else { | 876 } else { |
| 837 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex), | 877 addToHarfBuzzBufferInternal(buffer, |
| 838 numCharacters, 0, numCharacters); | 878 charactersForRun<CharType>(textRun, startIndex), numCharacters); |
| 839 } | 879 } |
| 840 } | 880 } |
| 841 | 881 |
| 882 template<typename CharType, bool normalizeSpace> |
| 883 static inline UChar32 normalizeCharacter(UChar32 character) |
| 884 { |
| 885 if (normalizeSpace && Character::isNormalizedCanvasSpaceCharacter(character)
) |
| 886 return space; |
| 887 if (Character::treatAsSpace(character) && character != characterTabulation) |
| 888 return space; |
| 889 if (Character::treatAsZeroWidthSpaceInComplexScript(static_cast<CharType>(ch
aracter))) |
| 890 return zeroWidthSpace; |
| 891 return character; |
| 892 } |
| 893 |
| 894 template<typename CharType, bool normalizeSpace> |
| 895 inline void normalizeHarfBuzzBuffer(hb_buffer_t* buffer) |
| 896 { |
| 897 unsigned length; |
| 898 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(buffer, &length); |
| 899 for (unsigned i = 0; i < length; i++) { |
| 900 UChar32 character = glyphInfos[i].codepoint; |
| 901 UChar32 normalized = normalizeCharacter<CharType, normalizeSpace>(charac
ter); |
| 902 if (character != normalized) |
| 903 glyphInfos[i].codepoint = normalized; |
| 904 } |
| 905 } |
| 906 |
| 907 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir, |
| 908 const String& localeString, const CachedShapingResults* cachedResults) |
| 909 { |
| 910 ASSERT(cachedResults); |
| 911 return cachedResults->dir == dir |
| 912 && cachedResults->font == *font |
| 913 && !cachedResults->font.loadingCustomFonts() |
| 914 && !font->loadingCustomFonts() |
| 915 && cachedResults->locale == localeString; |
| 916 } |
| 917 |
| 918 template<typename CharType> |
| 842 bool HarfBuzzShaper::shapeHarfBuzzRuns() | 919 bool HarfBuzzShaper::shapeHarfBuzzRuns() |
| 843 { | 920 { |
| 844 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_
destroy); | 921 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_
destroy); |
| 845 | 922 |
| 846 HarfBuzzRunCache& runCache = harfBuzzRunCache(); | 923 HarfBuzzRunCache& runCache = harfBuzzRunCache(); |
| 847 const FontDescription& fontDescription = m_font->fontDescription(); | 924 const FontDescription& fontDescription = m_font->fontDescription(); |
| 848 const String& localeString = fontDescription.locale(); | 925 const String& localeString = fontDescription.locale(); |
| 849 CString locale = localeString.latin1(); | 926 CString locale = localeString.latin1(); |
| 850 HarfBuzzRun* previousRun = nullptr; | 927 HarfBuzzRun* previousRun = nullptr; |
| 851 | 928 |
| 852 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { | 929 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { |
| 853 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; | 930 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; |
| 854 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); | 931 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); |
| 855 | 932 |
| 856 const SimpleFontData* currentFontData = currentRun->fontData(); | 933 const SimpleFontData* currentFontData = currentRun->fontData(); |
| 857 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF
ontData->platformData()); | 934 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF
ontData->platformData()); |
| 858 HarfBuzzFace* face = platformData->harfBuzzFace(); | 935 HarfBuzzFace* face = platformData->harfBuzzFace(); |
| 859 if (!face) | 936 if (!face) |
| 860 return false; | 937 return false; |
| 861 | 938 |
| 862 hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(loc
ale.data(), locale.length())); | 939 hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(loc
ale.data(), locale.length())); |
| 863 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); | 940 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); |
| 864 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction()); | 941 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction()); |
| 865 | 942 |
| 866 const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex(); | 943 const CharType* src = charactersForRun<CharType>(m_run, currentRun->star
tIndex()); |
| 867 std::wstring key(src, src + currentRun->numCharacters()); | 944 std::wstring key(src, src + currentRun->numCharacters()); |
| 868 | 945 |
| 869 CachedShapingResults* cachedResults = runCache.find(key); | 946 CachedShapingResults* cachedResults = runCache.find(key); |
| 870 if (cachedResults) { | 947 if (cachedResults) { |
| 871 if (isValidCachedResult(m_font, currentRun->direction(), | 948 if (isValidCachedResult(m_font, currentRun->direction(), |
| 872 localeString, cachedResults)) { | 949 localeString, cachedResults)) { |
| 873 currentRun->applyShapeResult(cachedResults->buffer); | 950 currentRun->applyShapeResult(cachedResults->buffer); |
| 874 setGlyphPositionsForHarfBuzzRun(currentRun, | 951 setGlyphPositionsForHarfBuzzRun(currentRun, |
| 875 cachedResults->buffer, previousRun); | 952 cachedResults->buffer, previousRun); |
| 876 hb_buffer_clear_contents(harfBuzzBuffer.get()); | 953 hb_buffer_clear_contents(harfBuzzBuffer.get()); |
| 877 runCache.moveToBack(cachedResults); | 954 runCache.moveToBack(cachedResults); |
| 878 previousRun = currentRun; | 955 previousRun = currentRun; |
| 879 continue; | 956 continue; |
| 880 } | 957 } |
| 881 runCache.remove(cachedResults); | 958 runCache.remove(cachedResults); |
| 882 } | 959 } |
| 883 | 960 |
| 884 // Add a space as pre-context to the buffer. This prevents showing dotte
d-circle | 961 // Add a space as pre-context to the buffer. This prevents showing dotte
d-circle |
| 885 // for combining marks at the beginning of runs. | 962 // for combining marks at the beginning of runs. |
| 886 static const uint16_t preContext = space; | 963 static const uint16_t preContext = space; |
| 887 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); | 964 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); |
| 888 | 965 |
| 889 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), | 966 addToHarfBuzzBuffer<CharType>(harfBuzzBuffer.get(), |
| 890 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(), | 967 fontDescription, m_run, currentRun->startIndex(), |
| 891 currentRun->numCharacters()); | 968 currentRun->numCharacters()); |
| 892 | 969 |
| 970 if (m_run.normalizeSpace()) |
| 971 normalizeHarfBuzzBuffer<CharType, true>(harfBuzzBuffer.get()); |
| 972 else |
| 973 normalizeHarfBuzzBuffer<CharType, false>(harfBuzzBuffer.get()); |
| 974 |
| 893 if (fontDescription.orientation() == Vertical) | 975 if (fontDescription.orientation() == Vertical) |
| 894 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); | 976 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); |
| 895 | 977 |
| 896 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de
stroy); | 978 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de
stroy); |
| 897 | 979 |
| 898 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty()
? 0 : m_features.data(), m_features.size()); | 980 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty()
? 0 : m_features.data(), m_features.size()); |
| 899 currentRun->applyShapeResult(harfBuzzBuffer.get()); | 981 currentRun->applyShapeResult(harfBuzzBuffer.get()); |
| 900 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get(), previo
usRun); | 982 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get(), previo
usRun); |
| 901 | 983 |
| 902 runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_fo
nt, currentRun->direction(), localeString)); | 984 runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_fo
nt, currentRun->direction(), localeString)); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 // HarfBuzz returns the shaping result in visual order. We need not to flip
for RTL. | 1016 // HarfBuzz returns the shaping result in visual order. We need not to flip
for RTL. |
| 935 for (size_t i = 0; i < numGlyphs; ++i) { | 1017 for (size_t i = 0; i < numGlyphs; ++i) { |
| 936 bool runEnd = i + 1 == numGlyphs; | 1018 bool runEnd = i + 1 == numGlyphs; |
| 937 uint16_t glyph = glyphInfos[i].codepoint; | 1019 uint16_t glyph = glyphInfos[i].codepoint; |
| 938 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); | 1020 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); |
| 939 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); | 1021 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); |
| 940 // One out of x_advance and y_advance is zero, depending on | 1022 // One out of x_advance and y_advance is zero, depending on |
| 941 // whether the buffer direction is horizontal or vertical. | 1023 // whether the buffer direction is horizontal or vertical. |
| 942 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl
yphPositions[i].y_advance); | 1024 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl
yphPositions[i].y_advance); |
| 943 | 1025 |
| 944 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i
].cluster; | 1026 int currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].clu
ster; |
| 945 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); | 1027 RELEASE_ASSERT(m_run.length() > currentCharacterIndex); |
| 946 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1]
.cluster; | 1028 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1]
.cluster; |
| 947 float spacing = 0; | 1029 float spacing = 0; |
| 948 | 1030 |
| 949 glyphToCharacterIndexes[i] = glyphInfos[i].cluster; | 1031 glyphToCharacterIndexes[i] = glyphInfos[i].cluster; |
| 950 | 1032 |
| 951 if (isClusterEnd) | 1033 if (isClusterEnd) |
| 952 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, previ
ousRun, offsetX, totalAdvance); | 1034 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, previ
ousRun, offsetX, totalAdvance); |
| 953 | 1035 |
| 954 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { | 1036 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { |
| 955 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); | 1037 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 975 | 1057 |
| 976 totalAdvance += advance; | 1058 totalAdvance += advance; |
| 977 } | 1059 } |
| 978 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); | 1060 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); |
| 979 m_totalWidth += currentRun->width(); | 1061 m_totalWidth += currentRun->width(); |
| 980 } | 1062 } |
| 981 | 1063 |
| 982 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex,
unsigned currentCharacterIndex, HarfBuzzRun* previousRun, float& offsetX, float&
totalAdvance) | 1064 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex,
unsigned currentCharacterIndex, HarfBuzzRun* previousRun, float& offsetX, float&
totalAdvance) |
| 983 { | 1065 { |
| 984 float spacing = 0; | 1066 float spacing = 0; |
| 985 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; | 1067 UChar32 character = normalizeCharacter<UChar, false>(m_run[currentCharacterI
ndex]); |
| 986 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) | 1068 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) |
| 987 spacing += m_letterSpacing; | 1069 spacing += m_letterSpacing; |
| 988 | 1070 |
| 989 bool treatAsSpace = Character::treatAsSpace(character); | 1071 bool treatAsSpace = Character::treatAsSpace(character); |
| 990 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al
lowTabs())) | 1072 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al
lowTabs())) |
| 991 spacing += m_wordSpacingAdjustment; | 1073 spacing += m_wordSpacingAdjustment; |
| 992 | 1074 |
| 993 if (!m_expansionOpportunityCount) | 1075 if (!m_expansionOpportunityCount) |
| 994 return spacing; | 1076 return spacing; |
| 995 | 1077 |
| 996 if (treatAsSpace) { | 1078 if (treatAsSpace) { |
| 997 spacing += nextExpansionPerOpportunity(); | 1079 spacing += nextExpansionPerOpportunity(); |
| 998 m_isAfterExpansion = true; | 1080 m_isAfterExpansion = true; |
| 999 return spacing; | 1081 return spacing; |
| 1000 } | 1082 } |
| 1001 | 1083 |
| 1002 if (m_run.textJustify() != TextJustify::TextJustifyAuto) { | 1084 if (m_run.textJustify() != TextJustify::TextJustifyAuto) { |
| 1003 m_isAfterExpansion = false; | 1085 m_isAfterExpansion = false; |
| 1004 return spacing; | 1086 return spacing; |
| 1005 } | 1087 } |
| 1006 | 1088 |
| 1007 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte
r each character. | 1089 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte
r each character. |
| 1008 // http://www.w3.org/TR/jlreq/#line_adjustment | 1090 // http://www.w3.org/TR/jlreq/#line_adjustment |
| 1009 if (U16_IS_LEAD(character) && currentCharacterIndex + 1 < m_normalizedBuffer
Length && U16_IS_TRAIL(m_normalizedBuffer[currentCharacterIndex + 1])) | 1091 if (!m_run.is8Bit() && U16_IS_LEAD(character) && currentCharacterIndex + 1 <
static_cast<unsigned>(m_run.charactersLength()) && U16_IS_TRAIL(m_run[currentCh
aracterIndex + 1])) { |
| 1010 character = U16_GET_SUPPLEMENTARY(character, m_normalizedBuffer[currentC
haracterIndex + 1]); | 1092 UChar32 nextChar = normalizeCharacter<UChar, false>(m_run[currentCharact
erIndex + 1]); |
| 1093 character = U16_GET_SUPPLEMENTARY(character, nextChar); |
| 1094 } |
| 1011 if (!Character::isCJKIdeographOrSymbol(character)) { | 1095 if (!Character::isCJKIdeographOrSymbol(character)) { |
| 1012 m_isAfterExpansion = false; | 1096 m_isAfterExpansion = false; |
| 1013 return spacing; | 1097 return spacing; |
| 1014 } | 1098 } |
| 1015 | 1099 |
| 1016 if (!m_isAfterExpansion) { | 1100 if (!m_isAfterExpansion) { |
| 1017 // Take the expansion opportunity before this ideograph. | 1101 // Take the expansion opportunity before this ideograph. |
| 1018 float expandBefore = nextExpansionPerOpportunity(); | 1102 float expandBefore = nextExpansionPerOpportunity(); |
| 1019 if (expandBefore) { | 1103 if (expandBefore) { |
| 1020 if (glyphIndex > 0) { | 1104 if (glyphIndex > 0) { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 | 1200 |
| 1117 clusterAdvance += advances[i]; | 1201 clusterAdvance += advances[i]; |
| 1118 | 1202 |
| 1119 if (isClusterEnd) { | 1203 if (isClusterEnd) { |
| 1120 uint16_t clusterEnd; | 1204 uint16_t clusterEnd; |
| 1121 if (m_run.rtl()) | 1205 if (m_run.rtl()) |
| 1122 clusterEnd = currentCharacterIndex; | 1206 clusterEnd = currentCharacterIndex; |
| 1123 else | 1207 else |
| 1124 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n
umCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1]; | 1208 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n
umCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1]; |
| 1125 | 1209 |
| 1126 graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get(
), m_normalizedBufferLength, clusterStart, clusterEnd); | 1210 graphemesInCluster = m_run.is8Bit() ? 1 : countGraphemesInCluster(m_
run.characters16(), m_run.length(), clusterStart, clusterEnd); |
| 1127 if (!graphemesInCluster || !clusterAdvance) | 1211 if (!graphemesInCluster || !clusterAdvance) |
| 1128 continue; | 1212 continue; |
| 1129 | 1213 |
| 1130 float glyphAdvanceX = clusterAdvance / graphemesInCluster; | 1214 float glyphAdvanceX = clusterAdvance / graphemesInCluster; |
| 1131 for (unsigned j = 0; j < graphemesInCluster; ++j) { | 1215 for (unsigned j = 0; j < graphemesInCluster; ++j) { |
| 1132 // Do not put emphasis marks on space, separator, and control ch
aracters. | 1216 // Do not put emphasis marks on space, separator, and control ch
aracters. |
| 1133 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[curre
ntCharacterIndex]) ? 1 : 0; | 1217 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[curre
ntCharacterIndex]) ? 1 : 0; |
| 1134 // The emphasis code expects mid-glyph offsets. | 1218 // The emphasis code expects mid-glyph offsets. |
| 1135 glyphBuffer->add(glyphToAdd, currentRun->fontData(), advanceSoFa
r + glyphAdvanceX / 2); | 1219 glyphBuffer->add(glyphToAdd, currentRun->fontData(), advanceSoFa
r + glyphAdvanceX / 2); |
| 1136 advanceSoFar += glyphAdvanceX; | 1220 advanceSoFar += glyphAdvanceX; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1160 } | 1244 } |
| 1161 return glyphBuffer->size(); | 1245 return glyphBuffer->size(); |
| 1162 } | 1246 } |
| 1163 | 1247 |
| 1164 int HarfBuzzShaper::offsetForPosition(float targetX) | 1248 int HarfBuzzShaper::offsetForPosition(float targetX) |
| 1165 { | 1249 { |
| 1166 int charactersSoFar = 0; | 1250 int charactersSoFar = 0; |
| 1167 float currentX = 0; | 1251 float currentX = 0; |
| 1168 | 1252 |
| 1169 if (m_run.rtl()) { | 1253 if (m_run.rtl()) { |
| 1170 charactersSoFar = m_normalizedBufferLength; | 1254 charactersSoFar = m_run.length(); |
| 1171 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { | 1255 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { |
| 1172 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); | 1256 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); |
| 1173 float nextX = currentX + m_harfBuzzRuns[i]->width(); | 1257 float nextX = currentX + m_harfBuzzRuns[i]->width(); |
| 1174 float offsetForRun = targetX - currentX; | 1258 float offsetForRun = targetX - currentX; |
| 1175 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width())
{ | 1259 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width())
{ |
| 1176 // The x value in question is within this script run. | 1260 // The x value in question is within this script run. |
| 1177 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi
tion(offsetForRun); | 1261 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi
tion(offsetForRun); |
| 1178 return charactersSoFar + index; | 1262 return charactersSoFar + index; |
| 1179 } | 1263 } |
| 1180 currentX = nextX; | 1264 currentX = nextX; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1238 // possibly invalid from, to arguments. | 1322 // possibly invalid from, to arguments. |
| 1239 if (!foundToX && !foundFromX) | 1323 if (!foundToX && !foundFromX) |
| 1240 fromX = toX = 0; | 1324 fromX = toX = 0; |
| 1241 | 1325 |
| 1242 if (fromX < toX) | 1326 if (fromX < toX) |
| 1243 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); | 1327 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); |
| 1244 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); | 1328 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); |
| 1245 } | 1329 } |
| 1246 | 1330 |
| 1247 } // namespace blink | 1331 } // namespace blink |
| OLD | NEW |