xref: /aosp_15_r20/external/skia/modules/skshaper/src/SkShaper_skunicode.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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