/* * Copyright 2023 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkRefCnt.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkDebug.h" #include "include/private/base/SkTFitsIn.h" #include "modules/skshaper/include/SkShaper.h" #include "modules/skshaper/include/SkShaper_skunicode.h" #include "modules/skunicode/include/SkUnicode.h" #include "src/base/SkUTF.h" #include #include #include #include using SkUnicodeBidi = std::unique_ptr; /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */ static inline SkUnichar utf8_next(const char** ptr, const char* end) { SkUnichar val = SkUTF::NextUTF8(ptr, end); return val < 0 ? 0xFFFD : val; } class SkUnicodeBidiRunIterator final : public SkShaper::BiDiRunIterator { public: SkUnicodeBidiRunIterator(const char* utf8, const char* end, SkUnicodeBidi bidi) : fBidi(std::move(bidi)) , fEndOfCurrentRun(utf8) , fBegin(utf8) , fEnd(end) , fUTF16LogicalPosition(0) , fLevel(SkBidiIterator::kLTR) {} void consume() override { SkASSERT(fUTF16LogicalPosition < fBidi->getLength()); int32_t endPosition = fBidi->getLength(); fLevel = fBidi->getLevelAt(fUTF16LogicalPosition); SkUnichar u = utf8_next(&fEndOfCurrentRun, fEnd); fUTF16LogicalPosition += SkUTF::ToUTF16(u); SkBidiIterator::Level level; while (fUTF16LogicalPosition < endPosition) { level = fBidi->getLevelAt(fUTF16LogicalPosition); if (level != fLevel) { break; } u = utf8_next(&fEndOfCurrentRun, fEnd); fUTF16LogicalPosition += SkUTF::ToUTF16(u); } } size_t endOfCurrentRun() const override { return fEndOfCurrentRun - fBegin; } bool atEnd() const override { return fUTF16LogicalPosition == fBidi->getLength(); } SkBidiIterator::Level currentLevel() const override { return fLevel; } private: SkUnicodeBidi fBidi; char const * fEndOfCurrentRun; char const * const fBegin; char const * const fEnd; int32_t fUTF16LogicalPosition; SkBidiIterator::Level fLevel; }; #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS) #if defined(SK_UNICODE_ICU_IMPLEMENTATION) #include "modules/skunicode/include/SkUnicode_icu.h" #endif #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION) #include "modules/skunicode/include/SkUnicode_libgrapheme.h" #endif #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION) #include "modules/skunicode/include/SkUnicode_icu4x.h" #endif sk_sp get_unicode() { #if defined(SK_UNICODE_ICU_IMPLEMENTATION) if (auto unicode = SkUnicodes::ICU::Make()) { return unicode; } #endif // defined(SK_UNICODE_ICU_IMPLEMENTATION) #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION) if (auto unicode = SkUnicodes::Libgrapheme::Make()) { return unicode; } #endif #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION) if (auto unicode = SkUnicodes::ICU4X::Make()) { return unicode; } #endif return nullptr; } std::unique_ptr SkShaper::MakeIcuBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) { static auto unicode = get_unicode(); if (!unicode) { return nullptr; } return SkShapers::unicode::BidiRunIterator(unicode, utf8, utf8Bytes, bidiLevel); } #endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS) namespace SkShapers::unicode { std::unique_ptr BidiRunIterator(sk_sp unicode, const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) { if (!unicode) { return nullptr; } // ubidi only accepts utf16 (though internally it basically works on utf32 chars). // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*); if (!SkTFitsIn(utf8Bytes)) { SkDEBUGF("Bidi error: text too long"); return nullptr; } int32_t utf16Units = SkUTF::UTF8ToUTF16(nullptr, 0, utf8, utf8Bytes); if (utf16Units < 0) { SkDEBUGF("Invalid utf8 input\n"); return nullptr; } std::unique_ptr utf16(new uint16_t[utf16Units]); (void)SkUTF::UTF8ToUTF16(utf16.get(), utf16Units, utf8, utf8Bytes); auto bidiDir = (bidiLevel % 2 == 0) ? SkBidiIterator::kLTR : SkBidiIterator::kRTL; SkUnicodeBidi bidi = unicode->makeBidiIterator(utf16.get(), utf16Units, bidiDir); if (!bidi) { SkDEBUGF("Bidi error\n"); return nullptr; } return std::make_unique(utf8, utf8 + utf8Bytes, std::move(bidi)); } } // namespace SkShapers::unicode