| Index: third_party/ots/test/idempotent.cc
|
| diff --git a/third_party/ots/test/idempotent.cc b/third_party/ots/test/idempotent.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ec50ab44bd4726526d22263f50431caaa5e7c98a
|
| --- /dev/null
|
| +++ b/third_party/ots/test/idempotent.cc
|
| @@ -0,0 +1,219 @@
|
| +// 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 <ft2build.h>
|
| +#include FT_FREETYPE_H
|
| +#include FT_OUTLINE_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);
|
| +
|
| + ots::OTSContext context;
|
| +
|
| + bool r = context.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 = context.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;
|
| +}
|
|
|