diff --git a/gm/userfont.cpp b/gm/userfont.cpp index 7be73d7768..b40410ea90 100644 --- a/gm/userfont.cpp +++ b/gm/userfont.cpp @@ -32,6 +32,7 @@ static sk_sp 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) { diff --git a/gn/core.gni b/gn/core.gni index 4c25c19e71..d08c2e4b2a 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -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", diff --git a/include/core/SkFontMetrics.h b/include/core/SkFontMetrics.h index ef41cfc3e7..717a87f056 100644 --- a/include/core/SkFontMetrics.h +++ b/include/core/SkFontMetrics.h @@ -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; diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h index 4937bfdc6b..7038cd0c7e 100644 --- a/include/core/SkTypeface.h +++ b/include/core/SkTypeface.h @@ -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 onMakeClone(const SkFontArguments&) const = 0; diff --git a/include/utils/SkCustomTypeface.h b/include/utils/SkCustomTypeface.h index 61f32afed5..8430e6f262 100644 --- a/include/utils/SkCustomTypeface.h +++ b/include/utils/SkCustomTypeface.h @@ -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); void setMetrics(const SkFontMetrics& fm, float scale = 1); + void setFontStyle(SkFontStyle); sk_sp detach(); @@ -36,6 +38,7 @@ private: std::vector fPaths; std::vector fAdvances; SkFontMetrics fMetrics; + SkFontStyle fStyle; static sk_sp Deserialize(SkStream*); diff --git a/src/utils/SkCustomTypeface.cpp b/src/utils/SkCustomTypeface.cpp index 00e0be7ed6..5649b475a7 100644 --- a/src/utils/SkCustomTypeface.cpp +++ b/src/utils/SkCustomTypeface.cpp @@ -45,7 +45,7 @@ private: friend class SkCustomTypefaceBuilder; friend class SkUserScalerContext; - SkUserTypeface() : SkTypeface(SkFontStyle()) {} + explicit SkUserTypeface(SkFontStyle style) : SkTypeface(style) {} std::vector fPaths; std::vector 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 SkCustomTypefaceBuilder::detach() { SkASSERT(fPaths.size() == fAdvances.size()); if (fPaths.empty()) return nullptr; - sk_sp tf(new SkUserTypeface()); + sk_sp tf(new SkUserTypeface(fStyle)); tf->fAdvances = std::move(fAdvances); tf->fPaths = std::move(fPaths); tf->fMetrics = fMetrics; @@ -314,6 +318,9 @@ std::unique_ptr 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 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 SkCustomTypefaceBuilder::Deserialize(SkStream* stream) { SkCustomTypefaceBuilder builder; builder.setMetrics(metrics); + builder.setFontStyle(style); std::vector advances(glyphCount); if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) { diff --git a/tests/FontTest.cpp b/tests/FontTest.cpp index 1ae8aa8c3a..0e2ea548ba 100644 --- a/tests/FontTest.cpp +++ b/tests/FontTest.cpp @@ -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 typefaces = sk_make_sp(); 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 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 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& typeface : typefaces) { + font.setTypeface(typeface); + SkFont clone = serialize_deserialize(font, reporter); + REPORTER_ASSERT(reporter, font == clone); + } } } } diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp index 3f32b45ea4..ab10179e19 100644 --- a/tests/SerializationTest.cpp +++ b/tests/SerializationTest.cpp @@ -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 typeface) { + SkDynamicMemoryWStream typefaceWStream; + typeface->serialize(&typefaceWStream); + + std::unique_ptr typefaceStream = typefaceWStream.detachAsStream(); + sk_sp 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); } diff --git a/tools/ToolUtils.h b/tools/ToolUtils.h index 5c3edfba84..d193f3f579 100644 --- a/tools/ToolUtils.h +++ b/tools/ToolUtils.h @@ -62,6 +62,9 @@ sk_sp emoji_typeface(); /** Sample text for the emoji_typeface font. */ const char* emoji_sample_text(); +/** A simple SkUserTypeface for testing. */ +sk_sp sample_user_typeface(); + /** * Returns a platform-independent text renderer. */ diff --git a/tools/fonts/ToolUtilsFont.cpp b/tools/fonts/ToolUtilsFont.cpp index ad68785f53..64d70230bb 100644 --- a/tools/fonts/ToolUtilsFont.cpp +++ b/tools/fonts/ToolUtilsFont.cpp @@ -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 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 create_font(const char* name, SkFontStyle style) { static sk_sp portableFontMgr = MakePortableFontMgr(); return portableFontMgr->legacyMakeTypeface(name, style);