void HarfBuzzShaper::setNormalizedBuffer(NormalizeMode normalizeMode) { // Normalize the text run in three ways: // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks // (U+0300..) are used in the run. This conversion is necessary since most OpenType // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in // their GSUB tables. // // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since // the API returns FALSE (= not normalized) for complex runs that don't require NFC // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, // HarfBuzz will do the same thing for us using the GSUB table. // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs // for characters like '\n' otherwise. // 3) Convert mirrored characters such as parenthesis for rtl text. // Convert to NFC form if the text has diacritical marks. icu::UnicodeString normalizedString; UErrorCode error = U_ZERO_ERROR; const UChar* runCharacters; String stringFor8BitRun; if (m_run.is8Bit()) { stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length()); runCharacters = stringFor8BitRun.characters16(); } else runCharacters = m_run.characters16(); for (unsigned i = 0; i < m_run.length(); ++i) { UChar ch = runCharacters[i]; if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) { icu::Normalizer::normalize(icu::UnicodeString(runCharacters, m_run.length()), UNORM_NFC, 0 /* no options */, normalizedString, error); if (U_FAILURE(error)) normalizedString.remove(); break; } } const UChar* sourceText; if (normalizedString.isEmpty()) { m_normalizedBufferLength = m_run.length(); sourceText = runCharacters; } else { m_normalizedBufferLength = normalizedString.length(); sourceText = normalizedString.getBuffer(); } m_normalizedBuffer = std::make_unique<UChar[]>(m_normalizedBufferLength + 1); normalizeSpacesAndMirrorChars(sourceText, m_normalizedBuffer.get(), m_normalizedBufferLength, normalizeMode); }
const TextRun& ComplexTextController::getNormalizedTextRun(const TextRun& originalRun, OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer) { // Normalize the text run in three ways: // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks // (U+0300..) are used in the run. This conversion is necessary since most OpenType // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in // their GSUB tables. // // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since // the API returns FALSE (= not normalized) for complex runs that don't require NFC // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, // Harfbuzz will do the same thing for us using the GSUB table. // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs // for characters like '\n' otherwise. // 3) Convert mirrored characters such as parenthesis for rtl text. // Convert to NFC form if the text has diacritical marks. icu::UnicodeString normalizedString; UErrorCode error = U_ZERO_ERROR; for (int16_t i = 0; i < originalRun.length(); ++i) { UChar ch = originalRun[i]; if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) { icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error); if (U_FAILURE(error)) return originalRun; break; } } // Normalize space and mirror parenthesis for rtl text. int normalizedBufferLength; const UChar* sourceText; if (normalizedString.isEmpty()) { normalizedBufferLength = originalRun.length(); sourceText = originalRun.characters(); } else { normalizedBufferLength = normalizedString.length(); sourceText = normalizedString.getBuffer(); } normalizedBuffer = adoptArrayPtr(new UChar[normalizedBufferLength + 1]); normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(), normalizedBufferLength); normalizedRun.set(new TextRun(originalRun)); normalizedRun->setText(normalizedBuffer.get(), normalizedBufferLength); return *normalizedRun; }