// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #if !defined(_WIN32) #ifdef __linux__ // Linux #include <freetype/ftoutln.h> #include <ft2build.h> #include FT_FREETYPE_H #else // Mac OS X #include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa #endif // __linux__ #include <unistd.h> #else // Windows #include <io.h> #include <Windows.h> #endif // !defiend(_WIN32) #include <fcntl.h> #include <sys/stat.h> #include <cstdio> #include <cstdlib> #include <cstring> #include "opentype-sanitiser.h" #include "ots-memory-stream.h" namespace { int Usage(const char *argv0) { std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0); return 1; } bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size); bool DumpResults(const uint8_t *result1, const size_t len1, const uint8_t *result2, const size_t len2); #if defined(_WIN32) #define ADDITIONAL_OPEN_FLAGS O_BINARY #else #define ADDITIONAL_OPEN_FLAGS 0 #endif bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size) { const int fd = open(file_name, O_RDONLY | ADDITIONAL_OPEN_FLAGS); if (fd < 0) { return false; } struct stat st; fstat(fd, &st); *file_size = st.st_size; *data = new uint8_t[st.st_size]; if (read(fd, *data, st.st_size) != st.st_size) { close(fd); return false; } close(fd); return true; } bool DumpResults(const uint8_t *result1, const size_t len1, const uint8_t *result2, const size_t len2) { int fd1 = open("out1.ttf", O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600); int fd2 = open("out2.ttf", O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600); if (fd1 < 0 || fd2 < 0) { perror("opening output file"); return false; } if ((write(fd1, result1, len1) < 0) || (write(fd2, result2, len2) < 0)) { perror("writing output file"); close(fd1); close(fd2); return false; } close(fd1); close(fd2); return true; } // Platform specific implementations. bool VerifyTranscodedFont(uint8_t *result, const size_t len); #if defined(__linux__) // Linux bool VerifyTranscodedFont(uint8_t *result, const size_t len) { FT_Library library; FT_Error error = ::FT_Init_FreeType(&library); if (error) { return false; } FT_Face dummy; error = ::FT_New_Memory_Face(library, result, len, 0, &dummy); if (error) { return false; } ::FT_Done_Face(dummy); return true; } #elif defined(__APPLE_CC__) // Mac bool VerifyTranscodedFont(uint8_t *result, const size_t len) { CFDataRef data = CFDataCreate(0, result, len); if (!data) { return false; } CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider); CGDataProviderRelease(dataProvider); CFRelease(data); if (!cgFontRef) { return false; } size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef); CGFontRelease(cgFontRef); if (!numGlyphs) { return false; } return true; } #elif defined(_WIN32) // Windows bool VerifyTranscodedFont(uint8_t *result, const size_t len) { DWORD num_fonts = 0; HANDLE handle = AddFontMemResourceEx(result, len, 0, &num_fonts); if (!handle) { return false; } RemoveFontMemResourceEx(handle); return true; } #else bool VerifyTranscodedFont(uint8_t *result, const size_t len) { std::fprintf(stderr, "Can't verify the transcoded font on this platform.\n"); return false; } #endif } // namespace int main(int argc, char **argv) { if (argc != 2) return Usage(argv[0]); size_t file_size = 0; uint8_t *data = 0; if (!ReadFile(argv[1], &data, &file_size)) { std::fprintf(stderr, "Failed to read file!\n"); return 1; } // A transcoded font is usually smaller than an original font. // However, it can be slightly bigger than the original one due to // name table replacement and/or padding for glyf table. // // However, a WOFF font gets decompressed and so can be *much* larger than // the original. uint8_t *result = new uint8_t[file_size * 8]; ots::MemoryStream output(result, file_size * 8); bool r = ots::Process(&output, data, file_size); if (!r) { std::fprintf(stderr, "Failed to sanitise file!\n"); return 1; } const size_t result_len = output.Tell(); delete[] data; uint8_t *result2 = new uint8_t[result_len]; ots::MemoryStream output2(result2, result_len); r = ots::Process(&output2, result, result_len); if (!r) { std::fprintf(stderr, "Failed to sanitise previous output!\n"); return 1; } const size_t result2_len = output2.Tell(); bool dump_results = false; if (result2_len != result_len) { std::fprintf(stderr, "Outputs differ in length\n"); dump_results = true; } else if (std::memcmp(result2, result, result_len)) { std::fprintf(stderr, "Outputs differ in content\n"); dump_results = true; } if (dump_results) { std::fprintf(stderr, "Dumping results to out1.tff and out2.tff\n"); if (!DumpResults(result, result_len, result2, result2_len)) { std::fprintf(stderr, "Failed to dump output files.\n"); return 1; } } // Verify that the transcoded font can be opened by the font renderer for // Linux (FreeType2), Mac OS X, or Windows. if (!VerifyTranscodedFont(result, result_len)) { std::fprintf(stderr, "Failed to verify the transcoded font\n"); return 1; } return 0; }