xref: /aosp_15_r20/external/skia/modules/skottie/include/TextShaper.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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