Cache ICU break iterators in SkUnicode_icu
Gate this behind an ifdef that can be disabled in environments where
the ICU ubrk_safeClone API is not available.
Change-Id: Ia1a3f677271622f2b7ae478b4d1ce76c74eed057
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/352876
Reviewed-by: Julia Lavrova <jlavrova@google.com>
Commit-Queue: Jason Simmons <jsimmons@google.com>
diff --git a/gn/skia.gni b/gn/skia.gni
index a6ffb6e..21e8e53 100644
--- a/gn/skia.gni
+++ b/gn/skia.gni
@@ -21,6 +21,7 @@
skia_enable_fontmgr_win = is_win
skia_enable_fontmgr_win_gdi = is_win
skia_enable_gpu = true
+ skia_enable_icu_ubrk_safeclone = false
skia_enable_pdf = true
skia_enable_skottie = !(is_win && is_component_build)
skia_enable_skrive = true
diff --git a/modules/skshaper/BUILD.gn b/modules/skshaper/BUILD.gn
index 57160c1..2063f20 100644
--- a/modules/skshaper/BUILD.gn
+++ b/modules/skshaper/BUILD.gn
@@ -20,6 +20,9 @@
defines += [ "SK_SHAPER_HARFBUZZ_AVAILABLE" ]
defines += [ "SK_UNICODE_AVAILABLE" ]
}
+ if (skia_enable_icu_ubrk_safeclone) {
+ defines += [ "SK_ENABLE_ICU_UBRK_SAFECLONE" ]
+ }
}
component("skshaper") {
diff --git a/modules/skshaper/src/SkUnicode_icu.cpp b/modules/skshaper/src/SkUnicode_icu.cpp
index 66185b6..99bb55b 100644
--- a/modules/skshaper/src/SkUnicode_icu.cpp
+++ b/modules/skshaper/src/SkUnicode_icu.cpp
@@ -5,7 +5,9 @@
* found in the LICENSE file.
*/
#include "include/core/SkString.h"
+#include "include/private/SkMutex.h"
#include "include/private/SkTFitsIn.h"
+#include "include/private/SkTHash.h"
#include "include/private/SkTemplates.h"
#include "modules/skshaper/src/SkUnicode.h"
#include "src/utils/SkUTF.h"
@@ -32,6 +34,16 @@
return val < 0 ? 0xFFFD : val;
}
+static UBreakIteratorType convertType(SkUnicode::BreakType type) {
+ switch (type) {
+ case SkUnicode::BreakType::kLines: return UBRK_LINE;
+ case SkUnicode::BreakType::kGraphemes: return UBRK_CHARACTER;
+ case SkUnicode::BreakType::kWords: return UBRK_WORD;
+ default:
+ return UBRK_CHARACTER;
+ }
+}
+
class SkBidiIterator_icu : public SkBidiIterator {
SkUnicodeBidi fBidi;
public:
@@ -155,27 +167,58 @@
fLastResult = 0;
return true;
}
+};
- static UBreakIteratorType convertType(SkUnicode::BreakType type) {
- switch (type) {
- case SkUnicode::BreakType::kLines: return UBRK_LINE;
- case SkUnicode::BreakType::kGraphemes: return UBRK_CHARACTER;
- case SkUnicode::BreakType::kWords: return UBRK_WORD;
- default:
- return UBRK_CHARACTER;
- }
+class SkIcuBreakIteratorCache {
+ SkTHashMap<SkUnicode::BreakType, ICUBreakIterator> fBreakCache;
+ SkMutex fBreakCacheMutex;
+
+ public:
+ static SkIcuBreakIteratorCache& get() {
+ static SkIcuBreakIteratorCache instance;
+ return instance;
}
- static std::unique_ptr<SkBreakIterator> makeUtf8BreakIterator
- (const char locale[], SkUnicode::BreakType type) {
+#ifdef SK_ENABLE_ICU_UBRK_SAFECLONE
+
+ ICUBreakIterator makeBreakIterator(SkUnicode::BreakType type) {
UErrorCode status = U_ZERO_ERROR;
- ICUBreakIterator iterator(ubrk_open(convertType(type), locale, nullptr, 0, &status));
+ ICUBreakIterator* cachedIterator;
+ {
+ SkAutoMutexExclusive lock(fBreakCacheMutex);
+ cachedIterator = fBreakCache.find(type);
+ if (!cachedIterator) {
+ ICUBreakIterator newIterator(ubrk_open(convertType(type), uloc_getDefault(), nullptr, 0, &status));
+ if (U_FAILURE(status)) {
+ SkDEBUGF("Break error: %s", u_errorName(status));
+ } else {
+ cachedIterator = fBreakCache.set(type, std::move(newIterator));
+ }
+ }
+ }
+ ICUBreakIterator iterator;
+ if (cachedIterator) {
+ iterator.reset(ubrk_safeClone(cachedIterator->get(), nullptr, nullptr, &status));
+ if (U_FAILURE(status)) {
+ SkDEBUGF("Break error: %s", u_errorName(status));
+ }
+ }
+ return iterator;
+ }
+
+#else // SK_ENABLE_ICU_UBRK_SAFECLONE
+
+ ICUBreakIterator makeBreakIterator(SkUnicode::BreakType type) {
+ UErrorCode status = U_ZERO_ERROR;
+ ICUBreakIterator iterator(ubrk_open(convertType(type), uloc_getDefault(), nullptr, 0, &status));
if (U_FAILURE(status)) {
SkDEBUGF("Break error: %s", u_errorName(status));
- return nullptr;
}
- return std::unique_ptr<SkBreakIterator>(new SkBreakIterator_icu(std::move(iterator)));
+ return iterator;
}
+
+#endif // SK_ENABLE_ICU_UBRK_SAFECLONE
+
};
class SkScriptIterator_icu : public SkScriptIterator {
@@ -198,18 +241,6 @@
};
class SkUnicode_icu : public SkUnicode {
-
- static UBreakIteratorType convertType(BreakType type) {
- switch (type) {
- case BreakType::kLines: return UBRK_LINE;
- case BreakType::kGraphemes: return UBRK_CHARACTER;
- case BreakType::kWords: return UBRK_WORD;
- default:
- SkDEBUGF("Convert error: wrong break type");
- return UBRK_CHARACTER;
- }
- }
-
static bool extractBidi(const char utf8[],
int utf8Units,
TextDirection dir,
@@ -271,9 +302,8 @@
UErrorCode status = U_ZERO_ERROR;
- UBreakIteratorType breakType = convertType(BreakType::kWords);
- ICUBreakIterator iterator(ubrk_open(breakType, uloc_getDefault(), nullptr, 0, &status));
- if (U_FAILURE(status)) {
+ ICUBreakIterator iterator = SkIcuBreakIteratorCache::get().makeBreakIterator(BreakType::kWords);
+ if (!iterator) {
SkDEBUGF("Break error: %s", u_errorName(status));
return false;
}
@@ -313,9 +343,9 @@
}
SkASSERT(text);
- ICUBreakIterator iterator(ubrk_open(convertType(type), uloc_getDefault(), nullptr, 0, &status));
- if (U_FAILURE(status)) {
- SkDEBUGF("Break error: %s", u_errorName(status));
+ ICUBreakIterator iterator = SkIcuBreakIteratorCache::get().makeBreakIterator(type);
+ if (!iterator) {
+ return false;
}
ubrk_setUText(iterator.get(), text.get(), &status);
@@ -408,7 +438,13 @@
}
std::unique_ptr<SkBreakIterator> makeBreakIterator(const char locale[],
BreakType breakType) override {
- return SkBreakIterator_icu::makeUtf8BreakIterator(locale, breakType);
+ UErrorCode status = U_ZERO_ERROR;
+ ICUBreakIterator iterator(ubrk_open(convertType(breakType), locale, nullptr, 0, &status));
+ if (U_FAILURE(status)) {
+ SkDEBUGF("Break error: %s", u_errorName(status));
+ return nullptr;
+ }
+ return std::unique_ptr<SkBreakIterator>(new SkBreakIterator_icu(std::move(iterator)));
}
std::unique_ptr<SkScriptIterator> makeScriptIterator() override {
return SkScriptIterator_icu::makeScriptIterator();