blob: fa9f052890b86cf78e73994dba2356e10705dd88 [file] [log] [blame]
yusukes@chromium.orgd257d182009-11-04 04:56:32 +00001// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
bashi@chromium.org54651a62011-02-18 09:05:42 +00005#if !defined(_WIN32)
yusukes@chromium.org9601aa92009-12-03 10:25:32 +00006#ifdef __linux__
7// Linux
8#include <freetype/ftoutln.h>
9#include <ft2build.h>
10#include FT_FREETYPE_H
11#else
12// Mac OS X
13#include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa
14#endif // __linux__
bashi@chromium.org54651a62011-02-18 09:05:42 +000015#include <unistd.h>
yusukes@chromium.org9601aa92009-12-03 10:25:32 +000016#else
17// Windows
bashi@chromium.org54651a62011-02-18 09:05:42 +000018#include <io.h>
bashi@chromium.org8d71e042012-05-07 08:45:16 +000019#include <Windows.h>
bashi@chromium.org54651a62011-02-18 09:05:42 +000020#endif // !defiend(_WIN32)
yusukes@chromium.org9601aa92009-12-03 10:25:32 +000021
yusukes@chromium.orgd257d182009-11-04 04:56:32 +000022#include <fcntl.h>
23#include <sys/stat.h>
yusukes@chromium.orgd257d182009-11-04 04:56:32 +000024
25#include <cstdio>
26#include <cstdlib>
27#include <cstring>
28
29#include "opentype-sanitiser.h"
30#include "ots-memory-stream.h"
31
32namespace {
33
34int Usage(const char *argv0) {
35 std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0);
36 return 1;
37}
38
bashi@chromium.org54651a62011-02-18 09:05:42 +000039bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size);
40bool DumpResults(const uint8_t *result1, const size_t len1,
41 const uint8_t *result2, const size_t len2);
42
43#if defined(_WIN32)
44#define ADDITIONAL_OPEN_FLAGS O_BINARY
45#else
46#define ADDITIONAL_OPEN_FLAGS 0
47#endif
48
49bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size) {
50 const int fd = open(file_name, O_RDONLY | ADDITIONAL_OPEN_FLAGS);
51 if (fd < 0) {
52 return false;
53 }
54
55 struct stat st;
56 fstat(fd, &st);
57
58 *file_size = st.st_size;
59 *data = new uint8_t[st.st_size];
60 if (read(fd, *data, st.st_size) != st.st_size) {
61 close(fd);
62 return false;
63 }
64 close(fd);
65 return true;
66}
67
68bool DumpResults(const uint8_t *result1, const size_t len1,
69 const uint8_t *result2, const size_t len2) {
70 int fd1 = open("out1.ttf",
71 O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600);
72 int fd2 = open("out2.ttf",
73 O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600);
74 if (fd1 < 0 || fd2 < 0) {
75 perror("opening output file");
76 return false;
77 }
78 if ((write(fd1, result1, len1) < 0) ||
79 (write(fd2, result2, len2) < 0)) {
80 perror("writing output file");
81 close(fd1);
82 close(fd2);
83 return false;
84 }
85 close(fd1);
86 close(fd2);
87 return true;
88}
89
90// Platform specific implementations.
91bool VerifyTranscodedFont(uint8_t *result, const size_t len);
92
93#if defined(__linux__)
94// Linux
95bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
96 FT_Library library;
97 FT_Error error = ::FT_Init_FreeType(&library);
98 if (error) {
99 return false;
100 }
101 FT_Face dummy;
102 error = ::FT_New_Memory_Face(library, result, len, 0, &dummy);
103 if (error) {
104 return false;
105 }
106 ::FT_Done_Face(dummy);
107 return true;
108}
109
110#elif defined(__APPLE_CC__)
111// Mac
112bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
ksakamoto@chromium.org2e1bb352013-04-03 08:32:41 +0000113 CFDataRef data = CFDataCreate(0, result, len);
114 if (!data) {
bashi@chromium.org54651a62011-02-18 09:05:42 +0000115 return false;
116 }
117
ksakamoto@chromium.org2e1bb352013-04-03 08:32:41 +0000118 CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
119 CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider);
120 CGDataProviderRelease(dataProvider);
121 CFRelease(data);
122 if (!cgFontRef) {
bashi@chromium.org54651a62011-02-18 09:05:42 +0000123 return false;
124 }
125
ksakamoto@chromium.org2e1bb352013-04-03 08:32:41 +0000126 size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef);
127 CGFontRelease(cgFontRef);
128 if (!numGlyphs) {
bashi@chromium.org54651a62011-02-18 09:05:42 +0000129 return false;
130 }
131 return true;
132}
133
134#elif defined(_WIN32)
135// Windows
136bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
137 DWORD num_fonts = 0;
138 HANDLE handle = AddFontMemResourceEx(result, len, 0, &num_fonts);
139 if (!handle) {
140 return false;
141 }
142 RemoveFontMemResourceEx(handle);
143 return true;
144}
145
146#else
147bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
148 std::fprintf(stderr, "Can't verify the transcoded font on this platform.\n");
149 return false;
150}
151
152#endif
153
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000154} // namespace
155
156int main(int argc, char **argv) {
157 if (argc != 2) return Usage(argv[0]);
158
bashi@chromium.org54651a62011-02-18 09:05:42 +0000159 size_t file_size = 0;
160 uint8_t *data = 0;
161 if (!ReadFile(argv[1], &data, &file_size)) {
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000162 std::fprintf(stderr, "Failed to read file!\n");
163 return 1;
164 }
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000165
166 // A transcoded font is usually smaller than an original font.
167 // However, it can be slightly bigger than the original one due to
168 // name table replacement and/or padding for glyf table.
agl@chromium.org5089f9c2010-04-28 21:23:06 +0000169 //
170 // However, a WOFF font gets decompressed and so can be *much* larger than
171 // the original.
bashi@chromium.org54651a62011-02-18 09:05:42 +0000172 uint8_t *result = new uint8_t[file_size * 8];
173 ots::MemoryStream output(result, file_size * 8);
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000174
bashi@chromium.org54651a62011-02-18 09:05:42 +0000175 bool r = ots::Process(&output, data, file_size);
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000176 if (!r) {
177 std::fprintf(stderr, "Failed to sanitise file!\n");
178 return 1;
179 }
180 const size_t result_len = output.Tell();
yusukes@chromium.orga90c5832010-07-15 06:02:28 +0000181 delete[] data;
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000182
183 uint8_t *result2 = new uint8_t[result_len];
184 ots::MemoryStream output2(result2, result_len);
185 r = ots::Process(&output2, result, result_len);
186 if (!r) {
187 std::fprintf(stderr, "Failed to sanitise previous output!\n");
188 return 1;
189 }
190 const size_t result2_len = output2.Tell();
191
192 bool dump_results = false;
193 if (result2_len != result_len) {
194 std::fprintf(stderr, "Outputs differ in length\n");
195 dump_results = true;
196 } else if (std::memcmp(result2, result, result_len)) {
197 std::fprintf(stderr, "Outputs differ in content\n");
198 dump_results = true;
199 }
200
201 if (dump_results) {
202 std::fprintf(stderr, "Dumping results to out1.tff and out2.tff\n");
bashi@chromium.org54651a62011-02-18 09:05:42 +0000203 if (!DumpResults(result, result_len, result2, result2_len)) {
204 std::fprintf(stderr, "Failed to dump output files.\n");
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000205 return 1;
206 }
207 }
208
yusukes@chromium.org9601aa92009-12-03 10:25:32 +0000209 // Verify that the transcoded font can be opened by the font renderer for
210 // Linux (FreeType2), Mac OS X, or Windows.
bashi@chromium.org54651a62011-02-18 09:05:42 +0000211 if (!VerifyTranscodedFont(result, result_len)) {
212 std::fprintf(stderr, "Failed to verify the transcoded font\n");
yusukes@chromium.org9601aa92009-12-03 10:25:32 +0000213 return 1;
214 }
yusukes@chromium.org9601aa92009-12-03 10:25:32 +0000215
yusukes@chromium.orgd257d182009-11-04 04:56:32 +0000216 return 0;
217}