• 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 #include "modules/skottie/src/text/TextValue.h"
9 
10 #include "modules/skottie/src/SkottieJson.h"
11 #include "modules/skottie/src/SkottiePriv.h"
12 #include "modules/skottie/src/SkottieValue.h"
13 
14 namespace skottie {
15 
16 template <>
FromJSON(const skjson::Value & jv,const internal::AnimationBuilder * abuilder,TextValue * v)17 bool ValueTraits<TextValue>::FromJSON(const skjson::Value& jv,
18                                        const internal::AnimationBuilder* abuilder,
19                                        TextValue* v) {
20     const skjson::ObjectValue* jtxt = jv;
21     if (!jtxt) {
22         return false;
23     }
24 
25     const skjson::StringValue* font_name   = (*jtxt)["f"];
26     const skjson::StringValue* text        = (*jtxt)["t"];
27     const skjson::NumberValue* text_size   = (*jtxt)["s"];
28     const skjson::NumberValue* line_height = (*jtxt)["lh"];
29     if (!font_name || !text || !text_size || !line_height) {
30         return false;
31     }
32 
33     const auto* font = abuilder->findFont(SkString(font_name->begin(), font_name->size()));
34     if (!font) {
35         abuilder->log(Logger::Level::kError, nullptr, "Unknown font: \"%s\".", font_name->begin());
36         return false;
37     }
38 
39     v->fText.set(text->begin(), text->size());
40     v->fTextSize   = **text_size;
41     v->fLineHeight = **line_height;
42     v->fTypeface   = font->fTypeface;
43     v->fAscent     = font->fAscentPct * -0.01f * v->fTextSize; // negative ascent per SkFontMetrics
44 
45     static constexpr SkTextUtils::Align gAlignMap[] = {
46         SkTextUtils::kLeft_Align,  // 'j': 0
47         SkTextUtils::kRight_Align, // 'j': 1
48         SkTextUtils::kCenter_Align // 'j': 2
49     };
50     v->fHAlign = gAlignMap[SkTMin<size_t>(ParseDefault<size_t>((*jtxt)["j"], 0),
51                                           SK_ARRAY_COUNT(gAlignMap))];
52 
53     // Optional text box size.
54     if (const skjson::ArrayValue* jsz = (*jtxt)["sz"]) {
55         if (jsz->size() == 2) {
56             v->fBox.setWH(ParseDefault<SkScalar>((*jsz)[0], 0),
57                           ParseDefault<SkScalar>((*jsz)[1], 0));
58         }
59     }
60 
61     // Optional text box position.
62     if (const skjson::ArrayValue* jps = (*jtxt)["ps"]) {
63         if (jps->size() == 2) {
64             v->fBox.offset(ParseDefault<SkScalar>((*jps)[0], 0),
65                            ParseDefault<SkScalar>((*jps)[1], 0));
66         }
67     }
68 
69     // In point mode, the text is baseline-aligned.
70     v->fVAlign = v->fBox.isEmpty() ? Shaper::VAlign::kTopBaseline
71                                    : Shaper::VAlign::kTop;
72 
73     // Skia vertical alignment extension "sk_vj":
74     static constexpr Shaper::VAlign gVAlignMap[] = {
75         Shaper::VAlign::kVisualTop,         // 'sk_vj': 0
76         Shaper::VAlign::kVisualCenter,      // 'sk_vj': 1
77         Shaper::VAlign::kVisualBottom,      // 'sk_vj': 2
78         Shaper::VAlign::kVisualResizeToFit, // 'sk_vj': 3
79     };
80     size_t sk_vj;
81     if (Parse((*jtxt)["sk_vj"], &sk_vj) && sk_vj < SK_ARRAY_COUNT(gVAlignMap)) {
82         v->fVAlign = gVAlignMap[sk_vj];
83     }
84 
85     const auto& parse_color = [] (const skjson::ArrayValue* jcolor,
86                                   const internal::AnimationBuilder* abuilder,
87                                   SkColor* c) {
88         if (!jcolor) {
89             return false;
90         }
91 
92         VectorValue color_vec;
93         if (!ValueTraits<VectorValue>::FromJSON(*jcolor, abuilder, &color_vec)) {
94             return false;
95         }
96 
97         *c = ValueTraits<VectorValue>::As<SkColor>(color_vec);
98         return true;
99     };
100 
101     v->fHasFill   = parse_color((*jtxt)["fc"], abuilder, &v->fFillColor);
102     v->fHasStroke = parse_color((*jtxt)["sc"], abuilder, &v->fStrokeColor);
103 
104     if (v->fHasStroke) {
105         v->fStrokeWidth = ParseDefault((*jtxt)["s"], 0.0f);
106     }
107 
108     return true;
109 }
110 
111 template <>
CanLerp(const TextValue &,const TextValue &)112 bool ValueTraits<TextValue>::CanLerp(const TextValue&, const TextValue&) {
113     // Text values are never interpolated, but we pretend that they could be.
114     return true;
115 }
116 
117 template <>
Lerp(const TextValue & v0,const TextValue &,float,TextValue * result)118 void ValueTraits<TextValue>::Lerp(const TextValue& v0, const TextValue&, float, TextValue* result) {
119     // Text value keyframes are treated as selectors, not as interpolated values.
120     *result = v0;
121 }
122 
123 } // namespace skottie
124