blob: e35e73f58bd87dca2eb443dfebbae5a6e47b90d1 [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.com17aa07d2012-02-23 14:51:10 +000011
12//#define DUMP_TABLES
13
14#define kFontTableTag_head SkSetFourByteTag('h', 'e', 'a', 'd')
15#define kFontTableTag_hhea SkSetFourByteTag('h', 'h', 'e', 'a')
reed@google.com17aa07d2012-02-23 14:51:10 +000016#define kFontTableTag_maxp SkSetFourByteTag('m', 'a', 'x', 'p')
17
18static const struct TagSize {
19 SkFontTableTag fTag;
20 size_t fSize;
21} gKnownTableSizes[] = {
22 { kFontTableTag_head, 54 },
23 { kFontTableTag_hhea, 36 },
reed@google.com17aa07d2012-02-23 14:51:10 +000024 { kFontTableTag_maxp, 32 },
25};
26
27static void test_tables(skiatest::Reporter* reporter, SkTypeface* face) {
28 SkFontID fontID = face->uniqueID();
caryclark@google.com42639cd2012-06-06 12:03:39 +000029 if (false) { // avoid bit rot, suppress warning
30 REPORTER_ASSERT(reporter, fontID);
31 }
reed@google.com17aa07d2012-02-23 14:51:10 +000032
reed@google.com8b0a3352012-04-19 18:52:39 +000033 int count = face->countTables();
reed@google.com17aa07d2012-02-23 14:51:10 +000034
35 SkAutoTMalloc<SkFontTableTag> storage(count);
36 SkFontTableTag* tags = storage.get();
reed@google.comfbd033d2012-02-23 16:15:58 +000037
reed@google.com8b0a3352012-04-19 18:52:39 +000038 int count2 = face->getTableTags(tags);
reed@google.comfbd033d2012-02-23 16:15:58 +000039 REPORTER_ASSERT(reporter, count2 == count);
reed@google.com17aa07d2012-02-23 14:51:10 +000040
41 for (int i = 0; i < count; ++i) {
reed@google.com8b0a3352012-04-19 18:52:39 +000042 size_t size = face->getTableSize(tags[i]);
reed@google.com17aa07d2012-02-23 14:51:10 +000043 REPORTER_ASSERT(reporter, size > 0);
44
45#ifdef DUMP_TABLES
46 char name[5];
47 name[0] = (tags[i] >> 24) & 0xFF;
48 name[1] = (tags[i] >> 16) & 0xFF;
49 name[2] = (tags[i] >> 8) & 0xFF;
50 name[3] = (tags[i] >> 0) & 0xFF;
51 name[4] = 0;
52 SkDebugf("%s %d\n", name, size);
53#endif
54
55 for (size_t j = 0; j < SK_ARRAY_COUNT(gKnownTableSizes); ++j) {
56 if (gKnownTableSizes[j].fTag == tags[i]) {
57 REPORTER_ASSERT(reporter, gKnownTableSizes[j].fSize == size);
58 }
59 }
reed@google.comfbd033d2012-02-23 16:15:58 +000060
61 // do we get the same size from GetTableData and GetTableSize
62 {
63 SkAutoMalloc data(size);
reed@google.com8b0a3352012-04-19 18:52:39 +000064 size_t size2 = face->getTableData(tags[i], 0, size, data.get());
reed@google.comfbd033d2012-02-23 16:15:58 +000065 REPORTER_ASSERT(reporter, size2 == size);
66 }
reed@google.com17aa07d2012-02-23 14:51:10 +000067 }
68}
69
70static void test_tables(skiatest::Reporter* reporter) {
71 static const char* const gNames[] = {
72 NULL, // default font
73 "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
74 "Courier New",
75 };
76
77 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
78 SkTypeface* face = SkTypeface::CreateFromName(gNames[i],
79 SkTypeface::kNormal);
80 if (face) {
81#ifdef DUMP_TABLES
82 SkDebugf("%s\n", gNames[i]);
83#endif
84 test_tables(reporter, face);
85 face->unref();
86 }
87 }
88}
89
bungeman@google.com34f10262012-03-23 18:11:47 +000090/*
91 * Verifies that the advance values returned by generateAdvance and
92 * generateMetrics match.
93 */
94static void test_advances(skiatest::Reporter* reporter) {
95 static const char* const faces[] = {
96 NULL, // default font
97 "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
98 "Courier New", "Verdana", "monospace",
99 };
100
101 static const struct {
102 SkPaint::Hinting hinting;
103 unsigned flags;
104 } settings[] = {
105 { SkPaint::kNo_Hinting, 0 },
106 { SkPaint::kNo_Hinting, SkPaint::kLinearText_Flag },
107 { SkPaint::kNo_Hinting, SkPaint::kSubpixelText_Flag },
108 { SkPaint::kSlight_Hinting, 0 },
109 { SkPaint::kSlight_Hinting, SkPaint::kLinearText_Flag },
110 { SkPaint::kSlight_Hinting, SkPaint::kSubpixelText_Flag },
111 { SkPaint::kNormal_Hinting, 0 },
112 { SkPaint::kNormal_Hinting, SkPaint::kLinearText_Flag },
113 { SkPaint::kNormal_Hinting, SkPaint::kSubpixelText_Flag },
114 };
115
116 SkPaint paint;
117 char txt[] = "long.text.with.lots.of.dots.";
118
119 for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
120 SkTypeface* face = SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal);
121 paint.setTypeface(face);
122
123 for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) {
124 paint.setHinting(settings[j].hinting);
125 paint.setLinearText((settings[j].flags & SkPaint::kLinearText_Flag) != 0);
126 paint.setSubpixelText((settings[j].flags & SkPaint::kSubpixelText_Flag) != 0);
127
128 SkRect bounds;
129
130 // For no hinting and light hinting this should take the
131 // optimized generateAdvance path.
132 SkScalar width1 = paint.measureText(txt, strlen(txt));
133
134 // Requesting the bounds forces a generateMetrics call.
135 SkScalar width2 = paint.measureText(txt, strlen(txt), &bounds);
136
137 // SkDebugf("Font: %s, generateAdvance: %f, generateMetrics: %f\n",
138 // faces[i], SkScalarToFloat(width1), SkScalarToFloat(width2));
139
140 REPORTER_ASSERT(reporter, width1 == width2);
141 }
142 }
143}
144
reed@google.com17aa07d2012-02-23 14:51:10 +0000145static void TestFontHost(skiatest::Reporter* reporter) {
146 test_tables(reporter);
bungeman@google.com34f10262012-03-23 18:11:47 +0000147 test_advances(reporter);
reed@google.com17aa07d2012-02-23 14:51:10 +0000148}
149
150// need tests for SkStrSearch
151
152#include "TestClassDef.h"
153DEFINE_TESTCLASS("FontHost", FontHostTestClass, TestFontHost)