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