blob: a311b03c00cc2cf7f1e4972a6e7fcc58c0b34cbe [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 Lembergb47b97d2009-04-04 07:51:45 +02007/* Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 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
suzuki toshiya25dba9c2009-08-01 00:32:09 +0900113 if ( face->num_locations != (FT_ULong)face->root.num_glyphs )
Werner Lemberg6b19e092008-07-09 06:20:12 +0000114 {
115 FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n",
116 face->num_locations, face->root.num_glyphs ));
117
118 /* we only handle the case where `maxp' gives a larger value */
suzuki toshiya25dba9c2009-08-01 00:32:09 +0900119 if ( face->num_locations < (FT_ULong)face->root.num_glyphs )
Werner Lemberg6b19e092008-07-09 06:20:12 +0000120 {
121 FT_Long new_loca_len = (FT_Long)face->root.num_glyphs << shift;
122
123 TT_Table entry = face->dir_tables;
124 TT_Table limit = entry + face->num_tables;
125
126 FT_Long pos = FT_Stream_Pos( stream );
127 FT_Long dist = 0x7FFFFFFFL;
128
129
130 /* compute the distance to next table in font file */
131 for ( ; entry < limit; entry++ )
132 {
133 FT_Long diff = entry->Offset - pos;
134
135
136 if ( diff > 0 && diff < dist )
137 dist = diff;
138 }
139
140 if ( new_loca_len <= dist )
141 {
suzuki toshiya25dba9c2009-08-01 00:32:09 +0900142 face->num_locations = face->root.num_glyphs;
Werner Lemberg6b19e092008-07-09 06:20:12 +0000143 table_len = new_loca_len;
144
145 FT_TRACE2(( "adjusting num_locations to %d\n",
146 face->num_locations ));
147 }
148 }
David Turnere70d5532005-02-22 16:53:06 +0000149 }
150
Werner Lemberge7930922005-03-01 02:13:50 +0000151 /*
152 * Extract the frame. We don't need to decompress it since
153 * we are able to parse it directly.
154 */
David Turnere70d5532005-02-22 16:53:06 +0000155 if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
156 goto Exit;
157
158 FT_TRACE2(( "loaded\n" ));
159
160 Exit:
161 return error;
162 }
163
164
165 FT_LOCAL_DEF( FT_ULong )
Werner Lemberge7930922005-03-01 02:13:50 +0000166 tt_face_get_location( TT_Face face,
167 FT_UInt gindex,
168 FT_UInt *asize )
David Turnere70d5532005-02-22 16:53:06 +0000169 {
170 FT_ULong pos1, pos2;
171 FT_Byte* p;
172 FT_Byte* p_limit;
173
Werner Lemberge7930922005-03-01 02:13:50 +0000174
David Turnere70d5532005-02-22 16:53:06 +0000175 pos1 = pos2 = 0;
Werner Lemberge7930922005-03-01 02:13:50 +0000176
David Turnere70d5532005-02-22 16:53:06 +0000177 if ( gindex < face->num_locations )
178 {
179 if ( face->header.Index_To_Loc_Format != 0 )
180 {
Werner Lemberge7930922005-03-01 02:13:50 +0000181 p = face->glyph_locations + gindex * 4;
182 p_limit = face->glyph_locations + face->num_locations * 4;
David Turnere70d5532005-02-22 16:53:06 +0000183
Werner Lemberge7930922005-03-01 02:13:50 +0000184 pos1 = FT_NEXT_ULONG( p );
David Turnere70d5532005-02-22 16:53:06 +0000185 pos2 = pos1;
186
Werner Lemberge7930922005-03-01 02:13:50 +0000187 if ( p + 4 <= p_limit )
188 pos2 = FT_NEXT_ULONG( p );
David Turnere70d5532005-02-22 16:53:06 +0000189 }
190 else
191 {
Werner Lemberge7930922005-03-01 02:13:50 +0000192 p = face->glyph_locations + gindex * 2;
193 p_limit = face->glyph_locations + face->num_locations * 2;
David Turnere70d5532005-02-22 16:53:06 +0000194
Werner Lemberge7930922005-03-01 02:13:50 +0000195 pos1 = FT_NEXT_USHORT( p );
David Turnere70d5532005-02-22 16:53:06 +0000196 pos2 = pos1;
197
Werner Lemberge7930922005-03-01 02:13:50 +0000198 if ( p + 2 <= p_limit )
199 pos2 = FT_NEXT_USHORT( p );
David Turnere70d5532005-02-22 16:53:06 +0000200
201 pos1 <<= 1;
202 pos2 <<= 1;
203 }
204 }
205
Werner Lembergb47b97d2009-04-04 07:51:45 +0200206 /* The `loca' table must be ordered; it refers to the length of */
207 /* an entry as the difference between the current and the next */
208 /* position. However, there do exist (malformed) fonts which */
209 /* don't obey this rule, so we are only able to provide an */
210 /* upper bound for the size. */
Werner Lemberg1474f432008-12-09 06:51:56 +0000211 /* */
212 /* We get (intentionally) a wrong, non-zero result in case the */
213 /* `glyf' table is missing. */
Werner Lemberg43ebad42005-05-07 06:10:19 +0000214 if ( pos2 >= pos1 )
Werner Lemberg5452fbe2005-05-05 07:44:20 +0000215 *asize = (FT_UInt)( pos2 - pos1 );
216 else
217 *asize = (FT_UInt)( face->glyf_len - pos1 );
David Turnere70d5532005-02-22 16:53:06 +0000218
219 return pos1;
220 }
221
222
223 FT_LOCAL_DEF( void )
224 tt_face_done_loca( TT_Face face )
225 {
Werner Lemberge7930922005-03-01 02:13:50 +0000226 FT_Stream stream = face->root.stream;
227
David Turnere70d5532005-02-22 16:53:06 +0000228
229 FT_FRAME_RELEASE( face->glyph_locations );
230 face->num_locations = 0;
231 }
232
233
David Turnere70d5532005-02-22 16:53:06 +0000234
David Turnerd2b1f351999-12-16 23:11:37 +0000235 /*************************************************************************/
236 /* */
237 /* <Function> */
David Turnerb08fe2d2002-08-27 20:20:29 +0000238 /* tt_face_load_cvt */
David Turnerd2b1f351999-12-16 23:11:37 +0000239 /* */
240 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000241 /* Load the control value table into a face object. */
David Turnerd2b1f351999-12-16 23:11:37 +0000242 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000243 /* <InOut> */
David Turnerd2b1f351999-12-16 23:11:37 +0000244 /* face :: A handle to the target face object. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000245 /* */
246 /* <Input> */
David Turnerd2b1f351999-12-16 23:11:37 +0000247 /* stream :: A handle to the input stream. */
248 /* */
249 /* <Return> */
Werner Lemberg9ca2af32000-06-21 03:03:28 +0000250 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000251 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000252 FT_LOCAL_DEF( FT_Error )
David Turnerb08fe2d2002-08-27 20:20:29 +0000253 tt_face_load_cvt( TT_Face face,
254 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000255 {
David Turner6aa260c2006-08-25 22:45:13 +0000256#ifdef TT_USE_BYTECODE_INTERPRETER
David Turnere70d5532005-02-22 16:53:06 +0000257
David Turnerf9b8dec2000-06-16 19:34:52 +0000258 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000259 FT_Memory memory = stream->memory;
David Turnerf9b8dec2000-06-16 19:34:52 +0000260 FT_ULong table_len;
David Turnerd2b1f351999-12-16 23:11:37 +0000261
Werner Lemberg78575dc2000-06-12 19:36:41 +0000262
David Turnerd2b1f351999-12-16 23:11:37 +0000263 FT_TRACE2(( "CVT " ));
264
265 error = face->goto_table( face, TTAG_cvt, stream, &table_len );
Werner Lemberg78575dc2000-06-12 19:36:41 +0000266 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000267 {
Werner Lemberg858abbe2009-06-26 06:15:41 +0200268 FT_TRACE2(( "is missing\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000269
270 face->cvt_size = 0;
271 face->cvt = NULL;
272 error = TT_Err_Ok;
273
274 goto Exit;
275 }
276
277 face->cvt_size = table_len / 2;
278
David Turnere459d742002-03-22 13:52:37 +0000279 if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000280 goto Exit;
281
David Turner7d3a2642002-03-20 10:49:31 +0000282 if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000283 goto Exit;
284
285 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000286 FT_Short* cur = face->cvt;
287 FT_Short* limit = cur + face->cvt_size;
David Turnerd2b1f351999-12-16 23:11:37 +0000288
Werner Lemberg78575dc2000-06-12 19:36:41 +0000289
David Turnerd2b1f351999-12-16 23:11:37 +0000290 for ( ; cur < limit; cur++ )
David Turnera890c292002-03-22 12:55:23 +0000291 *cur = FT_GET_SHORT();
David Turnerd2b1f351999-12-16 23:11:37 +0000292 }
293
David Turner7d3a2642002-03-20 10:49:31 +0000294 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000295 FT_TRACE2(( "loaded\n" ));
296
Werner Lemberg44bb3032004-04-25 20:15:11 +0000297#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
298 if ( face->doblend )
299 error = tt_face_vary_cvt( face, stream );
300#endif
301
David Turnerd2b1f351999-12-16 23:11:37 +0000302 Exit:
303 return error;
David Turnere70d5532005-02-22 16:53:06 +0000304
David Turner6aa260c2006-08-25 22:45:13 +0000305#else /* !TT_USE_BYTECODE_INTERPRETER */
Werner Lemberge7930922005-03-01 02:13:50 +0000306
307 FT_UNUSED( face );
308 FT_UNUSED( stream );
309
Werner Lembergc11aeb62005-03-10 15:49:45 +0000310 return TT_Err_Ok;
Werner Lemberge7930922005-03-01 02:13:50 +0000311
David Turnere70d5532005-02-22 16:53:06 +0000312#endif
David Turnerd2b1f351999-12-16 23:11:37 +0000313 }
314
315
316 /*************************************************************************/
317 /* */
318 /* <Function> */
David Turnerb08fe2d2002-08-27 20:20:29 +0000319 /* tt_face_load_fpgm */
David Turnerd2b1f351999-12-16 23:11:37 +0000320 /* */
321 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000322 /* Load the font program. */
David Turnerd2b1f351999-12-16 23:11:37 +0000323 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000324 /* <InOut> */
David Turnerd2b1f351999-12-16 23:11:37 +0000325 /* face :: A handle to the target face object. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000326 /* */
327 /* <Input> */
David Turnerd2b1f351999-12-16 23:11:37 +0000328 /* stream :: A handle to the input stream. */
329 /* */
330 /* <Return> */
Werner Lemberg9ca2af32000-06-21 03:03:28 +0000331 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000332 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000333 FT_LOCAL_DEF( FT_Error )
David Turnerb08fe2d2002-08-27 20:20:29 +0000334 tt_face_load_fpgm( TT_Face face,
335 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000336 {
David Turner6aa260c2006-08-25 22:45:13 +0000337#ifdef TT_USE_BYTECODE_INTERPRETER
David Turnere70d5532005-02-22 16:53:06 +0000338
Werner Lemberg52254022006-02-15 06:05:52 +0000339 FT_Error error;
340 FT_ULong table_len;
David Turnerd2b1f351999-12-16 23:11:37 +0000341
Werner Lemberg78575dc2000-06-12 19:36:41 +0000342
Werner Lembergf6978662000-01-08 20:00:54 +0000343 FT_TRACE2(( "Font program " ));
David Turnerd2b1f351999-12-16 23:11:37 +0000344
345 /* The font program is optional */
346 error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
Werner Lembergf6978662000-01-08 20:00:54 +0000347 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000348 {
349 face->font_program = NULL;
350 face->font_program_size = 0;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000351 error = TT_Err_Ok;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000352
Werner Lemberg858abbe2009-06-26 06:15:41 +0200353 FT_TRACE2(( "is missing\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000354 }
355 else
356 {
357 face->font_program_size = table_len;
David Turner7d3a2642002-03-20 10:49:31 +0000358 if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000359 goto Exit;
360
361 FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
362 }
363
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000364 Exit:
365 return error;
366
David Turner6aa260c2006-08-25 22:45:13 +0000367#else /* !TT_USE_BYTECODE_INTERPRETER */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000368
369 FT_UNUSED( face );
370 FT_UNUSED( stream );
371
372 return TT_Err_Ok;
373
374#endif
375 }
376
377
378 /*************************************************************************/
379 /* */
380 /* <Function> */
381 /* tt_face_load_prep */
382 /* */
383 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000384 /* Load the cvt program. */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000385 /* */
386 /* <InOut> */
387 /* face :: A handle to the target face object. */
388 /* */
389 /* <Input> */
390 /* stream :: A handle to the input stream. */
391 /* */
392 /* <Return> */
393 /* FreeType error code. 0 means success. */
394 /* */
395 FT_LOCAL_DEF( FT_Error )
396 tt_face_load_prep( TT_Face face,
397 FT_Stream stream )
398 {
David Turner6aa260c2006-08-25 22:45:13 +0000399#ifdef TT_USE_BYTECODE_INTERPRETER
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000400
Werner Lemberg52254022006-02-15 06:05:52 +0000401 FT_Error error;
402 FT_ULong table_len;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000403
404
David Turnerd2b1f351999-12-16 23:11:37 +0000405 FT_TRACE2(( "Prep program " ));
406
407 error = face->goto_table( face, TTAG_prep, stream, &table_len );
Werner Lembergf6978662000-01-08 20:00:54 +0000408 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000409 {
410 face->cvt_program = NULL;
411 face->cvt_program_size = 0;
Werner Lembergf6978662000-01-08 20:00:54 +0000412 error = TT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000413
Werner Lemberg858abbe2009-06-26 06:15:41 +0200414 FT_TRACE2(( "is missing\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000415 }
416 else
417 {
418 face->cvt_program_size = table_len;
David Turner7d3a2642002-03-20 10:49:31 +0000419 if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
David Turner2e421312000-05-26 22:13:17 +0000420 goto Exit;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000421
David Turnerd2b1f351999-12-16 23:11:37 +0000422 FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
423 }
424
425 Exit:
426 return error;
David Turnere70d5532005-02-22 16:53:06 +0000427
David Turner6aa260c2006-08-25 22:45:13 +0000428#else /* !TT_USE_BYTECODE_INTERPRETER */
Werner Lemberge7930922005-03-01 02:13:50 +0000429
430 FT_UNUSED( face );
431 FT_UNUSED( stream );
432
Werner Lembergc11aeb62005-03-10 15:49:45 +0000433 return TT_Err_Ok;
Werner Lemberge7930922005-03-01 02:13:50 +0000434
David Turnere70d5532005-02-22 16:53:06 +0000435#endif
David Turnerd2b1f351999-12-16 23:11:37 +0000436 }
437
438
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000439 /*************************************************************************/
440 /* */
441 /* <Function> */
442 /* tt_face_load_hdmx */
443 /* */
444 /* <Description> */
Werner Lemberg52254022006-02-15 06:05:52 +0000445 /* Load the `hdmx' table into the face object. */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000446 /* */
447 /* <Input> */
448 /* face :: A handle to the target face object. */
449 /* */
450 /* stream :: A handle to the input stream. */
451 /* */
452 /* <Return> */
453 /* FreeType error code. 0 means success. */
454 /* */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000455
456 FT_LOCAL_DEF( FT_Error )
457 tt_face_load_hdmx( TT_Face face,
458 FT_Stream stream )
459 {
460 FT_Error error;
461 FT_Memory memory = stream->memory;
462 FT_UInt version, nn, num_records;
463 FT_ULong table_size, record_size;
464 FT_Byte* p;
465 FT_Byte* limit;
466
467
468 /* this table is optional */
469 error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
470 if ( error || table_size < 8 )
471 return TT_Err_Ok;
472
473 if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
474 goto Exit;
475
476 p = face->hdmx_table;
477 limit = p + table_size;
478
479 version = FT_NEXT_USHORT( p );
480 num_records = FT_NEXT_USHORT( p );
481 record_size = FT_NEXT_ULONG( p );
482
Werner Lemberg36d2eab2006-09-05 19:24:34 +0000483 /* The maximum number of bytes in an hdmx device record is the */
484 /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */
485 /* the reason why `record_size' is a long (which we read as */
486 /* unsigned long for convenience). In practice, two bytes */
487 /* sufficient to hold the size value. */
488 /* */
489 /* There are at least two fonts, HANNOM-A and HANNOM-B version */
490 /* 2.0 (2005), which get this wrong: The upper two bytes of */
491 /* the size value are set to 0xFF instead of 0x00. We catch */
492 /* and fix this. */
493
494 if ( record_size >= 0xFFFF0000UL )
495 record_size &= 0xFFFFU;
496
497 /* The limit for `num_records' is a heuristic value. */
498
499 if ( version != 0 || num_records > 255 || record_size > 0x10001L )
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000500 {
501 error = TT_Err_Invalid_File_Format;
502 goto Fail;
503 }
504
505 if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
506 goto Fail;
507
508 for ( nn = 0; nn < num_records; nn++ )
509 {
510 if ( p + record_size > limit )
511 break;
David Turnerda95af62006-03-20 13:32:33 +0000512
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000513 face->hdmx_record_sizes[nn] = p[0];
514 p += record_size;
515 }
David Turnerda95af62006-03-20 13:32:33 +0000516
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000517 face->hdmx_record_count = nn;
518 face->hdmx_table_size = table_size;
Wu, Chia-I (吳佳一)facd9af2006-02-22 07:59:35 +0000519 face->hdmx_record_size = record_size;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000520
521 Exit:
522 return error;
David Turnerda95af62006-03-20 13:32:33 +0000523
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000524 Fail:
525 FT_FRAME_RELEASE( face->hdmx_table );
526 face->hdmx_table_size = 0;
527 goto Exit;
528 }
529
530
531 FT_LOCAL_DEF( void )
532 tt_face_free_hdmx( TT_Face face )
533 {
534 FT_Stream stream = face->root.stream;
535 FT_Memory memory = stream->memory;
David Turnerda95af62006-03-20 13:32:33 +0000536
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000537
538 FT_FREE( face->hdmx_record_sizes );
539 FT_FRAME_RELEASE( face->hdmx_table );
540 }
541
Werner Lemberg52254022006-02-15 06:05:52 +0000542
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000543 /*************************************************************************/
544 /* */
Werner Lemberg52254022006-02-15 06:05:52 +0000545 /* Return the advance width table for a given pixel size if it is found */
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000546 /* in the font's `hdmx' table (if any). */
547 /* */
548 FT_LOCAL_DEF( FT_Byte* )
549 tt_face_get_device_metrics( TT_Face face,
David Turnerda95af62006-03-20 13:32:33 +0000550 FT_UInt ppem,
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000551 FT_UInt gindex )
552 {
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000553 FT_UInt nn;
554 FT_Byte* result = NULL;
555 FT_ULong record_size = face->hdmx_record_size;
556 FT_Byte* record = face->hdmx_table + 8;
557
558
559 for ( nn = 0; nn < face->hdmx_record_count; nn++ )
560 if ( face->hdmx_record_sizes[nn] == ppem )
561 {
562 gindex += 2;
563 if ( gindex < record_size )
Wu, Chia-I (吳佳一)facd9af2006-02-22 07:59:35 +0000564 result = record + nn * record_size + gindex;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000565 break;
566 }
567
568 return result;
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +0000569 }
570
571
David Turnerd2b1f351999-12-16 23:11:37 +0000572/* END */