ICU project: script iterator in SkShaper
Change-Id: Idcc9290a7666cb590532150a44304d704c8ee34c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319777
Commit-Queue: Julia Lavrova <jlavrova@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
diff --git a/modules/skparagraph/src/OneLineShaper.cpp b/modules/skparagraph/src/OneLineShaper.cpp
index 45c622c..49c9942 100644
--- a/modules/skparagraph/src/OneLineShaper.cpp
+++ b/modules/skparagraph/src/OneLineShaper.cpp
@@ -603,8 +603,8 @@
LangIterator langIter(unresolvedText, blockSpan,
fParagraph->paragraphStyle().getTextStyle());
SkShaper::TrivialBiDiRunIterator bidiIter(defaultBidiLevel, unresolvedText.size());
- auto scriptIter = SkShaper::MakeHbIcuScriptRunIterator
- (unresolvedText.begin(), unresolvedText.size());
+ auto scriptIter = SkShaper::MakeSkUnicodeHbScriptRunIterator
+ (fParagraph->getUnicode(), unresolvedText.begin(), unresolvedText.size());
fCurrentText = unresolvedRange;
shaper->shape(unresolvedText.begin(), unresolvedText.size(),
fontIter, bidiIter,*scriptIter, langIter,
diff --git a/modules/skparagraph/tests/SkParagraphTest.cpp b/modules/skparagraph/tests/SkParagraphTest.cpp
index 8c19970..3e6335a 100644
--- a/modules/skparagraph/tests/SkParagraphTest.cpp
+++ b/modules/skparagraph/tests/SkParagraphTest.cpp
@@ -3678,7 +3678,9 @@
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(1);
- paragraph_style.setEllipsis(u"\u2026");
+ std::u16string ellipsis = u"\u2026";
+ paragraph_style.setEllipsis(ellipsis);
+ std::u16string e = paragraph_style.getEllipsisUtf16();
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
diff --git a/modules/skshaper/include/SkShaper.h b/modules/skshaper/include/SkShaper.h
index 9e5e2673..6e57ecb 100644
--- a/modules/skshaper/include/SkShaper.h
+++ b/modules/skshaper/include/SkShaper.h
@@ -151,7 +151,9 @@
static std::unique_ptr<ScriptRunIterator>
MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag script);
- #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
+ #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_UNICODE_AVAILABLE)
+ static std::unique_ptr<ScriptRunIterator>
+ MakeSkUnicodeHbScriptRunIterator(SkUnicode* unicode, const char* utf8, size_t utf8Bytes);
static std::unique_ptr<ScriptRunIterator>
MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes);
#endif
diff --git a/modules/skshaper/src/SkShaper.cpp b/modules/skshaper/src/SkShaper.cpp
index 185d349..c47e3ad 100644
--- a/modules/skshaper/src/SkShaper.cpp
+++ b/modules/skshaper/src/SkShaper.cpp
@@ -40,6 +40,9 @@
SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
#ifdef SK_UNICODE_AVAILABLE
auto unicode = SkUnicode::Make();
+ if (!unicode) {
+ return nullptr;
+ }
std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
utf8,
@@ -54,9 +57,13 @@
std::unique_ptr<SkShaper::ScriptRunIterator>
SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
-#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_UNICODE_AVAILABLE)
+ auto unicode = SkUnicode::Make();
+ if (!unicode) {
+ return nullptr;
+ }
std::unique_ptr<SkShaper::ScriptRunIterator> script =
- SkShaper::MakeHbIcuScriptRunIterator(utf8, utf8Bytes);
+ SkShaper::MakeSkUnicodeHbScriptRunIterator(unicode.get(), utf8, utf8Bytes);
if (script) {
return script;
}
diff --git a/modules/skshaper/src/SkShaper_harfbuzz.cpp b/modules/skshaper/src/SkShaper_harfbuzz.cpp
index 293924e..e6ed1b0 100644
--- a/modules/skshaper/src/SkShaper_harfbuzz.cpp
+++ b/modules/skshaper/src/SkShaper_harfbuzz.cpp
@@ -63,6 +63,7 @@
using SkUnicodeBidi = std::unique_ptr<SkBidiIterator>;
using SkUnicodeBreak = std::unique_ptr<SkBreakIterator>;
+using SkUnicodeScript = std::unique_ptr<SkScriptIterator>;
hb_position_t skhb_position(SkScalar value) {
// Treat HarfBuzz hb_position_t as 16.16 fixed-point.
@@ -378,21 +379,19 @@
SkBidiIterator::Level fLevel;
};
-class HbIcuScriptRunIterator final : public SkShaper::ScriptRunIterator {
+class SkUnicodeHbScriptRunIterator final: public SkShaper::ScriptRunIterator {
public:
- HbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes)
- : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
+ SkUnicodeHbScriptRunIterator(SkUnicodeScript script, const char* utf8, size_t utf8Bytes)
+ : fScript(std::move(script))
+ , fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
, fCurrentScript(HB_SCRIPT_UNKNOWN)
{}
- static hb_script_t hb_script_from_icu(SkUnichar u) {
- UErrorCode status = U_ZERO_ERROR;
- UScriptCode scriptCode = uscript_getScript(u, &status);
-
- if (U_FAILURE (status)) {
+ hb_script_t hb_script_from_icu(SkUnichar u) {
+ SkScriptIterator::ScriptID scriptId;
+ if (!fScript->getScript(u, &scriptId)) {
return HB_SCRIPT_UNKNOWN;
}
-
- return hb_icu_script_to_script(scriptCode);
+ return hb_icu_script_to_script((UScriptCode)scriptId);
}
void consume() override {
SkASSERT(fCurrent < fEnd);
@@ -428,6 +427,7 @@
return SkSetFourByteTag(HB_UNTAG(fCurrentScript));
}
private:
+ SkUnicodeScript fScript;
char const * fCurrent;
char const * const fBegin;
char const * const fEnd;
@@ -804,7 +804,9 @@
return;
}
- std::unique_ptr<ScriptRunIterator> script(MakeHbIcuScriptRunIterator(utf8, utf8Bytes));
+ std::unique_ptr<ScriptRunIterator> script(MakeSkUnicodeHbScriptRunIterator(fUnicode.get(),
+ utf8,
+ utf8Bytes));
if (!script) {
return;
}
@@ -1400,12 +1402,13 @@
std::unique_ptr<SkShaper::BiDiRunIterator>
SkShaper::MakeIcuBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
auto unicode = SkUnicode::Make();
- std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
- SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
- utf8,
- utf8Bytes,
- bidiLevel);
- return bidi;
+ if (!unicode) {
+ return nullptr;
+ }
+ return SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
+ utf8,
+ utf8Bytes,
+ bidiLevel);
}
std::unique_ptr<SkShaper::BiDiRunIterator>
@@ -1438,7 +1441,20 @@
std::unique_ptr<SkShaper::ScriptRunIterator>
SkShaper::MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes) {
- return std::make_unique<HbIcuScriptRunIterator>(utf8, utf8Bytes);
+ auto unicode = SkUnicode::Make();
+ if (!unicode) {
+ return nullptr;
+ }
+ return SkShaper::MakeSkUnicodeHbScriptRunIterator(unicode.get(), utf8, utf8Bytes);
+}
+
+std::unique_ptr<SkShaper::ScriptRunIterator>
+SkShaper::MakeSkUnicodeHbScriptRunIterator(SkUnicode* unicode, const char* utf8, size_t utf8Bytes) {
+ auto script = unicode->makeScriptIterator();
+ if (!script) {
+ return nullptr;
+ }
+ return std::make_unique<SkUnicodeHbScriptRunIterator>(std::move(script), utf8, utf8Bytes);
}
std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fontmgr) {
diff --git a/modules/skshaper/src/SkUnicode.h b/modules/skshaper/src/SkUnicode.h
index 07b0904..0db2302 100644
--- a/modules/skshaper/src/SkUnicode.h
+++ b/modules/skshaper/src/SkUnicode.h
@@ -68,9 +68,15 @@
virtual bool setText(const char utftext8[], int utf8Units) = 0;
};
+class SKUNICODE_API SkScriptIterator {
+ public:
+ typedef uint32_t ScriptID;
+ virtual ~SkScriptIterator() = default;
+ virtual bool getScript(SkUnichar u, ScriptID* script) = 0;
+};
+
class SKUNICODE_API SkUnicode {
public:
- typedef uint32_t ScriptID;
typedef uint32_t CombiningClass;
typedef uint32_t GeneralCategory;
enum class TextDirection {
@@ -116,6 +122,7 @@
(const char text[], int count, SkBidiIterator::Direction) = 0;
virtual std::unique_ptr<SkBreakIterator> makeBreakIterator
(const char locale[], BreakType breakType) = 0;
+ virtual std::unique_ptr<SkScriptIterator> makeScriptIterator() = 0;
// High level methods (that we actually use somewhere=SkParagraph)
virtual bool getBidiRegions
diff --git a/modules/skshaper/src/SkUnicode_icu.cpp b/modules/skshaper/src/SkUnicode_icu.cpp
index 7eb0f86..806900d 100644
--- a/modules/skshaper/src/SkUnicode_icu.cpp
+++ b/modules/skshaper/src/SkUnicode_icu.cpp
@@ -11,6 +11,7 @@
#include "src/utils/SkUTF.h"
#include <unicode/ubidi.h>
#include <unicode/ubrk.h>
+#include <unicode/uscript.h>
#include <unicode/ustring.h>
#include <unicode/utext.h>
#include <unicode/utypes.h>
@@ -179,6 +180,25 @@
}
};
+class SkScriptIterator_icu : public SkScriptIterator {
+ public:
+ bool getScript(SkUnichar u, ScriptID* script) override {
+ UErrorCode status = U_ZERO_ERROR;
+ UScriptCode scriptCode = uscript_getScript(u, &status);
+ if (U_FAILURE (status)) {
+ return false;
+ }
+ if (script) {
+ *script = (ScriptID)scriptCode;
+ }
+ return true;
+ }
+
+ static std::unique_ptr<SkScriptIterator> makeScriptIterator() {
+ return std::unique_ptr<SkScriptIterator>(new SkScriptIterator_icu());
+ }
+};
+
class SkUnicode_icu : public SkUnicode {
static UBreakIteratorType convertType(BreakType type) {
@@ -376,6 +396,9 @@
BreakType breakType) override {
return SkBreakIterator_icu::makeUtf8BreakIterator(locale, breakType);
}
+ std::unique_ptr<SkScriptIterator> makeScriptIterator() override {
+ return SkScriptIterator_icu::makeScriptIterator();
+ }
// TODO: Use ICU data file to detect controls and whitespaces
bool isControl(SkUnichar utf8) override {