xref: /aosp_15_r20/external/skia/modules/skunicode/include/SkUnicode.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkUnicode_DEFINED
8*c8dee2aaSAndroid Build Coastguard Worker #define SkUnicode_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkUTF.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
17*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
18*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
19*c8dee2aaSAndroid Build Coastguard Worker #include <string>
20*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
21*c8dee2aaSAndroid Build Coastguard Worker namespace sknonstd { template <typename T> struct is_bitmask_enum; }
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SKUNICODE_IMPLEMENTATION)
24*c8dee2aaSAndroid Build Coastguard Worker     #define SKUNICODE_IMPLEMENTATION 0
25*c8dee2aaSAndroid Build Coastguard Worker #endif
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SKUNICODE_API)
28*c8dee2aaSAndroid Build Coastguard Worker     #if defined(SKUNICODE_DLL)
29*c8dee2aaSAndroid Build Coastguard Worker         #if defined(_MSC_VER)
30*c8dee2aaSAndroid Build Coastguard Worker             #if SKUNICODE_IMPLEMENTATION
31*c8dee2aaSAndroid Build Coastguard Worker                 #define SKUNICODE_API __declspec(dllexport)
32*c8dee2aaSAndroid Build Coastguard Worker             #else
33*c8dee2aaSAndroid Build Coastguard Worker                 #define SKUNICODE_API __declspec(dllimport)
34*c8dee2aaSAndroid Build Coastguard Worker             #endif
35*c8dee2aaSAndroid Build Coastguard Worker         #else
36*c8dee2aaSAndroid Build Coastguard Worker             #define SKUNICODE_API __attribute__((visibility("default")))
37*c8dee2aaSAndroid Build Coastguard Worker         #endif
38*c8dee2aaSAndroid Build Coastguard Worker     #else
39*c8dee2aaSAndroid Build Coastguard Worker         #define SKUNICODE_API
40*c8dee2aaSAndroid Build Coastguard Worker     #endif
41*c8dee2aaSAndroid Build Coastguard Worker #endif
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker class SKUNICODE_API SkBidiIterator {
44*c8dee2aaSAndroid Build Coastguard Worker public:
45*c8dee2aaSAndroid Build Coastguard Worker     typedef int32_t Position;
46*c8dee2aaSAndroid Build Coastguard Worker     typedef uint8_t Level;
47*c8dee2aaSAndroid Build Coastguard Worker     struct Region {
RegionRegion48*c8dee2aaSAndroid Build Coastguard Worker         Region(Position start, Position end, Level level)
49*c8dee2aaSAndroid Build Coastguard Worker             : start(start), end(end), level(level) { }
50*c8dee2aaSAndroid Build Coastguard Worker         Position start;
51*c8dee2aaSAndroid Build Coastguard Worker         Position end;
52*c8dee2aaSAndroid Build Coastguard Worker         Level level;
53*c8dee2aaSAndroid Build Coastguard Worker     };
54*c8dee2aaSAndroid Build Coastguard Worker     enum Direction {
55*c8dee2aaSAndroid Build Coastguard Worker         kLTR,
56*c8dee2aaSAndroid Build Coastguard Worker         kRTL,
57*c8dee2aaSAndroid Build Coastguard Worker     };
58*c8dee2aaSAndroid Build Coastguard Worker     virtual ~SkBidiIterator() = default;
59*c8dee2aaSAndroid Build Coastguard Worker     virtual Position getLength() = 0;
60*c8dee2aaSAndroid Build Coastguard Worker     virtual Level getLevelAt(Position) = 0;
61*c8dee2aaSAndroid Build Coastguard Worker };
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker class SKUNICODE_API SkBreakIterator {
64*c8dee2aaSAndroid Build Coastguard Worker public:
65*c8dee2aaSAndroid Build Coastguard Worker     typedef int32_t Position;
66*c8dee2aaSAndroid Build Coastguard Worker     typedef int32_t Status;
67*c8dee2aaSAndroid Build Coastguard Worker     virtual ~SkBreakIterator() = default;
68*c8dee2aaSAndroid Build Coastguard Worker     virtual Position first() = 0;
69*c8dee2aaSAndroid Build Coastguard Worker     virtual Position current() = 0;
70*c8dee2aaSAndroid Build Coastguard Worker     virtual Position next() = 0;
71*c8dee2aaSAndroid Build Coastguard Worker     virtual Status status() = 0;
72*c8dee2aaSAndroid Build Coastguard Worker     virtual bool isDone() = 0;
73*c8dee2aaSAndroid Build Coastguard Worker     virtual bool setText(const char utftext8[], int utf8Units) = 0;
74*c8dee2aaSAndroid Build Coastguard Worker     virtual bool setText(const char16_t utftext16[], int utf16Units) = 0;
75*c8dee2aaSAndroid Build Coastguard Worker };
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker class SKUNICODE_API SkUnicode : public SkRefCnt {
78*c8dee2aaSAndroid Build Coastguard Worker     public:
79*c8dee2aaSAndroid Build Coastguard Worker         enum CodeUnitFlags {
80*c8dee2aaSAndroid Build Coastguard Worker             kNoCodeUnitFlag = 0x00,
81*c8dee2aaSAndroid Build Coastguard Worker             kPartOfWhiteSpaceBreak = 0x01,
82*c8dee2aaSAndroid Build Coastguard Worker             kGraphemeStart = 0x02,
83*c8dee2aaSAndroid Build Coastguard Worker             kSoftLineBreakBefore = 0x04,
84*c8dee2aaSAndroid Build Coastguard Worker             kHardLineBreakBefore = 0x08,
85*c8dee2aaSAndroid Build Coastguard Worker             kPartOfIntraWordBreak = 0x10,
86*c8dee2aaSAndroid Build Coastguard Worker             kControl = 0x20,
87*c8dee2aaSAndroid Build Coastguard Worker             kTabulation = 0x40,
88*c8dee2aaSAndroid Build Coastguard Worker             kGlyphClusterStart = 0x80,
89*c8dee2aaSAndroid Build Coastguard Worker             kIdeographic = 0x100,
90*c8dee2aaSAndroid Build Coastguard Worker             kEmoji = 0x200,
91*c8dee2aaSAndroid Build Coastguard Worker             kWordBreak = 0x400,
92*c8dee2aaSAndroid Build Coastguard Worker             kSentenceBreak = 0x800,
93*c8dee2aaSAndroid Build Coastguard Worker         };
94*c8dee2aaSAndroid Build Coastguard Worker         enum class TextDirection {
95*c8dee2aaSAndroid Build Coastguard Worker             kLTR,
96*c8dee2aaSAndroid Build Coastguard Worker             kRTL,
97*c8dee2aaSAndroid Build Coastguard Worker         };
98*c8dee2aaSAndroid Build Coastguard Worker         typedef size_t Position;
99*c8dee2aaSAndroid Build Coastguard Worker         typedef uint8_t BidiLevel;
100*c8dee2aaSAndroid Build Coastguard Worker         struct BidiRegion {
BidiRegionBidiRegion101*c8dee2aaSAndroid Build Coastguard Worker             BidiRegion(Position start, Position end, BidiLevel level)
102*c8dee2aaSAndroid Build Coastguard Worker               : start(start), end(end), level(level) { }
103*c8dee2aaSAndroid Build Coastguard Worker             Position start;
104*c8dee2aaSAndroid Build Coastguard Worker             Position end;
105*c8dee2aaSAndroid Build Coastguard Worker             BidiLevel level;
106*c8dee2aaSAndroid Build Coastguard Worker         };
107*c8dee2aaSAndroid Build Coastguard Worker         enum class LineBreakType {
108*c8dee2aaSAndroid Build Coastguard Worker             kSoftLineBreak = 0,
109*c8dee2aaSAndroid Build Coastguard Worker             kHardLineBreak = 100,
110*c8dee2aaSAndroid Build Coastguard Worker         };
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker         enum class BreakType { kWords, kGraphemes, kLines, kSentences };
113*c8dee2aaSAndroid Build Coastguard Worker         struct LineBreakBefore {
LineBreakBeforeLineBreakBefore114*c8dee2aaSAndroid Build Coastguard Worker             LineBreakBefore(Position pos, LineBreakType breakType)
115*c8dee2aaSAndroid Build Coastguard Worker               : pos(pos), breakType(breakType) { }
116*c8dee2aaSAndroid Build Coastguard Worker             Position pos;
117*c8dee2aaSAndroid Build Coastguard Worker             LineBreakType breakType;
118*c8dee2aaSAndroid Build Coastguard Worker         };
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker         ~SkUnicode() override = default;
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker         // deprecated
123*c8dee2aaSAndroid Build Coastguard Worker         virtual SkString toUpper(const SkString&) = 0;
124*c8dee2aaSAndroid Build Coastguard Worker         virtual SkString toUpper(const SkString&, const char* locale) = 0;
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isControl(SkUnichar utf8) = 0;
127*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isWhitespace(SkUnichar utf8) = 0;
128*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isSpace(SkUnichar utf8) = 0;
129*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isTabulation(SkUnichar utf8) = 0;
130*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isHardBreak(SkUnichar utf8) = 0;
131*c8dee2aaSAndroid Build Coastguard Worker         /**
132*c8dee2aaSAndroid Build Coastguard Worker          * Returns if a code point may start an emoji sequence.
133*c8dee2aaSAndroid Build Coastguard Worker          * Returns true for '#', '*', and '0'-'9' since they may start an emoji sequence.
134*c8dee2aaSAndroid Build Coastguard Worker          * To determine if a list of code points begins with an emoji sequence, use
135*c8dee2aaSAndroid Build Coastguard Worker          * getEmojiSequence.
136*c8dee2aaSAndroid Build Coastguard Worker          **/
137*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isEmoji(SkUnichar utf8) = 0;
138*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isEmojiComponent(SkUnichar utf8) = 0;
139*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isEmojiModifierBase(SkUnichar utf8) = 0;
140*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isEmojiModifier(SkUnichar utf8) = 0;
141*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isRegionalIndicator(SkUnichar utf8) = 0;
142*c8dee2aaSAndroid Build Coastguard Worker         virtual bool isIdeographic(SkUnichar utf8) = 0;
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker         // Methods used in SkShaper and SkText
145*c8dee2aaSAndroid Build Coastguard Worker         virtual std::unique_ptr<SkBidiIterator> makeBidiIterator
146*c8dee2aaSAndroid Build Coastguard Worker             (const uint16_t text[], int count, SkBidiIterator::Direction) = 0;
147*c8dee2aaSAndroid Build Coastguard Worker         virtual std::unique_ptr<SkBidiIterator> makeBidiIterator
148*c8dee2aaSAndroid Build Coastguard Worker             (const char text[], int count, SkBidiIterator::Direction) = 0;
149*c8dee2aaSAndroid Build Coastguard Worker         virtual std::unique_ptr<SkBreakIterator> makeBreakIterator
150*c8dee2aaSAndroid Build Coastguard Worker             (const char locale[], BreakType breakType) = 0;
151*c8dee2aaSAndroid Build Coastguard Worker         virtual std::unique_ptr<SkBreakIterator> makeBreakIterator(BreakType type) = 0;
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker         // Methods used in SkParagraph
154*c8dee2aaSAndroid Build Coastguard Worker         static bool hasTabulationFlag(SkUnicode::CodeUnitFlags flags);
155*c8dee2aaSAndroid Build Coastguard Worker         static bool hasHardLineBreakFlag(SkUnicode::CodeUnitFlags flags);
156*c8dee2aaSAndroid Build Coastguard Worker         static bool hasSoftLineBreakFlag(SkUnicode::CodeUnitFlags flags);
157*c8dee2aaSAndroid Build Coastguard Worker         static bool hasGraphemeStartFlag(SkUnicode::CodeUnitFlags flags);
158*c8dee2aaSAndroid Build Coastguard Worker         static bool hasControlFlag(SkUnicode::CodeUnitFlags flags);
159*c8dee2aaSAndroid Build Coastguard Worker         static bool hasPartOfWhiteSpaceBreakFlag(SkUnicode::CodeUnitFlags flags);
160*c8dee2aaSAndroid Build Coastguard Worker 
161*c8dee2aaSAndroid Build Coastguard Worker         static bool extractBidi(const char utf8[],
162*c8dee2aaSAndroid Build Coastguard Worker                                 int utf8Units,
163*c8dee2aaSAndroid Build Coastguard Worker                                 TextDirection dir,
164*c8dee2aaSAndroid Build Coastguard Worker                                 std::vector<BidiRegion>* bidiRegions);
165*c8dee2aaSAndroid Build Coastguard Worker         virtual bool getBidiRegions(const char utf8[],
166*c8dee2aaSAndroid Build Coastguard Worker                                     int utf8Units,
167*c8dee2aaSAndroid Build Coastguard Worker                                     TextDirection dir,
168*c8dee2aaSAndroid Build Coastguard Worker                                     std::vector<BidiRegion>* results) = 0;
169*c8dee2aaSAndroid Build Coastguard Worker         // Returns results in utf16
170*c8dee2aaSAndroid Build Coastguard Worker         virtual bool getWords(const char utf8[], int utf8Units, const char* locale,
171*c8dee2aaSAndroid Build Coastguard Worker                               std::vector<Position>* results) = 0;
172*c8dee2aaSAndroid Build Coastguard Worker         virtual bool getUtf8Words(const char utf8[],
173*c8dee2aaSAndroid Build Coastguard Worker                                   int utf8Units,
174*c8dee2aaSAndroid Build Coastguard Worker                                   const char* locale,
175*c8dee2aaSAndroid Build Coastguard Worker                                   std::vector<Position>* results) = 0;
176*c8dee2aaSAndroid Build Coastguard Worker         virtual bool getSentences(const char utf8[],
177*c8dee2aaSAndroid Build Coastguard Worker                                   int utf8Units,
178*c8dee2aaSAndroid Build Coastguard Worker                                   const char* locale,
179*c8dee2aaSAndroid Build Coastguard Worker                                   std::vector<Position>* results) = 0;
180*c8dee2aaSAndroid Build Coastguard Worker         virtual bool computeCodeUnitFlags(
181*c8dee2aaSAndroid Build Coastguard Worker                 char utf8[], int utf8Units, bool replaceTabs,
182*c8dee2aaSAndroid Build Coastguard Worker                 skia_private::TArray<SkUnicode::CodeUnitFlags, true>* results) = 0;
183*c8dee2aaSAndroid Build Coastguard Worker         virtual bool computeCodeUnitFlags(
184*c8dee2aaSAndroid Build Coastguard Worker                 char16_t utf16[], int utf16Units, bool replaceTabs,
185*c8dee2aaSAndroid Build Coastguard Worker                 skia_private::TArray<SkUnicode::CodeUnitFlags, true>* results) = 0;
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker         static SkString convertUtf16ToUtf8(const char16_t * utf16, int utf16Units);
188*c8dee2aaSAndroid Build Coastguard Worker         static SkString convertUtf16ToUtf8(const std::u16string& utf16);
189*c8dee2aaSAndroid Build Coastguard Worker         static std::u16string convertUtf8ToUtf16(const char* utf8, int utf8Units);
190*c8dee2aaSAndroid Build Coastguard Worker         static std::u16string convertUtf8ToUtf16(const SkString& utf8);
191*c8dee2aaSAndroid Build Coastguard Worker 
192*c8dee2aaSAndroid Build Coastguard Worker         template <typename Appender8, typename Appender16>
extractUtfConversionMapping(SkSpan<const char> utf8,Appender8 && appender8,Appender16 && appender16)193*c8dee2aaSAndroid Build Coastguard Worker         static bool extractUtfConversionMapping(SkSpan<const char> utf8, Appender8&& appender8, Appender16&& appender16) {
194*c8dee2aaSAndroid Build Coastguard Worker             size_t size8 = 0;
195*c8dee2aaSAndroid Build Coastguard Worker             size_t size16 = 0;
196*c8dee2aaSAndroid Build Coastguard Worker             auto ptr = utf8.begin();
197*c8dee2aaSAndroid Build Coastguard Worker             auto end = utf8.end();
198*c8dee2aaSAndroid Build Coastguard Worker             while (ptr < end) {
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker                 size_t index = SkToSizeT(ptr - utf8.begin());
201*c8dee2aaSAndroid Build Coastguard Worker                 SkUnichar u = SkUTF::NextUTF8(&ptr, end);
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker                 // All UTF8 code units refer to the same codepoint
204*c8dee2aaSAndroid Build Coastguard Worker                 size_t next = SkToSizeT(ptr - utf8.begin());
205*c8dee2aaSAndroid Build Coastguard Worker                 for (auto i = index; i < next; ++i) {
206*c8dee2aaSAndroid Build Coastguard Worker                     //fUTF16IndexForUTF8Index.emplace_back(fUTF8IndexForUTF16Index.size());
207*c8dee2aaSAndroid Build Coastguard Worker                     appender16(size8);
208*c8dee2aaSAndroid Build Coastguard Worker                     ++size16;
209*c8dee2aaSAndroid Build Coastguard Worker                 }
210*c8dee2aaSAndroid Build Coastguard Worker                 //SkASSERT(fUTF16IndexForUTF8Index.size() == next);
211*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(size16 == next);
212*c8dee2aaSAndroid Build Coastguard Worker                 if (size16 != next) {
213*c8dee2aaSAndroid Build Coastguard Worker                     return false;
214*c8dee2aaSAndroid Build Coastguard Worker                 }
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker                 // One or two UTF16 code units refer to the same codepoint
217*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t buffer[2];
218*c8dee2aaSAndroid Build Coastguard Worker                 size_t count = SkUTF::ToUTF16(u, buffer);
219*c8dee2aaSAndroid Build Coastguard Worker                 //fUTF8IndexForUTF16Index.emplace_back(index);
220*c8dee2aaSAndroid Build Coastguard Worker                 appender8(index);
221*c8dee2aaSAndroid Build Coastguard Worker                 ++size8;
222*c8dee2aaSAndroid Build Coastguard Worker                 if (count > 1) {
223*c8dee2aaSAndroid Build Coastguard Worker                     //fUTF8IndexForUTF16Index.emplace_back(index);
224*c8dee2aaSAndroid Build Coastguard Worker                     appender8(index);
225*c8dee2aaSAndroid Build Coastguard Worker                     ++size8;
226*c8dee2aaSAndroid Build Coastguard Worker                 }
227*c8dee2aaSAndroid Build Coastguard Worker             }
228*c8dee2aaSAndroid Build Coastguard Worker             //fUTF16IndexForUTF8Index.emplace_back(fUTF8IndexForUTF16Index.size());
229*c8dee2aaSAndroid Build Coastguard Worker             appender16(size8);
230*c8dee2aaSAndroid Build Coastguard Worker             ++size16;
231*c8dee2aaSAndroid Build Coastguard Worker             //fUTF8IndexForUTF16Index.emplace_back(fText.size());
232*c8dee2aaSAndroid Build Coastguard Worker             appender8(utf8.size());
233*c8dee2aaSAndroid Build Coastguard Worker             ++size8;
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker             return true;
236*c8dee2aaSAndroid Build Coastguard Worker         }
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker         template <typename Callback>
forEachCodepoint(const char * utf8,int32_t utf8Units,Callback && callback)239*c8dee2aaSAndroid Build Coastguard Worker         void forEachCodepoint(const char* utf8, int32_t utf8Units, Callback&& callback) {
240*c8dee2aaSAndroid Build Coastguard Worker             const char* current = utf8;
241*c8dee2aaSAndroid Build Coastguard Worker             const char* end = utf8 + utf8Units;
242*c8dee2aaSAndroid Build Coastguard Worker             while (current < end) {
243*c8dee2aaSAndroid Build Coastguard Worker                 auto before = current - utf8;
244*c8dee2aaSAndroid Build Coastguard Worker                 SkUnichar unichar = SkUTF::NextUTF8(&current, end);
245*c8dee2aaSAndroid Build Coastguard Worker                 if (unichar < 0) unichar = 0xFFFD;
246*c8dee2aaSAndroid Build Coastguard Worker                 auto after = current - utf8;
247*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t buffer[2];
248*c8dee2aaSAndroid Build Coastguard Worker                 size_t count = SkUTF::ToUTF16(unichar, buffer);
249*c8dee2aaSAndroid Build Coastguard Worker                 callback(unichar, before, after, count);
250*c8dee2aaSAndroid Build Coastguard Worker             }
251*c8dee2aaSAndroid Build Coastguard Worker         }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker         template <typename Callback>
forEachCodepoint(const char16_t * utf16,int32_t utf16Units,Callback && callback)254*c8dee2aaSAndroid Build Coastguard Worker         void forEachCodepoint(const char16_t* utf16, int32_t utf16Units, Callback&& callback) {
255*c8dee2aaSAndroid Build Coastguard Worker             const char16_t* current = utf16;
256*c8dee2aaSAndroid Build Coastguard Worker             const char16_t* end = utf16 + utf16Units;
257*c8dee2aaSAndroid Build Coastguard Worker             while (current < end) {
258*c8dee2aaSAndroid Build Coastguard Worker                 auto before = current - utf16;
259*c8dee2aaSAndroid Build Coastguard Worker                 SkUnichar unichar = SkUTF::NextUTF16((const uint16_t**)&current, (const uint16_t*)end);
260*c8dee2aaSAndroid Build Coastguard Worker                 auto after = current - utf16;
261*c8dee2aaSAndroid Build Coastguard Worker                 callback(unichar, before, after);
262*c8dee2aaSAndroid Build Coastguard Worker             }
263*c8dee2aaSAndroid Build Coastguard Worker         }
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker         template <typename Callback>
forEachBidiRegion(const uint16_t utf16[],int utf16Units,SkBidiIterator::Direction dir,Callback && callback)266*c8dee2aaSAndroid Build Coastguard Worker         void forEachBidiRegion(const uint16_t utf16[], int utf16Units, SkBidiIterator::Direction dir, Callback&& callback) {
267*c8dee2aaSAndroid Build Coastguard Worker             auto iter = makeBidiIterator(utf16, utf16Units, dir);
268*c8dee2aaSAndroid Build Coastguard Worker             const uint16_t* start16 = utf16;
269*c8dee2aaSAndroid Build Coastguard Worker             const uint16_t* end16 = utf16 + utf16Units;
270*c8dee2aaSAndroid Build Coastguard Worker             SkBidiIterator::Level currentLevel = 0;
271*c8dee2aaSAndroid Build Coastguard Worker 
272*c8dee2aaSAndroid Build Coastguard Worker             SkBidiIterator::Position pos16 = 0;
273*c8dee2aaSAndroid Build Coastguard Worker             while (pos16 <= iter->getLength()) {
274*c8dee2aaSAndroid Build Coastguard Worker                 auto level = iter->getLevelAt(pos16);
275*c8dee2aaSAndroid Build Coastguard Worker                 if (pos16 == 0) {
276*c8dee2aaSAndroid Build Coastguard Worker                     currentLevel = level;
277*c8dee2aaSAndroid Build Coastguard Worker                 } else if (level != currentLevel) {
278*c8dee2aaSAndroid Build Coastguard Worker                     callback(pos16, start16 - utf16, currentLevel);
279*c8dee2aaSAndroid Build Coastguard Worker                     currentLevel = level;
280*c8dee2aaSAndroid Build Coastguard Worker                 }
281*c8dee2aaSAndroid Build Coastguard Worker                 if (start16 == end16) {
282*c8dee2aaSAndroid Build Coastguard Worker                     break;
283*c8dee2aaSAndroid Build Coastguard Worker                 }
284*c8dee2aaSAndroid Build Coastguard Worker                 SkUnichar u = SkUTF::NextUTF16(&start16, end16);
285*c8dee2aaSAndroid Build Coastguard Worker                 pos16 += SkUTF::ToUTF16(u);
286*c8dee2aaSAndroid Build Coastguard Worker             }
287*c8dee2aaSAndroid Build Coastguard Worker         }
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker         template <typename Callback>
forEachBreak(const char16_t utf16[],int utf16Units,SkUnicode::BreakType type,Callback && callback)290*c8dee2aaSAndroid Build Coastguard Worker         void forEachBreak(const char16_t utf16[], int utf16Units, SkUnicode::BreakType type, Callback&& callback) {
291*c8dee2aaSAndroid Build Coastguard Worker             auto iter = makeBreakIterator(type);
292*c8dee2aaSAndroid Build Coastguard Worker             iter->setText(utf16, utf16Units);
293*c8dee2aaSAndroid Build Coastguard Worker             auto pos = iter->first();
294*c8dee2aaSAndroid Build Coastguard Worker             do {
295*c8dee2aaSAndroid Build Coastguard Worker                 callback(pos, iter->status());
296*c8dee2aaSAndroid Build Coastguard Worker                 pos = iter->next();
297*c8dee2aaSAndroid Build Coastguard Worker             } while (!iter->isDone());
298*c8dee2aaSAndroid Build Coastguard Worker         }
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker         virtual void reorderVisual(const BidiLevel runLevels[], int levelsCount, int32_t logicalFromVisual[]) = 0;
301*c8dee2aaSAndroid Build Coastguard Worker };
302*c8dee2aaSAndroid Build Coastguard Worker 
303*c8dee2aaSAndroid Build Coastguard Worker namespace sknonstd {
304*c8dee2aaSAndroid Build Coastguard Worker template <> struct is_bitmask_enum<SkUnicode::CodeUnitFlags> : std::true_type {};
305*c8dee2aaSAndroid Build Coastguard Worker }  // namespace sknonstd
306*c8dee2aaSAndroid Build Coastguard Worker 
307*c8dee2aaSAndroid Build Coastguard Worker #endif // SkUnicode_DEFINED
308