/* * Copyright 2020 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkUnicode_DEFINED #define SkUnicode_DEFINED #include "include/core/SkSpan.h" #include "include/core/SkTypes.h" #include "src/utils/SkUTF.h" #include #if !defined(SKUNICODE_IMPLEMENTATION) #define SKUNICODE_IMPLEMENTATION 0 #endif #if !defined(SKUNICODE_API) #if defined(SKUNICODE_DLL) #if defined(_MSC_VER) #if SKUNICODE_IMPLEMENTATION #define SKUNICODE_API __declspec(dllexport) #else #define SKUNICODE_API __declspec(dllimport) #endif #else #define SKUNICODE_API __attribute__((visibility("default"))) #endif #else #define SKUNICODE_API #endif #endif class SKUNICODE_API SkBidiIterator { public: typedef int32_t Position; typedef uint8_t Level; struct Region { Region(Position start, Position end, Level level) : start(start), end(end), level(level) { } Position start; Position end; Level level; }; enum Direction { kLTR, kRTL, }; virtual ~SkBidiIterator() = default; virtual Position getLength() = 0; virtual Level getLevelAt(Position) = 0; static void ReorderVisual(const Level runLevels[], int levelsCount, int32_t logicalFromVisual[]); }; class SKUNICODE_API SkBreakIterator { public: typedef int32_t Position; typedef int32_t Status; virtual ~SkBreakIterator() = default; virtual Position first() = 0; virtual Position current() = 0; virtual Position next() = 0; virtual Position preceding(Position offset) = 0; virtual Position following(Position offset) = 0; virtual Status status() = 0; virtual bool isDone() = 0; virtual bool setText(const char utftext8[], int utf8Units) = 0; virtual bool setText(const char16_t utftext16[], int utf16Units) = 0; }; class SKUNICODE_API SkScriptIterator { public: typedef uint32_t ScriptID; virtual ~SkScriptIterator() = default; virtual bool getScript(SkUnichar u, ScriptID* script) = 0; }; class SKUNICODE_API SkUnicode { public: typedef uint32_t CombiningClass; typedef uint32_t GeneralCategory; enum class TextDirection { kLTR, kRTL, }; typedef size_t Position; typedef uint8_t BidiLevel; struct BidiRegion { BidiRegion(Position start, Position end, BidiLevel level) : start(start), end(end), level(level) { } Position start; Position end; BidiLevel level; }; enum class LineBreakType { kSoftLineBreak = 0, kHardLineBreak = 100, }; enum class BreakType { kWords, kGraphemes, kLines }; struct LineBreakBefore { LineBreakBefore(Position pos, LineBreakType breakType) : pos(pos), breakType(breakType) { } Position pos; LineBreakType breakType; }; virtual ~SkUnicode() = default; virtual bool isControl(SkUnichar utf8) = 0; virtual bool isWhitespace(SkUnichar utf8) = 0; virtual bool isSpace(SkUnichar utf8) = 0; virtual SkString toUpper(const SkString&) = 0; // Methods used in SkShaper and SkText virtual std::unique_ptr makeBidiIterator (const uint16_t text[], int count, SkBidiIterator::Direction) = 0; virtual std::unique_ptr makeBidiIterator (const char text[], int count, SkBidiIterator::Direction) = 0; virtual std::unique_ptr makeBreakIterator (const char locale[], BreakType breakType) = 0; virtual std::unique_ptr makeBreakIterator(BreakType type) = 0; virtual std::unique_ptr makeScriptIterator() = 0; // High level methods (that we actually use somewhere=SkParagraph) virtual bool getBidiRegions (const char utf8[], int utf8Units, TextDirection dir, std::vector* results) = 0; virtual bool getLineBreaks (const char utf8[], int utf8Units, std::vector* results) = 0; virtual bool getWords (const char utf8[], int utf8Units, std::vector* results) = 0; virtual bool getGraphemes (const char utf8[], int utf8Units, std::vector* results) = 0; static SkString convertUtf16ToUtf8(const char16_t * utf16, int utf16Units) { int utf8Units = SkUTF::UTF16ToUTF8(nullptr, 0, (uint16_t*)utf16, utf16Units); if (utf8Units < 0) { SkDEBUGF("Convert error: Invalid utf16 input"); return SkString(); } SkAutoTArray utf8(utf8Units); SkDEBUGCODE(int dstLen =) SkUTF::UTF16ToUTF8(utf8.data(), utf8Units, (uint16_t*)utf16, utf16Units); SkASSERT(dstLen == utf8Units); return SkString(utf8.data(), utf8Units); } static SkString convertUtf16ToUtf8(const std::u16string& utf16) { return convertUtf16ToUtf8(utf16.c_str(), utf16.size()); } static std::u16string convertUtf8ToUtf16(const char* utf8, int utf8Units) { int utf16Units = SkUTF::UTF8ToUTF16(nullptr, 0, utf8, utf8Units); if (utf16Units < 0) { SkDEBUGF("Convert error: Invalid utf8 input"); return std::u16string(); } SkAutoTArray utf16(utf16Units); SkDEBUGCODE(int dstLen =) SkUTF::UTF8ToUTF16(utf16.data(), utf16Units, utf8, utf8Units); SkASSERT(dstLen == utf16Units); return std::u16string((char16_t *)utf16.data(), utf16Units); } static std::u16string convertUtf8ToUtf16(const SkString& utf8) { return convertUtf8ToUtf16(utf8.c_str(), utf8.size()); } template void forEachCodepoint(const char* utf8, int32_t utf8Units, Callback&& callback) { const char* current = utf8; const char* end = utf8 + utf8Units; while (current < end) { auto before = current - utf8; SkUnichar unichar = SkUTF::NextUTF8(¤t, end); if (unichar < 0) unichar = 0xFFFD; auto after = current - utf8; uint16_t buffer[2]; size_t count = SkUTF::ToUTF16(unichar, buffer); callback(unichar, before, after, count); } } template void forEachCodepoint(const char16_t* utf16, int32_t utf16Units, Callback&& callback) { const char16_t* current = utf16; const char16_t* end = utf16 + utf16Units; while (current < end) { auto before = current - utf16; SkUnichar unichar = SkUTF::NextUTF16((const uint16_t**)¤t, (const uint16_t*)end); auto after = current - utf16; callback(unichar, before, after); } } template void forEachBidiRegion(const uint16_t utf16[], int utf16Units, SkBidiIterator::Direction dir, Callback&& callback) { auto iter = makeBidiIterator(utf16, utf16Units, dir); const uint16_t* start16 = utf16; const uint16_t* end16 = utf16 + utf16Units; SkBidiIterator::Level currentLevel = 0; SkBidiIterator::Position pos16 = 0; while (pos16 <= iter->getLength()) { auto level = iter->getLevelAt(pos16); if (pos16 == 0) { currentLevel = level; } else if (level != currentLevel) { callback(pos16, start16 - utf16, currentLevel); currentLevel = level; } if (start16 == end16) { break; } SkUnichar u = SkUTF::NextUTF16(&start16, end16); pos16 += SkUTF::ToUTF16(u); } } template void forEachBreak(const char16_t utf16[], int utf16Units, SkUnicode::BreakType type, Callback&& callback) { auto iter = makeBreakIterator(type); iter->setText(utf16, utf16Units); auto pos = iter->first(); do { callback(pos, iter->status()); pos = iter->next(); } while (!iter->isDone()); } virtual void reorderVisual(const BidiLevel runLevels[], int levelsCount, int32_t logicalFromVisual[]) = 0; static std::unique_ptr Make(); }; #endif // SkUnicode_DEFINED