[skottie] Use explicit font ascent in Shaper

Bodymovin exports an explicit ascent for each font, as a percentage of
the text size.

Change-Id: I25708944b2b79b42a6ccb05abbe002685e36dfa1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/223986
Reviewed-by: Ben Wagner <bungeman@google.com>
diff --git a/modules/skottie/src/SkottiePriv.h b/modules/skottie/src/SkottiePriv.h
index d2b23b2..cc24fac 100644
--- a/modules/skottie/src/SkottiePriv.h
+++ b/modules/skottie/src/SkottiePriv.h
@@ -53,7 +53,15 @@
 
     std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
 
-    sk_sp<SkTypeface> findFont(const SkString& name) const;
+    struct FontInfo {
+        SkString                  fFamily,
+                                  fStyle;
+        SkScalar                  fAscentPct;
+        sk_sp<SkTypeface>         fTypeface;
+
+        bool matches(const char family[], const char style[]) const;
+    };
+    const FontInfo* findFont(const SkString& name) const;
 
     // This is the workhorse for property binding: depending on whether the property is animated,
     // it will either apply immediately or instantiate and attach a keyframe animator.
@@ -195,15 +203,6 @@
         mutable bool               fIsAttaching; // Used for cycle detection
     };
 
-    struct FontInfo {
-        SkString                  fFamily,
-                                  fStyle;
-        SkScalar                  fAscent;
-        sk_sp<SkTypeface>         fTypeface;
-
-        bool matches(const char family[], const char style[]) const;
-    };
-
     struct ImageAssetInfo {
         sk_sp<ImageAsset> fAsset;
         SkISize           fSize;
diff --git a/modules/skottie/src/SkottieTest.cpp b/modules/skottie/src/SkottieTest.cpp
index 72069d5..a8934dd 100644
--- a/modules/skottie/src/SkottieTest.cpp
+++ b/modules/skottie/src/SkottieTest.cpp
@@ -294,6 +294,7 @@
                 typeface,
                 tsize.text_size,
                 tsize.text_size,
+                0,
                 talign.align,
                 skottie::Shaper::VAlign::kTopBaseline,
                 Shaper::Flags::kNone
@@ -357,6 +358,7 @@
                 typeface,
                 tsize.text_size,
                 tsize.text_size,
+                0,
                 SkTextUtils::Align::kCenter_Align,
                 talign.align,
                 Shaper::Flags::kNone
@@ -391,6 +393,7 @@
         SkTypeface::MakeDefault(),
         18,
         18,
+         0,
         SkTextUtils::Align::kCenter_Align,
         Shaper::VAlign::kTop,
         Shaper::Flags::kNone
diff --git a/modules/skottie/src/text/SkottieShaper.cpp b/modules/skottie/src/text/SkottieShaper.cpp
index fb2b48b..862785f 100644
--- a/modules/skottie/src/text/SkottieShaper.cpp
+++ b/modules/skottie/src/text/SkottieShaper.cpp
@@ -115,26 +115,30 @@
             fResult.fFragments.push_back({fBuilder.make(), {fBox.x(), fBox.y()}, 0, false});
         }
 
+        // Use the explicit ascent, when specified.
+        // Note: ascent values are negative (relative to the baseline).
+        const auto ascent = fDesc.fAscent ? fDesc.fAscent : fFirstLineAscent;
+
         // By default, first line is vertically-aligned on a baseline of 0.
         // The content height considered for vertical alignment is the distance between the first
         // line top (ascent) to the last line bottom (descent).
