1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkFont.h"
9 #include "include/core/SkFontTypes.h"
10 #include "include/core/SkRefCnt.h"
11 #include "include/core/SkTypeface.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/base/SkAutoMalloc.h"
15 #include "src/core/SkFontPriv.h"
16 #include "src/core/SkPtrRecorder.h"
17 #include "src/core/SkReadBuffer.h"
18 #include "src/core/SkWriteBuffer.h"
19 #include "tests/Test.h"
20 #include "tools/ToolUtils.h"
21 
22 #include <cstddef>
23 
serialize_deserialize(const SkFont & font,skiatest::Reporter * reporter)24 static SkFont serialize_deserialize(const SkFont& font, skiatest::Reporter* reporter) {
25     sk_sp<SkRefCntSet> typefaces = sk_make_sp<SkRefCntSet>();
26     SkBinaryWriteBuffer wb;
27     wb.setTypefaceRecorder(typefaces);
28 
29     SkFontPriv::Flatten(font, wb);
30     size_t size = wb.bytesWritten();
31     SkAutoMalloc storage(size);
32     wb.writeToMemory(storage.get());
33 
34     int count = typefaces->count();
35     SkASSERT((!font.getTypeface() && count == 0) ||
36              ( font.getTypeface() && count == 1));
37     if (count) {
38         SkTypeface* typeface;
39         typefaces->copyToArray((SkRefCnt**)&typeface);
40         SkASSERT(typeface == font.getTypeface());
41     }
42 
43     SkReadBuffer rb(storage.get(), size);
44     sk_sp<SkTypeface> cloneTypeface = font.refTypeface();
45     if (count) {
46         rb.setTypefaceArray(&cloneTypeface, 1);
47     }
48     SkFont clone;
49     REPORTER_ASSERT(reporter, SkFontPriv::Unflatten(&clone, rb));
50     return clone;
51 }
52 
53 enum {
54     kForceAutoHinting      = 1 << 0,
55     kEmbeddedBitmaps       = 1 << 1,
56     kSubpixel              = 1 << 2,
57     kLinearMetrics         = 1 << 3,
58     kEmbolden              = 1 << 4,
59     kBaselineSnap          = 1 << 5,
60 
61     kAllBits = 0x3F,
62 };
63 
apply_flags(SkFont * font,unsigned flags)64 static void apply_flags(SkFont* font, unsigned flags) {
65     font->setForceAutoHinting(SkToBool(flags & kForceAutoHinting));
66     font->setEmbeddedBitmaps( SkToBool(flags & kEmbeddedBitmaps));
67     font->setSubpixel(        SkToBool(flags & kSubpixel));
68     font->setLinearMetrics(   SkToBool(flags & kLinearMetrics));
69     font->setEmbolden(        SkToBool(flags & kEmbolden));
70     font->setBaselineSnap(    SkToBool(flags & kBaselineSnap));
71 }
72 
DEF_TEST(Font_flatten,reporter)73 DEF_TEST(Font_flatten, reporter) {
74     const float sizes[] = {0, 0.001f, 1, 10, 10.001f, 100000.01f};
75     const float scales[] = {-5, 0, 1, 5};
76     const float skews[] = {-5, 0, 5};
77     const SkFont::Edging edges[] = {
78         SkFont::Edging::kAlias, SkFont::Edging::kSubpixelAntiAlias
79     };
80     const SkFontHinting hints[] = {
81         SkFontHinting::kNone, SkFontHinting::kFull
82     };
83     const unsigned int flags[] = {
84         kForceAutoHinting, kEmbeddedBitmaps, kSubpixel, kLinearMetrics, kEmbolden, kBaselineSnap,
85         kAllBits,
86     };
87     const sk_sp<SkTypeface> typefaces[] = {
88         nullptr, ToolUtils::sample_user_typeface()
89     };
90 
91     SkFont font;
92     for (float size : sizes) {
93         font.setSize(size);
94         for (float scale : scales) {
95             font.setScaleX(scale);
96             for (float skew : skews) {
97                 font.setSkewX(skew);
98                 for (auto edge : edges) {
99                     font.setEdging(edge);
100                     for (auto hint : hints) {
101                         font.setHinting(hint);
102                         for (auto flag : flags) {
103                             apply_flags(&font, flag);
104                             for (const sk_sp<SkTypeface>& typeface : typefaces) {
105                                 font.setTypeface(typeface);
106                                 SkFont clone = serialize_deserialize(font, reporter);
107                                 REPORTER_ASSERT(reporter, font == clone);
108                             }
109                         }
110                     }
111                 }
112             }
113         }
114     }
115 }
116