add fontmetrics to custom typeface

Change-Id: Ib6f468f6fd35b73e590d22a33d1322d3de48edb2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290645
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/gm/userfont.cpp b/gm/userfont.cpp
index b228ab1..55c9cf9 100644
--- a/gm/userfont.cpp
+++ b/gm/userfont.cpp
@@ -21,6 +21,12 @@
     font.setSize(1.0f);
     font.setHinting(SkFontHinting::kNone);
 
+    {
+        SkFontMetrics metrics;
+        font.getMetrics(&metrics);
+        builder.setMetrics(metrics);
+    }
+
     // Steal the first 128 chars from the default font
     for (SkGlyphID index = 0; index <= 127; ++index) {
         SkGlyphID glyph = font.unicharToGlyph(index);
@@ -39,6 +45,12 @@
 
 #include "include/core/SkTextBlob.h"
 
+static sk_sp<SkTypeface> round_trip(sk_sp<SkTypeface> tf) {
+    auto data = tf->serialize();
+    SkMemoryStream stream(data->data(), data->size());
+    return SkTypeface::MakeDeserialize(&stream);
+}
+
 class UserFontGM : public skiagm::GM {
     sk_sp<SkTypeface> fTF;
 
@@ -47,12 +59,15 @@
 
     void onOnceBeforeDraw() override {
         fTF = make_tf();
+        // test serialization
+        fTF = round_trip(fTF);
     }
 
-    static sk_sp<SkTextBlob> make_blob(sk_sp<SkTypeface> tf, float size) {
+    static sk_sp<SkTextBlob> make_blob(sk_sp<SkTypeface> tf, float size, float* spacing) {
         SkFont font(tf);
         font.setSize(size);
         font.setEdging(SkFont::Edging::kAntiAlias);
+        *spacing = font.getMetrics(nullptr);
         return SkTextBlob::MakeFromString("Typeface", font);
     }
 
@@ -60,17 +75,24 @@
 
     SkString onShortName() override { return SkString("user_typeface"); }
 
-    SkISize onISize() override { return {810, 512}; }
+    SkISize onISize() override { return {810, 452}; }
 
     void onDraw(SkCanvas* canvas) override {
         auto waterfall = [&](sk_sp<SkTypeface> tf) {
             SkPaint paint;
             paint.setAntiAlias(true);
 
+            float spacing;
             float x = 20,
                   y = 16;
             for (float size = 9; size <= 100; size *= 1.25f) {
-                auto blob = make_blob(tf, size);
+                auto blob = make_blob(tf, size, &spacing);
+
+                // shared baseline
+                if (tf == nullptr) {
+                    paint.setColor(0xFFDDDDDD);
+                    canvas->drawRect({0, y, 810, y+1}, paint);
+                }
 
                 paint.setColor(0xFFCCCCCC);
                 paint.setStyle(SkPaint::kStroke_Style);
@@ -80,7 +102,7 @@
                 paint.setColor(SK_ColorBLACK);
                 canvas->drawTextBlob(blob, x, y, paint);
 
-                y += size * 1.5f;
+                y += SkScalarRoundToInt(spacing * 1.25f + 2);
             }
         };
 
diff --git a/include/utils/SkCustomTypeface.h b/include/utils/SkCustomTypeface.h
index b609b21..2ca6116 100644
--- a/include/utils/SkCustomTypeface.h
+++ b/include/utils/SkCustomTypeface.h
@@ -8,6 +8,7 @@
 #ifndef SkCustomTypeface_DEFINED
 #define SkCustomTypeface_DEFINED
 
+#include "include/core/SkFontMetrics.h"
 #include "include/core/SkImage.h"
 #include "include/core/SkPaint.h"
 #include "include/core/SkPath.h"
@@ -27,11 +28,14 @@
     void setGlyph(SkGlyphID, float advance, sk_sp<SkImage>, float scale);
     void setGlyph(SkGlyphID, float advance, sk_sp<SkPicture>);
 
+    void setMetrics(const SkFontMetrics& fm) { fMetrics = fm; }
+
     sk_sp<SkTypeface> detach();
 
 private:
     std::vector<SkPath> fPaths;
     std::vector<float>  fAdvances;
+    SkFontMetrics       fMetrics;
 
     static sk_sp<SkTypeface> Deserialize(SkStream*);
 
diff --git a/src/utils/SkCustomTypeface.cpp b/src/utils/SkCustomTypeface.cpp
index 36d2838..b49cf02 100644
--- a/src/utils/SkCustomTypeface.cpp
+++ b/src/utils/SkCustomTypeface.cpp
@@ -20,7 +20,7 @@
 
     std::vector<SkPath> fPaths;
     std::vector<float>  fAdvances;
-    SkRect              fBounds;
+    SkFontMetrics       fMetrics;
 
     SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
                                            const SkDescriptor* desc) const override;
@@ -44,7 +44,10 @@
     }
     int onCountGlyphs() const override { return this->glyphCount(); }
     int onGetUPEM() const override { return 2048; /* ?? */ }
-    bool onComputeBounds(SkRect* bounds) const override { *bounds = fBounds; return true; }
+    bool onComputeBounds(SkRect* bounds) const override {
+        bounds->setLTRB(fMetrics.fXMin, fMetrics.fTop, fMetrics.fXMax, fMetrics.fBottom);
+        return true;
+    }
 
     // noops
 
@@ -62,7 +65,9 @@
     }
 };
 
