| /* | |
| * Copyright 2019 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkottieTextShaper_DEFINED | |
| #define SkottieTextShaper_DEFINED | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/private/SkTypeTraits.h" | |
| #include "include/utils/SkTextUtils.h" | |
| #include "modules/skunicode/include/SkUnicode.h" | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <type_traits> | |
| #include <vector> | |
| class SkCanvas; | |
| class SkFontMgr; | |
| class SkPaint; | |
| class SkString; | |
| class SkTypeface; | |
| struct SkRect; | |
| namespace SkShapers { class Factory; } | |
| namespace skottie { | |
| // Helper implementing After Effects text shaping semantics on top of SkShaper. | |
| class Shaper final { | |
| public: | |
| struct RunRec { | |
| SkFont fFont; | |
| size_t fSize; | |
| static_assert(::sk_is_trivially_relocatable<decltype(fFont)>::value); | |
| using sk_is_trivially_relocatable = std::true_type; | |
| }; | |
| struct ShapedGlyphs { | |
| std::vector<RunRec> fRuns; | |
| // Consolidated storage for all runs. | |
| std::vector<SkGlyphID> fGlyphIDs; | |
| std::vector<SkPoint> fGlyphPos; | |
| // fClusters[i] is an input string index, pointing to the start of the UTF sequence | |
| // associated with fGlyphs[i]. The number of entries matches the number of glyphs. | |
| // Only available with Flags::kClusters. | |
| std::vector<size_t> fClusters; | |
| enum class BoundsType { kConservative, kTight }; | |
| SkRect computeBounds(BoundsType) const; | |
| void draw(SkCanvas*, const SkPoint& origin, const SkPaint&) const; | |
| }; | |
| struct Fragment { | |
| ShapedGlyphs fGlyphs; | |
| SkPoint fOrigin; | |
| // Only valid for kFragmentGlyphs | |
| float fAdvance, | |
| fAscent; | |
| uint32_t fLineIndex; // 0-based index for the line this fragment belongs to. | |
| bool fIsWhitespace; // True if the first code point in the corresponding | |
| // cluster is whitespace. | |
| }; | |
| struct Result { | |
| std::vector<Fragment> fFragments; | |
| size_t fMissingGlyphCount = 0; | |
| // Relative text size scale, when using an auto-scaling ResizePolicy | |
| // (otherwise 1.0). This is informative of the final text size, and is | |
| // not required to render the Result. | |
| float fScale = 1.0f; | |
| SkRect computeVisualBounds() const; | |
| }; | |
| enum class VAlign : uint8_t { | |
| // Align the first line typographical top with the text box top (AE box text). | |
| kTop, | |
| // Align the first line typographical baseline with the text box top (AE point text). | |
| kTopBaseline, | |
| // Skottie vertical alignment extensions | |
| // These are based on a hybrid extent box defined (in Y) as | |
| // | |
| // ------------------------------------------------------ | |
| // MIN(visual_top_extent , typographical_top_extent ) | |
| // | |
| // ... | |
| // | |
| // MAX(visual_bottom_extent, typographical_bottom_extent) | |
| // ------------------------------------------------------ | |
| kHybridTop, // extent box top -> text box top | |
| kHybridCenter, // extent box center -> text box center | |
| kHybridBottom, // extent box bottom -> text box bottom | |
| // Visual alignement modes -- these are using tight visual bounds for the paragraph. | |
| kVisualTop, // visual top -> text box top | |
| kVisualCenter, // visual center -> text box center | |
| kVisualBottom, // visual bottom -> text box bottom | |
| }; | |
| enum class ResizePolicy : uint8_t { | |
| // Use the specified text size. | |
| kNone, | |
| // Resize the text such that the extent box fits (snuggly) in the text box, | |
| // both horizontally and vertically. | |
| kScaleToFit, | |
| // Same kScaleToFit if the text doesn't fit at the specified font size. | |
| // Otherwise, same as kNone. | |
| kDownscaleToFit, | |
| }; | |
| enum class LinebreakPolicy : uint8_t { | |
| // Break lines such that they fit in a non-empty paragraph box, horizontally. | |
| kParagraph, | |
| // Only break lines when requested explicitly (\r), regardless of paragraph box dimensions. | |
| kExplicit, | |
| }; | |
| // Initial text direction. | |
| enum class Direction : uint8_t { kLTR, kRTL }; | |
| enum class Capitalization { | |
| kNone, | |
| kUpperCase, | |
| }; | |
| enum Flags : uint32_t { | |
| kNone = 0x00, | |
| // Split out individual glyphs into separate Fragments | |
| // (useful when the caller intends to manipulate glyphs independently). | |
| kFragmentGlyphs = 0x01, | |
| // Compute the advance and ascent for each fragment. | |
| kTrackFragmentAdvanceAscent = 0x02, | |
| // Return cluster information. | |
| kClusters = 0x04, | |
| }; | |
| struct TextDesc { | |
| const sk_sp<SkTypeface>& fTypeface; | |
| SkScalar fTextSize = 0, | |
| fMinTextSize = 0, // when auto-sizing | |
| fMaxTextSize = 0, // when auto-sizing | |
| fLineHeight = 0, | |
| fLineShift = 0, | |
| fAscent = 0; | |
| SkTextUtils::Align fHAlign = SkTextUtils::kLeft_Align; | |
| VAlign fVAlign = Shaper::VAlign::kTop; | |
| ResizePolicy fResize = Shaper::ResizePolicy::kNone; | |
| LinebreakPolicy fLinebreak = Shaper::LinebreakPolicy::kExplicit; | |
| Direction fDirection = Shaper::Direction::kLTR ; | |
| Capitalization fCapitalization = Shaper::Capitalization::kNone; | |
| size_t fMaxLines = 0; // when auto-sizing, 0 -> no max | |
| uint32_t fFlags = 0; | |
| const char* fLocale = nullptr; | |
| const char* fFontFamily = nullptr; | |
| float fTextTracking = 0; | |
| }; | |
| // Performs text layout along an infinite horizontal line, starting at |point|. | |
| // Only explicit line breaks (\r) are observed. | |
| static Result Shape(const SkString& text, const TextDesc& desc, const SkPoint& point, | |
| const sk_sp<SkFontMgr>&, const sk_sp<SkShapers::Factory>&); | |
| // Performs text layout within |box|, injecting line breaks as needed to ensure | |
| // horizontal fitting. The result is *not* guaranteed to fit vertically (it may extend | |
| // below the box bottom). | |
| static Result Shape(const SkString& text, const TextDesc& desc, const SkRect& box, | |
| const sk_sp<SkFontMgr>&, const sk_sp<SkShapers::Factory>&); | |
| private: | |
| Shaper() = delete; | |
| }; | |
| // Returns an SkUnicode wrapper which suppresses mid-word line breaks. | |
| sk_sp<SkUnicode> SK_API MakeStrictLinebreakUnicode(sk_sp<SkUnicode>); | |
| } // namespace skottie | |
| #endif // SkottieTextShaper_DEFINED |