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