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/SkPoint.h"
12 #include "include/utils/SkTextUtils.h"
13 
14 #include <vector>
15 
16 class SkFontMgr;
17 class SkTextBlob;
18 
19 namespace skottie {
20 
21 // Helper implementing After Effects text shaping semantics on top of SkShaper.
22 
23 class Shaper final {
24 public:
25     struct Fragment {
26         sk_sp<SkTextBlob> fBlob;
27         SkPoint           fPos;
28 
29         // Only valid for kFragmentGlyphs
30         float             fAdvance,
31                           fAscent;
32         uint32_t          fLineIndex;    // 0-based index for the line this fragment belongs to.
33         bool              fIsWhitespace; // True if the first code point in the corresponding
34                                          // cluster is whitespace.
35     };
36 
37     struct Result {
38         std::vector<Fragment> fFragments;
39         size_t                fMissingGlyphCount = 0;
40 
41         SkRect computeVisualBounds() const;
42     };
43 
44     enum class VAlign : uint8_t {
45         // Align the first line typographical top with the text box top (AE box text).
46         kTop,
47         // Align the first line typographical baseline with the text box top (AE point text).
48         kTopBaseline,
49 
50         // Skottie vertical alignment extensions: these are based on an extent box defined (in Y) as
51         //
52         //   ------------------------------------------------------
53         //   MIN(visual_top_extent   , typographical_top_extent   )
54         //
55         //                         ...
56         //
57         //   MAX(visual_bottom_extent, typographical_bottom_extent)
58         //   ------------------------------------------------------
59 
60         // extent box top -> text box top
61         kVisualTop,
62         // extent box center -> text box center
63         kVisualCenter,
64         // extent box bottom -> text box bottom
65         kVisualBottom,
66     };
67 
68     enum class ResizePolicy : uint8_t {
69         // Use the specified text size.
70         kNone,
71         // Resize the text such that the extent box fits (snuggly) in the text box,
72         // both horizontally and vertically.
73         kScaleToFit,
74         // Same kScaleToFit if the text doesn't fit at the specified font size.
75         // Otherwise, same as kNone.
76         kDownscaleToFit,
77     };
78 
79     enum class LinebreakPolicy : uint8_t {
80         // Break lines such that they fit in a non-empty paragraph box, horizontally.
81         kParagraph,
82         // Only break lines when requested explicitly (\r), regardless of paragraph box dimensions.
83         kExplicit,
84     };
85 
86     // Initial text direction.
87     enum class Direction : uint8_t { kLTR, kRTL };
88 
89     enum Flags : uint32_t {
90         kNone                       = 0x00,
91 
92         // Split out individual glyphs into separate Fragments
93         // (useful when the caller intends to manipulate glyphs independently).
94         kFragmentGlyphs             = 0x01,
95 
96         // Compute the advance and ascent for each fragment.
97         kTrackFragmentAdvanceAscent = 0x02,
98     };
99 
100     struct TextDesc {
101         const sk_sp<SkTypeface>&  fTypeface;
102         SkScalar                  fTextSize,
103                                   fMinTextSize,
104                                   fMaxTextSize,
105                                   fLineHeight,
106                                   fLineShift,
107                                   fAscent;
108         SkTextUtils::Align        fHAlign;
109         VAlign                    fVAlign;
110         ResizePolicy              fResize;
111         LinebreakPolicy           fLinebreak;
112         Direction                 fDirection;
113         uint32_t                  fFlags;
114     };
115 
116     // Performs text layout along an infinite horizontal line, starting at |textPoint|.
117     // Only explicit line breaks (\r) are observed.
118     static Result Shape(const SkString& text, const TextDesc& desc, const SkPoint& textPoint,
119                         const sk_sp<SkFontMgr>&);
120 
121     // Performs text layout within |textBox|, injecting line breaks as needed to ensure
122     // horizontal fitting.  The result is *not* guaranteed to fit vertically (it may extend
123     // below the box bottom).
124     static Result Shape(const SkString& text, const TextDesc& desc, const SkRect& textBox,
125                         const sk_sp<SkFontMgr>&);
126 
127 private:
128     Shaper() = delete;
129 };
130 
131 } // namespace skottie
132 
133 #endif // SkottieShaper_DEFINED
134