• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 #ifndef SkUnicode_DEFINED
8 #define SkUnicode_DEFINED
9 
10 #include "include/core/SkSpan.h"
11 #include "include/core/SkTypes.h"
12 #include "src/utils/SkUTF.h"
13 #include <vector>
14 
15 #if !defined(SKUNICODE_IMPLEMENTATION)
16     #define SKUNICODE_IMPLEMENTATION 0
17 #endif
18 
19 #if !defined(SKUNICODE_API)
20     #if defined(SKUNICODE_DLL)
21         #if defined(_MSC_VER)
22             #if SKUNICODE_IMPLEMENTATION
23                 #define SKUNICODE_API __declspec(dllexport)
24             #else
25                 #define SKUNICODE_API __declspec(dllimport)
26             #endif
27         #else
28             #define SKUNICODE_API __attribute__((visibility("default")))
29         #endif
30     #else
31         #define SKUNICODE_API
32     #endif
33 #endif
34 
35 class SKUNICODE_API SkBidiIterator {
36 public:
37     typedef int32_t Position;
38     typedef uint8_t Level;
39     struct Region {
RegionRegion40         Region(Position start, Position end, Level level)
41             : start(start), end(end), level(level) { }
42         Position start;
43         Position end;
44         Level level;
45     };
46     enum Direction {
47         kLTR,
48         kRTL,
49     };
50     virtual ~SkBidiIterator() = default;
51     virtual Position getLength() = 0;
52     virtual Level getLevelAt(Position) = 0;
53     static void ReorderVisual(const Level runLevels[], int levelsCount, int32_t logicalFromVisual[]);
54 };
55 
56 class SKUNICODE_API SkBreakIterator {
57 public:
58     typedef int32_t Position;
59     typedef int32_t Status;
60     virtual ~SkBreakIterator() = default;
61     virtual Position first() = 0;
62     virtual Position current() = 0;
63     virtual Position next() = 0;
64     virtual Position preceding(Position offset) = 0;
65     virtual Position following(Position offset) = 0;
66     virtual Status status() = 0;
67     virtual bool isDone() = 0;
68     virtual bool setText(const char utftext8[], int utf8Units) = 0;
69     virtual bool setText(const char16_t utftext16[], int utf16Units) = 0;
70 };
71 
72 class SKUNICODE_API SkScriptIterator {
73  public:
74     typedef uint32_t ScriptID;
75     virtual ~SkScriptIterator() = default;
76     virtual bool getScript(SkUnichar u, ScriptID* script) = 0;
77 };
78 
79 class SKUNICODE_API SkUnicode {
80     public:
81         typedef uint32_t CombiningClass;
82         typedef uint32_t GeneralCategory;
83         enum class TextDirection {
84             kLTR,
85             kRTL,
86         };
87         typedef size_t Position;
88         typedef uint8_t BidiLevel;
89         struct BidiRegion {
BidiRegionBidiRegion90             BidiRegion(Position start, Position end, BidiLevel level)
91               : start(start), end(end), level(level) { }
92             Position start;
93             Position end;
94             BidiLevel level;
95         };
96         enum class LineBreakType {
97             kSoftLineBreak = 0,
98             kHardLineBreak = 100,
99         };
100 
101         enum class BreakType {
102             kWords,
103             kGraphemes,
104             kLines
105         };
106         struct LineBreakBefore {
LineBreakBeforeLineBreakBefore107             LineBreakBefore(Position pos, LineBreakType breakType)
108               : pos(pos), breakType(breakType) { }
109             Position pos;
110             LineBreakType breakType;
111         };
112 
113         virtual ~SkUnicode() = default;
114 
115         virtual bool isControl(SkUnichar utf8) = 0;
116         virtual bool isWhitespace(SkUnichar utf8) = 0;
117         virtual bool isSpace(SkUnichar utf8) = 0;
118         virtual SkString toUpper(const SkString&) = 0;
119 
120         // Methods used in SkShaper and SkText
121         virtual std::unique_ptr<SkBidiIterator> makeBidiIterator
122             (const uint16_t text[], int count, SkBidiIterator::Direction) = 0;
123         virtual std::unique_ptr<SkBidiIterator> makeBidiIterator
124             (const char text[], int count, SkBidiIterator::Direction) = 0;
125         virtual std::unique_ptr<SkBreakIterator> makeBreakIterator
126             (const char locale[], BreakType breakType) = 0;
127         virtual std::unique_ptr<SkBreakIterator> makeBreakIterator(BreakType type) = 0;
128         virtual std::unique_ptr<SkScriptIterator> makeScriptIterator() = 0;
129 
130         // High level methods (that we actually use somewhere=SkParagraph)
131         virtual bool getBidiRegions
132                (const char utf8[], int utf8Units, TextDirection dir, std::vector<BidiRegion>* results) = 0;
133         virtual bool getLineBreaks
134                (const char utf8[], int utf8Units, std::vector<LineBreakBefore>* results) = 0;
135         virtual bool getWords
136                (const char utf8[], int utf8Units, std::vector<Position>* results) = 0;
137         virtual bool getGraphemes
138                (const char utf8[], int utf8Units, std::vector<Position>* results) = 0;
139 
convertUtf16ToUtf8(const char16_t * utf16,int utf16Units)140         static SkString convertUtf16ToUtf8(const char16_t * utf16, int utf16Units) {
141 
142             int utf8Units = SkUTF::UTF16ToUTF8(nullptr, 0, (uint16_t*)utf16, utf16Units);
143             if (utf8Units < 0) {
144                 SkDEBUGF("Convert error: Invalid utf16 input");
145                 return SkString();
146             }
147             SkAutoTArray<char> utf8(utf8Units);
148             SkDEBUGCODE(int dstLen =) SkUTF::UTF16ToUTF8(utf8.data(), utf8Units, (uint16_t*)utf16, utf16Units);
149             SkASSERT(dstLen == utf8Units);
150 
151             return SkString(utf8.data(), utf8Units);
152         }
153 
convertUtf16ToUtf8(const std::u16string & utf16)154         static SkString convertUtf16ToUtf8(const std::u16string& utf16) {
155             return convertUtf16ToUtf8(utf16.c_str(), utf16.size());
156         }
157 
convertUtf8ToUtf16(const char * utf8,int utf8Units)158         static std::u16string convertUtf8ToUtf16(const char* utf8, int utf8Units) {
159 
160             int utf16Units = SkUTF::UTF8ToUTF16(nullptr, 0, utf8, utf8Units);
161             if (utf16Units < 0) {
162                 SkDEBUGF("Convert error: Invalid utf8 input");
163                 return std::u16string();
164             }
165 
166             SkAutoTArray<uint16_t> utf16(utf16Units);
167             SkDEBUGCODE(int dstLen =) SkUTF::UTF8ToUTF16(utf16.data(), utf16Units, utf8, utf8Units);
168             SkASSERT(dstLen == utf16Units);
169 
170             return std::u16string((char16_t *)utf16.data(), utf16Units);
171         }
172 
convertUtf8ToUtf16(const SkString & utf8)173         static std::u16string convertUtf8ToUtf16(const SkString& utf8) {
174             return convertUtf8ToUtf16(utf8.c_str(), utf8.size());
175         }
176 
177         template <typename Callback>
forEachCodepoint(const char * utf8,int32_t utf8Units,Callback && callback)178         void forEachCodepoint(const char* utf8, int32_t utf8Units, Callback&& callback) {
179             const char* current = utf8;
180             const char* end = utf8 + utf8Units;
181             while (current < end) {
182                 auto before = current - utf8;
183                 SkUnichar unichar = SkUTF::NextUTF8(&current, end);
184                 if (unichar < 0) unichar = 0xFFFD;
185                 auto after = current - utf8;
186                 uint16_t buffer[2];
187                 size_t count = SkUTF::ToUTF16(unichar, buffer);
188                 callback(unichar, before, after, count);
189             }
190         }
191 
192         template <typename Callback>
forEachCodepoint(const char16_t * utf16,int32_t utf16Units,Callback && callback)193         void forEachCodepoint(const char16_t* utf16, int32_t utf16Units, Callback&& callback) {
194             const char16_t* current = utf16;
195             const char16_t* end = utf16 + utf16Units;
196             while (current < end) {
197                 auto before = current - utf16;
198                 SkUnichar unichar = SkUTF::NextUTF16((const uint16_t**)&current, (const uint16_t*)end);
199                 auto after = current - utf16;
200                 callback(unichar, before, after);
201             }
202         }
203 
204         template <typename Callback>
forEachBidiRegion(const uint16_t utf16[],int utf16Units,SkBidiIterator::Direction dir,Callback && callback)205         void forEachBidiRegion(const uint16_t utf16[], int utf16Units, SkBidiIterator::Direction dir, Callback&& callback) {
206             auto iter = makeBidiIterator(utf16, utf16Units, dir);
207             const uint16_t* start16 = utf16;
208             const uint16_t* end16 = utf16 + utf16Units;
209             SkBidiIterator::Level currentLevel = 0;
210 
211             SkBidiIterator::Position pos16 = 0;
212             while (pos16 <= iter->getLength()) {
213                 auto level = iter->getLevelAt(pos16);
214                 if (pos16 == 0) {
215                     currentLevel = level;
216                 } else if (level != currentLevel) {
217                     callback(pos16, start16 - utf16, currentLevel);
218                     currentLevel = level;
219                 }
220                 if (start16 == end16) {
221                     break;
222                 }
223                 SkUnichar u = SkUTF::NextUTF16(&start16, end16);
224                 pos16 += SkUTF::ToUTF16(u);
225             }
226         }
227 
228         template <typename Callback>
forEachBreak(const char16_t utf16[],int utf16Units,SkUnicode::BreakType type,Callback && callback)229         void forEachBreak(const char16_t utf16[], int utf16Units, SkUnicode::BreakType type, Callback&& callback) {
230             auto iter = makeBreakIterator(type);
231             iter->setText(utf16, utf16Units);
232             auto pos = iter->first();
233             do {
234                 callback(pos, iter->status());
235                 pos = iter->next();
236             } while (!iter->isDone());
237         }
238 
239         virtual void reorderVisual(const BidiLevel runLevels[], int levelsCount, int32_t logicalFromVisual[]) = 0;
240 
241         static std::unique_ptr<SkUnicode> Make();
242 };
243 
244 #endif // SkUnicode_DEFINED
245