blob: 818b29d2638d714de5c3bb88c48574d4be80472d [file] [log] [blame]
David Turnerd2b1f351999-12-16 23:11:37 +00001/***************************************************************************/
2/* */
David Turner19ed8af2000-12-08 02:42:29 +00003/* ttpload.c */
David Turnerd2b1f351999-12-16 23:11:37 +00004/* */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +00005/* TrueType-specific tables loader (body). */
David Turnerd2b1f351999-12-16 23:11:37 +00006/* */
Werner Lemberg01caf4a2011-03-23 05:19:59 +01007/* Copyright 1996-2002, 2004-2011 by */
David Turnerd2b1f351999-12-16 23:11:37 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000010/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
David Turnerd2b1f351999-12-16 23:11:37 +000012/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
Werner Lembergcc069be2000-12-08 16:17:16 +000018
David Turner19ed8af2000-12-08 02:42:29 +000019#include <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_OBJECTS_H
22#include FT_INTERNAL_STREAM_H
23#include FT_TRUETYPE_TAGS_H
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000024
David Turner8d3a4012001-03-20 11:14:24 +000025#include "ttpload.h"
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000026
Werner Lemberg44bb3032004-04-25 20:15:11 +000027#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
28#include "ttgxvar.h"
29#endif
30
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000031#include "tterrors.h"
David Turnerd2b1f351999-12-16 23:11:37 +000032
Werner Lemberg78575dc2000-06-12 19:36:41 +000033
34 /*************************************************************************/
35 /* */
36 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
37 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
38 /* messages during execution. */
39 /* */
David Turnerd2b1f351999-12-16 23:11:37 +000040#undef FT_COMPONENT
Werner Lemberg78575dc2000-06-12 19:36:41 +000041#define FT_COMPONENT trace_ttpload
42
David Turnerd2b1f351999-12-16 23:11:37 +000043
44 /*************************************************************************/
45 /* */
46 /* <Function> */
David Turnerb08fe2d2002-08-27 20:20:29 +000047 /* tt_face_load_loca */
David Turnerd2b1f351999-12-16 23:11:37 +000048 /* */
49 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +000050 /* Load the locations table. */
David Turnerd2b1f351999-12-16 23:11:37 +000051 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000052 /* <InOut> */
David Turnerd2b1f351999-12-16 23:11:37 +000053 /* face :: A handle to the target face object. */
Werner Lemberg78575dc2000-06-12 19:36:41 +000054 /* */
55 /* <Input> */
David Turnerd2b1f351999-12-16 23:11:37 +000056 /* stream :: The input stream. */
57 /* */
58 /* <Return> */
Werner Lemberg9ca2af32000-06-21 03:03:28 +000059 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +000060 /* */
David Turnere70d5532005-02-22 16:53:06 +000061 FT_LOCAL_DEF( FT_Error )
62 tt_face_load_loca( TT_Face face,
63 FT_Stream stream )
64 {
Werner Lembergf13516c2005-03-03 17:09:08 +000065 FT_Error error;
66 FT_ULong table_len;
Werner Lemberg6b19e092008-07-09 06:20:12 +000067 FT_Int shift;
David Turnere70d5532005-02-22 16:53:06 +000068
69
Werner Lemberg5452fbe2005-05-05 07:44:20 +000070 /* we need the size of the `glyf' table for malformed `loca' tables */
71 error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len );
Werner Lemberg1474f432008-12-09 06:51:56 +000072
73 /* it is possible that a font doesn't have a glyf table at all */
74 /* or its size is zero */
75 if ( error == TT_Err_Table_Missing )
76 face->glyf_len = 0;
77 else if ( error )
Werner Lemberg5452fbe2005-05-05 07:44:20 +000078 goto Exit;
79
David Turnere70d5532005-02-22 16:53:06 +000080 FT_TRACE2(( "Locations " ));
81 error = face->goto_table( face, TTAG_loca, stream, &table_len );
82 if ( error )
83 {
84 error = TT_Err_Locations_Missing;
85 goto Exit;
86 }
87
88 if ( face->header.Index_To_Loc_Format != 0 )
89 {
Werner Lemberg6b19e092008-07-09 06:20:12 +000090 shift = 2;
91
Werner Lembergf1c2b912006-01-13 14:53:28 +000092 if ( table_len >= 0x40000L )
David Turnere70d5532005-02-22 16:53:06 +000093 {
Werner Lemberg858abbe2009-06-26 06:15:41 +020094 FT_TRACE2(( "table too large\n" ));
David Turnere70d5532005-02-22 16:53:06 +000095 error = TT_Err_Invalid_Table;
96 goto Exit;
97 }
suzuki toshiya25dba9c2009-08-01 00:32:09 +090098 face->num_locations = table_len >> shift;
David Turnere70d5532005-02-22 16:53:06 +000099 }
100 else
101 {
Werner Lemberg6b19e092008-07-09 06:20:12 +0000102 shift = 1;
103
Werner Lembergf1c2b912006-01-13 14:53:28 +0000104 if ( table_len >= 0x20000L )
David Turnere70d5532005-02-22 16:53:06 +0000105 {
Werner Lemberg858abbe2009-06-26 06:15:41 +0200106 FT_TRACE2(( "table too large\n" ));
David Turnere70d5532005-02-22 16:53:06 +0000107 error = TT_Err_Invalid_Table;
108 goto Exit;
109 }
suzuki toshiya25dba9c2009-08-01 00:32:09 +0900110 face->num_locations = table_len >> shift;
Werner Lemberg6b19e092008-07-09 06:20:12 +0000111 }
112
Werner Lemberg01caf4a2011-03-23 05:19:59 +0100113 if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 )
Werner Lemberg6b19e092008-07-09 06:20:12 +0000114 {
115 FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n",
Werner Lemberg01caf4a2011-03-23 05:19:59 +0100116 face->num_locations - 1, face->root.num_glyphs ));
Werner Lemberg6b19e092008-07-09 06:20:12 +0000117
118 /* we only handle the case where `maxp' gives a larger value */
Werner Lemberg01caf4a2011-03-23 05:19:59 +0100119 if ( face->num_locations <= (FT_ULong)face->root.num_glyphs )
Werner Lemberg6b19e092008-07-09 06:20:12 +0000120 {
Werner Lemberg01caf4a2011-03-23 05:19:59 +0100121 FT_Long new_loca_len =
122 ( (FT_Long)( face->root.num_glyphs ) + 1 ) << shift;
Werner Lemberg6b19e092008-07-09 06:20:12 +0000123
124 TT_Table entry = face->dir_tables;
125 TT_Table limit = entry + face->num_tables;
126
127 FT_Long pos = FT_Stream_Pos( stream );
128 FT_Long dist = 0x7FFFFFFFL;
129
130
131 /* compute the distance to next table in font file */
132 for ( ; entry < limit; entry++ )
133 {
134 FT_Long diff = entry->Offset - pos;
135
136
137 if ( diff > 0 && diff < dist )
138 dist = diff;
139 }
140
Werner Lembergec4372f2010-11-18 20:34:22 +0100141 if ( entry == limit )
142 {
143 /* `loca' is the last table */
144 dist = stream->size - pos;
145 }
146
Werner Lemberg6b19e092008-07-09 06:20:12 +0000147 if ( new_loca_len <= dist )
148 {
Werner Lemberg01caf4a2011-03-23 05:19:59 +0100149 face->num_locations = face->root.num_glyphs + 1;
Werner Lemberg6b19e092008-07-09 06:20:12 +0000150 table_len = new_loca_len;
151
152 FT_TRACE2(( "adjusting num_locations to %d\n",
153 face->num_locations ));
154 }
155 }
David Turnere70d5532005-02-22 16:53:06 +0000156 }
157
Werner Lemberge7930922005-03-01 02:13:50 +0000158 /*
159 * Extract the frame. We don't need to decompress it since
160 * we are able to parse it directly.
161 */
David Turnere70d5532005-02-22 16:53:06 +0000162 if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
163 goto Exit;
164
165 FT_TRACE2(( "loaded\n" ));
166
167 Exit:
168 return error;
169 }
170
171
172 FT_LOCAL_DEF( FT_ULong )
Werner Lemberge7930922005-03-01 02:13:50 +0000173 tt_face_get_location( TT_Face face,
174 FT_UInt gindex,
175 FT_UInt *asize )
David Turnere70d5532005-02-22 16:53:06 +0000176 {
177 FT_ULong pos1, pos2;
178 FT_Byte* p;
179 FT_Byte* p_limit;
180
Werner Lemberge7930922005-03-01 02:13:50 +0000181
David Turnere70d5532005-02-22 16:53:06 +0000182 pos1 = pos2 = 0;
Werner Lemberge7930922005-03-01 02:13:50 +0000183
David Turnere70d5532005-02-22 16:53:06 +0000184 if ( gindex < face->num_locations )
185 {
186 if ( face->header.Index_To_Loc_Format != 0 )
187 {
Werner Lemberge7930922005-03-01 02:13:50 +0000188 p = face->glyph_locations + gindex * 4;
189 p_limit = face->glyph_locations + face->num_locations * 4;
David Turnere70d5532005-02-22 16:53:06 +0000190
Werner Lemberge7930922005-03-01 02:13:50 +0000191 pos1 = FT_NEXT_ULONG( p );
David Turnere70d5532005-02-22 16:53:06 +0000192 pos2 = pos1;
193
Werner Lemberge7930922005-03-01 02:13:50 +0000194 if ( p + 4 <= p_limit )
195 pos2 = FT_NEXT_ULONG( p );
David Turnere70d5532005-02-22 16:53:06 +0000196 }
197 else
198 {
Werner Lemberge7930922005-03-01 02:13:50 +0000199 p = face->glyph_locations + gindex * 2;
200 p_limit = face->glyph_locations + face->num_locations * 2;
David Turnere70d5532005-02-22 16:53:06 +0000201
Werner Lemberge7930922005-03-01 02:13:50 +0000202 pos1 = FT_NEXT_USHORT( p );
David Turnere70d5532005-02-22 16:53:06 +0000203 pos2 = pos1;
204
Werner Lemberge7930922005-03-01 02:13:50 +0000205 if ( p + 2 <= p_limit )
206 pos2 = FT_NEXT_USHORT( p );
David Turnere70d5532005-02-22 16:53:06 +0000207
208 pos1 <<= 1;
209 pos2 <<= 1;
210 }
211 }
212
suzuki toshiya643d49d2010-09-20 01:07:57 +0900213 /* Check broken location data */
214 if ( pos1 >= face->glyf_len )
215 {
216 FT_TRACE1(( "tt_face_get_location:"
217 " too large offset=0x%08lx found for gid=0x%04lx,"
218 " exceeding the end of glyf table (0x%08lx)\n",
219 pos1, gindex, face->glyf_len ));
220 *asize = 0;
221 return 0;
222 }
223
224 if ( pos2 >= face->glyf_len )
225 {
226 FT_TRACE1(( "tt_face_get_location:"
227 " too large offset=0x%08lx found for gid=0x%04lx,"
228 " truncate at the end of glyf table (0x%08lx)\n",
229 pos2, gindex + 1, face->glyf_len ));
230 pos2 = face->glyf_len;
231 }
232
Werner Lembergb47b97d2009-04-04 07:51:45 +0200233 /* The `loca' table must be ordered; it refers to the length of */
234 /* an entry as the difference between the current and the next */
235 /* position. However, there do exist (malformed) fonts which */
236 /* don't obey this rule, so we are only able to provide an */
237 /* upper bound for the size. */
Werner Lemberg1474f432008-12-09 06:51:56 +0000238 /* */
239 /* We get (intentionally) a wrong, non-zero result in case the */
240 /* `glyf' table is missing. */
Werner Lemberg43ebad42005-05-07 06:10:19 +0000241 if ( pos2 >= pos1 )
Werner Lemberg5452fbe2005-05-05 07:44:20 +0000242 *asize = (FT_UInt)( pos2 - pos1 );
243 else
244 *asize = (FT_UInt)( face->glyf_len - pos1 );
David Turnere70d5532005-02-22 16:53:06 +0000245
246 return pos1;
247 }
248
249
250 FT_LOCAL_DEF( void )
251 tt_face_done_loca( TT_Face face )
252 {
Werner Lemberge7930922005-03-01 02:13:50 +0000253 FT_Stream stream = face->root.stream;
254
David Turnere70d5532005-02-22 16:53:06 +0000255
256 FT_FRAME_RELEASE( face->glyph_locations );
257 face->num_locations = 0;
258 }
259
260
David Turnere70d5532005-02-22 16:53:06 +0000261
David Turnerd2b1f351999-12-16 23:11:37 +0000262 /*************************************************************************/
263 /* */
264 /* <Function> */
David Turnerb08fe2d2002-08-27 20:20:29 +0000265 /* tt_face_load_cvt */
David Turnerd2b1f351999-12-16 23:11:37 +0000266 /* */
267 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000268 /* Load the control value table into a face object. */
David Turnerd2b1f351999-12-16 23:11:37 +0000269 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000270 /* <InOut> */
David Turnerd2b1f351999-12-16 23:11:37 +0000271 /* face :: A handle to the target face object. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000272 /* */
273 /* <Input> */
David Turnerd2b1f351999-12-16 23:11:37 +0000274 /* stream :: A handle to the input stream. */
275 /* */
276 /* <Return> */
Werner Lemberg9ca2af32000-06-21 03:03:28 +0000277 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000278 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000279 FT_LOCAL_DEF( FT_Error )
David Turnerb08fe2d2002-08-27 20:20:29 +0000280 tt_face_load_cvt( TT_Face face,
281 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000282 {
David Turner6aa260c2006-08-25 22:45:13 +0000283#ifdef TT_USE_BYTECODE_INTERPRETER
David Turnere70d5532005-02-22 16:53:06 +0000284
David Turnerf9b8dec2000-06-16 19:34:52 +0000285 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000286 FT_Memory memory = stream->memory;
David Turnerf9b8dec2000-06-16 19:34:52 +0000287 FT_ULong table_len;
David Turnerd2b1f351999-12-16 23:11:37 +0000288
Werner Lemberg78575dc2000-06-12 19:36:41 +0000289
David Turnerd2b1f351999-12-16 23:11:37 +0000290 FT_TRACE2(( "CVT " ));
291
292 error = face->goto_table( face, TTAG_cvt, stream, &table_len );
Werner Lemberg78575dc2000-06-12 19:36:41 +0000293 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000294 {
Werner Lemberg858abbe2009-06-26 06:15:41 +0200295 FT_TRACE2(( "is missing\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000296
297 face->cvt_size = 0;
298 face->cvt = NULL;
299 error = TT_Err_Ok;
300
301 goto Exit;
302 }
303
304 face->cvt_size = table_len / 2;
305
David Turnere459d742002-03-22 13:52:37 +0000306 if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000307 goto Exit;
308
David Turner7d3a2642002-03-20 10:49:31 +0000309 if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000310 goto Exit;
311
312 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000313 FT_Short* cur = face->cvt;
314 FT_Short* limit = cur + face->cvt_size;
David Turnerd2b1f351999-12-16 23:11:37 +0000315
Werner Lemberg78575dc2000-06-12 19:36:41 +0000316
Werner Lembergec4372f2010-11-18 20:34:22 +0100317 for ( ; cur < limit; cur++ )
David Turnera890c292002-03-22 12:55:23 +0000318 *cur = FT_GET_SHORT();
David Turnerd2b1f351999-12-16 23:11:37 +0000319 }
320
David Turner7d3a2642002-03-20 10:49:31 +0000321 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000322 FT_TRACE2(( "loaded\n" ));
323
Werner Lemberg44bb3032004-04-25 20:15:11 +0000324#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
325 if ( face->doblend )
326 error = tt_face_vary_cvt( face, stream );
327#endif
328
David Turnerd2b1f351999-12-16 23:11:37 +0000329 Exit:
330 return error;
David Turnere70d5532005-02-22 16:53:06 +0000331
David Turner6aa260c2006-08-25 22:45:13 +0000332#else /* !TT_USE_BYTECODE_INTERPRETER */
Werner Lemberge7930922005-03-01 02:13:50 +0000333
334 FT_UNUSED( face );
335 FT_UNUSED( stream );
336
Werner Lembergc11aeb62005-03-10 15:49:45 +0000337 return TT_Err_Ok;
Werner Lemberge7930922005-03-01 02:13:50 +0000338
David Turnere70d5532005-02-22 16:53:06 +0000339#endif
David Turnerd2b1f351999-12-16 23:11:37 +0000340 }
341
342
343 /*************************************************************************/
344 /* */
345 /* <Function> */
David Turnerb08fe2d2002-08-27 20:20:29 +0000346 /* tt_face_load_fpgm */
David Turnerd2b1f351999-12-16 23:11:37 +0000347 /* */
348 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000349 /* Load the font program. */
David Turnerd2b1f351999-12-16 23:11:37 +0000350 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000351 /* <InOut> */
David Turnerd2b1f351999-12-16 23:11:37 +0000352 /* face :: A handle to the target face object. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000353 /* */
354 /* <Input> */
David Turnerd2b1f351999-12-16 23:11:37 +0000355 /* stream :: A handle to the input stream. */
356 /* */
357 /* <Return> */
Werner Lemberg9ca2af32000-06-21 03:03:28 +0000358 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000359 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000360 FT_LOCAL_DEF( FT_Error )
David Turnerb08fe2d2002-08-27 20:20:29 +0000361 tt_face_load_fpgm( TT_Face face,
362 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000363 {
David Turner6aa260c2006-08-25 22:45:13 +0000364#ifdef TT_USE_BYTECODE_INTERPRETER
David Turnere70d5532005-02-22 16:53:06 +0000365
Werner Lemberg52254022006-02-15 06:05:52 +0000366 FT_Error error;
367 FT_ULong table_len;
David Turnerd2b1f351999-12-16 23:11:37 +0000368
Werner Lemberg78575dc2000-06-12 19:36:41 +0000369
Werner Lembergf6978662000-01-08 20:00:54 +0000370 FT_TRACE2(( "Font program " ));
David Turnerd2b1f351999-12-16 23:11:37 +0000371
372 /* The font program is optional */
373 error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
Werner Lembergf6978662000-01-08 20:00:54 +0000374 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000375 {
376 face->font_program = NULL;
377 face->font_program_size = 0;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000378 error = TT_Err_Ok;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000379
Werner Lemberg858abbe2009-06-26 06:15:41 +0200380 FT_TRACE2(( "is missing\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000381 }
382 else
383 {
384 face->font_program_size = table_len;
David Turner7d3a2642002-03-20 10:49:31 +0000385 if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000386 goto Exit;
387
388 FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
389 }
390
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000391 Exit:
392 return error;
393
David Turner6aa260c2006-08-25 22:45:13 +0000394#else /* !TT_USE_BYTECODE_INTERPRETER */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000395
396 FT_UNUSED( face );
397 FT_UNUSED( stream );
398
399 return TT_Err_Ok;
400
401#endif
402 }
403
404
405 /*************************************************************************/
406 /* */
407 /* <Function> */
408 /* tt_face_load_prep */
409 /* */
410 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000411 /* Load the cvt program. */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000412 /* */
413 /* <InOut> */
414 /* face :: A handle to the target face object. */
415 /* */
416 /* <Input> */
417 /* stream :: A handle to the input stream. */
418 /* */
419 /* <Return> */
420 /* FreeType error code. 0 means success. */
421 /* */
422 FT_LOCAL_DEF( FT_Error )
423 tt_face_load_prep( TT_Face face,
424 FT_Stream stream )
425 {
David Turner6aa260c2006-08-25 22:45:13 +0000426#ifdef TT_USE_BYTECODE_INTERPRETER
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000427
Werner Lemberg52254022006-02-15 06:05:52 +0000428 FT_Error error;
429 FT_ULong table_len;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000430
431
David Turnerd2b1f351999-12-16 23:11:37 +0000432 FT_TRACE2(( "Prep program " ));
433
434 error = face->goto_table( face, TTAG_prep, stream, &table_len );
Werner Lembergf6978662000-01-08 20:00:54 +0000435 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000436 {
437 face->cvt_program = NULL;
438 face->cvt_program_size = 0;
Werner Lembergf6978662000-01-08 20:00:54 +0000439 error = TT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000440
Werner Lemberg858abbe2009-06-26 06:15:41 +0200441 FT_TRACE2(( "is missing\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000442 }
443 else
444 {
445 face->cvt_program_size = table_len;
David Turner7d3a2642002-03-20 10:49:31 +0000446 if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
David Turner2e421312000-05-26 22:13:17 +0000447 goto Exit;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000448
David Turnerd2b1f351999-12-16 23:11:37 +0000449 FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
450 }
451
452 Exit:
453 return error;
David Turnere70d5532005-02-22 16:53:06 +0000454
David Turner6aa260c2006-08-25 22:45:13 +0000455#else /* !TT_USE_BYTECODE_INTERPRETER */
Werner Lemberge7930922005-03-01 02:13:50 +0000456
457 FT_UNUSED( face );
458 FT_UNUSED( stream );
459
Werner Lembergc11aeb62005-03-10 15:49:45 +0000460 return TT_Err_Ok;
Werner Lemberge7930922005-03-01 02:13:50 +0000461
David Turnere70d5532005-02-22 16:53:06 +0000462#endif
David Turnerd2b1f351999-12-16 23:11:37 +0000463 }
464
465
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000466 /*************************************************************************/
467 /* */
468 /* <Function> */
469 /* tt_face_load_hdmx */
470 /* */
471 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000472 /* Load the `hdmx' table into the face object. */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000473 /* */
474 /* <Input> */
475 /* face :: A handle to the target face object. */
476 /* */
477 /* stream :: A handle to the input stream. */
478 /* */
479 /* <Return> */
480 /* FreeType error code. 0 means success. */
481 /* */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000482
483 FT_LOCAL_DEF( FT_Error )
484 tt_face_load_hdmx( TT_Face face,
485 FT_Stream stream )
486 {
487 FT_Error error;
488 FT_Memory memory = stream->memory;
489 FT_UInt version, nn, num_records;
490 FT_ULong table_size, record_size;
491 FT_Byte* p;
492 FT_Byte* limit;
493
494
495 /* this table is optional */
496 error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
497 if ( error || table_size < 8 )
498 return TT_Err_Ok;
499
500 if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
501 goto Exit;
502
503 p = face->hdmx_table;
504 limit = p + table_size;
505
506 version = FT_NEXT_USHORT( p );
507 num_records = FT_NEXT_USHORT( p );
508 record_size = FT_NEXT_ULONG( p );
509
Werner Lemberg36d2eab2006-09-05 19:24:34 +0000510 /* The maximum number of bytes in an hdmx device record is the */
511 /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */
512 /* the reason why `record_size' is a long (which we read as */
513 /* unsigned long for convenience). In practice, two bytes */
514 /* sufficient to hold the size value. */
515 /* */
516 /* There are at least two fonts, HANNOM-A and HANNOM-B version */
517 /* 2.0 (2005), which get this wrong: The upper two bytes of */
518 /* the size value are set to 0xFF instead of 0x00. We catch */
519 /* and fix this. */
520
521 if ( record_size >= 0xFFFF0000UL )
522 record_size &= 0xFFFFU;
523
524 /* The limit for `num_records' is a heuristic value. */
525
526 if ( version != 0 || num_records > 255 || record_size > 0x10001L )
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000527 {
528 error = TT_Err_Invalid_File_Format;
529 goto Fail;
530 }
531
532 if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
533 goto Fail;
534
535 for ( nn = 0; nn < num_records; nn++ )
536 {
537 if ( p + record_size > limit )
538 break;
David Turnerda95af62006-03-20 13:32:33 +0000539
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000540 face->hdmx_record_sizes[nn] = p[0];
541 p += record_size;
542 }
David Turnerda95af62006-03-20 13:32:33 +0000543
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000544 face->hdmx_record_count = nn;
545 face->hdmx_table_size = table_size;
Wu, Chia-I (吳佳一)facd9af2006-02-22 07:59:35 +0000546 face->hdmx_record_size = record_size;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000547
548 Exit:
549 return error;
David Turnerda95af62006-03-20 13:32:33 +0000550
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000551 Fail:
552 FT_FRAME_RELEASE( face->hdmx_table );
553 face->hdmx_table_size = 0;
554 goto Exit;
555 }
556
557
558 FT_LOCAL_DEF( void )
559 tt_face_free_hdmx( TT_Face face )
560 {
561 FT_Stream stream = face->root.stream;
562 FT_Memory memory = stream->memory;
David Turnerda95af62006-03-20 13:32:33 +0000563
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000564
565 FT_FREE( face->hdmx_record_sizes );
566 FT_FRAME_RELEASE( face->hdmx_table );
567 }
568
Werner Lemberg52254022006-02-15 06:05:52 +0000569
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000570 /*************************************************************************/
571 /* */
Werner Lemberg52254022006-02-15 06:05:52 +0000572 /* Return the advance width table for a given pixel size if it is found */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000573 /* in the font's `hdmx' table (if any). */
574 /* */
575 FT_LOCAL_DEF( FT_Byte* )
576 tt_face_get_device_metrics( TT_Face face,
David Turnerda95af62006-03-20 13:32:33 +0000577 FT_UInt ppem,
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000578 FT_UInt gindex )
579 {
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000580 FT_UInt nn;
581 FT_Byte* result = NULL;
582 FT_ULong record_size = face->hdmx_record_size;
583 FT_Byte* record = face->hdmx_table + 8;
584
585
586 for ( nn = 0; nn < face->hdmx_record_count; nn++ )
587 if ( face->hdmx_record_sizes[nn] == ppem )
588 {
589 gindex += 2;
590 if ( gindex < record_size )
Wu, Chia-I (吳佳一)facd9af2006-02-22 07:59:35 +0000591 result = record + nn * record_size + gindex;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000592 break;
593 }
594
595 return result;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000596 }
597
598
David Turnerd2b1f351999-12-16 23:11:37 +0000599/* END */