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(¤t, 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**)¤t, (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