Really load different faces and omit table duplicates.
[ttfautohint.git] / src / ttfautohint.c
blobb7d110ec4dc9aa7e7ec2c5671a6cc19a72ed3cf9
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_TAGS_H
16 #include "ttfautohint.h"
19 typedef struct SFNT_Table_ {
20 FT_ULong tag;
21 FT_ULong len;
22 FT_Byte* buf;
23 } SFNT_Table;
25 typedef struct SFNT_ {
26 FT_Face face;
27 SFNT_Table* table_infos;
28 FT_ULong num_table_infos;
29 } SFNT;
32 TA_Error
33 TTF_autohint(FILE *in,
34 FILE *out)
36 FT_Library lib = NULL;
38 FT_Byte* in_buf;
39 size_t in_len;
41 SFNT* sfnts;
42 FT_Long num_sfnts = 0;
44 SFNT_Table* tables = NULL;
45 FT_ULong num_tables = 0;
47 FT_ULong glyf_idx;
49 FT_Error error;
51 FT_Long i;
52 FT_ULong j;
55 /*** load font into memory ***/
57 fseek(in, 0, SEEK_END);
58 in_len = ftell(in);
59 fseek(in, 0, SEEK_SET);
61 /* a TTF can never be that small */
62 if (in_len < 100)
63 return FT_Err_Invalid_Argument;
65 in_buf = (FT_Byte*)malloc(in_len);
66 if (!in_buf)
67 return FT_Err_Out_Of_Memory;
69 if (fread(in_buf, 1, in_len, in) != in_len)
71 error = FT_Err_Invalid_Stream_Read;
72 goto Err;
75 error = FT_Init_FreeType(&lib);
76 if (error)
77 goto Err;
80 FT_Face f;
83 error = FT_New_Memory_Face(lib, in_buf, in_len, -1, &f);
84 if (error)
85 goto Err;
86 num_sfnts = f->num_faces;
87 FT_Done_Face(f);
90 /* it is a TTC if we have more than a single face */
91 sfnts = (SFNT*)calloc(1, num_sfnts * sizeof (SFNT));
92 if (!sfnts)
94 error = FT_Err_Out_Of_Memory;
95 goto Err;
98 for (i = 0; i < num_sfnts; i++)
100 SFNT *sfnt = &sfnts[i];
103 error = FT_New_Memory_Face(lib, in_buf, in_len, i, &sfnt->face);
104 if (error)
105 goto Err;
107 /* check that font is TTF */
108 if (!FT_IS_SFNT(sfnt->face))
110 error = FT_Err_Invalid_Argument;
111 goto Err;
114 error = FT_Sfnt_Table_Info(sfnt->face, 0, NULL, &sfnt->num_table_infos);
115 if (error)
116 goto Err;
118 sfnt->table_infos =
119 (SFNT_Table*)calloc(1, sfnt->num_table_infos * sizeof (SFNT_Table));
120 if (!sfnt->table_infos)
122 error = FT_Err_Out_Of_Memory;
123 goto Err;
126 /* collect SFNT table data */
127 glyf_idx = sfnt->num_table_infos;
128 for (j = 0; j < sfnt->num_table_infos; j++)
130 FT_ULong tag, len;
133 error = FT_Sfnt_Table_Info(sfnt->face, j, &tag, &len);
134 if (error && error != FT_Err_Table_Missing)
135 goto Err;
137 if (!error)
139 if (tag == TTAG_glyf)
140 glyf_idx = j;
142 /* ignore tables which we are going to create by ourselves */
143 if (!(tag == TTAG_fpgm
144 || tag == TTAG_prep
145 || tag == TTAG_cvt))
147 sfnt->table_infos[j].tag = tag;
148 sfnt->table_infos[j].len = len;
153 /* no (non-empty) `glyf' table; this can't be a TTF with outlines */
154 if (glyf_idx == sfnt->num_table_infos)
156 error = FT_Err_Invalid_Argument;
157 goto Err;
161 /*** split font into SFNT tables ***/
163 for (j = 0; j < sfnt->num_table_infos; j++)
165 SFNT_Table *table_info = &sfnt->table_infos[j];
168 if (table_info->len)
170 SFNT_Table* tables_new;
171 SFNT_Table* table_last;
172 SFNT_Table* table;
173 FT_Byte* buf;
175 FT_Long k;
178 buf = (FT_Byte*)malloc(table_info->len);
179 if (!buf)
181 error = FT_Err_Out_Of_Memory;
182 goto Err;
185 /* load table */
186 error = FT_Load_Sfnt_Table(sfnt->face, table_info->tag, 0,
187 buf, &table_info->len);
188 if (error)
189 goto Err;
191 /* check whether we already have this table */
192 for (k = 0; k < num_tables; k++)
194 table = &tables[k];
196 if (table->tag == table_info->tag
197 && table->len == table_info->len
198 && !memcmp(table->buf, buf, table->len))
199 break;
202 /* add one element to table array if it's missing or not the same */
203 if (k == num_tables)
205 num_tables++;
206 tables_new =
207 (SFNT_Table*)realloc(tables,
208 num_tables * sizeof (SFNT_Table));
209 if (!tables_new)
211 error = FT_Err_Out_Of_Memory;
212 goto Err;
214 else
215 tables = tables_new;
217 table_last = &tables[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 = tables[k].buf;
235 /* compute global hints */
236 /* construct `fpgm' table */
237 /* construct `prep' table */
238 /* construct `cvt ' table */
240 /* split `glyf' table */
241 /* handle all glyphs in a loop */
242 /* strip bytecode */
243 /* hint the glyph */
244 /* construct bytecode */
246 /* construct `glyf' table */
247 /* build font from SFNT tables */
248 /* write font from memory */
250 error = TA_Err_Ok;
252 Err:
253 /* in case of error it is expected that the unallocated pointers */
254 /* are NULL (and counters are zero) */
255 if (tables)
257 for (j = 0; j < num_tables; j++)
258 free(tables[j].buf);
259 free(tables);
261 if (sfnts)
263 for (i = 0; i < num_sfnts; i++)
265 FT_Done_Face(sfnts[i].face);
266 free(sfnts[i].table_infos);
268 free(sfnts);
270 FT_Done_FreeType(lib);
271 free(in_buf);
273 return error;
276 /* end of ttfautohint.c */