Cache ICU break iterators in SkUnicode_icu

Change-Id: I2d6abd1a12d629b590a6616d0d1c71d71d5f4812
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/344476
Commit-Queue: Jason Simmons <jsimmons@google.com>
Reviewed-by: Julia Lavrova <jlavrova@google.com>
This commit is contained in:
Jason Simmons 2021-01-07 11:10:01 -08:00 committed by Skia Commit-Bot
parent 627c0022ff
commit 504451c7cc

View File

@ -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 @@ static inline SkUnichar utf8_next(const char** ptr, const char* end) {
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,26 +167,41 @@ class SkBreakIterator_icu : public SkBreakIterator {
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) {
ICUBreakIterator makeBreakIterator(SkUnicode::BreakType type) {
UErrorCode status = U_ZERO_ERROR;
ICUBreakIterator iterator(ubrk_open(convertType(type), locale, nullptr, 0, &status));
if (U_FAILURE(status)) {
SkDEBUGF("Break error: %s", u_errorName(status));
return nullptr;
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));
}
}
}
return std::unique_ptr<SkBreakIterator>(new SkBreakIterator_icu(std::move(iterator)));
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;
}
};
@ -198,18 +225,6 @@ class SkScriptIterator_icu : public SkScriptIterator {
};
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 +286,8 @@ class SkUnicode_icu : public SkUnicode {
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 +327,9 @@ class SkUnicode_icu : public SkUnicode {
}
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 +422,13 @@ public:
}
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();