1 /*
2 * Copyright 2023 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 #include "include/core/SkRefCnt.h"
8 #include "include/private/base/SkAssert.h"
9 #include "include/private/base/SkDebug.h"
10 #include "include/private/base/SkTFitsIn.h"
11 #include "modules/skshaper/include/SkShaper.h"
12 #include "modules/skshaper/include/SkShaper_skunicode.h"
13 #include "modules/skunicode/include/SkUnicode.h"
14 #include "src/base/SkUTF.h"
15
16 #include <cstddef>
17 #include <cstdint>
18 #include <memory>
19 #include <utility>
20
21 using SkUnicodeBidi = std::unique_ptr<SkBidiIterator>;
22
23 /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
utf8_next(const char ** ptr,const char * end)24 static inline SkUnichar utf8_next(const char** ptr, const char* end) {
25 SkUnichar val = SkUTF::NextUTF8(ptr, end);
26 return val < 0 ? 0xFFFD : val;
27 }
28
29 class SkUnicodeBidiRunIterator final : public SkShaper::BiDiRunIterator {
30 public:
SkUnicodeBidiRunIterator(const char * utf8,const char * end,SkUnicodeBidi bidi)31 SkUnicodeBidiRunIterator(const char* utf8, const char* end, SkUnicodeBidi bidi)
32 : fBidi(std::move(bidi))
33 , fEndOfCurrentRun(utf8)
34 , fBegin(utf8)
35 , fEnd(end)
36 , fUTF16LogicalPosition(0)
37 , fLevel(SkBidiIterator::kLTR)
38 {}
39
consume()40 void consume() override {
41 SkASSERT(fUTF16LogicalPosition < fBidi->getLength());
42 int32_t endPosition = fBidi->getLength();
43 fLevel = fBidi->getLevelAt(fUTF16LogicalPosition);
44 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEnd);
45 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
46 SkBidiIterator::Level level;
47 while (fUTF16LogicalPosition < endPosition) {
48 level = fBidi->getLevelAt(fUTF16LogicalPosition);
49 if (level != fLevel) {
50 break;
51 }
52 u = utf8_next(&fEndOfCurrentRun, fEnd);
53
54 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
55 }
56 }
endOfCurrentRun() const57 size_t endOfCurrentRun() const override {
58 return fEndOfCurrentRun - fBegin;
59 }
atEnd() const60 bool atEnd() const override {
61 return fUTF16LogicalPosition == fBidi->getLength();
62 }
currentLevel() const63 SkBidiIterator::Level currentLevel() const override {
64 return fLevel;
65 }
66 private:
67 SkUnicodeBidi fBidi;
68 char const * fEndOfCurrentRun;
69 char const * const fBegin;
70 char const * const fEnd;
71 int32_t fUTF16LogicalPosition;
72 SkBidiIterator::Level fLevel;
73 };
74
75 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
76
77 #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
78 #include "modules/skunicode/include/SkUnicode_icu.h"
79 #endif
80
81 #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
82 #include "modules/skunicode/include/SkUnicode_libgrapheme.h"
83 #endif
84
85 #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
86 #include "modules/skunicode/include/SkUnicode_icu4x.h"
87 #endif
88
get_unicode()89 sk_sp<SkUnicode> get_unicode() {
90 #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
91 if (auto unicode = SkUnicodes::ICU::Make()) {
92 return unicode;
93 }
94 #endif // defined(SK_UNICODE_ICU_IMPLEMENTATION)
95 #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
96 if (auto unicode = SkUnicodes::Libgrapheme::Make()) {
97 return unicode;
98 }
99 #endif
100 #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
101 if (auto unicode = SkUnicodes::ICU4X::Make()) {
102 return unicode;
103 }
104 #endif
105 return nullptr;
106 }
107
MakeIcuBiDiRunIterator(const char * utf8,size_t utf8Bytes,uint8_t bidiLevel)108 std::unique_ptr<SkShaper::BiDiRunIterator> SkShaper::MakeIcuBiDiRunIterator(const char* utf8,
109 size_t utf8Bytes,
110 uint8_t bidiLevel) {
111 static auto unicode = get_unicode();
112 if (!unicode) {
113 return nullptr;
114 }
115 return SkShapers::unicode::BidiRunIterator(unicode, utf8, utf8Bytes, bidiLevel);
116 }
117 #endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
118
119 namespace SkShapers::unicode {
BidiRunIterator(sk_sp<SkUnicode> unicode,const char * utf8,size_t utf8Bytes,uint8_t bidiLevel)120 std::unique_ptr<SkShaper::BiDiRunIterator> BidiRunIterator(sk_sp<SkUnicode> unicode,
121 const char* utf8,
122 size_t utf8Bytes,
123 uint8_t bidiLevel) {
124 if (!unicode) {
125 return nullptr;
126 }
127 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
128 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
129 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
130 SkDEBUGF("Bidi error: text too long");
131 return nullptr;
132 }
133
134 int32_t utf16Units = SkUTF::UTF8ToUTF16(nullptr, 0, utf8, utf8Bytes);
135 if (utf16Units < 0) {
136 SkDEBUGF("Invalid utf8 input\n");
137 return nullptr;
138 }
139
140 std::unique_ptr<uint16_t[]> utf16(new uint16_t[utf16Units]);
141 (void)SkUTF::UTF8ToUTF16(utf16.get(), utf16Units, utf8, utf8Bytes);
142
143 auto bidiDir = (bidiLevel % 2 == 0) ? SkBidiIterator::kLTR : SkBidiIterator::kRTL;
144 SkUnicodeBidi bidi = unicode->makeBidiIterator(utf16.get(), utf16Units, bidiDir);
145 if (!bidi) {
146 SkDEBUGF("Bidi error\n");
147 return nullptr;
148 }
149
150 return std::make_unique<SkUnicodeBidiRunIterator>(utf8, utf8 + utf8Bytes, std::move(bidi));
151 }
152 } // namespace SkShapers::unicode
153