-SkCustomTypefaceBuilder::SkCustomTypefaceBuilder() {}
+SkCustomTypefaceBuilder::SkCustomTypefaceBuilder() {
+    sk_bzero(&fMetrics, sizeof(fMetrics));
+}
 
 void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance, const SkPath& path) {
     SkASSERT(fPaths.size() == fAdvances.size());
@@ -81,6 +86,7 @@
     sk_sp<SkUserTypeface> tf(new SkUserTypeface());
     tf->fAdvances = std::move(fAdvances);
     tf->fPaths    = std::move(fPaths);
+    tf->fMetrics  = fMetrics;
 
     // initially inverted, so that any "union" will overwrite the first time
     SkRect bounds = {SK_ScalarMax, SK_ScalarMax, -SK_ScalarMax, -SK_ScalarMax};
@@ -90,7 +96,10 @@
             bounds.join(path.getBounds());
         }
     }
-    tf->fBounds = bounds;
+    tf->fMetrics.fTop    = bounds.top();
+    tf->fMetrics.fBottom = bounds.bottom();
+    tf->fMetrics.fXMin   = bounds.left();
+    tf->fMetrics.fXMax   = bounds.right();
 
     return std::move(tf);
 }
@@ -177,15 +186,33 @@
     }
 
     void generateFontMetrics(SkFontMetrics* metrics) override {
-        auto [_, sy] = fMatrix.mapXY(0, 1);
+        // for safety, assign everything, and then post-scale as needed
+        *metrics = this->userTF()->fMetrics;
 
-        sk_bzero(metrics, sizeof(*metrics));
-        metrics->fTop    = this->userTF()->fBounds.fTop    * sy;
-        metrics->fBottom = this->userTF()->fBounds.fBottom * sy;
+        auto [sx, sy] = fMatrix.mapXY(1, 1);
 
-        // todo: get these from the creator of the typeface?
-        metrics->fAscent = metrics->fTop;
-        metrics->fDescent = metrics->fBottom;
+#define SCALE_X(field)  metrics->field *= sx
+#define SCALE_Y(field)  metrics->field *= sy
+
+        SCALE_X(fAvgCharWidth);
+        SCALE_X(fMaxCharWidth);
+        SCALE_X(fXMin);
+        SCALE_X(fXMax);
+
+        SCALE_Y(fTop);
+        SCALE_Y(fAscent);
+        SCALE_Y(fDescent);
+        SCALE_Y(fBottom);
+        SCALE_Y(fLeading);
+        SCALE_Y(fXHeight);
+        SCALE_Y(fCapHeight);
+        SCALE_Y(fUnderlineThickness);
+        SCALE_Y(fUnderlinePosition);
+        SCALE_Y(fStrikeoutThickness);
+        SCALE_Y(fStrikeoutPosition);
+
+#undef SCALE_X
+#undef SCALE_Y
     }
 
 private:
@@ -269,7 +296,7 @@
 
 static constexpr int kMaxGlyphCount = 65536;
 static constexpr size_t kHeaderSize = 16;
-static const char gHeaderString[] = "SkUserTypeface00";
+static const char gHeaderString[] = "SkUserTypeface01";
 static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes");
 
 std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const {
@@ -277,6 +304,8 @@
 
     wstream.write(gHeaderString, kHeaderSize);
 
+    wstream.write(&fMetrics, sizeof(fMetrics));
+
     // just hacking around -- this makes the serialized font 1/2 size
     const bool use_compression = false;
 
@@ -332,6 +361,11 @@
         return nullptr;
     }
 
+    SkFontMetrics metrics;
+    if (stream->read(&metrics, sizeof(metrics)) != sizeof(metrics)) {
+        return nullptr;
+    }
+
     int glyphCount;
     if (!stream->readS32(&glyphCount) || glyphCount < 0 || glyphCount > kMaxGlyphCount) {
         return nullptr;
@@ -339,6 +373,8 @@
 
     SkCustomTypefaceBuilder builder;
 
+    builder.setMetrics(metrics);
+
     std::vector<float> advances(glyphCount);
     if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) {
         return nullptr;