Home | History | Annotate | Download | only in test
      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 
     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 
     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 
     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
     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
    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
    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
    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 
    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