Flutter Engine
The Flutter Engine
SkShaper_skunicode.cpp
Go to the documentation of this file.
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 */
14#include "src/base/SkUTF.h"
15
16#include <cstddef>
17#include <cstdint>
18#include <memory>
19#include <utility>
20
21using SkUnicodeBidi = std::unique_ptr<SkBidiIterator>;
22
23/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
24static 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
30public:
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
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);
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 }
57 size_t endOfCurrentRun() const override {
58 return fEndOfCurrentRun - fBegin;
59 }
60 bool atEnd() const override {
61 return fUTF16LogicalPosition == fBidi->getLength();
62 }
64 return fLevel;
65 }
66private:
67 SkUnicodeBidi fBidi;
68 char const * fEndOfCurrentRun;
69 char const * const fBegin;
70 char const * const fEnd;
71 int32_t fUTF16LogicalPosition;
73};
74
75#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
76
77#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
79#endif
80
81#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
83#endif
84
85#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
87#endif
88
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)
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
108std::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
119namespace SkShapers::unicode {
120std::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
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkDEBUGF(...)
Definition: SkDebug.h:24
std::unique_ptr< SkBidiIterator > SkUnicodeBidi
sk_sp< SkUnicode > get_unicode()
static SkUnichar utf8_next(const char **ptr, const char *end)
int32_t SkUnichar
Definition: SkTypes.h:175
uint8_t Level
Definition: SkUnicode.h:46
size_t endOfCurrentRun() const override
SkUnicodeBidiRunIterator(const char *utf8, const char *end, SkUnicodeBidi bidi)
SkBidiIterator::Level currentLevel() const override
bool atEnd() const override
glong glong end
SKSHAPER_API std::unique_ptr< SkShaper::BiDiRunIterator > BidiRunIterator(sk_sp< SkUnicode > unicode, const char *utf8, size_t utf8Bytes, uint8_t bidiLevel)
SK_SPI int UTF8ToUTF16(uint16_t dst[], int dstCapacity, const char src[], size_t srcByteLength)
Definition: SkUTF.cpp:259
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition: SkUTF.cpp:118
SK_SPI size_t ToUTF16(SkUnichar uni, uint16_t utf16[2]=nullptr)
Definition: SkUTF.cpp:243
SKUNICODE_API sk_sp< SkUnicode > Make()
SKUNICODE_API sk_sp< SkUnicode > Make()
SKUNICODE_API sk_sp< SkUnicode > Make()
Definition: ref_ptr.h:256