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;