Formatting.
[ttfautohint.git] / src / ttfautohint.c
blobef645b940e5453112b6b62a0396fb416f224db8d
1 /* ttfautohint.c */
3 /* written 2011 by Werner Lemberg <wl@gnu.org> */
5 /* This file needs FreeType 2.4.5 or newer. */
8 #include <config.h>
9 #include <stdio.h>
10 #include <string.h>
12 #include <ft2build.h>
13 #include FT_FREETYPE_H
14 #include FT_TRUETYPE_TABLES_H
15 #include FT_TRUETYPE_TAGS_H
17 #include "ttfautohint.h"
20 /* this structure represents both the data contained in the SFNT */
21 /* table records and the actual SFNT table data */
22 typedef struct SFNT_Table_ {
23 FT_ULong tag;
24 FT_ULong len;
25 FT_Byte* buf;
26 } SFNT_Table;
28 /* this structure is used to model a font within a TTC */
29 typedef struct SFNT_ {
30 FT_Face face;
31 SFNT_Table* table_infos;
32 FT_ULong num_table_infos;
33 } SFNT;
35 /* our font object */
36 typedef struct FONT_ {
37 FT_Library lib;
39 FT_Byte* in_buf;
40 size_t in_len;
42 SFNT* sfnts;
43 FT_Long num_sfnts;
45 SFNT_Table* tables;
46 FT_ULong num_tables;
47 } FONT;
50 static FT_Error
51 TA_font_load_into_memory(FILE* in,
52 FONT* font)
54 fseek(in, 0, SEEK_END);
55 font->in_len = ftell(in);
56 fseek(in, 0, SEEK_SET);
58 /* a TTF can never be that small */
59 if (font->in_len < 100)
60 return FT_Err_Invalid_Argument;
62 font->in_buf = (FT_Byte*)malloc(font->in_len);
63 if (!font->in_buf)
64 return FT_Err_Out_Of_Memory;
66 if (fread(font->in_buf, 1, font->in_len, in) != font->in_len)
67 return FT_Err_Invalid_Stream_Read;
69 return TA_Err_Ok;
73 static FT_Error
74 TA_font_init(FONT* font)
76 FT_Error error;
77 FT_Face f;
80 error = FT_Init_FreeType(&font->lib);
81 if (error)
82 return error;
84 /* get number of faces (i.e. subfonts) */
85 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len, -1, &f);
86 if (error)
87 return error;
88 font->num_sfnts = f->num_faces;
89 FT_Done_Face(f);
91 /* it is a TTC if we have more than a single subfont */
92 font->sfnts = (SFNT*)calloc(1, font->num_sfnts * sizeof (SFNT));
93 if (!font->sfnts)
94 return FT_Err_Out_Of_Memory;
96 return TA_Err_Ok;
100 static FT_Error
101 TA_font_collect_table_info(SFNT* sfnt)
103 FT_Error error;
104 FT_ULong glyf_idx;
105 FT_ULong i;
108 /* check that font is TTF */
109 if (!FT_IS_SFNT(sfnt->face))
110 return FT_Err_Invalid_Argument;
112 error = FT_Sfnt_Table_Info(sfnt->face, 0, NULL, &sfnt->num_table_infos);
113 if (error)
114 return error;
116 sfnt->table_infos =
117 (SFNT_Table*)calloc(1, sfnt->num_table_infos * sizeof (SFNT_Table));
118 if (!sfnt->table_infos)
119 return FT_Err_Out_Of_Memory;
121 /* collect SFNT table information and search for `glyf' table */
122 glyf_idx = sfnt->num_table_infos;
123 for (i = 0; i < sfnt->num_table_infos; i++)
125 FT_ULong tag, len;
128 error = FT_Sfnt_Table_Info(sfnt->face, i, &tag, &len);
129 if (error && error != FT_Err_Table_Missing)
130 return error;
132 if (!error)
134 if (tag == TTAG_glyf)
135 glyf_idx = i;
137 /* ignore tables which we are going to create by ourselves */
138 if (!(tag == TTAG_fpgm
139 || tag == TTAG_prep
140 || tag == TTAG_cvt))
142 sfnt->table_infos[i].tag = tag;
143 sfnt->table_infos[i].len = len;
148 /* no (non-empty) `glyf' table; this can't be a TTF with outlines */
149 if (glyf_idx == sfnt->num_table_infos)
150 return FT_Err_Invalid_Argument;
152 return TA_Err_Ok;
156 static FT_Error
157 TA_font_split_into_SFNT_tables(SFNT* sfnt,
158 FONT* font)
160 FT_Error error;
161 FT_ULong i;
164 for (i = 0; i < sfnt->num_table_infos; i++)
166 SFNT_Table* table_info = &sfnt->table_infos[i];
169 /* we ignore empty tables */
170 if (table_info->len)
172 FT_Byte* buf;
173 FT_ULong j;
176 buf = (FT_Byte*)malloc(table_info->len);
177 if (!buf)
178 return FT_Err_Out_Of_Memory;
180 /* load table */
181 error = FT_Load_Sfnt_Table(sfnt->face, table_info->tag, 0,
182 buf, &table_info->len);
183 if (error)
184 goto Err;
186 /* check whether we already have this table */
187 for (j = 0; j < font->num_tables; j++)
189 SFNT_Table* table = &font->tables[j];
192 if (table->tag == table_info->tag
193 && table->len == table_info->len
194 && !memcmp(table->buf, buf, table->len))
195 break;
198 /* add element to table array if it's missing or not the same */
199 if (j == font->num_tables)
201 SFNT_Table* tables_new;
202 SFNT_Table* table_last;
205 font->num_tables++;
206 tables_new =
207 (SFNT_Table*)realloc(font->tables,
208 font->num_tables * sizeof (SFNT_Table));
209 if (!tables_new)
211 error = FT_Err_Out_Of_Memory;
212 goto Err;
214 else
215 font->tables = tables_new;
217 table_last = &font->tables[font->num_tables - 1];
219 table_last->tag = table_info->tag;
220 table_last->len = table_info->len;
221 table_last->buf = buf;
223 /* link buffer pointer */
224 table_info->buf = table_last->buf;
226 else
228 free(buf);
229 table_info->buf = font->tables[j].buf;
231 continue;
233 Err:
234 free(buf);
235 return error;
239 return TA_Err_Ok;
243 static void
244 TA_font_unload(FONT* font)
246 /* in case of error it is expected that unallocated pointers */
247 /* are NULL (and counters are zero) */
249 if (!font)
250 return;
252 if (font->tables)
254 FT_ULong i;
257 for (i = 0; i < font->num_tables; i++)
258 free(font->tables[i].buf);
259 free(font->tables);
262 if (font->sfnts)
264 FT_Long i;
267 for (i = 0; i < font->num_sfnts; i++)
269 FT_Done_Face(font->sfnts[i].face);
270 free(font->sfnts[i].table_infos);
272 free(font->sfnts);
275 FT_Done_FreeType(font->lib);
276 free(font->in_buf);
277 free(font);
281 TA_Error
282 TTF_autohint(FILE* in,
283 FILE* out)
285 FONT* font;
286 FT_Error error;
287 FT_Long i;
290 font = (FONT*)calloc(1, sizeof (FONT));
291 if (!font)
292 return FT_Err_Out_Of_Memory;
294 error = TA_font_load_into_memory(in, font);
295 if (error)
296 goto Err;
298 error = TA_font_init(font);
299 if (error)
300 goto Err;
302 /* loop over subfonts */
303 for (i = 0; i < font->num_sfnts; i++)
305 SFNT* sfnt = &font->sfnts[i];
308 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len,
309 i, &sfnt->face);
310 if (error)
311 goto Err;
313 error = TA_font_collect_table_info(sfnt);
314 if (error)
315 goto Err;
317 error = TA_font_split_into_SFNT_tables(sfnt, font);
318 if (error)
319 goto Err;
323 /* compute global hints */
324 /* construct `fpgm' table */
325 /* construct `prep' table */
326 /* construct `cvt ' table */
328 /* split `glyf' table */
329 /* handle all glyphs in a loop */
330 /* strip bytecode */
331 /* hint the glyph */
332 /* construct bytecode */
334 /* construct `glyf' table */
335 /* build font from SFNT tables */
336 /* write font from memory */
338 error = TA_Err_Ok;
340 Err:
341 TA_font_unload(font);
343 return error;
346 /* end of ttfautohint.c */