-        const auto content_height = fLastLineDescent - fFirstLineAscent +
+        const auto content_height = fLastLineDescent - ascent +
                                     fDesc.fLineHeight * (fLineCount > 0 ? fLineCount - 1 : 0ul);
 
         // Perform additional adjustments based on VAlign.
         float v_offset = 0;
         switch (fDesc.fVAlign) {
         case Shaper::VAlign::kTop:
-            v_offset = -fFirstLineAscent;
+            v_offset = -ascent;
             break;
         case Shaper::VAlign::kTopBaseline:
             // Default behavior.
             break;
         case Shaper::VAlign::kCenter:
-            v_offset = -fFirstLineAscent + (fBox.height() - content_height) * 0.5f;
+            v_offset = -ascent + (fBox.height() - content_height) * 0.5f;
             break;
         case Shaper::VAlign::kBottom:
-            v_offset = -fFirstLineAscent + (fBox.height() - content_height);
+            v_offset = -ascent + (fBox.height() - content_height);
             break;
         case Shaper::VAlign::kResizeToFit:
             SkASSERT(false);
@@ -310,6 +314,7 @@
         SkASSERT(try_scale >= in_scale && try_scale <= out_scale);
         desc.fTextSize   = try_scale * orig_desc.fTextSize;
         desc.fLineHeight = try_scale * orig_desc.fLineHeight;
+        desc.fAscent     = try_scale * orig_desc.fAscent;
 
         float res_height = 0;
         auto res = ShapeImpl(txt, desc, box, &res_height);
diff --git a/modules/skottie/src/text/SkottieShaper.h b/modules/skottie/src/text/SkottieShaper.h
index a919e43..64d624a 100644
--- a/modules/skottie/src/text/SkottieShaper.h
+++ b/modules/skottie/src/text/SkottieShaper.h
@@ -59,7 +59,8 @@
     struct TextDesc {
         const sk_sp<SkTypeface>&  fTypeface;
         SkScalar                  fTextSize,
-                                  fLineHeight;
+                                  fLineHeight,
+                                  fAscent;
         SkTextUtils::Align        fHAlign;
         VAlign                    fVAlign;
         uint32_t                  fFlags;
diff --git a/modules/skottie/src/text/TextAdapter.cpp b/modules/skottie/src/text/TextAdapter.cpp
index 58556d4..a3ee5b3 100644
--- a/modules/skottie/src/text/TextAdapter.cpp
+++ b/modules/skottie/src/text/TextAdapter.cpp
@@ -123,6 +123,7 @@
         fText.fTypeface,
         fText.fTextSize,
         fText.fLineHeight,
+        fText.fAscent,
         fText.fHAlign,
         fText.fVAlign,
         fHasAnimators ? Shaper::Flags::kFragmentGlyphs : Shaper::Flags::kNone,
diff --git a/modules/skottie/src/text/TextLayer.cpp b/modules/skottie/src/text/TextLayer.cpp
index 6acc3ec..be17d77 100644
--- a/modules/skottie/src/text/TextLayer.cpp
+++ b/modules/skottie/src/text/TextLayer.cpp
@@ -244,13 +244,8 @@
     }
 }
 
-sk_sp<SkTypeface> AnimationBuilder::findFont(const SkString& font_name) const {
-    if (const auto* font = fFonts.find(font_name)) {
-        return font->fTypeface;
-    }
-
-    this->log(Logger::Level::kError, nullptr, "Unknown font: \"%s\".", font_name.c_str());
-    return nullptr;
+const AnimationBuilder::FontInfo* AnimationBuilder::findFont(const SkString& font_name) const {
+    return fFonts.find(font_name);
 }
 
 sk_sp<sksg::RenderNode> AnimationBuilder::attachTextLayer(const skjson::ObjectValue& layer,
diff --git a/modules/skottie/src/text/TextValue.cpp b/modules/skottie/src/text/TextValue.cpp
index 0229d75..b53b26b 100644
--- a/modules/skottie/src/text/TextValue.cpp
+++ b/modules/skottie/src/text/TextValue.cpp
@@ -44,13 +44,21 @@
     const skjson::StringValue* text        = (*jtxt)["t"];
     const skjson::NumberValue* text_size   = (*jtxt)["s"];
     const skjson::NumberValue* line_height = (*jtxt)["lh"];
-    if (!font_name || !text || !text_size || !line_height ||
-        !(v->fTypeface = abuilder->findFont(SkString(font_name->begin(), font_name->size())))) {
+    if (!font_name || !text || !text_size || !line_height) {
         return false;
     }
+
+    const auto* font = abuilder->findFont(SkString(font_name->begin(), font_name->size()));
+    if (!font) {
+        abuilder->log(Logger::Level::kError, nullptr, "Unknown font: \"%s\".", font_name->begin());
+        return false;
+    }
+
     v->fText.set(text->begin(), text->size());
     v->fTextSize   = **text_size;
     v->fLineHeight = **line_height;
+    v->fTypeface   = font->fTypeface;
+    v->fAscent     = font->fAscentPct * -0.01f * v->fTextSize; // negative ascent per SkFontMetrics
 
     static constexpr SkTextUtils::Align gAlignMap[] = {
         SkTextUtils::kLeft_Align,  // 'j': 0
diff --git a/modules/skottie/src/text/TextValue.h b/modules/skottie/src/text/TextValue.h
index 685f7e7..1201956 100644
--- a/modules/skottie/src/text/TextValue.h
+++ b/modules/skottie/src/text/TextValue.h
@@ -20,7 +20,8 @@
     SkString           fText;
     float              fTextSize    = 0,
                        fStrokeWidth = 0,
-                       fLineHeight  = 0;
+                       fLineHeight  = 0,
+                       fAscent      = 0;
     SkTextUtils::Align fHAlign      = SkTextUtils::kLeft_Align;
     Shaper::VAlign     fVAlign      = Shaper::VAlign::kTop;
     SkRect             fBox         = SkRect::MakeEmpty();