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:
parent
dbcf680f8f
commit
98bc22c689
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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*);
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user