blob: 879fdd07207d0840de5f63573b0818df9c57127f [file] [log] [blame]
reed@google.com17aa07d2012-02-23 14:51:10 +00001/*
2 * Copyright 2012 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 "Test.h"
reed@google.com8b0a3352012-04-19 18:52:39 +00009#include "SkPaint.h"
reed@google.com17aa07d2012-02-23 14:51:10 +000010#include "SkTypeface.h"
reed@google.com4b2af9c2012-07-31 17:24:44 +000011#include "SkEndian.h"
reed@google.com17aa07d2012-02-23 14:51:10 +000012
13//#define DUMP_TABLES
14
15#define kFontTableTag_head SkSetFourByteTag('h', 'e', 'a', 'd')
16#define kFontTableTag_hhea SkSetFourByteTag('h', 'h', 'e', 'a')
reed@google.com17aa07d2012-02-23 14:51:10 +000017#define kFontTableTag_maxp SkSetFourByteTag('m', 'a', 'x', 'p')
18
19static const struct TagSize {
20 SkFontTableTag fTag;
21 size_t fSize;
22} gKnownTableSizes[] = {
23 { kFontTableTag_head, 54 },
24 { kFontTableTag_hhea, 36 },
reed@google.com17aa07d2012-02-23 14:51:10 +000025 { kFontTableTag_maxp, 32 },
26};
27
reed@google.com4b2af9c2012-07-31 17:24:44 +000028static void test_unitsPerEm(skiatest::Reporter* reporter, SkTypeface* face) {
29 int upem = face->getUnitsPerEm();
bungeman@google.comc0d3f2f2012-07-31 21:39:05 +000030 if (0 == upem) return;
reed@google.com4b2af9c2012-07-31 17:24:44 +000031
32 size_t size = face->getTableSize(kFontTableTag_head);
33 if (size) {
34 SkAutoMalloc storage(size);
35 char* ptr = (char*)storage.get();
36 face->getTableData(kFontTableTag_head, 0, size, ptr);
37 // unitsPerEm is at offset 18 into the 'head' table.
38 int upem2 = SkEndian_SwapBE16(*(uint16_t*)&ptr[18]);
39 REPORTER_ASSERT(reporter, upem2 == upem);
40 }
41}
42
reed@google.com17aa07d2012-02-23 14:51:10 +000043static void test_tables(skiatest::Reporter* reporter, SkTypeface* face) {
44 SkFontID fontID = face->uniqueID();
caryclark@google.com42639cd2012-06-06 12:03:39 +000045 if (false) { // avoid bit rot, suppress warning
46 REPORTER_ASSERT(reporter, fontID);
47 }
reed@google.com17aa07d2012-02-23 14:51:10 +000048
reed@google.com8b0a3352012-04-19 18:52:39 +000049 int count = face->countTables();
reed@google.com17aa07d2012-02-23 14:51:10 +000050
51 SkAutoTMalloc<SkFontTableTag> storage(count);
52 SkFontTableTag* tags = storage.get();
reed@google.comfbd033d2012-02-23 16:15:58 +000053
reed@google.com8b0a3352012-04-19 18:52:39 +000054 int count2 = face->getTableTags(tags);
reed@google.comfbd033d2012-02-23 16:15:58 +000055 REPORTER_ASSERT(reporter, count2 == count);
reed@google.com17aa07d2012-02-23 14:51:10 +000056
57 for (int i = 0; i < count; ++i) {
reed@google.com8b0a3352012-04-19 18:52:39 +000058 size_t size = face->getTableSize(tags[i]);
reed@google.com17aa07d2012-02-23 14:51:10 +000059 REPORTER_ASSERT(reporter, size > 0);
60
61#ifdef DUMP_TABLES
62 char name[5];
63 name[0] = (tags[i] >> 24) & 0xFF;
64 name[1] = (tags[i] >> 16) & 0xFF;
65 name[2] = (tags[i] >> 8) & 0xFF;
66 name[3] = (tags[i] >> 0) & 0xFF;
67 name[4] = 0;
68 SkDebugf("%s %d\n", name, size);
69#endif
70
71 for (size_t j = 0; j < SK_ARRAY_COUNT(gKnownTableSizes); ++j) {
72 if (gKnownTableSizes[j].fTag == tags[i]) {
73 REPORTER_ASSERT(reporter, gKnownTableSizes[j].fSize == size);
74 }
75 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000076
reed@google.comfbd033d2012-02-23 16:15:58 +000077 // do we get the same size from GetTableData and GetTableSize
78 {
79 SkAutoMalloc data(size);
reed@google.com8b0a3352012-04-19 18:52:39 +000080 size_t size2 = face->getTableData(tags[i], 0, size, data.get());
reed@google.comfbd033d2012-02-23 16:15:58 +000081 REPORTER_ASSERT(reporter, size2 == size);
82 }
reed@google.com17aa07d2012-02-23 14:51:10 +000083 }
84}
85
86static void test_tables(skiatest::Reporter* reporter) {
87 static const char* const gNames[] = {
88 NULL, // default font
89 "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
bungeman@google.comc0d3f2f2012-07-31 21:39:05 +000090 "Courier New", "Terminal", "MS Sans Serif",
reed@google.com17aa07d2012-02-23 14:51:10 +000091 };
92
93 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
94 SkTypeface* face = SkTypeface::CreateFromName(gNames[i],
95 SkTypeface::kNormal);
96 if (face) {
97#ifdef DUMP_TABLES
98 SkDebugf("%s\n", gNames[i]);
99#endif
100 test_tables(reporter, face);
reed@google.com4b2af9c2012-07-31 17:24:44 +0000101 test_unitsPerEm(reporter, face);
reed@google.com17aa07d2012-02-23 14:51:10 +0000102 face->unref();
103 }
104 }
105}
106
bungeman@google.com34f10262012-03-23 18:11:47 +0000107/*
108 * Verifies that the advance values returned by generateAdvance and
109 * generateMetrics match.
110 */
111static void test_advances(skiatest::Reporter* reporter) {
112 static const char* const faces[] = {
113 NULL, // default font
114 "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
115 "Courier New", "Verdana", "monospace",
116 };
117
118 static const struct {
119 SkPaint::Hinting hinting;
120 unsigned flags;
121 } settings[] = {
122 { SkPaint::kNo_Hinting, 0 },
123 { SkPaint::kNo_Hinting, SkPaint::kLinearText_Flag },
124 { SkPaint::kNo_Hinting, SkPaint::kSubpixelText_Flag },
125 { SkPaint::kSlight_Hinting, 0 },
126 { SkPaint::kSlight_Hinting, SkPaint::kLinearText_Flag },
127 { SkPaint::kSlight_Hinting, SkPaint::kSubpixelText_Flag },
128 { SkPaint::kNormal_Hinting, 0 },
129 { SkPaint::kNormal_Hinting, SkPaint::kLinearText_Flag },
130 { SkPaint::kNormal_Hinting, SkPaint::kSubpixelText_Flag },
131 };
132
reed@google.comd074c372012-07-18 13:45:58 +0000133 static const struct {
134 SkScalar fScaleX;
135 SkScalar fSkewX;
136 } gScaleRec[] = {
137 { SK_Scalar1, 0 },
138 { SK_Scalar1/2, 0 },
139 // these two exercise obliquing (skew)
140 { SK_Scalar1, -SK_Scalar1/4 },
141 { SK_Scalar1/2, -SK_Scalar1/4 },
142 };
143
bungeman@google.com34f10262012-03-23 18:11:47 +0000144 SkPaint paint;
145 char txt[] = "long.text.with.lots.of.dots.";
146
147 for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
148 SkTypeface* face = SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal);
149 paint.setTypeface(face);
150
151 for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) {
reed@google.comd074c372012-07-18 13:45:58 +0000152 paint.setHinting(settings[j].hinting);
153 paint.setLinearText((settings[j].flags & SkPaint::kLinearText_Flag) != 0);
154 paint.setSubpixelText((settings[j].flags & SkPaint::kSubpixelText_Flag) != 0);
bungeman@google.com34f10262012-03-23 18:11:47 +0000155
reed@google.comd074c372012-07-18 13:45:58 +0000156 for (size_t k = 0; k < SK_ARRAY_COUNT(gScaleRec); ++k) {
157 paint.setTextScaleX(gScaleRec[k].fScaleX);
158 paint.setTextSkewX(gScaleRec[k].fSkewX);
bungeman@google.com34f10262012-03-23 18:11:47 +0000159
reed@google.comd074c372012-07-18 13:45:58 +0000160 SkRect bounds;
bungeman@google.com34f10262012-03-23 18:11:47 +0000161
reed@google.comd074c372012-07-18 13:45:58 +0000162 // For no hinting and light hinting this should take the
163 // optimized generateAdvance path.
164 SkScalar width1 = paint.measureText(txt, strlen(txt));
bungeman@google.com34f10262012-03-23 18:11:47 +0000165
reed@google.comd074c372012-07-18 13:45:58 +0000166 // Requesting the bounds forces a generateMetrics call.
167 SkScalar width2 = paint.measureText(txt, strlen(txt), &bounds);
bungeman@google.com34f10262012-03-23 18:11:47 +0000168
reed@google.comd074c372012-07-18 13:45:58 +0000169 // SkDebugf("Font: %s, generateAdvance: %f, generateMetrics: %f\n",
170 // faces[i], SkScalarToFloat(width1), SkScalarToFloat(width2));
171
172 REPORTER_ASSERT(reporter, width1 == width2);
173 }
bungeman@google.com34f10262012-03-23 18:11:47 +0000174 }
175 }
176}
177
reed@google.com17aa07d2012-02-23 14:51:10 +0000178static void TestFontHost(skiatest::Reporter* reporter) {
179 test_tables(reporter);
bungeman@google.com34f10262012-03-23 18:11:47 +0000180 test_advances(reporter);
reed@google.com17aa07d2012-02-23 14:51:10 +0000181}
182
183// need tests for SkStrSearch
184
185#include "TestClassDef.h"
186DEFINE_TESTCLASS("FontHost", FontHostTestClass, TestFontHost)