• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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