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