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.
10 #include <sys/types.h>
17 #include "opentype-sanitiser.h"
18 #include "ots-memory-stream.h"
22 void DumpBitmap(const FT_Bitmap
*bitmap
) {
23 for (int i
= 0; i
< bitmap
->rows
* bitmap
->width
; ++i
) {
24 if (bitmap
->buffer
[i
] > 192) {
25 std::fprintf(stderr
, "#");
26 } else if (bitmap
->buffer
[i
] > 128) {
27 std::fprintf(stderr
, "*");
28 } else if (bitmap
->buffer
[i
] > 64) {
29 std::fprintf(stderr
, "+");
30 } else if (bitmap
->buffer
[i
] > 32) {
31 std::fprintf(stderr
, ".");
33 std::fprintf(stderr
, " ");
36 if ((i
+ 1) % bitmap
->width
== 0) {
37 std::fprintf(stderr
, "\n");
42 int CompareBitmaps(const FT_Bitmap
*orig
, const FT_Bitmap
*trans
) {
45 if (orig
->width
== trans
->width
&&
46 orig
->rows
== trans
->rows
) {
47 for (int i
= 0; i
< orig
->rows
* orig
->width
; ++i
) {
48 if (orig
->buffer
[i
] != trans
->buffer
[i
]) {
49 std::fprintf(stderr
, "bitmap data doesn't match!\n");
55 std::fprintf(stderr
, "bitmap metrics doesn't match! (%d, %d), (%d, %d)\n",
56 orig
->width
, orig
->rows
, trans
->width
, trans
->rows
);
61 std::fprintf(stderr
, "EXPECTED:\n");
63 std::fprintf(stderr
, "\nACTUAL:\n");
65 std::fprintf(stderr
, "\n\n");
68 delete[] orig
->buffer
;
69 delete[] trans
->buffer
;
73 int GetBitmap(FT_Library library
, FT_Outline
*outline
, FT_Bitmap
*bitmap
) {
75 FT_Outline_Get_CBox(outline
, &bbox
);
79 bbox
.xMax
= (bbox
.xMax
+ 63) & ~63;
80 bbox
.yMax
= (bbox
.yMax
+ 63) & ~63;
81 FT_Outline_Translate(outline
, -bbox
.xMin
, -bbox
.yMin
);
83 const int w
= (bbox
.xMax
- bbox
.xMin
) >> 6;
84 const int h
= (bbox
.yMax
- bbox
.yMin
) >> 6;
86 if (w
== 0 || h
== 0) {
87 return -1; // white space
90 std::fprintf(stderr
, "bad width/height\n");
94 uint8_t *buf
= new uint8_t[w
* h
];
95 std::memset(buf
, 0x0, w
* h
);
100 bitmap
->buffer
= buf
;
101 bitmap
->pixel_mode
= FT_PIXEL_MODE_GRAY
;
102 bitmap
->num_grays
= 256;
103 if (FT_Outline_Get_Bitmap(library
, outline
, bitmap
)) {
104 std::fprintf(stderr
, "can't get outline\n");
112 int LoadChar(FT_Face face
, bool use_bitmap
, int pt
, FT_ULong c
) {
113 static const int kDpi
= 72;
116 matrix
.xx
= matrix
.yy
= 1 << 16;
117 matrix
.xy
= matrix
.yx
= 0 << 16;
119 FT_Int32 flags
= FT_LOAD_DEFAULT
| FT_LOAD_TARGET_NORMAL
;
121 // Since the transcoder drops embedded bitmaps from the transcoded one,
122 // we have to use FT_LOAD_NO_BITMAP flag for the original face.
123 flags
|= FT_LOAD_NO_BITMAP
;
126 FT_Error error
= FT_Set_Char_Size(face
, pt
* (1 << 6), 0, kDpi
, 0);
128 std::fprintf(stderr
, "Failed to set the char size!\n");
132 FT_Set_Transform(face
, &matrix
, 0);
134 error
= FT_Load_Char(face
, c
, flags
);
135 if (error
) return -1; // no such glyf in the font.
137 if (face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
) {
138 std::fprintf(stderr
, "bad format\n");
145 int LoadCharThenCompare(FT_Library library
,
146 FT_Face orig_face
, FT_Face trans_face
,
147 int pt
, FT_ULong c
) {
148 FT_Bitmap orig_bitmap
, trans_bitmap
;
150 // Load original bitmap.
151 int ret
= LoadChar(orig_face
, false, pt
, c
);
152 if (ret
) return ret
; // 1: error, -1: no such glyph
154 FT_Outline
*outline
= &orig_face
->glyph
->outline
;
155 ret
= GetBitmap(library
, outline
, &orig_bitmap
);
156 if (ret
) return ret
; // white space?
158 // Load transformed bitmap.
159 ret
= LoadChar(trans_face
, true, pt
, c
);
161 std::fprintf(stderr
, "the glyph is not found on the transcoded font\n");
163 if (ret
) return 1; // -1 should be treated as error.
164 outline
= &trans_face
->glyph
->outline
;
165 ret
= GetBitmap(library
, outline
, &trans_bitmap
);
166 if (ret
) return ret
; // white space?
168 return CompareBitmaps(&orig_bitmap
, &trans_bitmap
);
171 int SideBySide(FT_Library library
, const char *file_name
,
172 uint8_t *orig_font
, size_t orig_len
,
173 uint8_t *trans_font
, size_t trans_len
) {
176 = FT_New_Memory_Face(library
, orig_font
, orig_len
, 0, &orig_face
);
178 std::fprintf(stderr
, "Failed to open the original font: %s!\n", file_name
);
183 error
= FT_New_Memory_Face(library
, trans_font
, trans_len
, 0, &trans_face
);
185 std::fprintf(stderr
, "Failed to open the transcoded font: %s!\n",
190 static const int kPts
[] = {100, 20, 18, 16, 12, 10, 8}; // pt
191 static const size_t kPtsLen
= sizeof(kPts
) / sizeof(kPts
[0]);
193 static const int kUnicodeRanges
[] = {
194 0x0020, 0x007E, // Basic Latin (ASCII)
195 0x00A1, 0x017F, // Latin-1
196 0x1100, 0x11FF, // Hangul
197 0x3040, 0x309F, // Japanese HIRAGANA letters
198 0x3130, 0x318F, // Hangul
199 0x4E00, 0x4F00, // CJK Kanji/Hanja
200 0xAC00, 0xAD00, // Hangul
202 static const size_t kUnicodeRangesLen
203 = sizeof(kUnicodeRanges
) / sizeof(kUnicodeRanges
[0]);
205 for (size_t i
= 0; i
< kPtsLen
; ++i
) {
206 for (size_t j
= 0; j
< kUnicodeRangesLen
; j
+= 2) {
207 for (int k
= 0; k
<= kUnicodeRanges
[j
+ 1] - kUnicodeRanges
[j
]; ++k
) {
208 int ret
= LoadCharThenCompare(library
, orig_face
, trans_face
,
210 kUnicodeRanges
[j
] + k
);
212 std::fprintf(stderr
, "Glyph mismatch! (file: %s, U+%04x, %dpt)!\n",
213 file_name
, kUnicodeRanges
[j
] + k
, kPts
[i
]);
225 int main(int argc
, char **argv
) {
227 std::fprintf(stderr
, "Usage: %s ttf_or_otf_filename\n", argv
[0]);
231 // load the font to memory.
232 const int fd
= ::open(argv
[1], O_RDONLY
);
240 const off_t orig_len
= st
.st_size
;
242 uint8_t *orig_font
= new uint8_t[orig_len
];
243 if (::read(fd
, orig_font
, orig_len
) != orig_len
) {
244 std::fprintf(stderr
, "Failed to read file!\n");
249 // check if FreeType2 can open the original font.
251 FT_Error error
= FT_Init_FreeType(&library
);
253 std::fprintf(stderr
, "Failed to initialize FreeType2!\n");
257 error
= FT_New_Memory_Face(library
, orig_font
, orig_len
, 0, &dummy
);
259 std::fprintf(stderr
, "Failed to open the original font with FT2! %s\n",
264 // transcode the original font.
265 static const size_t kPadLen
= 20 * 1024;
266 uint8_t *trans_font
= new uint8_t[orig_len
+ kPadLen
];
267 ots::MemoryStream
output(trans_font
, orig_len
+ kPadLen
);
268 ots::OTSContext context
;
270 bool result
= context
.Process(&output
, orig_font
, orig_len
);
272 std::fprintf(stderr
, "Failed to sanitise file! %s\n", argv
[1]);
275 const size_t trans_len
= output
.Tell();
277 // perform side-by-side tests.
278 return SideBySide(library
, argv
[1],
280 trans_font
, trans_len
);