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:
parent
59a3c3be94
commit
81eabce6a3
@ -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) {
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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*);
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user