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>
This commit is contained in:
Mike Reed 2020-05-18 16:17:05 -04:00 committed by Skia Commit-Bot
parent dbcf680f8f
commit 98bc22c689
3 changed files with 78 additions and 16 deletions

View File

@ -21,6 +21,12 @@ static sk_sp<SkTypeface> make_tf() {
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 @@ static sk_sp<SkTypeface> make_tf() {
#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 @@ public:
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 @@ public:
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 @@ public:
paint.setColor(SK_ColorBLACK);
canvas->drawTextBlob(blob, x, y, paint);
y += size * 1.5f;
y += SkScalarRoundToInt(spacing * 1.25f + 2);
}
};

View File

@ -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 @@ public:
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*);

View File

@ -20,7 +20,7 @@ private:
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 @@ private:
}
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 @@ private:
}
};
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<SkTypeface> SkCustomTypefaceBuilder::detach() {
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 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() {
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 @@ protected:
}
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 void compress_write(SkWStream* stream, const SkPath& path, int upem) {
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 @@ std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const
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 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
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 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
SkCustomTypefaceBuilder builder;
builder.setMetrics(metrics);
std::vector<float> advances(glyphCount);
if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) {
return nullptr;