diff --git a/intl/unicharutil/moz.build b/intl/unicharutil/moz.build index 7b93396fc856..461fd255efaf 100644 --- a/intl/unicharutil/moz.build +++ b/intl/unicharutil/moz.build @@ -27,9 +27,17 @@ UNIFIED_SOURCES += [ 'nsCategoryImp.cpp', 'nsEntityConverter.cpp', 'nsSaveAsCharset.cpp', - 'nsUnicodeNormalizer.cpp', ] +if CONFIG['ENABLE_INTL_API']: + UNIFIED_SOURCES += [ + 'nsUnicodeNormalizer_ICU.cpp', + ] +else: + UNIFIED_SOURCES += [ + 'nsUnicodeNormalizer.cpp', + ] + FINAL_LIBRARY = 'xul' if CONFIG['GNU_CXX']: diff --git a/intl/unicharutil/nsUnicodeNormalizer.h b/intl/unicharutil/nsUnicodeNormalizer.h index 842a7aa808cd..5d9f1fe2432a 100644 --- a/intl/unicharutil/nsUnicodeNormalizer.h +++ b/intl/unicharutil/nsUnicodeNormalizer.h @@ -25,9 +25,12 @@ public: NS_IMETHOD NormalizeUnicodeNFKD( const nsAString& aSrc, nsAString& aDest) override; NS_IMETHOD NormalizeUnicodeNFKC( const nsAString& aSrc, nsAString& aDest) override; - // low-level access to the composition data needed for HarfBuzz callbacks +#if !ENABLE_INTL_API + // Low-level access to the composition data needed for HarfBuzz callbacks; + // only required when ICU is not available in the build. static bool Compose(uint32_t a, uint32_t b, uint32_t *ab); static bool DecomposeNonRecursively(uint32_t comp, uint32_t *c1, uint32_t *c2); +#endif private: virtual ~nsUnicodeNormalizer(); diff --git a/intl/unicharutil/nsUnicodeNormalizer_ICU.cpp b/intl/unicharutil/nsUnicodeNormalizer_ICU.cpp new file mode 100644 index 000000000000..6f6c3d2dd5ce --- /dev/null +++ b/intl/unicharutil/nsUnicodeNormalizer_ICU.cpp @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsUnicodeNormalizer.h" +#include "ICUUtils.h" +#include "unicode/unorm2.h" +#include "unicode/utext.h" + +NS_IMPL_ISUPPORTS(nsUnicodeNormalizer, nsIUnicodeNormalizer) + +nsUnicodeNormalizer::nsUnicodeNormalizer() +{ +} + +nsUnicodeNormalizer::~nsUnicodeNormalizer() +{ +} + +static nsresult +DoNormalization(const UNormalizer2* aNorm, const nsAString& aSrc, + nsAString& aDest) +{ + UErrorCode errorCode = U_ZERO_ERROR; + const int32_t length = aSrc.Length(); + const UChar* src = reinterpret_cast(aSrc.BeginReading()); + // Initial guess for a capacity that is likely to be enough for most cases. + int32_t capacity = length + (length >> 8) + 8; + do { + aDest.SetLength(capacity); + UChar* dest = reinterpret_cast(aDest.BeginWriting()); + int32_t len = unorm2_normalize(aNorm, src, aSrc.Length(), dest, capacity, + &errorCode); + if (U_SUCCESS(errorCode)) { + aDest.SetLength(len); + break; + } + if (errorCode == U_BUFFER_OVERFLOW_ERROR) { + // Buffer wasn't big enough; adjust to the reported size and try again. + capacity = len; + errorCode = U_ZERO_ERROR; + continue; + } + } while (false); + return ICUUtils::UErrorToNsResult(errorCode); +} + +nsresult +nsUnicodeNormalizer::NormalizeUnicodeNFD(const nsAString& aSrc, + nsAString& aDest) +{ + // The unorm2_getNF*Instance functions return static singletons that should + // not be deleted, so we just get them once on first use. + static UErrorCode errorCode = U_ZERO_ERROR; + static const UNormalizer2* norm = unorm2_getNFDInstance(&errorCode); + if (U_SUCCESS(errorCode)) { + return DoNormalization(norm, aSrc, aDest); + } + return ICUUtils::UErrorToNsResult(errorCode); +} + +nsresult +nsUnicodeNormalizer::NormalizeUnicodeNFC(const nsAString& aSrc, + nsAString& aDest) +{ + static UErrorCode errorCode = U_ZERO_ERROR; + static const UNormalizer2* norm = unorm2_getNFCInstance(&errorCode); + if (U_SUCCESS(errorCode)) { + return DoNormalization(norm, aSrc, aDest); + } + return ICUUtils::UErrorToNsResult(errorCode); +} + +nsresult +nsUnicodeNormalizer::NormalizeUnicodeNFKD(const nsAString& aSrc, + nsAString& aDest) +{ + static UErrorCode errorCode = U_ZERO_ERROR; + static const UNormalizer2* norm = unorm2_getNFKDInstance(&errorCode); + if (U_SUCCESS(errorCode)) { + return DoNormalization(norm, aSrc, aDest); + } + return ICUUtils::UErrorToNsResult(errorCode); +} + +nsresult +nsUnicodeNormalizer::NormalizeUnicodeNFKC(const nsAString& aSrc, + nsAString& aDest) +{ + static UErrorCode errorCode = U_ZERO_ERROR; + static const UNormalizer2* norm = unorm2_getNFKCInstance(&errorCode); + if (U_SUCCESS(errorCode)) { + return DoNormalization(norm, aSrc, aDest); + } + return ICUUtils::UErrorToNsResult(errorCode); +}