• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
5 #if !defined(_WIN32)
6 #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__
15 #include <unistd.h>
16 #else
17 // Windows
18 #include <io.h>
19 #include <Windows.h>
20 #endif  // !defiend(_WIN32)
21 
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28 
29 #include "opentype-sanitiser.h"
30 #include "ots-memory-stream.h"
31 
32 namespace {
33 
Usage(const char * argv0)34 int Usage(const char *argv0) {
35   std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0);
36   return 1;
37 }
38 
39 bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size);
40 bool 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 
ReadFile(const char * file_name,uint8_t ** data,size_t * file_size)49 bool 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 
DumpResults(const uint8_t * result1,const size_t len1,const uint8_t * result2,const size_t len2)68 bool 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.
91 bool VerifyTranscodedFont(uint8_t *result, const size_t len);
92 
93 #if defined(__linux__)
94 // Linux
VerifyTranscodedFont(uint8_t * result,const size_t len)95 bool 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
VerifyTranscodedFont(uint8_t * result,const size_t len)112 bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
113   CFDataRef data = CFDataCreate(0, result, len);
114   if (!data) {
115     return false;
116   }
117 
118   CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
119   CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider);
120   CGDataProviderRelease(dataProvider);
121   CFRelease(data);
122   if (!cgFontRef) {
123     return false;
124   }
125 
126   size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef);
127   CGFontRelease(cgFontRef);
128   if (!numGlyphs) {
129     return false;
130   }
131   return true;
132 }
133 
134 #elif defined(_WIN32)
135 // Windows
VerifyTranscodedFont(uint8_t * result,const size_t len)136 bool 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
VerifyTranscodedFont(uint8_t * result,const size_t len)147 bool 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 
154 }  // namespace
155 
main(int argc,char ** argv)156 int main(int argc, char **argv) {
157   if (argc != 2) return Usage(argv[0]);
158 
159   size_t file_size = 0;
160   uint8_t *data = 0;
161   if (!ReadFile(argv[1], &data, &file_size)) {
162     std::fprintf(stderr, "Failed to read file!\n");
163     return 1;
164   }
165 
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.
169   //
170   // However, a WOFF font gets decompressed and so can be *much* larger than
171   // the original.
172   uint8_t *result = new uint8_t[file_size * 8];
173   ots::MemoryStream output(result, file_size * 8);
174 
175   bool r = ots::Process(&output, data, file_size);
176   if (!r) {
177     std::fprintf(stderr, "Failed to sanitise file!\n");
178     return 1;
179   }
180   const size_t result_len = output.Tell();
181   delete[] data;
182 
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");
203     if (!DumpResults(result, result_len, result2, result2_len)) {
204       std::fprintf(stderr, "Failed to dump output files.\n");
205       return 1;
206     }
207   }
208 
209   // Verify that the transcoded font can be opened by the font renderer for
210   // Linux (FreeType2), Mac OS X, or Windows.
211   if (!VerifyTranscodedFont(result, result_len)) {
212     std::fprintf(stderr, "Failed to verify the transcoded font\n");
213     return 1;
214   }
215 
216   return 0;
217 }
218