// Copyright 2021 Google LLC. #ifndef Painter_DEFINED #define Painter_DEFINED #include "experimental/sktext/include/Text.h" #include "experimental/sktext/include/Types.h" #include "include/core/SkCanvas.h" namespace skia { namespace text { struct DecoratedBlock { DecoratedBlock(uint32_t count, SkPaint fg, SkPaint bg) : charCount(count) , foregroundPaint(std::move(fg)) , backgroundPaint(std::move(bg)) { } uint32_t charCount; SkPaint foregroundPaint; SkPaint backgroundPaint; }; class TrivialFontChain : public FontChain { public: TrivialFontChain(const char* ff, SkScalar size, SkFontStyle fontStyle) : fTypeface(sk_sp(SkFontMgr::RefDefault()->matchFamilyStyle(ff, SkFontStyle::Normal()))) , fSize(size) , fFontStyle(fontStyle) { } size_t count() const override { return (size_t)1; } sk_sp operator[](size_t index) const override { SkASSERT(index == 0); return fTypeface; } float fontSize() const override { return fSize; } SkString locale() const override { return SkString("en"); } sk_sp getTypeface() const { return fTypeface; } bool empty() const { return fTypeface == nullptr; } private: sk_sp fTypeface; SkScalar fSize; SkFontStyle fFontStyle; }; class MultipleFontChain : public FontChain { public: MultipleFontChain(std::vector ffs, SkScalar size, SkFontStyle fontStyle) : fSize(size) , fFontStyle(fontStyle) { for (auto& ff : ffs) { auto typeface = SkFontMgr::RefDefault()->matchFamilyStyle(ff, SkFontStyle::Normal()); if (typeface != nullptr) { fTypefaces.emplace_back(typeface); } } } size_t count() const override { return fTypefaces.size(); } sk_sp operator[](size_t index) const override { SkASSERT(index < fTypefaces.size()); return fTypefaces[index]; } float fontSize() const override { return fSize; } SkString locale() const override { return SkString("en"); } bool empty() const { return fTypefaces.empty(); } private: std::vector> fTypefaces; SkScalar fSize; SkFontStyle fFontStyle; }; class Paint : public Visitor { public: void paint(SkCanvas* canvas, SkPoint xy, UnicodeText* unicodeText, WrappedText* wrappedText, SkSpan decoratedBlocks); // Simplification (using default font manager, default font family and default everything possible) static bool drawText(std::u16string text, SkCanvas* canvas, SkScalar x, SkScalar y); static bool drawText(std::u16string text, SkCanvas* canvas, SkScalar width); static bool drawText(std::u16string text, SkCanvas* canvas, TextDirection textDirection, TextAlign textAlign, SkPaint foreground, SkPaint background, const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, SkScalar x, SkScalar y); static bool drawText(std::u16string text, SkCanvas* canvas, TextDirection textDirection, TextAlign textAlign, SkPaint foreground, SkPaint background, const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, SkSize reqSize, SkScalar x, SkScalar y); private: static std::unique_ptr layout(std::u16string text, TextDirection textDirection, TextAlign textAlign, SkSize reqSize, SkSpan fontBlocks); void onGlyphRun(const SkFont& font, DirTextRange dirTextRange, SkRect bounds, TextIndex trailingSpaces, size_t glyphCount, const uint16_t glyphs[], const SkPoint positions[], const TextIndex clusters[]) override; // We guarantee that the text range will be inside one of the decorated blocks DecoratedBlock findDecoratedBlock(TextRange textRange); SkCanvas* fCanvas; SkPoint fXY; SkSpan fFontBlocks; SkSpan fDecoratedBlocks; }; } // namespace text } // namespace skia #endif // Painter_DEFINED