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 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
545 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length()); | 545 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length()); |
546 source = stringFor8BitRun.characters16(); | 546 source = stringFor8BitRun.characters16(); |
547 } else { | 547 } else { |
548 source = run.characters16(); | 548 source = run.characters16(); |
549 } | 549 } |
550 | 550 |
551 *destinationLength = 0; | 551 *destinationLength = 0; |
552 while (position < length) { | 552 while (position < length) { |
553 UChar32 character; | 553 UChar32 character; |
554 U16_NEXT(source, position, length, character); | 554 U16_NEXT(source, position, length, character); |
555 // Don't normalize tabs as they are not treated as spaces for word-end. | 555 if (!(character == tabulationCharacter && run.allowTabs())) { |
556 if (run.normalizeSpace() && Character::isNormalizedCanvasSpaceCharacter( character)) | 556 // Don't normalize tabs as they are not treated as spaces for word-e nd. |
557 character = spaceCharacter; | 557 if (run.normalizeSpace() && Character::isNormalizedCanvasSpaceCharac ter(character)) |
558 else if (Character::treatAsSpace(character) && character != tabulationCh aracter) | 558 character = spaceCharacter; |
559 character = spaceCharacter; | 559 else if (Character::treatAsSpace(character) && character != tabulati onCharacter) |
560 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) | 560 character = spaceCharacter; |
561 character = zeroWidthSpaceCharacter; | 561 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) |
562 character = zeroWidthSpaceCharacter; | |
563 } | |
562 | 564 |
563 U16_APPEND(destination, *destinationLength, length, character, error); | 565 U16_APPEND(destination, *destinationLength, length, character, error); |
564 ASSERT_UNUSED(error, !error); | 566 ASSERT_UNUSED(error, !error); |
565 } | 567 } |
566 } | 568 } |
567 | 569 |
568 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, | 570 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, |
569 HashSet<const SimpleFontData*>* fallbackFonts) | 571 HashSet<const SimpleFontData*>* fallbackFonts) |
570 : Shaper(font, run, nullptr, fallbackFonts) | 572 : Shaper(font, run, nullptr, fallbackFonts) |
571 , m_normalizedBufferLength(0) | 573 , m_normalizedBufferLength(0) |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
725 } | 727 } |
726 | 728 |
727 struct CandidateRun { | 729 struct CandidateRun { |
728 UChar32 character; | 730 UChar32 character; |
729 unsigned start; | 731 unsigned start; |
730 unsigned end; | 732 unsigned end; |
731 const SimpleFontData* fontData; | 733 const SimpleFontData* fontData; |
732 UScriptCode script; | 734 UScriptCode script; |
733 }; | 735 }; |
734 | 736 |
737 static void collectCandidateRunsForTabulationCharacters(UTF16TextIterator& itera tor, | |
738 Vector<CandidateRun>* runs, unsigned& startIndexOfCurrentRun, | |
739 UChar32& character, const SimpleFontData* currentFontData) | |
740 { | |
741 ASSERT(character == tabulationCharacter); | |
742 for (iterator.advance(); iterator.consume(character); iterator.advance()) { | |
743 if (character != tabulationCharacter) | |
744 break; | |
745 } | |
746 CandidateRun run = { tabulationCharacter, startIndexOfCurrentRun, static_cas t<unsigned>(iterator.offset()), currentFontData, USCRIPT_COMMON }; | |
747 runs->append(run); | |
748 startIndexOfCurrentRun = iterator.offset(); | |
749 } | |
750 | |
751 static inline bool updateCharacterInfo(const Font* font, UChar32 character, cons t TextRun& textRun, | |
eae
2015/07/20 17:39:24
Update makes it sound like it has state, how about
kojii
2015/07/21 01:11:47
Glad you suggested this! I once did this but it ma
| |
752 const SimpleFontData*& fontData, UScriptCode& script) | |
753 { | |
754 fontData = font->glyphDataForCharacter(character, false, textRun.normalizeSp ace()).fontData; | |
755 UErrorCode errorCode = U_ZERO_ERROR; | |
756 script = uscript_getScript(character, &errorCode); | |
757 if (U_FAILURE(errorCode)) | |
758 return false; | |
759 return true; | |
760 } | |
761 | |
735 static inline bool collectCandidateRuns(const UChar* normalizedBuffer, | 762 static inline bool collectCandidateRuns(const UChar* normalizedBuffer, |
736 size_t bufferLength, const Font* font, Vector<CandidateRun>* runs, bool isSp aceNormalize) | 763 size_t bufferLength, const Font* font, Vector<CandidateRun>* runs, |
764 const TextRun& textRun) | |
737 { | 765 { |
738 UTF16TextIterator iterator(normalizedBuffer, bufferLength); | 766 UTF16TextIterator iterator(normalizedBuffer, bufferLength); |
739 UChar32 character; | 767 UChar32 character; |
740 unsigned startIndexOfCurrentRun = 0; | 768 unsigned startIndexOfCurrentRun = 0; |
741 | 769 |
742 if (!iterator.consume(character)) | 770 if (!iterator.consume(character)) |
743 return false; | 771 return false; |
744 | 772 |
745 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData; | 773 const SimpleFontData* nextFontData; |
746 UErrorCode errorCode = U_ZERO_ERROR; | 774 UScriptCode nextScript; |
747 UScriptCode nextScript = uscript_getScript(character, &errorCode); | 775 if (!updateCharacterInfo(font, character, textRun, nextFontData, nextScript) ) |
748 if (U_FAILURE(errorCode)) | |
749 return false; | 776 return false; |
750 | 777 |
751 do { | 778 do { |
779 // Tab characters need to go to its own run because the run doesn't use Harfbuzz. | |
780 if (character == tabulationCharacter && textRun.allowTabs()) { | |
eae
2015/07/20 17:39:24
How about adding UNLIKELY macros around the tab ch
kojii
2015/07/21 01:11:47
Thought UNLIKELY() is the past. Thanks, learned on
| |
781 collectCandidateRunsForTabulationCharacters(iterator, runs, | |
782 startIndexOfCurrentRun, character, nextFontData); | |
783 if (iterator.atEnd()) | |
784 break; | |
785 if (!updateCharacterInfo(font, character, textRun, nextFontData, nex tScript)) | |
786 return false; | |
787 } | |
788 | |
752 const UChar* currentCharacterPosition = iterator.characters(); | 789 const UChar* currentCharacterPosition = iterator.characters(); |
753 const SimpleFontData* currentFontData = nextFontData; | 790 const SimpleFontData* currentFontData = nextFontData; |
754 UScriptCode currentScript = nextScript; | 791 UScriptCode currentScript = nextScript; |
755 | 792 |
756 UChar32 lastCharacter = character; | 793 UChar32 lastCharacter = character; |
757 for (iterator.advance(); iterator.consume(character); iterator.advance() ) { | 794 for (iterator.advance(); iterator.consume(character); iterator.advance() ) { |
758 if (Character::treatAsZeroWidthSpace(character)) | 795 if (Character::treatAsZeroWidthSpace(character)) { |
796 if (character == tabulationCharacter && textRun.allowTabs()) | |
eae
2015/07/20 17:39:24
I'd move this check out of the treatAsZeroWidthSpa
kojii
2015/07/21 01:11:47
That's better to read. treatAsZeroWidthSpace() che
| |
797 break; | |
759 continue; | 798 continue; |
799 } | |
760 if ((U_GET_GC_MASK(character) & U_GC_M_MASK) | 800 if ((U_GET_GC_MASK(character) & U_GC_M_MASK) |
761 && (Character::isUnicodeVariationSelector(character) | 801 && (Character::isUnicodeVariationSelector(character) |
762 || currentFontData->canRenderCombiningCharacterSequence( | 802 || currentFontData->canRenderCombiningCharacterSequence( |
763 currentCharacterPosition, | 803 currentCharacterPosition, |
764 iterator.glyphEnd() - currentCharacterPosition))) | 804 iterator.glyphEnd() - currentCharacterPosition))) |
765 continue; | 805 continue; |
766 | 806 |
767 nextFontData = font->glyphDataForCharacter(character, false, isSpace Normalize).fontData; | 807 if (!updateCharacterInfo(font, character, textRun, nextFontData, nex tScript)) |
768 nextScript = uscript_getScript(character, &errorCode); | |
769 if (U_FAILURE(errorCode)) | |
770 return false; | 808 return false; |
771 if (lastCharacter == zeroWidthJoinerCharacter) | 809 if (lastCharacter == zeroWidthJoinerCharacter) |
772 currentFontData = nextFontData; | 810 currentFontData = nextFontData; |
773 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript)))) | 811 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript)))) |
774 break; | 812 break; |
775 currentCharacterPosition = iterator.characters(); | 813 currentCharacterPosition = iterator.characters(); |
776 lastCharacter = character; | 814 lastCharacter = character; |
777 } | 815 } |
778 | 816 |
779 CandidateRun run = { lastCharacter, startIndexOfCurrentRun, static_cast< unsigned>(iterator.offset()), currentFontData, currentScript }; | 817 CandidateRun run = { lastCharacter, startIndexOfCurrentRun, static_cast< unsigned>(iterator.offset()), currentFontData, currentScript }; |
780 runs->append(run); | 818 runs->append(run); |
781 | 819 |
782 startIndexOfCurrentRun = iterator.offset(); | 820 startIndexOfCurrentRun = iterator.offset(); |
783 } while (iterator.consume(character)); | 821 } while (!iterator.atEnd()); |
784 | 822 |
785 return true; | 823 return true; |
786 } | 824 } |
787 | 825 |
788 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, | 826 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, |
789 CandidateRun& adjacentRun) | 827 CandidateRun& adjacentRun) |
790 { | 828 { |
791 for (int i = 0; i < length; i++) { | 829 for (int i = 0; i < length; i++) { |
792 if (scriptExtensions[i] == adjacentRun.script) | 830 if (scriptExtensions[i] == adjacentRun.script) |
793 return true; | 831 return true; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
886 return true; | 924 return true; |
887 } | 925 } |
888 | 926 |
889 bool HarfBuzzShaper::createHarfBuzzRuns() | 927 bool HarfBuzzShaper::createHarfBuzzRuns() |
890 { | 928 { |
891 if (m_normalizedBufferLength == 1) | 929 if (m_normalizedBufferLength == 1) |
892 return createHarfBuzzRunsForSingleCharacter(); | 930 return createHarfBuzzRunsForSingleCharacter(); |
893 | 931 |
894 Vector<CandidateRun> candidateRuns; | 932 Vector<CandidateRun> candidateRuns; |
895 if (!collectCandidateRuns(m_normalizedBuffer.get(), | 933 if (!collectCandidateRuns(m_normalizedBuffer.get(), |
896 m_normalizedBufferLength, m_font, &candidateRuns, m_textRun.normalizeSpa ce())) | 934 m_normalizedBufferLength, m_font, &candidateRuns, m_textRun)) |
897 return false; | 935 return false; |
898 | 936 |
899 if (!resolveCandidateRuns(candidateRuns)) | 937 if (!resolveCandidateRuns(candidateRuns)) |
900 return false; | 938 return false; |
901 | 939 |
902 size_t length = candidateRuns.size(); | 940 size_t length = candidateRuns.size(); |
903 for (size_t i = 0; i < length; ) { | 941 for (size_t i = 0; i < length; ) { |
904 CandidateRun& run = candidateRuns[i]; | 942 CandidateRun& run = candidateRuns[i]; |
943 if (run.character == tabulationCharacter && m_textRun.allowTabs()) { | |
eae
2015/07/20 17:39:24
Is this really needed? Isn't the extra condition i
kojii
2015/07/21 01:11:47
Yeah, this check is needed if the first run is tab
| |
944 addHarfBuzzRun(run.start, run.end, run.fontData, run.script); | |
945 ++i; | |
946 continue; | |
947 } | |
905 CandidateRun lastMatchingRun = run; | 948 CandidateRun lastMatchingRun = run; |
906 for (i++; i < length; i++) { | 949 for (i++; i < length; i++) { |
907 if (candidateRuns[i].script != run.script | 950 if (candidateRuns[i].script != run.script |
908 || candidateRuns[i].fontData != run.fontData) | 951 || candidateRuns[i].fontData != run.fontData |
952 || candidateRuns[i].character == tabulationCharacter) | |
909 break; | 953 break; |
910 lastMatchingRun = candidateRuns[i]; | 954 lastMatchingRun = candidateRuns[i]; |
911 } | 955 } |
912 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script) ; | 956 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script) ; |
913 } | 957 } |
914 return !m_harfBuzzRuns.isEmpty(); | 958 return !m_harfBuzzRuns.isEmpty(); |
915 } | 959 } |
916 | 960 |
917 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built | 961 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built |
918 // without hb-icu. See http://crbug.com/356929 | 962 // without hb-icu. See http://crbug.com/356929 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
951 static const uint16_t* toUint16(const UChar* src) | 995 static const uint16_t* toUint16(const UChar* src) |
952 { | 996 { |
953 // FIXME: This relies on undefined behavior however it works on the | 997 // FIXME: This relies on undefined behavior however it works on the |
954 // current versions of all compilers we care about and avoids making | 998 // current versions of all compilers we care about and avoids making |
955 // a copy of the string. | 999 // a copy of the string. |
956 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t"); | 1000 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t"); |
957 return reinterpret_cast<const uint16_t*>(src); | 1001 return reinterpret_cast<const uint16_t*>(src); |
958 } | 1002 } |
959 | 1003 |
960 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, | 1004 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, |
961 const FontDescription& fontDescription, const UChar* normalizedBuffer, | 1005 const FontDescription& fontDescription, const UChar* characters, |
962 unsigned startIndex, unsigned numCharacters) | 1006 unsigned numCharacters) |
963 { | 1007 { |
964 if (fontDescription.variant() == FontVariantSmallCaps | 1008 if (fontDescription.variant() == FontVariantSmallCaps |
965 && u_islower(normalizedBuffer[startIndex])) { | 1009 && u_islower(characters[0])) { |
966 String upperText = String(normalizedBuffer + startIndex, numCharacters) | 1010 String upperText = String(characters, numCharacters) |
967 .upper(); | 1011 .upper(); |
968 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call | 1012 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call |
969 // makeUpper(). | 1013 // makeUpper(). |
970 ASSERT(!upperText.is8Bit()); | 1014 ASSERT(!upperText.is8Bit()); |
971 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), | 1015 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), |
972 numCharacters, 0, numCharacters); | 1016 numCharacters, 0, numCharacters); |
973 } else { | 1017 } else { |
974 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex), | 1018 hb_buffer_add_utf16(buffer, toUint16(characters), |
975 numCharacters, 0, numCharacters); | 1019 numCharacters, 0, numCharacters); |
976 } | 1020 } |
977 } | 1021 } |
978 | 1022 |
979 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeHarfBuzzRuns() | 1023 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeHarfBuzzRuns() |
980 { | 1024 { |
981 RefPtr<ShapeResult> result = ShapeResult::create( | 1025 RefPtr<ShapeResult> result = ShapeResult::create( |
982 m_normalizedBufferLength, m_textRun.direction()); | 1026 m_normalizedBufferLength, m_textRun.direction()); |
983 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy); | 1027 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy); |
984 | 1028 |
985 const FontDescription& fontDescription = m_font->fontDescription(); | 1029 const FontDescription& fontDescription = m_font->fontDescription(); |
986 const String& localeString = fontDescription.locale(); | 1030 const String& localeString = fontDescription.locale(); |
987 CString locale = localeString.latin1(); | 1031 CString locale = localeString.latin1(); |
988 const hb_language_t language = hb_language_from_string(locale.data(), locale .length()); | 1032 const hb_language_t language = hb_language_from_string(locale.data(), locale .length()); |
989 | 1033 |
990 result->m_runs.resize(m_harfBuzzRuns.size()); | 1034 result->m_runs.resize(m_harfBuzzRuns.size()); |
991 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { | 1035 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { |
992 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; | 1036 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; |
993 const HarfBuzzRun* currentRun = &m_harfBuzzRuns[runIndex]; | 1037 const HarfBuzzRun* currentRun = &m_harfBuzzRuns[runIndex]; |
1038 ASSERT(m_normalizedBufferLength >= currentRun->m_startIndex + currentRun ->m_numCharacters); | |
1039 const UChar* characters = m_normalizedBuffer.get() + currentRun->m_start Index; | |
1040 | |
1041 if (characters[0] == tabulationCharacter && m_textRun.allowTabs()) { | |
1042 shapeResultForTabulationCharacters(result.get(), i, currentRun); | |
1043 continue; | |
1044 } | |
994 | 1045 |
995 const SimpleFontData* currentFontData = currentRun->m_fontData; | 1046 const SimpleFontData* currentFontData = currentRun->m_fontData; |
996 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF ontData->platformData()); | 1047 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF ontData->platformData()); |
997 HarfBuzzFace* face = platformData->harfBuzzFace(); | 1048 HarfBuzzFace* face = platformData->harfBuzzFace(); |
998 if (!face) | 1049 if (!face) |
999 return nullptr; | 1050 return nullptr; |
1000 | 1051 |
1001 hb_buffer_set_language(harfBuzzBuffer.get(), language); | 1052 hb_buffer_set_language(harfBuzzBuffer.get(), language); |
1002 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->m_script); | 1053 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->m_script); |
1003 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->m_direction); | 1054 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->m_direction); |
1004 | 1055 |
1005 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle | 1056 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle |
1006 // for combining marks at the beginning of runs. | 1057 // for combining marks at the beginning of runs. |
1007 static const uint16_t preContext = spaceCharacter; | 1058 static const uint16_t preContext = spaceCharacter; |
1008 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); | 1059 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); |
1009 | 1060 |
1010 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), | 1061 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), |
1011 fontDescription, m_normalizedBuffer.get(), currentRun->m_startIndex, | 1062 fontDescription, characters, currentRun->m_numCharacters); |
1012 currentRun->m_numCharacters); | |
1013 | 1063 |
1014 if (fontDescription.isVerticalAnyUpright()) | 1064 if (fontDescription.isVerticalAnyUpright()) |
1015 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); | 1065 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); |
1016 | 1066 |
1017 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy); | 1067 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy); |
1018 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); | 1068 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); |
1019 shapeResult(result.get(), i, currentRun, harfBuzzBuffer.get()); | 1069 shapeResult(result.get(), i, currentRun, harfBuzzBuffer.get()); |
1020 | 1070 |
1021 hb_buffer_reset(harfBuzzBuffer.get()); | 1071 hb_buffer_reset(harfBuzzBuffer.get()); |
1022 } | 1072 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1060 bool runEnd = i + 1 == numGlyphs; | 1110 bool runEnd = i + 1 == numGlyphs; |
1061 uint16_t glyph = glyphInfos[i].codepoint; | 1111 uint16_t glyph = glyphInfos[i].codepoint; |
1062 offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); | 1112 offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); |
1063 offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); | 1113 offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); |
1064 | 1114 |
1065 // One out of x_advance and y_advance is zero, depending on | 1115 // One out of x_advance and y_advance is zero, depending on |
1066 // whether the buffer direction is horizontal or vertical. | 1116 // whether the buffer direction is horizontal or vertical. |
1067 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance); | 1117 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance); |
1068 unsigned currentCharacterIndex = currentRun->m_startIndex + glyphInfos[i ].cluster; | 1118 unsigned currentCharacterIndex = currentRun->m_startIndex + glyphInfos[i ].cluster; |
1069 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); | 1119 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); |
1120 ASSERT(m_normalizedBuffer[currentCharacterIndex] != tabulationCharacter || !m_textRun.allowTabs()); | |
1070 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster; | 1121 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster; |
1071 float spacing = 0; | 1122 float spacing = 0; |
1072 | 1123 |
1073 run->m_glyphData[i].characterIndex = glyphInfos[i].cluster; | 1124 run->m_glyphData[i].characterIndex = glyphInfos[i].cluster; |
1074 | 1125 |
1075 if (isClusterEnd) | 1126 if (isClusterEnd) |
1076 spacing += adjustSpacing(run, i, currentCharacterIndex, *directionOf fset, totalAdvance); | 1127 spacing += adjustSpacing(run, i, currentCharacterIndex, *directionOf fset, totalAdvance); |
1077 | 1128 |
1078 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { | 1129 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { |
1079 run->setGlyphAndPositions(i, glyph, 0, 0, 0); | 1130 run->setGlyphAndPositions(i, glyph, 0, 0, 0); |
(...skipping 16 matching lines...) Expand all Loading... | |
1096 result->m_glyphBoundingBox.unite(glyphBounds); | 1147 result->m_glyphBoundingBox.unite(glyphBounds); |
1097 glyphOrigin += FloatSize(advance + offsetX, offsetY); | 1148 glyphOrigin += FloatSize(advance + offsetX, offsetY); |
1098 } | 1149 } |
1099 | 1150 |
1100 run->m_width = totalAdvance > 0.0 ? totalAdvance : 0.0; | 1151 run->m_width = totalAdvance > 0.0 ? totalAdvance : 0.0; |
1101 result->m_width += run->m_width; | 1152 result->m_width += run->m_width; |
1102 for (auto& fallbackFont : *m_fallbackFonts) | 1153 for (auto& fallbackFont : *m_fallbackFonts) |
1103 result->m_fallbackFonts.add(const_cast<SimpleFontData*>(fallbackFont)); | 1154 result->m_fallbackFonts.add(const_cast<SimpleFontData*>(fallbackFont)); |
1104 } | 1155 } |
1105 | 1156 |
1157 void HarfBuzzShaper::shapeResultForTabulationCharacters(ShapeResult* result, uns igned index, const HarfBuzzRun* currentRun) | |
1158 { | |
1159 const SimpleFontData& fontData = *currentRun->m_fontData; | |
1160 ShapeResult::RunInfo* run = new ShapeResult::RunInfo(currentRun->m_fontData, | |
1161 currentRun->m_direction, currentRun->m_script, currentRun->m_startIndex, | |
1162 currentRun->m_numCharacters, currentRun->m_numCharacters); | |
1163 result->m_runs[index] = run; | |
1164 result->m_numGlyphs += currentRun->m_numCharacters; | |
1165 float position = m_textRun.xPos() + result->m_width; | |
1166 float positionStart = position; | |
1167 for (size_t i = 0; i < currentRun->m_numCharacters; ++i) { | |
1168 ASSERT(m_normalizedBuffer[currentRun->m_startIndex + i] == tabulationCha racter); | |
1169 float advance = m_font->tabWidth(fontData, m_textRun.tabSize(), position ); | |
1170 run->m_glyphData[i].characterIndex = i; | |
1171 run->setGlyphAndPositions(i, fontData.spaceGlyph(), advance, 0, 0); | |
1172 position += advance; | |
1173 } | |
1174 run->m_width = position - positionStart; | |
1175 result->m_width += run->m_width; | |
1176 } | |
1177 | |
1106 float HarfBuzzShaper::adjustSpacing(ShapeResult::RunInfo* run, size_t glyphIndex , unsigned currentCharacterIndex, float& offset, float& totalAdvance) | 1178 float HarfBuzzShaper::adjustSpacing(ShapeResult::RunInfo* run, size_t glyphIndex , unsigned currentCharacterIndex, float& offset, float& totalAdvance) |
1107 { | 1179 { |
1108 float spacing = 0; | 1180 float spacing = 0; |
1109 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; | 1181 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; |
1110 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) | 1182 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) |
1111 spacing += m_letterSpacing; | 1183 spacing += m_letterSpacing; |
1112 | 1184 |
1113 bool treatAsSpace = Character::treatAsSpace(character); | 1185 bool treatAsSpace = Character::treatAsSpace(character); |
1114 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu n.allowTabs())) | 1186 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu n.allowTabs())) |
1115 spacing += m_wordSpacingAdjustment; | 1187 spacing += m_wordSpacingAdjustment; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1153 return spacing; | 1225 return spacing; |
1154 } | 1226 } |
1155 | 1227 |
1156 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere d by !m_expansionOpportunityCount above | 1228 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere d by !m_expansionOpportunityCount above |
1157 spacing += nextExpansionPerOpportunity(); | 1229 spacing += nextExpansionPerOpportunity(); |
1158 m_isAfterExpansion = true; | 1230 m_isAfterExpansion = true; |
1159 return spacing; | 1231 return spacing; |
1160 } | 1232 } |
1161 | 1233 |
1162 } // namespace blink | 1234 } // namespace blink |
OLD | NEW |