1 /*
2 * Copyright 2013 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 "SkAdvancedTypefaceMetrics.h"
9 #include "SkData.h"
10 #include "SkFixed.h"
11 #include "SkFontMgr.h"
12 #include "SkMakeUnique.h"
13 #include "SkOTTable_OS_2.h"
14 #include "SkSFNTHeader.h"
15 #include "SkStream.h"
16 #include "SkRefCnt.h"
17 #include "SkTypeface.h"
18 #include "SkTypefaceCache.h"
19 #include "Resources.h"
20 #include "Test.h"
21
22 #include <memory>
23
TypefaceStyle_test(skiatest::Reporter * reporter,uint16_t weight,uint16_t width,SkData * data)24 static void TypefaceStyle_test(skiatest::Reporter* reporter,
25 uint16_t weight, uint16_t width, SkData* data)
26 {
27 sk_sp<SkData> dataCopy;
28 if (!data->unique()) {
29 dataCopy = SkData::MakeWithCopy(data->data(), data->size());
30 data = dataCopy.get();
31 }
32 SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(data->writable_data());
33
34 SkSFNTHeader::TableDirectoryEntry* tableEntry =
35 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
36 SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr;
37 int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
38 for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
39 if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) {
40 os2TableEntry = tableEntry + tableEntryIndex;
41 break;
42 }
43 }
44 SkASSERT_RELEASE(os2TableEntry);
45
46 size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset);
47 SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset);
48 os2Table->usWeightClass.value = SkEndian_SwapBE16(weight);
49 using WidthType = SkOTTableOS2_V0::WidthClass::Value;
50 os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width));
51
52 sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromStream(new SkMemoryStream(sk_ref_sp(data))));
53 if (!newTypeface) {
54 // Not all SkFontMgr can MakeFromStream().
55 return;
56 }
57
58 SkFontStyle newStyle = newTypeface->fontStyle();
59
60 //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF);
61 //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F);
62 //printf("%d, %d\n", weight, newStyle.weight());
63 //printf("%d, %d\n", width , newStyle.width());
64
65 // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently).
66 REPORTER_ASSERT(reporter,
67 newStyle.weight() == weight ||
68 (weight <= 10 && newStyle.weight() == 100 * weight) ||
69 (weight == 4 && newStyle.weight() == 350) || // GDI weirdness
70 (weight == 5 && newStyle.weight() == 400) || // GDI weirdness
71 (weight == 0 && newStyle.weight() == 1) || // DW weirdness
72 (weight == 1000 && newStyle.weight() == 999) // DW weirdness
73 );
74
75 // Some back-ends (GDI) don't support width, ensure these always report 'medium'.
76 REPORTER_ASSERT(reporter,
77 newStyle.width() == width ||
78 newStyle.width() == 5);
79 }
DEF_TEST(TypefaceStyle,reporter)80 DEF_TEST(TypefaceStyle, reporter) {
81 std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/Em.ttf"));
82 if (!stream) {
83 REPORT_FAILURE(reporter, "fonts/Em.ttf", SkString("Cannot load resource"));
84 return;
85 }
86 sk_sp<SkData> data(SkData::MakeFromStream(stream.get(), stream->getLength()));
87
88 using SkFS = SkFontStyle;
89 for (int weight = SkFS::kInvisible_Weight; weight <= SkFS::kExtraBlack_Weight; ++weight) {
90 TypefaceStyle_test(reporter, weight, 5, data.get());
91 }
92 for (int width = SkFS::kUltraCondensed_Width; width <= SkFS::kUltraExpanded_Width; ++width) {
93 TypefaceStyle_test(reporter, 400, width, data.get());
94 }
95 }
96
DEF_TEST(TypefaceAxes,reporter)97 DEF_TEST(TypefaceAxes, reporter) {
98 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
99 if (!distortable) {
100 REPORT_FAILURE(reporter, "distortable", SkString());
101 return;
102 }
103 constexpr int numberOfAxesInDistortable = 1;
104
105 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
106 // The position may be over specified. If there are multiple values for a given axis,
107 // ensure the last one since that's what css-fonts-4 requires.
108 const SkFontArguments::VariationPosition::Coordinate position[] = {
109 { SkSetFourByteTag('w','g','h','t'), 1.618033988749895f },
110 { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 },
111 };
112 SkFontArguments params;
113 params.setVariationDesignPosition({position, SK_ARRAY_COUNT(position)});
114 // TODO: if axes are set and the back-end doesn't support them, should we create the typeface?
115 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
116
117 if (!typeface) {
118 // Not all SkFontMgr can makeFromStream().
119 return;
120 }
121
122 int count = typeface->getVariationDesignPosition(nullptr, 0);
123 if (count == -1) {
124 return;
125 }
126 REPORTER_ASSERT(reporter, count == numberOfAxesInDistortable);
127
128 SkFontArguments::VariationPosition::Coordinate positionRead[numberOfAxesInDistortable];
129 count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
130 REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(positionRead));
131
132 REPORTER_ASSERT(reporter, positionRead[0].axis == position[1].axis);
133
134 // Convert to fixed for "almost equal".
135 SkFixed fixedRead = SkScalarToFixed(positionRead[0].value);
136 SkFixed fixedOriginal = SkScalarToFixed(position[1].value);
137 REPORTER_ASSERT(reporter, fixedRead == fixedOriginal);
138 }
139
DEF_TEST(TypefaceVariationIndex,reporter)140 DEF_TEST(TypefaceVariationIndex, reporter) {
141 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
142 if (!distortable) {
143 REPORT_FAILURE(reporter, "distortable", SkString());
144 return;
145 }
146
147 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
148 SkFontArguments params;
149 // The first named variation position in Distortable is 'Thin'.
150 params.setCollectionIndex(0x00010000);
151 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
152 if (!typeface) {
153 // FreeType is the only weird thing that supports this, Skia just needs to make sure if it
154 // gets one of these things make sense.
155 return;
156 }
157
158 int count = typeface->getVariationDesignPosition(nullptr, 0);
159 if (!(count == 1)) {
160 REPORT_FAILURE(reporter, "count == 1", SkString());
161 return;
162 }
163
164 SkFontArguments::VariationPosition::Coordinate positionRead[1];
165 count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
166 if (count == -1) {
167 return;
168 }
169 if (!(count == 1)) {
170 REPORT_FAILURE(reporter, "count == 1", SkString());
171 return;
172 }
173 REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
174 REPORTER_ASSERT(reporter, positionRead[0].value == 0.5);
175 }
176
DEF_TEST(Typeface,reporter)177 DEF_TEST(Typeface, reporter) {
178
179 sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
180 sk_sp<SkTypeface> t2(SkTypeface::MakeDefault());
181
182 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
183 REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t1.get()));
184 REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t2.get()));
185 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), nullptr));
186 REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), nullptr));
187 }
188
189 namespace {
190
191 class SkEmptyTypeface : public SkTypeface {
192 public:
Create()193 static sk_sp<SkTypeface> Create() { return sk_sp<SkTypeface>(new SkEmptyTypeface()); }
194 protected:
SkEmptyTypeface()195 SkEmptyTypeface() : SkTypeface(SkFontStyle(), true) { }
196
onOpenStream(int * ttcIndex) const197 SkStreamAsset* onOpenStream(int* ttcIndex) const override { return nullptr; }
onCreateScalerContext(const SkScalerContextEffects &,const SkDescriptor *) const198 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
199 const SkDescriptor*) const override {
200 return nullptr;
201 }
onFilterRec(SkScalerContextRec *) const202 void onFilterRec(SkScalerContextRec*) const override { }
onGetAdvancedMetrics() const203 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override {
204 return nullptr;
205 }
onGetFontDescriptor(SkFontDescriptor *,bool *) const206 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override { }
onCharsToGlyphs(const void * chars,Encoding encoding,uint16_t glyphs[],int glyphCount) const207 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
208 uint16_t glyphs[], int glyphCount) const override {
209 SK_ABORT("unimplemented");
210 return 0;
211 }
onCountGlyphs() const212 int onCountGlyphs() const override { return 0; }
onGetUPEM() const213 int onGetUPEM() const override { return 0; }
onGetFamilyName(SkString * familyName) const214 void onGetFamilyName(SkString* familyName) const override { familyName->reset(); }
onCreateFamilyNameIterator() const215 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
216 SK_ABORT("unimplemented");
217 return nullptr;
218 }
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const219 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
220 int coordinateCount) const override
221 {
222 return 0;
223 }
onGetTableTags(SkFontTableTag tags[]) const224 int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
onGetTableData(SkFontTableTag,size_t,size_t,void *) const225 size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
226 };
227
228 }
229
count_proc(SkTypeface * face,void * ctx)230 static bool count_proc(SkTypeface* face, void* ctx) {
231 int* count = static_cast<int*>(ctx);
232 *count = *count + 1;
233 return false;
234 }
count(skiatest::Reporter * reporter,const SkTypefaceCache & cache)235 static int count(skiatest::Reporter* reporter, const SkTypefaceCache& cache) {
236 int count = 0;
237 SkTypeface* none = cache.findByProcAndRef(count_proc, &count);
238 REPORTER_ASSERT(reporter, none == nullptr);
239 return count;
240 }
241
DEF_TEST(TypefaceCache,reporter)242 DEF_TEST(TypefaceCache, reporter) {
243 sk_sp<SkTypeface> t1(SkEmptyTypeface::Create());
244 {
245 SkTypefaceCache cache;
246 REPORTER_ASSERT(reporter, count(reporter, cache) == 0);
247 {
248 sk_sp<SkTypeface> t0(SkEmptyTypeface::Create());
249 cache.add(t0.get());
250 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
251 cache.add(t1.get());
252 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
253 cache.purgeAll();
254 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
255 }
256 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
257 cache.purgeAll();
258 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
259 }
260 REPORTER_ASSERT(reporter, t1->unique());
261 }
262