| 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 Flags : uint32_t { |
| 80 | kNone = 0x00, |
| 81 | |
| 82 | // Split out individual glyphs into separate Fragments |
| 83 | // (useful when the caller intends to manipulate glyphs independently). |
| 84 | kFragmentGlyphs = 0x01, |
| 85 | |
| 86 | // Compute the advance and ascent for each fragment. |
| 87 | kTrackFragmentAdvanceAscent = 0x02, |
| 88 | }; |
| 89 | |
| 90 | struct TextDesc { |
| 91 | const sk_sp<SkTypeface>& fTypeface; |
| 92 | SkScalar fTextSize, |
| 93 | fLineHeight, |
| 94 | fAscent; |
| 95 | SkTextUtils::Align fHAlign; |
| 96 | VAlign fVAlign; |
| 97 | ResizePolicy fResize; |
| 98 | uint32_t fFlags; |
| 99 | }; |
| 100 | |
| 101 | // Performs text layout along an infinite horizontal line, starting at |textPoint|. |
| 102 | // Only explicit line breaks (\r) are observed. |
| 103 | static Result Shape(const SkString& text, const TextDesc& desc, const SkPoint& textPoint, |
| 104 | const sk_sp<SkFontMgr>&); |
| 105 | |
| 106 | // Performs text layout within |textBox|, injecting line breaks as needed to ensure |
| 107 | // horizontal fitting. The result is *not* guaranteed to fit vertically (it may extend |
| 108 | // below the box bottom). |
| 109 | static Result Shape(const SkString& text, const TextDesc& desc, const SkRect& textBox, |
| 110 | const sk_sp<SkFontMgr>&); |
| 111 | |
| 112 | private: |
| 113 | Shaper() = delete; |
| 114 | }; |
| 115 | |
| 116 | } // namespace skottie |
| 117 | |
| 118 | #endif // SkottieShaper_DEFINED |
| 119 | |