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