| /* | 
 |  * Copyright 2020 Google LLC | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "gm/gm.h" | 
 | #include "include/core/SkCanvas.h" | 
 | #include "include/core/SkFont.h" | 
 | #include "include/core/SkFontMgr.h" | 
 | #include "include/core/SkPaint.h" | 
 | #include "include/core/SkPath.h" | 
 | #include "include/core/SkPictureRecorder.h" | 
 | #include "include/core/SkSize.h" | 
 | #include "include/core/SkStream.h" | 
 | #include "include/core/SkString.h" | 
 | #include "include/utils/SkCustomTypeface.h" | 
 | #include "src/core/SkFontPriv.h" | 
 | #include "tools/Resources.h" | 
 | #include "tools/fonts/FontToolUtils.h" | 
 |  | 
 | static sk_sp<SkDrawable> make_drawable(const SkPath& path) { | 
 |     const auto bounds = path.computeTightBounds(); | 
 |  | 
 |     SkPictureRecorder recorder; | 
 |     auto* canvas = recorder.beginRecording(bounds); | 
 |  | 
 |     SkPaint paint; | 
 |     paint.setColor(0xff008000); | 
 |     paint.setAntiAlias(true); | 
 |  | 
 |     canvas->drawPath(path, paint); | 
 |  | 
 |     return recorder.finishRecordingAsDrawable(); | 
 | } | 
 |  | 
 | static sk_sp<SkTypeface> make_tf() { | 
 |     SkCustomTypefaceBuilder builder; | 
 |     SkFont font = ToolUtils::DefaultFont(); | 
 |     SkASSERT(font.getTypeface()); | 
 |     const float upem = font.getTypeface()->getUnitsPerEm(); | 
 |  | 
 |     // request a big size, to improve precision at the fontscaler level | 
 |     font.setSize(upem); | 
 |     font.setHinting(SkFontHinting::kNone); | 
 |  | 
 |     // so we can scale our paths back down to 1-point | 
 |     const SkMatrix scale = SkMatrix::Scale(1.0f/upem, 1.0f/upem); | 
 |  | 
 |     { | 
 |         SkFontMetrics metrics; | 
 |         font.getMetrics(&metrics); | 
 |         builder.setMetrics(metrics, 1.0f/upem); | 
 |     } | 
 |     builder.setFontStyle(font.getTypeface()->fontStyle()); | 
 |  | 
 |     // Steal the first 128 chars from the default font | 
 |     for (SkUnichar index = 0; index <= 127; ++index) { | 
 |         SkGlyphID glyph = font.unicharToGlyph(index); | 
 |  | 
 |         SkScalar width = font.getWidth(glyph); | 
 |         SkPath path = font.getPath(glyph).value_or(SkPath()).makeTransform(scale); | 
 |  | 
 |         // we use the charcode to be our glyph index, since we have no cmap table | 
 |         if (index % 2) { | 
 |             builder.setGlyph(index, width/upem, make_drawable(path), path.computeTightBounds()); | 
 |         } else { | 
 |             builder.setGlyph(index, width/upem, path); | 
 |         } | 
 |     } | 
 |  | 
 |     return builder.detach(); | 
 | } | 
 |  | 
 | #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()); | 
 |     sk_sp<SkTypeface> face = SkTypeface::MakeDeserialize(&stream, nullptr); | 
 |     SkASSERT(face); | 
 |     return face; | 
 | } | 
 |  | 
 | class UserFontGM : public skiagm::GM { | 
 |     sk_sp<SkTypeface> fTF; | 
 |  | 
 | public: | 
 |     UserFontGM() {} | 
 |  | 
 |     void onOnceBeforeDraw() override { | 
 |         fTF = make_tf(); | 
 |         // test serialization | 
 |         fTF = round_trip(fTF); | 
 |     } | 
 |  | 
 |     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); | 
 |     } | 
 |  | 
 |     bool runAsBench() const override { return true; } | 
 |  | 
 |     SkString getName() const override { return SkString("user_typeface"); } | 
 |  | 
 |     SkISize getISize() override { return {810, 452}; } | 
 |  | 
 |     void onDraw(SkCanvas* canvas) override { | 
 |         auto waterfall = [&](sk_sp<SkTypeface> tf, bool defaultFace) { | 
 |             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, &spacing); | 
 |  | 
 |                 // shared baseline | 
 |                 if (defaultFace) { | 
 |                     paint.setColor(0xFFDDDDDD); | 
 |                     canvas->drawRect({0, y, 810, y+1}, paint); | 
 |                 } | 
 |  | 
 |                 paint.setColor(0xFFCCCCCC); | 
 |                 paint.setStyle(SkPaint::kStroke_Style); | 
 |                 canvas->drawRect(blob->bounds().makeOffset(x, y), paint); | 
 |  | 
 |                 paint.setStyle(SkPaint::kFill_Style); | 
 |                 paint.setColor(SK_ColorBLACK); | 
 |                 canvas->drawTextBlob(blob, x, y, paint); | 
 |  | 
 |                 y += SkScalarRoundToInt(spacing * 1.25f + 2); | 
 |             } | 
 |         }; | 
 |  | 
 |         waterfall(ToolUtils::DefaultTypeface(), true); | 
 |         canvas->translate(400, 0); | 
 |         waterfall(fTF, false); | 
 |     } | 
 | }; | 
 | DEF_GM(return new UserFontGM;) |