blob: 2a3b32d2cf1e8ac3210ddd02944e954e168d5299 [file] [log] [blame]
djsollen@google.com1f584ed2013-09-19 12:08:40 +00001/*
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
bungeman6e45bda2016-07-25 15:11:49 -07008#include "SkData.h"
9#include "SkOTTable_OS_2.h"
10#include "SkSFNTHeader.h"
11#include "SkStream.h"
bungeman82a455f2016-04-14 08:04:45 -070012#include "SkRefCnt.h"
djsollen@google.com1f584ed2013-09-19 12:08:40 +000013#include "SkTypeface.h"
bungeman82a455f2016-04-14 08:04:45 -070014#include "SkTypefaceCache.h"
bungeman6e45bda2016-07-25 15:11:49 -070015#include "Resources.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000016#include "Test.h"
djsollen@google.com1f584ed2013-09-19 12:08:40 +000017
bungeman6e45bda2016-07-25 15:11:49 -070018#include <memory>
19
20static void TypefaceStyle_test(skiatest::Reporter* reporter,
21 uint16_t weight, uint16_t width, SkData* data)
22{
23 sk_sp<SkData> dataCopy;
reed42943c82016-09-12 12:01:44 -070024 if (!data->unique()) {
bungeman6e45bda2016-07-25 15:11:49 -070025 dataCopy = SkData::MakeWithCopy(data->data(), data->size());
reed42943c82016-09-12 12:01:44 -070026 data = dataCopy.get();
bungeman6e45bda2016-07-25 15:11:49 -070027 }
reed42943c82016-09-12 12:01:44 -070028 SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(data->writable_data());
bungeman6e45bda2016-07-25 15:11:49 -070029
30 SkSFNTHeader::TableDirectoryEntry* tableEntry =
31 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
32 SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr;
33 int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
34 for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
35 if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) {
36 os2TableEntry = tableEntry + tableEntryIndex;
37 break;
38 }
39 }
40 SkASSERT_RELEASE(os2TableEntry);
41
42 size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset);
43 SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset);
44 os2Table->usWeightClass.value = SkEndian_SwapBE16(weight);
45 using WidthType = SkOTTableOS2_V0::WidthClass::Value;
46 os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width));
47
reed42943c82016-09-12 12:01:44 -070048 sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromStream(new SkMemoryStream(sk_ref_sp(data))));
bungeman6e45bda2016-07-25 15:11:49 -070049 SkASSERT_RELEASE(newTypeface);
50
51 SkFontStyle newStyle = newTypeface->fontStyle();
52
53 //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF);
54 //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F);
55 //printf("%d, %d\n", weight, newStyle.weight());
56 //printf("%d, %d\n", width , newStyle.width());
57
58 // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently).
59 REPORTER_ASSERT(reporter,
60 newStyle.weight() == weight ||
61 (weight <= 10 && newStyle.weight() == 100 * weight) ||
62 (weight == 4 && newStyle.weight() == 350) || // GDI weirdness
63 (weight == 5 && newStyle.weight() == 400) || // GDI weirdness
64 (weight == 0 && newStyle.weight() == 1) || // DW weirdness
65 (weight == 1000 && newStyle.weight() == 999) // DW weirdness
66 );
67
68 // Some back-ends (GDI) don't support width, ensure these always report 'medium'.
69 REPORTER_ASSERT(reporter,
70 newStyle.width() == width ||
71 newStyle.width() == 5);
72}
73DEF_TEST(TypefaceStyle, reporter) {
74 std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("/fonts/Em.ttf"));
75 if (!stream) {
76 REPORT_FAILURE(reporter, "/fonts/Em.ttf", SkString("Cannot load resource"));
77 return;
78 }
79 sk_sp<SkData> data(SkData::MakeFromStream(stream.get(), stream->getLength()));
80
81 using SkFS = SkFontStyle;
82 for (int weight = SkFS::kInvisible_Weight; weight <= SkFS::kExtraBlack_Weight; ++weight) {
83 TypefaceStyle_test(reporter, weight, 5, data.get());
84 }
bungemand783e082016-08-01 12:37:13 -070085 for (int width = SkFS::kUltraCondensed_Width; width <= SkFS::kUltraExpanded_Width; ++width) {
bungeman6e45bda2016-07-25 15:11:49 -070086 TypefaceStyle_test(reporter, 400, width, data.get());
87 }
88}
89
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +000090DEF_TEST(Typeface, reporter) {
djsollen@google.com1f584ed2013-09-19 12:08:40 +000091
mbocee6a9912016-05-31 11:42:36 -070092 sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
bungeman13b9c952016-05-12 10:09:30 -070093 sk_sp<SkTypeface> t2(SkTypeface::MakeDefault(SkTypeface::kNormal));
djsollen@google.com1f584ed2013-09-19 12:08:40 +000094
95 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
96 REPORTER_ASSERT(reporter, SkTypeface::Equal(0, t1.get()));
97 REPORTER_ASSERT(reporter, SkTypeface::Equal(0, t2.get()));
98 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), 0));
99 REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), 0));
100
101#ifdef SK_BUILD_FOR_ANDROID
mbocee6a9912016-05-31 11:42:36 -0700102 sk_sp<SkTypeface> t3(SkTypeface::MakeFromName("non-existent-font", SkFontStyle()));
bungeman13b9c952016-05-12 10:09:30 -0700103 REPORTER_ASSERT(reporter, nullptr == t3);
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000104#endif
105}
bungeman82a455f2016-04-14 08:04:45 -0700106
bungemana821af82016-04-14 09:44:34 -0700107namespace {
108
bungeman82a455f2016-04-14 08:04:45 -0700109class SkEmptyTypeface : public SkTypeface {
110public:
bungemane3aea102016-07-13 05:16:58 -0700111 static sk_sp<SkTypeface> Create() { return sk_sp<SkTypeface>(new SkEmptyTypeface()); }
bungeman82a455f2016-04-14 08:04:45 -0700112protected:
bungemane3aea102016-07-13 05:16:58 -0700113 SkEmptyTypeface() : SkTypeface(SkFontStyle(), true) { }
bungeman82a455f2016-04-14 08:04:45 -0700114
115 SkStreamAsset* onOpenStream(int* ttcIndex) const override { return nullptr; }
116 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
117 const SkDescriptor*) const override {
118 return nullptr;
119 }
120 void onFilterRec(SkScalerContextRec*) const override { }
121 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
122 PerGlyphInfo,
123 const uint32_t*, uint32_t) const override { return nullptr; }
124 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override { }
125 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
126 uint16_t glyphs[], int glyphCount) const override {
127 SK_ABORT("unimplemented");
128 return 0;
129 }
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400130 int onCountGlyphs() const override { return 0; }
131 int onGetUPEM() const override { return 0; }
bungeman82a455f2016-04-14 08:04:45 -0700132 void onGetFamilyName(SkString* familyName) const override { familyName->reset(); }
133 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
134 SK_ABORT("unimplemented");
135 return nullptr;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400136 }
bungeman82a455f2016-04-14 08:04:45 -0700137 int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
138 size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
139};
140
bungemana821af82016-04-14 09:44:34 -0700141}
142
bungeman82a455f2016-04-14 08:04:45 -0700143static bool count_proc(SkTypeface* face, void* ctx) {
144 int* count = static_cast<int*>(ctx);
145 *count = *count + 1;
146 return false;
147}
148static int count(skiatest::Reporter* reporter, const SkTypefaceCache& cache) {
149 int count = 0;
150 SkTypeface* none = cache.findByProcAndRef(count_proc, &count);
151 REPORTER_ASSERT(reporter, none == nullptr);
152 return count;
153}
154
155DEF_TEST(TypefaceCache, reporter) {
bungemane3aea102016-07-13 05:16:58 -0700156 sk_sp<SkTypeface> t1(SkEmptyTypeface::Create());
bungeman82a455f2016-04-14 08:04:45 -0700157 {
158 SkTypefaceCache cache;
159 REPORTER_ASSERT(reporter, count(reporter, cache) == 0);
160 {
bungemane3aea102016-07-13 05:16:58 -0700161 sk_sp<SkTypeface> t0(SkEmptyTypeface::Create());
bungeman82a455f2016-04-14 08:04:45 -0700162 cache.add(t0.get());
163 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
164 cache.add(t1.get());
165 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
166 cache.purgeAll();
167 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
168 }
169 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
170 cache.purgeAll();
171 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
172 }
173 REPORTER_ASSERT(reporter, t1->unique());
174}