1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google Inc. 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 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkottieTextShaper_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkottieTextShaper_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTypeTraits.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkTextUtils.h" 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 20*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 21*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> 22*c8dee2aaSAndroid Build Coastguard Worker #include <vector> 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker class SkCanvas; 25*c8dee2aaSAndroid Build Coastguard Worker class SkFontMgr; 26*c8dee2aaSAndroid Build Coastguard Worker class SkPaint; 27*c8dee2aaSAndroid Build Coastguard Worker class SkString; 28*c8dee2aaSAndroid Build Coastguard Worker class SkTypeface; 29*c8dee2aaSAndroid Build Coastguard Worker struct SkRect; 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker namespace SkShapers { class Factory; } 32*c8dee2aaSAndroid Build Coastguard Worker 33*c8dee2aaSAndroid Build Coastguard Worker namespace skottie { 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker // Helper implementing After Effects text shaping semantics on top of SkShaper. 36*c8dee2aaSAndroid Build Coastguard Worker 37*c8dee2aaSAndroid Build Coastguard Worker class Shaper final { 38*c8dee2aaSAndroid Build Coastguard Worker public: 39*c8dee2aaSAndroid Build Coastguard Worker struct RunRec { 40*c8dee2aaSAndroid Build Coastguard Worker SkFont fFont; 41*c8dee2aaSAndroid Build Coastguard Worker size_t fSize; 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker static_assert(::sk_is_trivially_relocatable<decltype(fFont)>::value); 44*c8dee2aaSAndroid Build Coastguard Worker 45*c8dee2aaSAndroid Build Coastguard Worker using sk_is_trivially_relocatable = std::true_type; 46*c8dee2aaSAndroid Build Coastguard Worker }; 47*c8dee2aaSAndroid Build Coastguard Worker 48*c8dee2aaSAndroid Build Coastguard Worker struct ShapedGlyphs { 49*c8dee2aaSAndroid Build Coastguard Worker std::vector<RunRec> fRuns; 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker // Consolidated storage for all runs. 52*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkGlyphID> fGlyphIDs; 53*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> fGlyphPos; 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker // fClusters[i] is an input string index, pointing to the start of the UTF sequence 56*c8dee2aaSAndroid Build Coastguard Worker // associated with fGlyphs[i]. The number of entries matches the number of glyphs. 57*c8dee2aaSAndroid Build Coastguard Worker // Only available with Flags::kClusters. 58*c8dee2aaSAndroid Build Coastguard Worker std::vector<size_t> fClusters; 59*c8dee2aaSAndroid Build Coastguard Worker 60*c8dee2aaSAndroid Build Coastguard Worker enum class BoundsType { kConservative, kTight }; 61*c8dee2aaSAndroid Build Coastguard Worker SkRect computeBounds(BoundsType) const; 62*c8dee2aaSAndroid Build Coastguard Worker 63*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas*, const SkPoint& origin, const SkPaint&) const; 64*c8dee2aaSAndroid Build Coastguard Worker }; 65*c8dee2aaSAndroid Build Coastguard Worker 66*c8dee2aaSAndroid Build Coastguard Worker struct Fragment { 67*c8dee2aaSAndroid Build Coastguard Worker ShapedGlyphs fGlyphs; 68*c8dee2aaSAndroid Build Coastguard Worker SkPoint fOrigin; 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker // Only valid for kFragmentGlyphs 71*c8dee2aaSAndroid Build Coastguard Worker float fAdvance, 72*c8dee2aaSAndroid Build Coastguard Worker fAscent; 73*c8dee2aaSAndroid Build Coastguard Worker uint32_t fLineIndex; // 0-based index for the line this fragment belongs to. 74*c8dee2aaSAndroid Build Coastguard Worker bool fIsWhitespace; // True if the first code point in the corresponding 75*c8dee2aaSAndroid Build Coastguard Worker // cluster is whitespace. 76*c8dee2aaSAndroid Build Coastguard Worker }; 77*c8dee2aaSAndroid Build Coastguard Worker 78*c8dee2aaSAndroid Build Coastguard Worker struct Result { 79*c8dee2aaSAndroid Build Coastguard Worker std::vector<Fragment> fFragments; 80*c8dee2aaSAndroid Build Coastguard Worker size_t fMissingGlyphCount = 0; 81*c8dee2aaSAndroid Build Coastguard Worker // Relative text size scale, when using an auto-scaling ResizePolicy 82*c8dee2aaSAndroid Build Coastguard Worker // (otherwise 1.0). This is informative of the final text size, and is 83*c8dee2aaSAndroid Build Coastguard Worker // not required to render the Result. 84*c8dee2aaSAndroid Build Coastguard Worker float fScale = 1.0f; 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Worker SkRect computeVisualBounds() const; 87*c8dee2aaSAndroid Build Coastguard Worker }; 88*c8dee2aaSAndroid Build Coastguard Worker 89*c8dee2aaSAndroid Build Coastguard Worker enum class VAlign : uint8_t { 90*c8dee2aaSAndroid Build Coastguard Worker // Align the first line typographical top with the text box top (AE box text). 91*c8dee2aaSAndroid Build Coastguard Worker kTop, 92*c8dee2aaSAndroid Build Coastguard Worker // Align the first line typographical baseline with the text box top (AE point text). 93*c8dee2aaSAndroid Build Coastguard Worker kTopBaseline, 94*c8dee2aaSAndroid Build Coastguard Worker 95*c8dee2aaSAndroid Build Coastguard Worker // Skottie vertical alignment extensions 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker // These are based on a hybrid extent box defined (in Y) as 98*c8dee2aaSAndroid Build Coastguard Worker // 99*c8dee2aaSAndroid Build Coastguard Worker // ------------------------------------------------------ 100*c8dee2aaSAndroid Build Coastguard Worker // MIN(visual_top_extent , typographical_top_extent ) 101*c8dee2aaSAndroid Build Coastguard Worker // 102*c8dee2aaSAndroid Build Coastguard Worker // ... 103*c8dee2aaSAndroid Build Coastguard Worker // 104*c8dee2aaSAndroid Build Coastguard Worker // MAX(visual_bottom_extent, typographical_bottom_extent) 105*c8dee2aaSAndroid Build Coastguard Worker // ------------------------------------------------------ 106*c8dee2aaSAndroid Build Coastguard Worker kHybridTop, // extent box top -> text box top 107*c8dee2aaSAndroid Build Coastguard Worker kHybridCenter, // extent box center -> text box center 108*c8dee2aaSAndroid Build Coastguard Worker kHybridBottom, // extent box bottom -> text box bottom 109*c8dee2aaSAndroid Build Coastguard Worker 110*c8dee2aaSAndroid Build Coastguard Worker // Visual alignement modes -- these are using tight visual bounds for the paragraph. 111*c8dee2aaSAndroid Build Coastguard Worker kVisualTop, // visual top -> text box top 112*c8dee2aaSAndroid Build Coastguard Worker kVisualCenter, // visual center -> text box center 113*c8dee2aaSAndroid Build Coastguard Worker kVisualBottom, // visual bottom -> text box bottom 114*c8dee2aaSAndroid Build Coastguard Worker }; 115*c8dee2aaSAndroid Build Coastguard Worker 116*c8dee2aaSAndroid Build Coastguard Worker enum class ResizePolicy : uint8_t { 117*c8dee2aaSAndroid Build Coastguard Worker // Use the specified text size. 118*c8dee2aaSAndroid Build Coastguard Worker kNone, 119*c8dee2aaSAndroid Build Coastguard Worker // Resize the text such that the extent box fits (snuggly) in the text box, 120*c8dee2aaSAndroid Build Coastguard Worker // both horizontally and vertically. 121*c8dee2aaSAndroid Build Coastguard Worker kScaleToFit, 122*c8dee2aaSAndroid Build Coastguard Worker // Same kScaleToFit if the text doesn't fit at the specified font size. 123*c8dee2aaSAndroid Build Coastguard Worker // Otherwise, same as kNone. 124*c8dee2aaSAndroid Build Coastguard Worker kDownscaleToFit, 125*c8dee2aaSAndroid Build Coastguard Worker }; 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker enum class LinebreakPolicy : uint8_t { 128*c8dee2aaSAndroid Build Coastguard Worker // Break lines such that they fit in a non-empty paragraph box, horizontally. 129*c8dee2aaSAndroid Build Coastguard Worker kParagraph, 130*c8dee2aaSAndroid Build Coastguard Worker // Only break lines when requested explicitly (\r), regardless of paragraph box dimensions. 131*c8dee2aaSAndroid Build Coastguard Worker kExplicit, 132*c8dee2aaSAndroid Build Coastguard Worker }; 133*c8dee2aaSAndroid Build Coastguard Worker 134*c8dee2aaSAndroid Build Coastguard Worker // Initial text direction. 135*c8dee2aaSAndroid Build Coastguard Worker enum class Direction : uint8_t { kLTR, kRTL }; 136*c8dee2aaSAndroid Build Coastguard Worker 137*c8dee2aaSAndroid Build Coastguard Worker enum class Capitalization { 138*c8dee2aaSAndroid Build Coastguard Worker kNone, 139*c8dee2aaSAndroid Build Coastguard Worker kUpperCase, 140*c8dee2aaSAndroid Build Coastguard Worker }; 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker enum Flags : uint32_t { 143*c8dee2aaSAndroid Build Coastguard Worker kNone = 0x00, 144*c8dee2aaSAndroid Build Coastguard Worker 145*c8dee2aaSAndroid Build Coastguard Worker // Split out individual glyphs into separate Fragments 146*c8dee2aaSAndroid Build Coastguard Worker // (useful when the caller intends to manipulate glyphs independently). 147*c8dee2aaSAndroid Build Coastguard Worker kFragmentGlyphs = 0x01, 148*c8dee2aaSAndroid Build Coastguard Worker 149*c8dee2aaSAndroid Build Coastguard Worker // Compute the advance and ascent for each fragment. 150*c8dee2aaSAndroid Build Coastguard Worker kTrackFragmentAdvanceAscent = 0x02, 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Worker // Return cluster information. 153*c8dee2aaSAndroid Build Coastguard Worker kClusters = 0x04, 154*c8dee2aaSAndroid Build Coastguard Worker }; 155*c8dee2aaSAndroid Build Coastguard Worker 156*c8dee2aaSAndroid Build Coastguard Worker struct TextDesc { 157*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<SkTypeface>& fTypeface; 158*c8dee2aaSAndroid Build Coastguard Worker SkScalar fTextSize = 0, 159*c8dee2aaSAndroid Build Coastguard Worker fMinTextSize = 0, // when auto-sizing 160*c8dee2aaSAndroid Build Coastguard Worker fMaxTextSize = 0, // when auto-sizing 161*c8dee2aaSAndroid Build Coastguard Worker fLineHeight = 0, 162*c8dee2aaSAndroid Build Coastguard Worker fLineShift = 0, 163*c8dee2aaSAndroid Build Coastguard Worker fAscent = 0; 164*c8dee2aaSAndroid Build Coastguard Worker SkTextUtils::Align fHAlign = SkTextUtils::kLeft_Align; 165*c8dee2aaSAndroid Build Coastguard Worker VAlign fVAlign = Shaper::VAlign::kTop; 166*c8dee2aaSAndroid Build Coastguard Worker ResizePolicy fResize = Shaper::ResizePolicy::kNone; 167*c8dee2aaSAndroid Build Coastguard Worker LinebreakPolicy fLinebreak = Shaper::LinebreakPolicy::kExplicit; 168*c8dee2aaSAndroid Build Coastguard Worker Direction fDirection = Shaper::Direction::kLTR ; 169*c8dee2aaSAndroid Build Coastguard Worker Capitalization fCapitalization = Shaper::Capitalization::kNone; 170*c8dee2aaSAndroid Build Coastguard Worker size_t fMaxLines = 0; // when auto-sizing, 0 -> no max 171*c8dee2aaSAndroid Build Coastguard Worker uint32_t fFlags = 0; 172*c8dee2aaSAndroid Build Coastguard Worker const char* fLocale = nullptr; 173*c8dee2aaSAndroid Build Coastguard Worker const char* fFontFamily = nullptr; 174*c8dee2aaSAndroid Build Coastguard Worker }; 175*c8dee2aaSAndroid Build Coastguard Worker 176*c8dee2aaSAndroid Build Coastguard Worker // Performs text layout along an infinite horizontal line, starting at |point|. 177*c8dee2aaSAndroid Build Coastguard Worker // Only explicit line breaks (\r) are observed. 178*c8dee2aaSAndroid Build Coastguard Worker static Result Shape(const SkString& text, const TextDesc& desc, const SkPoint& point, 179*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<SkFontMgr>&, const sk_sp<SkShapers::Factory>&); 180*c8dee2aaSAndroid Build Coastguard Worker 181*c8dee2aaSAndroid Build Coastguard Worker // Performs text layout within |box|, injecting line breaks as needed to ensure 182*c8dee2aaSAndroid Build Coastguard Worker // horizontal fitting. The result is *not* guaranteed to fit vertically (it may extend 183*c8dee2aaSAndroid Build Coastguard Worker // below the box bottom). 184*c8dee2aaSAndroid Build Coastguard Worker static Result Shape(const SkString& text, const TextDesc& desc, const SkRect& box, 185*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<SkFontMgr>&, const sk_sp<SkShapers::Factory>&); 186*c8dee2aaSAndroid Build Coastguard Worker 187*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_LEGACY_SHAPER_FACTORY) 188*c8dee2aaSAndroid Build Coastguard Worker static Result Shape(const SkString& text, const TextDesc& desc, const SkPoint& point, 189*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<SkFontMgr>&); 190*c8dee2aaSAndroid Build Coastguard Worker static Result Shape(const SkString& text, const TextDesc& desc, const SkRect& box, 191*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<SkFontMgr>&); 192*c8dee2aaSAndroid Build Coastguard Worker #endif 193*c8dee2aaSAndroid Build Coastguard Worker 194*c8dee2aaSAndroid Build Coastguard Worker private: 195*c8dee2aaSAndroid Build Coastguard Worker Shaper() = delete; 196*c8dee2aaSAndroid Build Coastguard Worker }; 197*c8dee2aaSAndroid Build Coastguard Worker 198*c8dee2aaSAndroid Build Coastguard Worker } // namespace skottie 199*c8dee2aaSAndroid Build Coastguard Worker 200*c8dee2aaSAndroid Build Coastguard Worker #endif // SkottieTextShaper_DEFINED 201