Fix character range documentation.
[ttfautohint.git] / lib / tacvt.c
blob8ba9859cffadefc4f9b7b9864fed7ac3db19147c
1 /* tacvt.c */
3 /*
4 * Copyright (C) 2011-2017 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 static FT_Error
20 TA_sfnt_compute_global_hints(SFNT* sfnt,
21 FONT* font,
22 TA_Style style_idx)
24 FT_Error error;
25 FT_Face face = sfnt->face;
26 FT_ULong glyph_index;
27 FT_Int32 load_flags;
30 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
31 if (error)
33 if (font->symbol)
35 error = FT_Select_Charmap(face, FT_ENCODING_MS_SYMBOL);
36 if (error)
37 return TA_Err_Missing_Symbol_CMap;
39 else
40 return TA_Err_Missing_Unicode_CMap;
44 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
45 FT_UShort* gstyles = globals->glyph_styles;
47 TA_StyleClass style_class = ta_style_classes[style_idx];
48 TA_ScriptClass script_class = ta_script_classes[style_class->script];
50 TA_StyleMetricsRec dummy;
52 void* shaper_buf;
53 const char* p;
56 /* we don't have a `TA_Loader' object yet */
57 dummy.globals = globals;
58 dummy.style_class = style_class;
60 p = script_class->standard_charstring;
61 shaper_buf = ta_shaper_buf_create(face);
64 * We check more than a single standard character to catch features
65 * like `c2sc' (small caps from caps) that don't contain lowercase
66 * letters by definition, or other features that mainly operate on
67 * numerals.
70 glyph_index = 0;
71 while (*p)
73 unsigned int num_idx;
76 while (*p == ' ')
77 p++;
79 /* reject input that maps to more than a single glyph */
80 p = ta_shaper_get_cluster(p, &dummy, shaper_buf, &num_idx);
81 if (num_idx > 1)
82 continue;
84 /* otherwise exit loop if we have a result */
85 glyph_index = ta_shaper_get_elem(&dummy,
86 shaper_buf,
88 NULL,
89 NULL);
90 if (glyph_index)
91 break;
94 ta_shaper_buf_destroy(face, shaper_buf);
96 if (!glyph_index)
98 if (font->fallback_style == style_idx)
100 /* Having TA_STYLE_NONE_DFLT as the fallback script means */
101 /* hinting without default characters */
102 /* (and without script-specific blue zones), so we proceed */
103 if (style_idx == TA_STYLE_NONE_DFLT)
104 goto Symbol;
106 /* in case of a symbol font, we also proceed */
107 if (font->symbol)
108 goto Symbol;
111 /* no standard characters to set up this style */
112 return TA_Err_Missing_Glyph;
116 * We now know that HarfBuzz can access the standard character in the
117 * current OpenType feature. However, this doesn't guarantee that there
118 * actually *is* a standard character in the corresponding coverage,
119 * since glyphs shifted with data from the GPOS table are ignored in the
120 * coverage (but neverless used to derive stem widths). For this
121 * reason, search an arbitrary character from the current coverage to
122 * trigger the coverage's metrics computation.
124 if ((gstyles[glyph_index] & TA_STYLE_MASK) != style_idx)
126 FT_ULong i;
129 for (i = 0; i < (FT_ULong)globals->glyph_count; i++)
131 if ((gstyles[i] & TA_STYLE_MASK) == style_idx)
132 break;
135 if (i == (FT_ULong)globals->glyph_count)
136 return TA_Err_Missing_Glyph;
138 glyph_index = i;
142 Symbol:
143 load_flags = 1 << 29; /* vertical hinting only */
144 error = ta_loader_load_glyph(font, face, (FT_UInt)glyph_index, load_flags);
146 return error;
150 static FT_Error
151 TA_table_build_cvt(FT_Byte** cvt,
152 FT_ULong* cvt_len,
153 SFNT* sfnt,
154 FONT* font)
156 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
157 glyf_Data* data = (glyf_Data*)glyf_table->data;
159 TA_LatinAxis haxis;
160 TA_LatinAxis vaxis;
162 FT_UInt hwidth_count;
163 FT_UInt vwidth_count;
164 FT_UInt blue_count;
166 FT_UInt i, j;
167 FT_UInt buf_len;
168 FT_UInt len;
169 FT_Byte* buf;
170 FT_Byte* bufp;
171 FT_UInt cvt_offset;
173 FT_Error error;
176 /* loop over all styles and collect the relevant CVT data */
177 /* to compute the necessary array sizes and meta-information */
178 hwidth_count = 0;
179 vwidth_count = 0;
180 blue_count = 0;
182 data->num_used_styles = 0;
184 for (i = 0; i < TA_STYLE_MAX; i++)
186 error = TA_sfnt_compute_global_hints(sfnt, font, (TA_Style)i);
187 if (error == TA_Err_Missing_Glyph)
189 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
190 FT_UShort* gstyles = globals->glyph_styles;
191 FT_Int nn;
194 data->style_ids[i] = 0xFFFFU;
196 /* remove all references to this style; */
197 /* otherwise blue zones are computed later on, which we don't want */
198 for (nn = 0; nn < globals->glyph_count; nn++)
200 if ((gstyles[nn] & TA_STYLE_MASK) == i)
202 gstyles[nn] &= ~TA_STYLE_MASK;
203 gstyles[nn] |= globals->font->fallback_style;
207 continue;
209 if (error)
210 return error;
212 data->style_ids[i] = data->num_used_styles++;
214 /* XXX: generalize this to handle other metrics also */
215 haxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[0];
216 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
218 hwidth_count += haxis->width_count;
219 vwidth_count += vaxis->width_count;
221 blue_count += vaxis->blue_count;
222 /* if windows compatibility mode is active */
223 /* we add two artificial blue zones at the end of the array */
224 /* that are not part of `vaxis->blue_count' */
225 if (font->windows_compatibility)
226 blue_count += 2;
229 /* exit if the font doesn't contain a single supported style, */
230 /* and we don't have a symbol font */
231 if (!data->num_used_styles && !font->symbol)
232 return TA_Err_Missing_Glyph;
234 buf_len = cvtl_max_runtime /* runtime values 1 */
235 + data->num_used_styles /* runtime values 2 (for scaling) */
236 + 2 * data->num_used_styles /* runtime values 3 (blue data) */
237 + 2 * data->num_used_styles /* vert. and horiz. std. widths */
238 + hwidth_count
239 + vwidth_count
240 + 2 * blue_count; /* round and flat blue zones */
241 buf_len <<= 1; /* we have 16bit values */
243 /* buffer length must be a multiple of four */
244 len = (buf_len + 3) & ~3U;
245 buf = (FT_Byte*)malloc(len);
246 if (!buf)
247 return FT_Err_Out_Of_Memory;
249 /* pad end of buffer with zeros */
250 buf[len - 1] = 0x00;
251 buf[len - 2] = 0x00;
252 buf[len - 3] = 0x00;
254 bufp = buf;
257 * some CVT values are initialized (and modified) at runtime:
259 * (1) the `cvtl_xxx' values (see `tabytecode.h')
260 * (2) a scaling value for each style
261 * (3) offset and size of the vertical widths array
262 * (needed by `bci_{smooth,strong}_stem_width') for each style
264 for (i = 0; i < (cvtl_max_runtime
265 + data->num_used_styles
266 + 2 * data->num_used_styles) * 2; i++)
267 *(bufp++) = 0;
269 cvt_offset = (FT_UInt)(bufp - buf);
271 /* loop again over all styles and copy CVT data */
272 for (i = 0; i < TA_STYLE_MAX; i++)
274 FT_UInt default_width = 50 * sfnt->face->units_per_EM / 2048;
277 /* collect offsets */
278 data->cvt_offsets[i] = ((FT_UInt)(bufp - buf) - cvt_offset) >> 1;
280 error = TA_sfnt_compute_global_hints(sfnt, font, (TA_Style)i);
281 if (error == TA_Err_Missing_Glyph)
282 continue;
283 if (error)
284 return error;
286 haxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[0];
287 vaxis = &((TA_LatinMetrics)font->loader->hints.metrics)->axis[1];
289 hwidth_count = haxis->width_count;
290 vwidth_count = vaxis->width_count;
292 blue_count = vaxis->blue_count;
293 if (font->windows_compatibility)
294 blue_count += 2; /* with artificial blue zones */
296 /* horizontal standard width */
297 if (hwidth_count > 0)
299 *(bufp++) = HIGH(haxis->widths[0].org);
300 *(bufp++) = LOW(haxis->widths[0].org);
302 else
304 *(bufp++) = HIGH(default_width);
305 *(bufp++) = LOW(default_width);
308 for (j = 0; j < hwidth_count; j++)
310 if (haxis->widths[j].org > 0xFFFF)
311 goto Err;
312 *(bufp++) = HIGH(haxis->widths[j].org);
313 *(bufp++) = LOW(haxis->widths[j].org);
316 /* vertical standard width */
317 if (vwidth_count > 0)
319 *(bufp++) = HIGH(vaxis->widths[0].org);
320 *(bufp++) = LOW(vaxis->widths[0].org);
322 else
324 *(bufp++) = HIGH(default_width);
325 *(bufp++) = LOW(default_width);
328 for (j = 0; j < vwidth_count; j++)
330 if (vaxis->widths[j].org > 0xFFFF)
331 goto Err;
332 *(bufp++) = HIGH(vaxis->widths[j].org);
333 *(bufp++) = LOW(vaxis->widths[j].org);
336 data->cvt_blue_adjustment_offsets[i] = 0xFFFFU;
338 for (j = 0; j < blue_count; j++)
340 if (vaxis->blues[j].ref.org > 0xFFFF)
341 goto Err;
342 *(bufp++) = HIGH(vaxis->blues[j].ref.org);
343 *(bufp++) = LOW(vaxis->blues[j].ref.org);
346 for (j = 0; j < blue_count; j++)
348 if (vaxis->blues[j].shoot.org > 0xFFFF)
349 goto Err;
350 *(bufp++) = HIGH(vaxis->blues[j].shoot.org);
351 *(bufp++) = LOW(vaxis->blues[j].shoot.org);
353 if (vaxis->blues[j].flags & TA_LATIN_BLUE_ADJUSTMENT)
354 data->cvt_blue_adjustment_offsets[i] = j;
357 data->cvt_horz_width_sizes[i] = hwidth_count;
358 data->cvt_vert_width_sizes[i] = vwidth_count;
359 data->cvt_blue_zone_sizes[i] = blue_count;
362 *cvt = buf;
363 *cvt_len = buf_len;
365 return FT_Err_Ok;
367 Err:
368 free(buf);
369 return TA_Err_Hinter_Overflow;
373 FT_Error
374 TA_sfnt_build_cvt_table(SFNT* sfnt,
375 FONT* font)
377 FT_Error error;
379 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
380 glyf_Data* data = (glyf_Data*)glyf_table->data;
382 FT_Byte* cvt_buf;
383 FT_ULong cvt_len;
386 error = TA_sfnt_add_table_info(sfnt);
387 if (error)
388 goto Exit;
390 /* `glyf', `cvt', `fpgm', and `prep' are always used in parallel */
391 if (glyf_table->processed)
393 sfnt->table_infos[sfnt->num_table_infos - 1] = data->cvt_idx;
394 goto Exit;
397 error = TA_table_build_cvt(&cvt_buf, &cvt_len, sfnt, font);
398 if (error)
399 goto Exit;
401 /* in case of success, `cvt_buf' gets linked */
402 /* and is eventually freed in `TA_font_unload' */
403 error = TA_font_add_table(font,
404 &sfnt->table_infos[sfnt->num_table_infos - 1],
405 TTAG_cvt, cvt_len, cvt_buf);
406 if (error)
407 free(cvt_buf);
408 else
409 data->cvt_idx = sfnt->table_infos[sfnt->num_table_infos - 1];
411 Exit:
412 return error;
415 /* end of tacvt.c */