| 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 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 } | 371 } |
| 372 | 372 |
| 373 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, const Glyph
Data* emphasisData, | 373 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, const Glyph
Data* emphasisData, |
| 374 HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* bounds) | 374 HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* bounds) |
| 375 : Shaper(font, run, emphasisData, fallbackFonts, bounds) | 375 : Shaper(font, run, emphasisData, fallbackFonts, bounds) |
| 376 , m_normalizedBufferLength(0) | 376 , m_normalizedBufferLength(0) |
| 377 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) | 377 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) |
| 378 , m_letterSpacing(font->fontDescription().letterSpacing()) | 378 , m_letterSpacing(font->fontDescription().letterSpacing()) |
| 379 , m_expansionOpportunityCount(0) | 379 , m_expansionOpportunityCount(0) |
| 380 , m_fromIndex(0) | 380 , m_fromIndex(0) |
| 381 , m_toIndex(m_run.length()) | 381 , m_toIndex(m_textRun.length()) |
| 382 , m_totalWidth(0) | 382 , m_totalWidth(0) |
| 383 { | 383 { |
| 384 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]); | 384 m_normalizedBuffer = adoptArrayPtr(new UChar[m_textRun.length() + 1]); |
| 385 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm
alizedBufferLength); | 385 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(),
&m_normalizedBufferLength); |
| 386 setExpansion(m_run.expansion()); | 386 setExpansion(m_textRun.expansion()); |
| 387 setFontFeatures(); | 387 setFontFeatures(); |
| 388 } | 388 } |
| 389 | 389 |
| 390 float HarfBuzzShaper::nextExpansionPerOpportunity() | 390 float HarfBuzzShaper::nextExpansionPerOpportunity() |
| 391 { | 391 { |
| 392 if (!m_expansionOpportunityCount) { | 392 if (!m_expansionOpportunityCount) { |
| 393 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha
per does not match to the one in expansionOpportunityCount() | 393 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha
per does not match to the one in expansionOpportunityCount() |
| 394 return 0; | 394 return 0; |
| 395 } | 395 } |
| 396 if (!--m_expansionOpportunityCount) { | 396 if (!--m_expansionOpportunityCount) { |
| 397 float remaining = m_expansion; | 397 float remaining = m_expansion; |
| 398 m_expansion = 0; | 398 m_expansion = 0; |
| 399 return remaining; | 399 return remaining; |
| 400 } | 400 } |
| 401 m_expansion -= m_expansionPerOpportunity; | 401 m_expansion -= m_expansionPerOpportunity; |
| 402 return m_expansionPerOpportunity; | 402 return m_expansionPerOpportunity; |
| 403 } | 403 } |
| 404 | 404 |
| 405 // setPadding sets a number of pixels to be distributed across the TextRun. | 405 // setPadding sets a number of pixels to be distributed across the TextRun. |
| 406 // WebKit uses this to justify text. | 406 // WebKit uses this to justify text. |
| 407 void HarfBuzzShaper::setExpansion(float padding) | 407 void HarfBuzzShaper::setExpansion(float padding) |
| 408 { | 408 { |
| 409 m_expansion = padding; | 409 m_expansion = padding; |
| 410 if (!m_expansion) | 410 if (!m_expansion) |
| 411 return; | 411 return; |
| 412 | 412 |
| 413 // If we have padding to distribute, then we try to give an equal | 413 // If we have padding to distribute, then we try to give an equal |
| 414 // amount to each expansion opportunity. | 414 // amount to each expansion opportunity. |
| 415 bool isAfterExpansion = m_isAfterExpansion; | 415 bool isAfterExpansion = m_isAfterExpansion; |
| 416 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_normali
zedBuffer.get(), m_normalizedBufferLength, m_run.direction(), isAfterExpansion,
m_run.textJustify()); | 416 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_normali
zedBuffer.get(), m_normalizedBufferLength, m_textRun.direction(), isAfterExpansi
on, m_textRun.textJustify()); |
| 417 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) { | 417 if (isAfterExpansion && !m_textRun.allowsTrailingExpansion()) { |
| 418 ASSERT(m_expansionOpportunityCount > 0); | 418 ASSERT(m_expansionOpportunityCount > 0); |
| 419 --m_expansionOpportunityCount; | 419 --m_expansionOpportunityCount; |
| 420 } | 420 } |
| 421 | 421 |
| 422 if (m_expansionOpportunityCount) | 422 if (m_expansionOpportunityCount) |
| 423 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; | 423 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; |
| 424 else | 424 else |
| 425 m_expansionPerOpportunity = 0; | 425 m_expansionPerOpportunity = 0; |
| 426 } | 426 } |
| 427 | 427 |
| 428 | 428 |
| 429 void HarfBuzzShaper::setDrawRange(int from, int to) | 429 void HarfBuzzShaper::setDrawRange(int from, int to) |
| 430 { | 430 { |
| 431 ASSERT_WITH_SECURITY_IMPLICATION(from >= 0); | 431 ASSERT_WITH_SECURITY_IMPLICATION(from >= 0); |
| 432 ASSERT_WITH_SECURITY_IMPLICATION(to <= m_run.length()); | 432 ASSERT_WITH_SECURITY_IMPLICATION(to <= m_textRun.length()); |
| 433 m_fromIndex = from; | 433 m_fromIndex = from; |
| 434 m_toIndex = to; | 434 m_toIndex = to; |
| 435 } | 435 } |
| 436 | 436 |
| 437 void HarfBuzzShaper::setFontFeatures() | 437 void HarfBuzzShaper::setFontFeatures() |
| 438 { | 438 { |
| 439 const FontDescription& description = m_font->fontDescription(); | 439 const FontDescription& description = m_font->fontDescription(); |
| 440 | 440 |
| 441 static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast
<unsigned>(-1) }; | 441 static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast
<unsigned>(-1) }; |
| 442 static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast
<unsigned>(-1) }; | 442 static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast
<unsigned>(-1) }; |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 } | 692 } |
| 693 | 693 |
| 694 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact
er length | 694 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact
er length |
| 695 // because most characters have break opportunities both before and after. | 695 // because most characters have break opportunities both before and after. |
| 696 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter() | 696 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter() |
| 697 { | 697 { |
| 698 ASSERT(m_normalizedBufferLength == 1); | 698 ASSERT(m_normalizedBufferLength == 1); |
| 699 UChar32 character = m_normalizedBuffer[0]; | 699 UChar32 character = m_normalizedBuffer[0]; |
| 700 if (!U16_IS_SINGLE(character)) | 700 if (!U16_IS_SINGLE(character)) |
| 701 return false; | 701 return false; |
| 702 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character, fa
lse, m_run.normalizeSpace()).fontData; | 702 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character, fa
lse, m_textRun.normalizeSpace()).fontData; |
| 703 UErrorCode errorCode = U_ZERO_ERROR; | 703 UErrorCode errorCode = U_ZERO_ERROR; |
| 704 UScriptCode script = uscript_getScript(character, &errorCode); | 704 UScriptCode script = uscript_getScript(character, &errorCode); |
| 705 if (U_FAILURE(errorCode)) | 705 if (U_FAILURE(errorCode)) |
| 706 return false; | 706 return false; |
| 707 addHarfBuzzRun(0, 1, fontData, script); | 707 addHarfBuzzRun(0, 1, fontData, script); |
| 708 return true; | 708 return true; |
| 709 } | 709 } |
| 710 | 710 |
| 711 bool HarfBuzzShaper::createHarfBuzzRuns() | 711 bool HarfBuzzShaper::createHarfBuzzRuns() |
| 712 { | 712 { |
| 713 if (m_normalizedBufferLength == 1) | 713 if (m_normalizedBufferLength == 1) |
| 714 return createHarfBuzzRunsForSingleCharacter(); | 714 return createHarfBuzzRunsForSingleCharacter(); |
| 715 | 715 |
| 716 Vector<CandidateRun> candidateRuns; | 716 Vector<CandidateRun> candidateRuns; |
| 717 if (!collectCandidateRuns(m_normalizedBuffer.get(), | 717 if (!collectCandidateRuns(m_normalizedBuffer.get(), |
| 718 m_normalizedBufferLength, m_font, &candidateRuns, m_run.normalizeSpace()
)) | 718 m_normalizedBufferLength, m_font, &candidateRuns, m_textRun.normalizeSpa
ce())) |
| 719 return false; | 719 return false; |
| 720 | 720 |
| 721 if (!resolveCandidateRuns(candidateRuns)) | 721 if (!resolveCandidateRuns(candidateRuns)) |
| 722 return false; | 722 return false; |
| 723 | 723 |
| 724 size_t length = candidateRuns.size(); | 724 size_t length = candidateRuns.size(); |
| 725 for (size_t i = 0; i < length; ) { | 725 for (size_t i = 0; i < length; ) { |
| 726 CandidateRun& run = candidateRuns[i]; | 726 CandidateRun& run = candidateRuns[i]; |
| 727 CandidateRun lastMatchingRun = run; | 727 CandidateRun lastMatchingRun = run; |
| 728 for (i++; i < length; i++) { | 728 for (i++; i < length; i++) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 755 void HarfBuzzShaper::addHarfBuzzRun(unsigned startCharacter, | 755 void HarfBuzzShaper::addHarfBuzzRun(unsigned startCharacter, |
| 756 unsigned endCharacter, const SimpleFontData* fontData, | 756 unsigned endCharacter, const SimpleFontData* fontData, |
| 757 UScriptCode script) | 757 UScriptCode script) |
| 758 { | 758 { |
| 759 ASSERT(endCharacter > startCharacter); | 759 ASSERT(endCharacter > startCharacter); |
| 760 ASSERT(script != USCRIPT_INVALID_CODE); | 760 ASSERT(script != USCRIPT_INVALID_CODE); |
| 761 if (m_fallbackFonts) | 761 if (m_fallbackFonts) |
| 762 trackNonPrimaryFallbackFont(fontData); | 762 trackNonPrimaryFallbackFont(fontData); |
| 763 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, | 763 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, |
| 764 startCharacter, endCharacter - startCharacter, | 764 startCharacter, endCharacter - startCharacter, |
| 765 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription().
orientation(), fontData), | 765 TextDirectionToHBDirection(m_textRun.direction(), m_font->fontDescriptio
n().orientation(), fontData), |
| 766 ICUScriptToHBScript(script))); | 766 ICUScriptToHBScript(script))); |
| 767 } | 767 } |
| 768 | 768 |
| 769 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir, | 769 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir, |
| 770 const String& localeString, const CachedShapingResults* cachedResults) | 770 const String& localeString, const CachedShapingResults* cachedResults) |
| 771 { | 771 { |
| 772 ASSERT(cachedResults); | 772 ASSERT(cachedResults); |
| 773 return cachedResults->dir == dir | 773 return cachedResults->dir == dir |
| 774 && cachedResults->font == *font | 774 && cachedResults->font == *font |
| 775 && !cachedResults->font.loadingCustomFonts() | 775 && !cachedResults->font.loadingCustomFonts() |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 { | 809 { |
| 810 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_
destroy); | 810 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_
destroy); |
| 811 | 811 |
| 812 HarfBuzzRunCache& runCache = harfBuzzRunCache(); | 812 HarfBuzzRunCache& runCache = harfBuzzRunCache(); |
| 813 const FontDescription& fontDescription = m_font->fontDescription(); | 813 const FontDescription& fontDescription = m_font->fontDescription(); |
| 814 const String& localeString = fontDescription.locale(); | 814 const String& localeString = fontDescription.locale(); |
| 815 CString locale = localeString.latin1(); | 815 CString locale = localeString.latin1(); |
| 816 const hb_language_t language = hb_language_from_string(locale.data(), locale
.length()); | 816 const hb_language_t language = hb_language_from_string(locale.data(), locale
.length()); |
| 817 | 817 |
| 818 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { | 818 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { |
| 819 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; | 819 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; |
| 820 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); | 820 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); |
| 821 | 821 |
| 822 const SimpleFontData* currentFontData = currentRun->fontData(); | 822 const SimpleFontData* currentFontData = currentRun->fontData(); |
| 823 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF
ontData->platformData()); | 823 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF
ontData->platformData()); |
| 824 HarfBuzzFace* face = platformData->harfBuzzFace(); | 824 HarfBuzzFace* face = platformData->harfBuzzFace(); |
| 825 if (!face) | 825 if (!face) |
| 826 return false; | 826 return false; |
| 827 | 827 |
| 828 hb_buffer_set_language(harfBuzzBuffer.get(), language); | 828 hb_buffer_set_language(harfBuzzBuffer.get(), language); |
| 829 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); | 829 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 | 914 |
| 915 if (isClusterEnd) | 915 if (isClusterEnd) |
| 916 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, *dire
ctionOffset, totalAdvance); | 916 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, *dire
ctionOffset, totalAdvance); |
| 917 | 917 |
| 918 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { | 918 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { |
| 919 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); | 919 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); |
| 920 continue; | 920 continue; |
| 921 } | 921 } |
| 922 | 922 |
| 923 advance += spacing; | 923 advance += spacing; |
| 924 if (m_run.rtl()) { | 924 if (m_textRun.rtl()) { |
| 925 // In RTL, spacing should be added to left side of glyphs. | 925 // In RTL, spacing should be added to left side of glyphs. |
| 926 *directionOffset += spacing; | 926 *directionOffset += spacing; |
| 927 if (!isClusterEnd) | 927 if (!isClusterEnd) |
| 928 *directionOffset += m_letterSpacing; | 928 *directionOffset += m_letterSpacing; |
| 929 } | 929 } |
| 930 | 930 |
| 931 currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); | 931 currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); |
| 932 | 932 |
| 933 if (m_glyphBoundingBox) { | 933 if (m_glyphBoundingBox) { |
| 934 FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); | 934 FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); |
| 935 glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); | 935 glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); |
| 936 m_glyphBoundingBox->unite(glyphBounds); | 936 m_glyphBoundingBox->unite(glyphBounds); |
| 937 glyphOrigin += FloatSize(advance + offsetX, offsetY); | 937 glyphOrigin += FloatSize(advance + offsetX, offsetY); |
| 938 } | 938 } |
| 939 | 939 |
| 940 totalAdvance += advance; | 940 totalAdvance += advance; |
| 941 } | 941 } |
| 942 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); | 942 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); |
| 943 m_totalWidth += currentRun->width(); | 943 m_totalWidth += currentRun->width(); |
| 944 } | 944 } |
| 945 | 945 |
| 946 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex,
unsigned currentCharacterIndex, float& offset, float& totalAdvance) | 946 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex,
unsigned currentCharacterIndex, float& offset, float& totalAdvance) |
| 947 { | 947 { |
| 948 float spacing = 0; | 948 float spacing = 0; |
| 949 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; | 949 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; |
| 950 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) | 950 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) |
| 951 spacing += m_letterSpacing; | 951 spacing += m_letterSpacing; |
| 952 | 952 |
| 953 bool treatAsSpace = Character::treatAsSpace(character); | 953 bool treatAsSpace = Character::treatAsSpace(character); |
| 954 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al
lowTabs())) | 954 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu
n.allowTabs())) |
| 955 spacing += m_wordSpacingAdjustment; | 955 spacing += m_wordSpacingAdjustment; |
| 956 | 956 |
| 957 if (!m_expansionOpportunityCount) | 957 if (!m_expansionOpportunityCount) |
| 958 return spacing; | 958 return spacing; |
| 959 | 959 |
| 960 if (treatAsSpace) { | 960 if (treatAsSpace) { |
| 961 spacing += nextExpansionPerOpportunity(); | 961 spacing += nextExpansionPerOpportunity(); |
| 962 m_isAfterExpansion = true; | 962 m_isAfterExpansion = true; |
| 963 return spacing; | 963 return spacing; |
| 964 } | 964 } |
| 965 | 965 |
| 966 if (m_run.textJustify() != TextJustify::TextJustifyAuto) { | 966 if (m_textRun.textJustify() != TextJustify::TextJustifyAuto) { |
| 967 m_isAfterExpansion = false; | 967 m_isAfterExpansion = false; |
| 968 return spacing; | 968 return spacing; |
| 969 } | 969 } |
| 970 | 970 |
| 971 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte
r each character. | 971 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte
r each character. |
| 972 // http://www.w3.org/TR/jlreq/#line_adjustment | 972 // http://www.w3.org/TR/jlreq/#line_adjustment |
| 973 if (U16_IS_LEAD(character) && currentCharacterIndex + 1 < m_normalizedBuffer
Length && U16_IS_TRAIL(m_normalizedBuffer[currentCharacterIndex + 1])) | 973 if (U16_IS_LEAD(character) && currentCharacterIndex + 1 < m_normalizedBuffer
Length && U16_IS_TRAIL(m_normalizedBuffer[currentCharacterIndex + 1])) |
| 974 character = U16_GET_SUPPLEMENTARY(character, m_normalizedBuffer[currentC
haracterIndex + 1]); | 974 character = U16_GET_SUPPLEMENTARY(character, m_normalizedBuffer[currentC
haracterIndex + 1]); |
| 975 if (!Character::isCJKIdeographOrSymbol(character)) { | 975 if (!Character::isCJKIdeographOrSymbol(character)) { |
| 976 m_isAfterExpansion = false; | 976 m_isAfterExpansion = false; |
| 977 return spacing; | 977 return spacing; |
| 978 } | 978 } |
| 979 | 979 |
| 980 if (!m_isAfterExpansion) { | 980 if (!m_isAfterExpansion) { |
| 981 // Take the expansion opportunity before this ideograph. | 981 // Take the expansion opportunity before this ideograph. |
| 982 float expandBefore = nextExpansionPerOpportunity(); | 982 float expandBefore = nextExpansionPerOpportunity(); |
| 983 if (expandBefore) { | 983 if (expandBefore) { |
| 984 if (glyphIndex > 0) { | 984 if (glyphIndex > 0) { |
| 985 currentRun->addAdvance(glyphIndex - 1, expandBefore); | 985 currentRun->addAdvance(glyphIndex - 1, expandBefore); |
| 986 totalAdvance += expandBefore; | 986 totalAdvance += expandBefore; |
| 987 } else { | 987 } else { |
| 988 offset += expandBefore; | 988 offset += expandBefore; |
| 989 spacing += expandBefore; | 989 spacing += expandBefore; |
| 990 } | 990 } |
| 991 } | 991 } |
| 992 if (!m_expansionOpportunityCount) | 992 if (!m_expansionOpportunityCount) |
| 993 return spacing; | 993 return spacing; |
| 994 } | 994 } |
| 995 | 995 |
| 996 // Don't need to check m_run.allowsTrailingExpansion() since it's covered by
!m_expansionOpportunityCount above | 996 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere
d by !m_expansionOpportunityCount above |
| 997 spacing += nextExpansionPerOpportunity(); | 997 spacing += nextExpansionPerOpportunity(); |
| 998 m_isAfterExpansion = true; | 998 m_isAfterExpansion = true; |
| 999 return spacing; | 999 return spacing; |
| 1000 } | 1000 } |
| 1001 | 1001 |
| 1002 float HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, | 1002 float HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, |
| 1003 HarfBuzzRun* currentRun, float initialAdvance) | 1003 HarfBuzzRun* currentRun, float initialAdvance) |
| 1004 { | 1004 { |
| 1005 unsigned numGlyphs = currentRun->numGlyphs(); | 1005 unsigned numGlyphs = currentRun->numGlyphs(); |
| 1006 float advanceSoFar = initialAdvance; | 1006 float advanceSoFar = initialAdvance; |
| 1007 if (m_run.rtl()) { | 1007 if (m_textRun.rtl()) { |
| 1008 for (unsigned i = 0; i < numGlyphs; ++i) { | 1008 for (unsigned i = 0; i < numGlyphs; ++i) { |
| 1009 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i); | 1009 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i); |
| 1010 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphDat
a.characterIndex; | 1010 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphDat
a.characterIndex; |
| 1011 if (currentCharacterIndex >= m_toIndex) { | 1011 if (currentCharacterIndex >= m_toIndex) { |
| 1012 advanceSoFar += glyphData.advance; | 1012 advanceSoFar += glyphData.advance; |
| 1013 } else if (currentCharacterIndex >= m_fromIndex) { | 1013 } else if (currentCharacterIndex >= m_fromIndex) { |
| 1014 FloatPoint runStartOffset = HB_DIRECTION_IS_HORIZONTAL(currentRu
n->direction()) ? | 1014 FloatPoint runStartOffset = HB_DIRECTION_IS_HORIZONTAL(currentRu
n->direction()) ? |
| 1015 FloatPoint(advanceSoFar, 0) : FloatPoint(0, advanceSoFar); | 1015 FloatPoint(advanceSoFar, 0) : FloatPoint(0, advanceSoFar); |
| 1016 glyphBuffer->add(glyphData.glyph, currentRun->fontData(), runSta
rtOffset + glyphData.offset); | 1016 glyphBuffer->add(glyphData.glyph, currentRun->fontData(), runSta
rtOffset + glyphData.offset); |
| 1017 advanceSoFar += glyphData.advance; | 1017 advanceSoFar += glyphData.advance; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1043 uint16_t clusterStart; | 1043 uint16_t clusterStart; |
| 1044 | 1044 |
| 1045 // A "cluster" in this context means a cluster as it is used by HarfBuzz: | 1045 // A "cluster" in this context means a cluster as it is used by HarfBuzz: |
| 1046 // The minimal group of characters and corresponding glyphs, that cannot be
broken | 1046 // The minimal group of characters and corresponding glyphs, that cannot be
broken |
| 1047 // down further from a text shaping point of view. | 1047 // down further from a text shaping point of view. |
| 1048 // A cluster can contain multiple glyphs and grapheme clusters, with mutuall
y | 1048 // A cluster can contain multiple glyphs and grapheme clusters, with mutuall
y |
| 1049 // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clu
sters, | 1049 // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clu
sters, |
| 1050 // then linearly split the sum of corresponding glyph advances by the number
of | 1050 // then linearly split the sum of corresponding glyph advances by the number
of |
| 1051 // grapheme clusters in order to find positions for emphasis mark drawing. | 1051 // grapheme clusters in order to find positions for emphasis mark drawing. |
| 1052 | 1052 |
| 1053 if (m_run.rtl()) | 1053 if (m_textRun.rtl()) |
| 1054 clusterStart = currentRun->startIndex() + currentRun->numCharacters(); | 1054 clusterStart = currentRun->startIndex() + currentRun->numCharacters(); |
| 1055 else | 1055 else |
| 1056 clusterStart = currentRun->glyphToCharacterIndex(0); | 1056 clusterStart = currentRun->glyphToCharacterIndex(0); |
| 1057 | 1057 |
| 1058 float advanceSoFar = initialAdvance; | 1058 float advanceSoFar = initialAdvance; |
| 1059 for (unsigned i = 0; i < numGlyphs; ++i) { | 1059 for (unsigned i = 0; i < numGlyphs; ++i) { |
| 1060 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i); | 1060 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i); |
| 1061 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphData.ch
aracterIndex; | 1061 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphData.ch
aracterIndex; |
| 1062 bool isRunEnd = (i + 1 == numGlyphs); | 1062 bool isRunEnd = (i + 1 == numGlyphs); |
| 1063 bool isClusterEnd = isRunEnd || (currentRun->glyphToCharacterIndex(i +
1) != currentCharacterIndex); | 1063 bool isClusterEnd = isRunEnd || (currentRun->glyphToCharacterIndex(i +
1) != currentCharacterIndex); |
| 1064 | 1064 |
| 1065 if ((m_run.rtl() && currentCharacterIndex >= m_toIndex) || (!m_run.rtl()
&& currentCharacterIndex < m_fromIndex)) { | 1065 if ((m_textRun.rtl() && currentCharacterIndex >= m_toIndex) || (!m_textR
un.rtl() && currentCharacterIndex < m_fromIndex)) { |
| 1066 advanceSoFar += glyphData.advance; | 1066 advanceSoFar += glyphData.advance; |
| 1067 m_run.rtl() ? --clusterStart : ++clusterStart; | 1067 m_textRun.rtl() ? --clusterStart : ++clusterStart; |
| 1068 continue; | 1068 continue; |
| 1069 } | 1069 } |
| 1070 | 1070 |
| 1071 clusterAdvance += glyphData.advance; | 1071 clusterAdvance += glyphData.advance; |
| 1072 | 1072 |
| 1073 if (isClusterEnd) { | 1073 if (isClusterEnd) { |
| 1074 uint16_t clusterEnd; | 1074 uint16_t clusterEnd; |
| 1075 if (m_run.rtl()) | 1075 if (m_textRun.rtl()) |
| 1076 clusterEnd = currentCharacterIndex; | 1076 clusterEnd = currentCharacterIndex; |
| 1077 else | 1077 else |
| 1078 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n
umCharacters() : currentRun->glyphToCharacterIndex(i + 1); | 1078 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n
umCharacters() : currentRun->glyphToCharacterIndex(i + 1); |
| 1079 | 1079 |
| 1080 graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get(
), m_normalizedBufferLength, clusterStart, clusterEnd); | 1080 graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get(
), m_normalizedBufferLength, clusterStart, clusterEnd); |
| 1081 if (!graphemesInCluster || !clusterAdvance) | 1081 if (!graphemesInCluster || !clusterAdvance) |
| 1082 continue; | 1082 continue; |
| 1083 | 1083 |
| 1084 float glyphAdvanceX = clusterAdvance / graphemesInCluster; | 1084 float glyphAdvanceX = clusterAdvance / graphemesInCluster; |
| 1085 for (unsigned j = 0; j < graphemesInCluster; ++j) { | 1085 for (unsigned j = 0; j < graphemesInCluster; ++j) { |
| 1086 // Do not put emphasis marks on space, separator, and control ch
aracters. | 1086 // Do not put emphasis marks on space, separator, and control ch
aracters. |
| 1087 if (Character::canReceiveTextEmphasis(m_run[currentCharacterInde
x])) | 1087 if (Character::canReceiveTextEmphasis(m_textRun[currentCharacter
Index])) |
| 1088 addEmphasisMark(glyphBuffer, advanceSoFar + glyphAdvanceX /
2); | 1088 addEmphasisMark(glyphBuffer, advanceSoFar + glyphAdvanceX /
2); |
| 1089 | 1089 |
| 1090 advanceSoFar += glyphAdvanceX; | 1090 advanceSoFar += glyphAdvanceX; |
| 1091 } | 1091 } |
| 1092 clusterStart = clusterEnd; | 1092 clusterStart = clusterEnd; |
| 1093 clusterAdvance = 0; | 1093 clusterAdvance = 0; |
| 1094 } | 1094 } |
| 1095 } | 1095 } |
| 1096 | 1096 |
| 1097 return advanceSoFar - initialAdvance; | 1097 return advanceSoFar - initialAdvance; |
| 1098 } | 1098 } |
| 1099 | 1099 |
| 1100 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer) | 1100 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer) |
| 1101 { | 1101 { |
| 1102 ASSERT(glyphBuffer); | 1102 ASSERT(glyphBuffer); |
| 1103 | 1103 |
| 1104 unsigned numRuns = m_harfBuzzRuns.size(); | 1104 unsigned numRuns = m_harfBuzzRuns.size(); |
| 1105 float advanceSoFar = 0; | 1105 float advanceSoFar = 0; |
| 1106 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) { | 1106 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) { |
| 1107 HarfBuzzRun* currentRun = m_harfBuzzRuns[m_run.ltr() ? runIndex : numRun
s - runIndex - 1].get(); | 1107 HarfBuzzRun* currentRun = m_harfBuzzRuns[m_textRun.ltr() ? runIndex : nu
mRuns - runIndex - 1].get(); |
| 1108 // Skip runs that only contain control characters. | 1108 // Skip runs that only contain control characters. |
| 1109 if (!currentRun->numGlyphs()) | 1109 if (!currentRun->numGlyphs()) |
| 1110 continue; | 1110 continue; |
| 1111 advanceSoFar += forTextEmphasis() | 1111 advanceSoFar += forTextEmphasis() |
| 1112 ? fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun, advanceSoF
ar) | 1112 ? fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun, advanceSoF
ar) |
| 1113 : fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, advanceSoF
ar); | 1113 : fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, advanceSoF
ar); |
| 1114 } | 1114 } |
| 1115 return glyphBuffer->size(); | 1115 return glyphBuffer->size(); |
| 1116 } | 1116 } |
| 1117 | 1117 |
| 1118 int HarfBuzzShaper::offsetForPosition(float targetX) | 1118 int HarfBuzzShaper::offsetForPosition(float targetX) |
| 1119 { | 1119 { |
| 1120 int charactersSoFar = 0; | 1120 int charactersSoFar = 0; |
| 1121 float currentX = 0; | 1121 float currentX = 0; |
| 1122 | 1122 |
| 1123 if (m_run.rtl()) { | 1123 if (m_textRun.rtl()) { |
| 1124 charactersSoFar = m_normalizedBufferLength; | 1124 charactersSoFar = m_normalizedBufferLength; |
| 1125 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { | 1125 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { |
| 1126 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); | 1126 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); |
| 1127 float nextX = currentX + m_harfBuzzRuns[i]->width(); | 1127 float nextX = currentX + m_harfBuzzRuns[i]->width(); |
| 1128 float offsetForRun = targetX - currentX; | 1128 float offsetForRun = targetX - currentX; |
| 1129 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width())
{ | 1129 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width())
{ |
| 1130 // The x value in question is within this script run. | 1130 // The x value in question is within this script run. |
| 1131 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi
tion(offsetForRun); | 1131 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi
tion(offsetForRun); |
| 1132 return charactersSoFar + index; | 1132 return charactersSoFar + index; |
| 1133 } | 1133 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1150 } | 1150 } |
| 1151 | 1151 |
| 1152 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int
from, int to) | 1152 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int
from, int to) |
| 1153 { | 1153 { |
| 1154 float currentX = 0; | 1154 float currentX = 0; |
| 1155 float fromX = 0; | 1155 float fromX = 0; |
| 1156 float toX = 0; | 1156 float toX = 0; |
| 1157 bool foundFromX = false; | 1157 bool foundFromX = false; |
| 1158 bool foundToX = false; | 1158 bool foundToX = false; |
| 1159 | 1159 |
| 1160 if (m_run.rtl()) | 1160 if (m_textRun.rtl()) |
| 1161 currentX = m_totalWidth; | 1161 currentX = m_totalWidth; |
| 1162 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { | 1162 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { |
| 1163 if (m_run.rtl()) | 1163 if (m_textRun.rtl()) |
| 1164 currentX -= m_harfBuzzRuns[i]->width(); | 1164 currentX -= m_harfBuzzRuns[i]->width(); |
| 1165 int numCharacters = m_harfBuzzRuns[i]->numCharacters(); | 1165 int numCharacters = m_harfBuzzRuns[i]->numCharacters(); |
| 1166 if (!foundFromX && from >= 0 && from < numCharacters) { | 1166 if (!foundFromX && from >= 0 && from < numCharacters) { |
| 1167 fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX; | 1167 fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX; |
| 1168 foundFromX = true; | 1168 foundFromX = true; |
| 1169 } else { | 1169 } else { |
| 1170 from -= numCharacters; | 1170 from -= numCharacters; |
| 1171 } | 1171 } |
| 1172 | 1172 |
| 1173 if (!foundToX && to >= 0 && to < numCharacters) { | 1173 if (!foundToX && to >= 0 && to < numCharacters) { |
| 1174 toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX; | 1174 toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX; |
| 1175 foundToX = true; | 1175 foundToX = true; |
| 1176 } else { | 1176 } else { |
| 1177 to -= numCharacters; | 1177 to -= numCharacters; |
| 1178 } | 1178 } |
| 1179 | 1179 |
| 1180 if (foundFromX && foundToX) | 1180 if (foundFromX && foundToX) |
| 1181 break; | 1181 break; |
| 1182 if (!m_run.rtl()) | 1182 if (!m_textRun.rtl()) |
| 1183 currentX += m_harfBuzzRuns[i]->width(); | 1183 currentX += m_harfBuzzRuns[i]->width(); |
| 1184 } | 1184 } |
| 1185 | 1185 |
| 1186 // The position in question might be just after the text. | 1186 // The position in question might be just after the text. |
| 1187 if (!foundFromX) | 1187 if (!foundFromX) |
| 1188 fromX = 0; | 1188 fromX = 0; |
| 1189 if (!foundToX) | 1189 if (!foundToX) |
| 1190 toX = m_run.rtl() ? 0 : m_totalWidth; | 1190 toX = m_textRun.rtl() ? 0 : m_totalWidth; |
| 1191 // None of our HarfBuzzRuns is part of the selection, | 1191 // None of our HarfBuzzRuns is part of the selection, |
| 1192 // possibly invalid from, to arguments. | 1192 // possibly invalid from, to arguments. |
| 1193 if (!foundToX && !foundFromX) | 1193 if (!foundToX && !foundFromX) |
| 1194 fromX = toX = 0; | 1194 fromX = toX = 0; |
| 1195 | 1195 |
| 1196 if (fromX < toX) | 1196 if (fromX < toX) |
| 1197 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); | 1197 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); |
| 1198 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); | 1198 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); |
| 1199 } | 1199 } |
| 1200 | 1200 |
| 1201 } // namespace blink | 1201 } // namespace blink |
| OLD | NEW |