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