SkCustomTypefaceBuilder to set SkFontStyle

Allow the user of SkCustomTypefaceBuilder to set the SkFontStyle of the
resulting SkTypeface. This allows users to build font families.

Fix the Font_flatten test to actually work (instead of relying on the
magic behavior of nullptr for SkTypeface), add a test with the custom
typeface, and reduce the number of times the inner loop runs from
302,400 times to 4,032 times so that the test finishes in a reasonable
amount of time.

Bug: skia:10630
Change-Id: I0b5e939552ee4a9a1249eefbb7a7279a59b38e5a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/311596
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Xiao Yu <xster@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Ben Wagner 2020-08-18 13:17:09 -04:00 committed by Skia Commit-Bot
parent 59a3c3be94
commit 81eabce6a3
10 changed files with 147 additions and 17 deletions

View File

@ -32,6 +32,7 @@ static sk_sp<SkTypeface> make_tf() {
font.getMetrics(&metrics);
builder.setMetrics(metrics, 1.0f/upem);
}
builder.setFontStyle(font.getTypefaceOrDefault()->fontStyle());
// Steal the first 128 chars from the default font
for (SkGlyphID index = 0; index <= 127; ++index) {

View File

@ -297,6 +297,7 @@ skia_core_sources = [
"$_src/core/SkPoint3.cpp",
"$_src/core/SkPromiseImageTexture.cpp",
"$_src/core/SkPtrRecorder.cpp",
"$_src/core/SkPtrRecorder.h",
"$_src/core/SkQuadClipper.cpp",
"$_src/core/SkQuadClipper.h",
"$_src/core/SkRRect.cpp",

View File

@ -15,6 +15,25 @@
The metric values are consistent with the Skia y-down coordinate system.
*/
struct SK_API SkFontMetrics {
bool operator==(const SkFontMetrics& that) {
return
this->fFlags == that.fFlags &&
this->fTop == that.fTop &&
this->fAscent == that.fAscent &&
this->fDescent == that.fDescent &&
this->fBottom == that.fBottom &&
this->fLeading == that.fLeading &&
this->fAvgCharWidth == that.fAvgCharWidth &&
this->fMaxCharWidth == that.fMaxCharWidth &&
this->fXMin == that.fXMin &&
this->fXMax == that.fXMax &&
this->fXHeight == that.fXHeight &&
this->fCapHeight == that.fCapHeight &&
this->fUnderlineThickness == that.fUnderlineThickness &&
this->fUnderlinePosition == that.fUnderlinePosition &&
this->fStrikeoutThickness == that.fStrikeoutThickness &&
this->fStrikeoutPosition == that.fStrikeoutPosition;
}
/** \enum FontMetricsFlags
FontMetricsFlags indicate when certain metrics are valid;

View File

@ -337,9 +337,7 @@ public:
}
protected:
/** uniqueID must be unique and non-zero
*/
SkTypeface(const SkFontStyle& style, bool isFixedPitch = false);
explicit SkTypeface(const SkFontStyle& style, bool isFixedPitch = false);
~SkTypeface() override;
virtual sk_sp<SkTypeface> onMakeClone(const SkFontArguments&) const = 0;

View File

@ -9,6 +9,7 @@
#define SkCustomTypeface_DEFINED
#include "include/core/SkFontMetrics.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkImage.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
@ -29,6 +30,7 @@ public:
void setGlyph(SkGlyphID, float advance, sk_sp<SkPicture>);
void setMetrics(const SkFontMetrics& fm, float scale = 1);
void setFontStyle(SkFontStyle);
sk_sp<SkTypeface> detach();
@ -36,6 +38,7 @@ private:
std::vector<SkPath> fPaths;
std::vector<float> fAdvances;
SkFontMetrics fMetrics;
SkFontStyle fStyle;
static sk_sp<SkTypeface> Deserialize(SkStream*);

View File

@ -45,7 +45,7 @@ private:
friend class SkCustomTypefaceBuilder;
friend class SkUserScalerContext;
SkUserTypeface() : SkTypeface(SkFontStyle()) {}
explicit SkUserTypeface(SkFontStyle style) : SkTypeface(style) {}
std::vector<SkPath> fPaths;
std::vector<float> fAdvances;
@ -102,6 +102,10 @@ void SkCustomTypefaceBuilder::setMetrics(const SkFontMetrics& fm, float scale) {
fMetrics = scale_fontmetrics(fm, scale, scale);
}
void SkCustomTypefaceBuilder::setFontStyle(SkFontStyle style) {
fStyle = style;
}
void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance, const SkPath& path) {
SkASSERT(fPaths.size() == fAdvances.size());
if (index >= fPaths.size()) {
@ -116,7 +120,7 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() {
SkASSERT(fPaths.size() == fAdvances.size());
if (fPaths.empty()) return nullptr;
sk_sp<SkUserTypeface> tf(new SkUserTypeface());
sk_sp<SkUserTypeface> tf(new SkUserTypeface(fStyle));
tf->fAdvances = std::move(fAdvances);
tf->fPaths = std::move(fPaths);
tf->fMetrics = fMetrics;
@ -314,6 +318,9 @@ std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const
wstream.write(&fMetrics, sizeof(fMetrics));
SkFontStyle style = this->fontStyle();
wstream.write(&style, sizeof(style));
// just hacking around -- this makes the serialized font 1/2 size
const bool use_compression = false;
@ -374,6 +381,11 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
return nullptr;
}
SkFontStyle style;
if (stream->read(&style, sizeof(style)) != sizeof(style)) {
return nullptr;
}
int glyphCount;
if (!stream->readS32(&glyphCount) || glyphCount < 0 || glyphCount > kMaxGlyphCount) {
return nullptr;
@ -382,6 +394,7 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
SkCustomTypefaceBuilder builder;
builder.setMetrics(metrics);
builder.setFontStyle(style);
std::vector<float> advances(glyphCount);
if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) {

View File

@ -6,22 +6,39 @@
*/
#include "include/core/SkFont.h"
#include "include/utils/SkCustomTypeface.h"
#include "src/core/SkAutoMalloc.h"
#include "src/core/SkFontPriv.h"
#include "src/core/SkPtrRecorder.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "tests/Test.h"
#include "tools/ToolUtils.h"
static SkFont serialize_deserialize(const SkFont& font, skiatest::Reporter* reporter) {
sk_sp<SkRefCntSet> typefaces = sk_make_sp<SkRefCntSet>();
SkBinaryWriteBuffer wb;
SkFontPriv::Flatten(font, wb);
wb.setTypefaceRecorder(typefaces);
SkFontPriv::Flatten(font, wb);
size_t size = wb.bytesWritten();
SkAutoMalloc storage(size);
wb.writeToMemory(storage.get());
SkReadBuffer rb(storage.get(), size);
int count = typefaces->count();
SkASSERT((!font.getTypeface() && count == 0) ||
( font.getTypeface() && count == 1));
if (count) {
SkTypeface* typeface;
typefaces->copyToArray((SkRefCnt**)&typeface);
SkASSERT(typeface == font.getTypeface());
}
SkReadBuffer rb(storage.get(), size);
sk_sp<SkTypeface> cloneTypeface = font.refTypeface();
if (count) {
rb.setTypefaceArray(&cloneTypeface, 1);
}
SkFont clone;
REPORTER_ASSERT(reporter, SkFontPriv::Unflatten(&clone, rb));
return clone;
@ -48,14 +65,21 @@ static void apply_flags(SkFont* font, unsigned flags) {
}
DEF_TEST(Font_flatten, reporter) {
const float sizes[] = {0, 0.001f, 1, 10, 10.001f, 100, 100000, 100000.01f};
const float scales[] = {-5, -1, 0, 1, 5};
const float skews[] = {-5, -1, 0, 1, 5};
const float sizes[] = {0, 0.001f, 1, 10, 10.001f, 100000.01f};
const float scales[] = {-5, 0, 1, 5};
const float skews[] = {-5, 0, 5};
const SkFont::Edging edges[] = {
SkFont::Edging::kAlias, SkFont::Edging::kAntiAlias, SkFont::Edging::kSubpixelAntiAlias
SkFont::Edging::kAlias, SkFont::Edging::kSubpixelAntiAlias
};
const SkFontHinting hints[] = {
SkFontHinting::kNone, SkFontHinting::kSlight, SkFontHinting::kNormal, SkFontHinting::kFull
SkFontHinting::kNone, SkFontHinting::kFull
};
const unsigned int flags[] = {
kForceAutoHinting, kEmbeddedBitmaps, kSubpixel, kLinearMetrics, kEmbolden, kBaselineSnap,
kAllBits,
};
const sk_sp<SkTypeface> typefaces[] = {
nullptr, ToolUtils::sample_user_typeface()
};
SkFont font;
@ -69,11 +93,13 @@ DEF_TEST(Font_flatten, reporter) {
font.setEdging(edge);
for (auto hint : hints) {
font.setHinting(hint);
for (unsigned flags = 0; flags <= kAllBits; ++flags) {
apply_flags(&font, flags);
SkFont clone = serialize_deserialize(font, reporter);
REPORTER_ASSERT(reporter, font == clone);
for (auto flag : flags) {
apply_flags(&font, flag);
for (const sk_sp<SkTypeface>& typeface : typefaces) {
font.setTypeface(typeface);
SkFont clone = serialize_deserialize(font, reporter);
REPORTER_ASSERT(reporter, font == clone);
}
}
}
}

View File

@ -6,6 +6,7 @@
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkImage.h"
#include "include/core/SkMallocPixelRef.h"
@ -448,6 +449,29 @@ static void TestPictureTypefaceSerialization(const SkSerialProcs* serial_procs,
}
}
static void TestTypefaceSerialization(skiatest::Reporter* reporter, sk_sp<SkTypeface> typeface) {
SkDynamicMemoryWStream typefaceWStream;
typeface->serialize(&typefaceWStream);
std::unique_ptr<SkStream> typefaceStream = typefaceWStream.detachAsStream();
sk_sp<SkTypeface> cloneTypeface = SkTypeface::MakeDeserialize(typefaceStream.get());
SkASSERT(cloneTypeface);
SkFont font(typeface, 12);
SkFont clone(cloneTypeface, 12);
SkFontMetrics fontMetrics, cloneMetrics;
font.getMetrics(&fontMetrics);
clone.getMetrics(&cloneMetrics);
REPORTER_ASSERT(reporter, fontMetrics == cloneMetrics);
REPORTER_ASSERT(reporter, typeface->countGlyphs() == cloneTypeface->countGlyphs());
REPORTER_ASSERT(reporter, typeface->fontStyle() == cloneTypeface->fontStyle());
}
DEF_TEST(Serialization_Typeface, reporter) {
SkFont font;
TestTypefaceSerialization(reporter, font.refTypefaceOrDefault());
TestTypefaceSerialization(reporter, ToolUtils::sample_user_typeface());
}
static void setup_bitmap_for_canvas(SkBitmap* bitmap) {
bitmap->allocN32Pixels(kBitmapSize, kBitmapSize);
}

View File

@ -62,6 +62,9 @@ sk_sp<SkTypeface> emoji_typeface();
/** Sample text for the emoji_typeface font. */
const char* emoji_sample_text();
/** A simple SkUserTypeface for testing. */
sk_sp<SkTypeface> sample_user_typeface();
/**
* Returns a platform-independent text renderer.
*/

View File

@ -11,6 +11,7 @@
#include "include/core/SkFontStyle.h"
#include "include/core/SkTypeface.h"
#include "include/private/SkMutex.h"
#include "include/utils/SkCustomTypeface.h"
#include "src/core/SkOSFile.h"
#include "src/utils/SkUTF.h"
#include "tools/Resources.h"
@ -61,6 +62,47 @@ const char* emoji_sample_text() {
" "
"\xE2\x99\xA2"; // 😀 ♢
}
sk_sp<SkTypeface> sample_user_typeface() {
SkCustomTypefaceBuilder builder;
SkFont font;
const float upem = 200;
{
SkFontMetrics metrics;
metrics.fFlags = 0;
metrics.fTop = -200;
metrics.fAscent = -150;
metrics.fDescent = 50;
metrics.fBottom = -75;
metrics.fLeading = 10;
metrics.fAvgCharWidth = 150;
metrics.fMaxCharWidth = 300;
metrics.fXMin = -20;
metrics.fXMax = 290;
metrics.fXHeight = -100;
metrics.fCapHeight = 0;
metrics.fUnderlineThickness = 5;
metrics.fUnderlinePosition = 2;
metrics.fStrikeoutThickness = 5;
metrics.fStrikeoutPosition = -50;
builder.setMetrics(metrics, 1.0f/upem);
}
builder.setFontStyle(SkFontStyle(367, 3, SkFontStyle::kOblique_Slant));
const SkMatrix scale = SkMatrix::Scale(1.0f/upem, 1.0f/upem);
for (SkGlyphID index = 0; index <= 67; ++index) {
SkScalar width;
width = 100;
SkPath path;
path.addCircle(50, -50, 75);
builder.setGlyph(index, width/upem, path.makeTransform(scale));
}
return builder.detach();
}
static sk_sp<SkTypeface> create_font(const char* name, SkFontStyle style) {
static sk_sp<SkFontMgr> portableFontMgr = MakePortableFontMgr();
return portableFontMgr->legacyMakeTypeface(name, style);