blob: 40b2ecfa15f5a070d1f34fc7e4894222c93c2cbe [file] [log] [blame]
David Turnerd2b1f351999-12-16 23:11:37 +00001/***************************************************************************/
2/* */
3/* ttload.c */
4/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00005/* Load the basic TrueType tables, i.e., tables that can be either in */
6/* TTF or OTF fonts (body). */
David Turnerd2b1f351999-12-16 23:11:37 +00007/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00008/* Copyright 1996-2000 by */
David Turnerd2b1f351999-12-16 23:11:37 +00009/* David Turner, Robert Wilhelm, and Werner Lemberg. */
10/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000011/* This file is part of the FreeType project, and may only be used, */
12/* modified, and distributed under the terms of the FreeType project */
David Turnerd2b1f351999-12-16 23:11:37 +000013/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14/* this file you indicate that you have read the license and */
15/* understand and accept it fully. */
16/* */
David Turnerd2b1f351999-12-16 23:11:37 +000017/***************************************************************************/
18
19
David Turnerefce08d2000-05-11 18:23:52 +000020#include <freetype/internal/ftdebug.h>
21#include <freetype/internal/tterrors.h>
22#include <freetype/tttags.h>
David Turnerd2b1f351999-12-16 23:11:37 +000023
Werner Lemberg7fa51b52000-07-08 19:51:42 +000024
David Turnera90663f2000-07-08 00:41:13 +000025#ifdef FT_FLAT_COMPILE
Werner Lemberg7fa51b52000-07-08 19:51:42 +000026
David Turnera90663f2000-07-08 00:41:13 +000027#include "ttload.h"
28#include "ttcmap.h"
Werner Lemberg7fa51b52000-07-08 19:51:42 +000029
David Turnera90663f2000-07-08 00:41:13 +000030#else
Werner Lemberg7fa51b52000-07-08 19:51:42 +000031
David Turnera90663f2000-07-08 00:41:13 +000032#include <sfnt/ttload.h>
33#include <sfnt/ttcmap.h>
Werner Lemberg7fa51b52000-07-08 19:51:42 +000034
David Turnera90663f2000-07-08 00:41:13 +000035#endif
36
37
Werner Lemberg4e6dd852000-06-05 05:26:15 +000038 /*************************************************************************/
39 /* */
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
43 /* */
44#undef FT_COMPONENT
45#define FT_COMPONENT trace_ttload
David Turnera56489e2000-02-13 13:41:56 +000046
David Turnerd2b1f351999-12-16 23:11:37 +000047
48 /*************************************************************************/
49 /* */
50 /* <Function> */
51 /* TT_LookUp_Table */
52 /* */
53 /* <Description> */
54 /* Looks for a TrueType table by name. */
55 /* */
56 /* <Input> */
57 /* face :: A face object handle. */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000058 /* tag :: The searched tag. */
David Turnerd2b1f351999-12-16 23:11:37 +000059 /* */
60 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000061 /* A pointer to the table directory entry. 0 if not found. */
David Turnerd2b1f351999-12-16 23:11:37 +000062 /* */
David Turnerbfe2f982000-05-12 12:17:15 +000063 LOCAL_FUNC
David Turnerd2b1f351999-12-16 23:11:37 +000064 TT_Table* TT_LookUp_Table( TT_Face face,
David Turnerf9b8dec2000-06-16 19:34:52 +000065 FT_ULong tag )
David Turnerd2b1f351999-12-16 23:11:37 +000066 {
67 TT_Table* entry;
68 TT_Table* limit;
David Turnere49ab252000-05-16 23:44:38 +000069
Werner Lemberg4e6dd852000-06-05 05:26:15 +000070
Werner Lemberg1c0d4ac2000-06-06 20:41:48 +000071 FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c'\n",
David Turner51179f02000-05-18 16:18:05 +000072 face,
David Turnerf9b8dec2000-06-16 19:34:52 +000073 (FT_Char)( tag >> 24 ),
74 (FT_Char)( tag >> 16 ),
75 (FT_Char)( tag >> 8 ),
Werner Lembergfbeb41d2000-07-02 00:27:53 +000076 (FT_Char)( tag ) ));
David Turnerd2b1f351999-12-16 23:11:37 +000077
78 entry = face->dir_tables;
79 limit = entry + face->num_tables;
Werner Lemberg4e6dd852000-06-05 05:26:15 +000080
David Turnerd2b1f351999-12-16 23:11:37 +000081 for ( ; entry < limit; entry++ )
82 {
83 if ( entry->Tag == tag )
84 return entry;
David Turnere49ab252000-05-16 23:44:38 +000085 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +000086
87 FT_TRACE3(( " Could not find table!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +000088 return 0;
89 }
90
Werner Lemberg4e6dd852000-06-05 05:26:15 +000091
David Turnerd2b1f351999-12-16 23:11:37 +000092 /*************************************************************************/
93 /* */
94 /* <Function> */
95 /* TT_Goto_Table */
96 /* */
97 /* <Description> */
98 /* Looks for a TrueType table by name, then seek a stream to it. */
99 /* */
100 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000101 /* face :: A face object handle. */
102 /* tag :: The searched tag. */
103 /* stream :: The stream to seek when the table is found. */
104 /* */
105 /* <Output> */
106 /* length :: The length of the table if found, undefined otherwise. */
David Turnerd2b1f351999-12-16 23:11:37 +0000107 /* */
108 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000109 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000110 /* */
David Turnerbfe2f982000-05-12 12:17:15 +0000111 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000112 FT_Error TT_Goto_Table( TT_Face face,
113 FT_ULong tag,
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000114 FT_Stream stream,
David Turnerf9b8dec2000-06-16 19:34:52 +0000115 FT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000116 {
117 TT_Table* table;
David Turnerf9b8dec2000-06-16 19:34:52 +0000118 FT_Error error;
David Turnere49ab252000-05-16 23:44:38 +0000119
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000120
David Turnerd2b1f351999-12-16 23:11:37 +0000121 table = TT_LookUp_Table( face, tag );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000122 if ( table )
David Turnerd2b1f351999-12-16 23:11:37 +0000123 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000124 if ( length )
David Turnerd2b1f351999-12-16 23:11:37 +0000125 *length = table->Length;
David Turnere49ab252000-05-16 23:44:38 +0000126
David Turnerd2b1f351999-12-16 23:11:37 +0000127 (void)FILE_Seek( table->Offset );
128 }
129 else
130 error = TT_Err_Table_Missing;
David Turnere49ab252000-05-16 23:44:38 +0000131
David Turnerd2b1f351999-12-16 23:11:37 +0000132 return error;
133 }
134
135
136 /*************************************************************************/
137 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000138 /* <Function> */
David Turnerb1677a82000-05-29 20:37:41 +0000139 /* TT_Load_SFNT_Header */
David Turnerd2b1f351999-12-16 23:11:37 +0000140 /* */
141 /* <Description> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000142 /* Loads the header of a SFNT font file. Supports collections. */
David Turnerd2b1f351999-12-16 23:11:37 +0000143 /* */
144 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000145 /* face :: A handle to the target face object. */
146 /* stream :: The input stream. */
147 /* face_index :: If the font is a collection, the number of the font */
148 /* in the collection, ignored otherwise. */
David Turnerb1677a82000-05-29 20:37:41 +0000149 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000150 /* <Output> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000151 /* sfnt :: The SFNT header. */
David Turnerd2b1f351999-12-16 23:11:37 +0000152 /* */
153 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000154 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000155 /* */
156 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000157 /* The stream cursor must be at the font file's origin. */
David Turnerd2b1f351999-12-16 23:11:37 +0000158 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000159 /* This function recognizes fonts embedded in a `TrueType collection' */
160 /* */
161 /* The header will be checked whether it is valid by looking at the */
162 /* values of `search_range', `entry_selector', and `range_shift'. */
David Turnerb1677a82000-05-29 20:37:41 +0000163 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000164 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000165 FT_Error TT_Load_SFNT_Header( TT_Face face,
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000166 FT_Stream stream,
David Turnerf9b8dec2000-06-16 19:34:52 +0000167 FT_Long face_index,
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000168 SFNT_Header* sfnt )
David Turnerd2b1f351999-12-16 23:11:37 +0000169 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000170 FT_Error error;
171 FT_ULong format_tag;
Werner Lemberg7a4fda82000-06-13 23:21:00 +0000172 FT_Memory memory = stream->memory;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000173
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000174 const FT_Frame_Field sfnt_header_fields[] =
175 {
176 FT_FRAME_START( 8 ),
177 FT_FRAME_USHORT( SFNT_Header, num_tables ),
178 FT_FRAME_USHORT( SFNT_Header, search_range ),
179 FT_FRAME_USHORT( SFNT_Header, entry_selector ),
180 FT_FRAME_USHORT( SFNT_Header, range_shift ),
181 FT_FRAME_END
182 };
Werner Lemberg920d41e2000-06-05 14:32:32 +0000183
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000184 const FT_Frame_Field ttc_header_fields[] =
185 {
186 FT_FRAME_START( 8 ),
187 FT_FRAME_LONG( TTC_Header, version ),
188 FT_FRAME_LONG( TTC_Header, DirCount ),
189 FT_FRAME_END };
David Turnerd2b1f351999-12-16 23:11:37 +0000190
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000191
192 FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n",
David Turner3581d062000-06-01 03:26:58 +0000193 face, face_index ));
David Turnerd2b1f351999-12-16 23:11:37 +0000194
195 face->ttc_header.Tag = 0;
196 face->ttc_header.version = 0;
197 face->ttc_header.DirCount = 0;
198
199 face->num_tables = 0;
200
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000201 /* first of all, read the first 4 bytes. If it is `ttcf', then the */
202 /* file is a TrueType collection, otherwise it can be any other */
203 /* kind of font. */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000204 if ( READ_ULong( format_tag ) )
205 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000206
David Turnerb1677a82000-05-29 20:37:41 +0000207 if ( format_tag == TTAG_ttcf )
David Turnerd2b1f351999-12-16 23:11:37 +0000208 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000209 FT_Int n;
David Turnere49ab252000-05-16 23:44:38 +0000210
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000211
212 FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" ));
David Turnere49ab252000-05-16 23:44:38 +0000213
David Turnerd2b1f351999-12-16 23:11:37 +0000214 /* it's a TrueType collection, i.e. a file containing several */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000215 /* font files. Read the font directory now */
David Turnera56489e2000-02-13 13:41:56 +0000216 if ( READ_Fields( ttc_header_fields, &face->ttc_header ) )
217 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000218
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000219 /* now read the offsets of each font in the file */
David Turnerd2b1f351999-12-16 23:11:37 +0000220 if ( ALLOC_ARRAY( face->ttc_header.TableDirectory,
221 face->ttc_header.DirCount,
David Turnerf9b8dec2000-06-16 19:34:52 +0000222 FT_ULong ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000223 ACCESS_Frame( face->ttc_header.DirCount * 4L ) )
224 goto Exit;
225
226 for ( n = 0; n < face->ttc_header.DirCount; n++ )
227 face->ttc_header.TableDirectory[n] = GET_ULong();
228
229 FORGET_Frame();
230
231 /* check face index */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000232 if ( face_index >= face->ttc_header.DirCount )
David Turnerd2b1f351999-12-16 23:11:37 +0000233 {
234 error = TT_Err_Bad_Argument;
235 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +0000236 }
237
David Turnerd2b1f351999-12-16 23:11:37 +0000238 /* seek to the appropriate TrueType file, then read tag */
David Turnerb1677a82000-05-29 20:37:41 +0000239 if ( FILE_Seek( face->ttc_header.TableDirectory[face_index] ) ||
240 READ_Long( format_tag ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000241 goto Exit;
242 }
David Turnerd2b1f351999-12-16 23:11:37 +0000243
David Turnerb1677a82000-05-29 20:37:41 +0000244 /* the format tag was read, now check the rest of the header */
245 sfnt->format_tag = format_tag;
246 if ( READ_Fields( sfnt_header_fields, sfnt ) )
247 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000248
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000249 /* now, check the values of `num_tables', `seach_range', etc. */
David Turnerb1677a82000-05-29 20:37:41 +0000250 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000251 FT_UInt num_tables = sfnt->num_tables;
252 FT_ULong entry_selector = 1L << sfnt->entry_selector;
David Turner3581d062000-06-01 03:26:58 +0000253
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000254
255 /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
256 /* we only check the `entry_selector' correctness here. */
257 /* */
258 if ( num_tables == 0 ||
259 entry_selector > num_tables ||
260 entry_selector * 2 <= num_tables )
David Turner3581d062000-06-01 03:26:58 +0000261 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000262 FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" ));
David Turnerb1677a82000-05-29 20:37:41 +0000263 error = FT_Err_Unknown_File_Format;
264 }
265 }
266
David Turnerd42c68e2000-01-27 13:56:02 +0000267 Exit:
268 return error;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000269 }
David Turnerb1677a82000-05-29 20:37:41 +0000270
David Turnerd2b1f351999-12-16 23:11:37 +0000271
David Turnerd42c68e2000-01-27 13:56:02 +0000272 /*************************************************************************/
273 /* */
274 /* <Function> */
275 /* TT_Load_Directory */
276 /* */
277 /* <Description> */
278 /* Loads the table directory into a face object. */
279 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000280 /* <InOut> */
281 /* face :: A handle to the target face object. */
282 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000283 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000284 /* stream :: The input stream. */
285 /* sfnt :: The SFNT directory header. */
David Turnerd42c68e2000-01-27 13:56:02 +0000286 /* */
287 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000288 /* FreeType error code. 0 means success. */
David Turnerd42c68e2000-01-27 13:56:02 +0000289 /* */
290 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000291 /* The stream cursor must be at the font file's origin. */
David Turnerd42c68e2000-01-27 13:56:02 +0000292 /* */
293 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000294 FT_Error TT_Load_Directory( TT_Face face,
David Turnerb1677a82000-05-29 20:37:41 +0000295 FT_Stream stream,
296 SFNT_Header* sfnt )
David Turnerd42c68e2000-01-27 13:56:02 +0000297 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000298 FT_Error error;
David Turnerd42c68e2000-01-27 13:56:02 +0000299 FT_Memory memory = stream->memory;
David Turnerd42c68e2000-01-27 13:56:02 +0000300
301 TT_Table *entry, *limit;
302
David Turnerd42c68e2000-01-27 13:56:02 +0000303
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000304 FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
305
306 FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
307 FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
David Turnerd42c68e2000-01-27 13:56:02 +0000308
David Turnerb1677a82000-05-29 20:37:41 +0000309 face->num_tables = sfnt->num_tables;
David Turnerd2b1f351999-12-16 23:11:37 +0000310
311 if ( ALLOC_ARRAY( face->dir_tables,
312 face->num_tables,
313 TT_Table ) )
314 goto Exit;
315
316 if ( ACCESS_Frame( face->num_tables * 16L ) )
317 goto Exit;
318
319 entry = face->dir_tables;
320 limit = entry + face->num_tables;
321
322 for ( ; entry < limit; entry++ )
David Turnerd42c68e2000-01-27 13:56:02 +0000323 { /* loop through the tables and get all entries */
David Turnerd2b1f351999-12-16 23:11:37 +0000324 entry->Tag = GET_Tag4();
325 entry->CheckSum = GET_ULong();
326 entry->Offset = GET_Long();
327 entry->Length = GET_Long();
328
329 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
David Turnerf9b8dec2000-06-16 19:34:52 +0000330 (FT_Char)( entry->Tag >> 24 ),
331 (FT_Char)( entry->Tag >> 16 ),
332 (FT_Char)( entry->Tag >> 8 ),
333 (FT_Char)( entry->Tag ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000334 entry->Offset,
335 entry->Length ));
David Turnerd2b1f351999-12-16 23:11:37 +0000336 }
337
338 FORGET_Frame();
339
340 FT_TRACE2(( "Directory loaded\n\n" ));
341
342 Exit:
343 return error;
344 }
345
346
347 /*************************************************************************/
348 /* */
349 /* <Function> */
350 /* TT_Load_Any */
351 /* */
352 /* <Description> */
Werner Lembergc8f9cf32000-07-19 02:59:31 +0000353 /* Loads any font table into client memory. */
David Turnerd2b1f351999-12-16 23:11:37 +0000354 /* */
355 /* <Input> */
356 /* face :: The face object to look for. */
357 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000358 /* tag :: The tag of table to load. Use the value 0 if you want */
David Turnerd2b1f351999-12-16 23:11:37 +0000359 /* to access the whole font file, else set this parameter */
360 /* to a valid TrueType table tag that you can forge with */
361 /* the MAKE_TT_TAG macro. */
362 /* */
363 /* offset :: The starting offset in the table (or the file if */
364 /* tag == 0). */
365 /* */
366 /* length :: The address of the decision variable: */
367 /* */
368 /* If length == NULL: */
369 /* Loads the whole table. Returns an error if */
370 /* `offset' == 0! */
371 /* */
372 /* If *length == 0: */
373 /* Exits immediately; returning the length of the given */
374 /* table or of the font file, depending on the value of */
375 /* `tag'. */
376 /* */
377 /* If *length != 0: */
378 /* Loads the next `length' bytes of table or font, */
379 /* starting at offset `offset' (in table or font too). */
380 /* */
381 /* <Output> */
382 /* buffer :: The address of target buffer. */
383 /* */
384 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000385 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000386 /* */
387 LOCAL_FUNC
Werner Lembergbd5ae402000-07-05 04:32:02 +0000388 FT_Error TT_Load_Any( TT_Face face,
389 FT_ULong tag,
390 FT_Long offset,
391 FT_Byte* buffer,
392 FT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000393 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000394 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000395 FT_Stream stream;
396 TT_Table* table;
David Turnerf9b8dec2000-06-16 19:34:52 +0000397 FT_ULong size;
David Turnerd2b1f351999-12-16 23:11:37 +0000398
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000399
David Turnerd2b1f351999-12-16 23:11:37 +0000400 if ( tag != 0 )
401 {
402 /* look for tag in font directory */
403 table = TT_LookUp_Table( face, tag );
404 if ( !table )
405 {
406 error = TT_Err_Table_Missing;
407 goto Exit;
408 }
409
410 offset += table->Offset;
411 size = table->Length;
412 }
413 else
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000414 /* tag == 0 -- the user wants to access the font file directly */
David Turnerd2b1f351999-12-16 23:11:37 +0000415 size = face->root.stream->size;
David Turnerd2b1f351999-12-16 23:11:37 +0000416
417 if ( length && *length == 0 )
418 {
419 *length = size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000420
David Turnerd2b1f351999-12-16 23:11:37 +0000421 return TT_Err_Ok;
422 }
423
424 if ( length )
425 size = *length;
426
427 stream = face->root.stream;
428 (void)FILE_Read_At( offset, buffer, size );
429
430 Exit:
431 return error;
432 }
433
434
435 /*************************************************************************/
436 /* */
437 /* <Function> */
438 /* TT_Load_Header */
439 /* */
440 /* <Description> */
441 /* Loads the TrueType font header. */
442 /* */
443 /* <Input> */
444 /* face :: A handle to the target face object. */
445 /* stream :: The input stream. */
446 /* */
447 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000448 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000449 /* */
450 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000451 FT_Error TT_Load_Header( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +0000452 FT_Stream stream )
453 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000454 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000455 TT_Header* header;
David Turnerb1677a82000-05-29 20:37:41 +0000456
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000457 static const FT_Frame_Field header_fields[] =
458 {
459 FT_FRAME_START( 54 ),
460 FT_FRAME_ULONG( TT_Header, Table_Version ),
461 FT_FRAME_ULONG( TT_Header, Font_Revision ),
462 FT_FRAME_LONG( TT_Header, CheckSum_Adjust ),
463 FT_FRAME_LONG( TT_Header, Magic_Number ),
464 FT_FRAME_USHORT( TT_Header, Flags ),
465 FT_FRAME_USHORT( TT_Header, Units_Per_EM ),
466 FT_FRAME_LONG( TT_Header, Created[0] ),
467 FT_FRAME_LONG( TT_Header, Created[1] ),
468 FT_FRAME_LONG( TT_Header, Modified[0] ),
469 FT_FRAME_LONG( TT_Header, Modified[1] ),
470 FT_FRAME_SHORT( TT_Header, xMin ),
471 FT_FRAME_SHORT( TT_Header, yMin ),
472 FT_FRAME_SHORT( TT_Header, xMax ),
473 FT_FRAME_SHORT( TT_Header, yMax ),
474 FT_FRAME_USHORT( TT_Header, Mac_Style ),
475 FT_FRAME_USHORT( TT_Header, Lowest_Rec_PPEM ),
476 FT_FRAME_SHORT( TT_Header, Font_Direction ),
477 FT_FRAME_SHORT( TT_Header, Index_To_Loc_Format ),
478 FT_FRAME_SHORT( TT_Header, Glyph_Data_Format ),
479 FT_FRAME_END
480 };
David Turnerd2b1f351999-12-16 23:11:37 +0000481
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000482
483 FT_TRACE2(( "Load_TT_Header: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000484
485 error = face->goto_table( face, TTAG_head, stream, 0 );
486 if ( error )
487 {
488 FT_TRACE0(( "Font Header is missing!\n" ));
489 goto Exit;
490 }
491
David Turnera56489e2000-02-13 13:41:56 +0000492 header = &face->header;
493
David Turnerb1677a82000-05-29 20:37:41 +0000494 if ( READ_Fields( header_fields, header ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000495 goto Exit;
496
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000497 FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
498 FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
David Turnerd2b1f351999-12-16 23:11:37 +0000499 FT_TRACE2(( "Font Header Loaded.\n" ));
500
501 Exit:
502 return error;
503 }
504
505
506 /*************************************************************************/
507 /* */
508 /* <Function> */
509 /* TT_Load_MaxProfile */
510 /* */
511 /* <Description> */
512 /* Loads the maximum profile into a face object. */
513 /* */
514 /* <Input> */
515 /* face :: A handle to the target face object. */
516 /* stream :: The input stream. */
517 /* */
518 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000519 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000520 /* */
521 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000522 FT_Error TT_Load_MaxProfile( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +0000523 FT_Stream stream )
524 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000525 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000526 TT_MaxProfile* maxProfile = &face->max_profile;
David Turnerb1677a82000-05-29 20:37:41 +0000527
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000528 const FT_Frame_Field maxp_fields[] =
529 {
530 FT_FRAME_START( 32 ),
531 FT_FRAME_ULONG( TT_MaxProfile, version ),
532 FT_FRAME_USHORT( TT_MaxProfile, numGlyphs ),
533 FT_FRAME_USHORT( TT_MaxProfile, maxPoints ),
534 FT_FRAME_USHORT( TT_MaxProfile, maxContours ),
535 FT_FRAME_USHORT( TT_MaxProfile, maxCompositePoints ),
536 FT_FRAME_USHORT( TT_MaxProfile, maxCompositeContours ),
537 FT_FRAME_USHORT( TT_MaxProfile, maxZones ),
538 FT_FRAME_USHORT( TT_MaxProfile, maxTwilightPoints ),
539 FT_FRAME_USHORT( TT_MaxProfile, maxStorage ),
540 FT_FRAME_USHORT( TT_MaxProfile, maxFunctionDefs ),
541 FT_FRAME_USHORT( TT_MaxProfile, maxInstructionDefs ),
542 FT_FRAME_USHORT( TT_MaxProfile, maxStackElements ),
543 FT_FRAME_USHORT( TT_MaxProfile, maxSizeOfInstructions ),
544 FT_FRAME_USHORT( TT_MaxProfile, maxComponentElements ),
545 FT_FRAME_USHORT( TT_MaxProfile, maxComponentDepth ),
546 FT_FRAME_END };
David Turnerd2b1f351999-12-16 23:11:37 +0000547
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000548
549 FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000550
551 error = face->goto_table( face, TTAG_maxp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000552 if ( error )
553 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000554
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000555 if ( READ_Fields( maxp_fields, maxProfile ) )
556 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000557
558 /* XXX: an adjustment that is necessary to load certain */
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000559 /* broken fonts like `Keystrokes MT' :-( */
David Turnerd2b1f351999-12-16 23:11:37 +0000560 /* */
561 /* We allocate 64 function entries by default when */
562 /* the maxFunctionDefs field is null. */
563
564 if ( maxProfile->maxFunctionDefs == 0 )
565 maxProfile->maxFunctionDefs = 64;
566
567 face->root.num_glyphs = maxProfile->numGlyphs;
568
569 face->root.max_points = MAX( maxProfile->maxCompositePoints,
570 maxProfile->maxPoints );
571
572 face->root.max_contours = MAX( maxProfile->maxCompositeContours,
573 maxProfile->maxContours );
574
David Turnerf9b8dec2000-06-16 19:34:52 +0000575 face->max_components = (FT_ULong)maxProfile->maxComponentElements +
David Turnerd2b1f351999-12-16 23:11:37 +0000576 maxProfile->maxComponentDepth;
577
578 /* XXX: some fonts have maxComponents set to 0; we will */
579 /* then use 16 of them by default. */
580 if ( face->max_components == 0 )
581 face->max_components = 16;
582
583 /* We also increase maxPoints and maxContours in order to support */
584 /* some broken fonts. */
585 face->root.max_points += 8;
586 face->root.max_contours += 4;
587
588 FT_TRACE2(( "MAXP loaded.\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000589
David Turnerd2b1f351999-12-16 23:11:37 +0000590 Exit:
591 return error;
592 }
593
594
595 /*************************************************************************/
596 /* */
597 /* <Function> */
598 /* TT_Load_Metrics */
599 /* */
600 /* <Description> */
601 /* Loads the horizontal or vertical metrics table into a face object. */
602 /* */
603 /* <Input> */
604 /* face :: A handle to the target face object. */
605 /* stream :: The input stream. */
606 /* vertical :: A boolean flag. If set, load vertical metrics. */
607 /* */
608 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000609 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000610 /* */
611 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000612 FT_Error TT_Load_Metrics( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +0000613 FT_Stream stream,
David Turnerf9b8dec2000-06-16 19:34:52 +0000614 FT_Bool vertical )
David Turnerd2b1f351999-12-16 23:11:37 +0000615 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000616 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000617 FT_Memory memory = stream->memory;
618
David Turnerf9b8dec2000-06-16 19:34:52 +0000619 FT_ULong table_len;
620 FT_Long num_shorts, num_longs, num_shorts_checked;
David Turnerd2b1f351999-12-16 23:11:37 +0000621
622 TT_LongMetrics** longs;
623 TT_ShortMetrics** shorts;
624
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000625
626 FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
627 : "Horizontal",
628 face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000629
630 if ( vertical )
631 {
632 /* The table is optional, quit silently if it wasn't found */
633 /* XXX: Some fonts have a valid vertical header with a non-null */
634 /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
635 /* table to get the metrics from (e.g. mingliu). */
636 /* */
637 /* For safety, we set the field to 0! */
638 /* */
639 error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
640 if ( error )
641 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000642 /* Set number_Of_VMetrics to 0! */
David Turnerd2b1f351999-12-16 23:11:37 +0000643 FT_TRACE2(( " no vertical header in file.\n" ));
644 face->vertical.number_Of_VMetrics = 0;
645 error = TT_Err_Ok;
646 goto Exit;
647 }
648
649 num_longs = face->vertical.number_Of_VMetrics;
650 longs = (TT_LongMetrics**)&face->vertical.long_metrics;
651 shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
652 }
653 else
654 {
655 error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000656 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000657 {
658 FT_ERROR(( " no horizontal metrics in file!\n" ));
659 error = TT_Err_Hmtx_Table_Missing;
660 goto Exit;
661 }
662
663 num_longs = face->horizontal.number_Of_HMetrics;
664 longs = (TT_LongMetrics**)&face->horizontal.long_metrics;
665 shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
666 }
667
668 /* never trust derived values */
669
670 num_shorts = face->max_profile.numGlyphs - num_longs;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000671 num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000672
673 if ( num_shorts < 0 )
674 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000675 FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
676 vertical ? "Vertical"
677 : "Horizontal" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000678
679 error = vertical ? TT_Err_Invalid_Vert_Metrics
680 : TT_Err_Invalid_Horiz_Metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000681 goto Exit;
682 }
683
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000684 if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000685 ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
686 goto Exit;
687
688 if ( ACCESS_Frame( table_len ) )
689 goto Exit;
690
691 {
692 TT_LongMetrics* cur = *longs;
693 TT_LongMetrics* limit = cur + num_longs;
694
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000695
David Turnerd2b1f351999-12-16 23:11:37 +0000696 for ( ; cur < limit; cur++ )
697 {
698 cur->advance = GET_UShort();
699 cur->bearing = GET_Short();
700 }
701 }
702
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000703 /* do we have an inconsistent number of metric values? */
David Turnerd2b1f351999-12-16 23:11:37 +0000704 {
705 TT_ShortMetrics* cur = *shorts;
706 TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
707
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000708
David Turnerd2b1f351999-12-16 23:11:37 +0000709 for ( ; cur < limit; cur++ )
710 *cur = GET_Short();
711
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000712 /* we fill up the missing left side bearings with the */
713 /* last valid value. Since this will occur for buggy CJK */
714 /* fonts usually only, nothing serious will happen */
David Turnerd2b1f351999-12-16 23:11:37 +0000715 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
716 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000717 FT_Short val = *(shorts)[num_shorts_checked - 1];
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000718
David Turnerd2b1f351999-12-16 23:11:37 +0000719
720 limit = *shorts + num_shorts;
721 for ( ; cur < limit; cur++ )
722 *cur = val;
723 }
724 }
725
726 FORGET_Frame();
727
728 FT_TRACE2(( "loaded\n" ));
729
730 Exit:
731 return error;
732 }
733
734
735 /*************************************************************************/
736 /* */
737 /* <Function> */
738 /* TT_Load_Metrics_Header */
739 /* */
740 /* <Description> */
741 /* Loads the horizontal or vertical header in a face object. */
742 /* */
743 /* <Input> */
744 /* face :: A handle to the target face object. */
745 /* stream :: The input stream. */
746 /* vertical :: A boolean flag. If set, load vertical metrics. */
747 /* */
748 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000749 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000750 /* */
751 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000752 FT_Error TT_Load_Metrics_Header( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +0000753 FT_Stream stream,
David Turnerf9b8dec2000-06-16 19:34:52 +0000754 FT_Bool vertical )
David Turnerd2b1f351999-12-16 23:11:37 +0000755 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000756 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000757 TT_HoriHeader* header;
David Turnerb1677a82000-05-29 20:37:41 +0000758
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000759 const FT_Frame_Field metrics_header_fields[] =
760 {
761 FT_FRAME_START( 36 ),
762 FT_FRAME_ULONG( TT_HoriHeader, Version ),
763 FT_FRAME_SHORT( TT_HoriHeader, Ascender ),
764 FT_FRAME_SHORT( TT_HoriHeader, Descender ),
765 FT_FRAME_SHORT( TT_HoriHeader, Line_Gap ),
766 FT_FRAME_USHORT( TT_HoriHeader, advance_Width_Max ),
767 FT_FRAME_SHORT( TT_HoriHeader, min_Left_Side_Bearing ),
768 FT_FRAME_SHORT( TT_HoriHeader, min_Right_Side_Bearing ),
769 FT_FRAME_SHORT( TT_HoriHeader, xMax_Extent ),
770 FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Rise ),
771 FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Run ),
772 FT_FRAME_SHORT( TT_HoriHeader, Reserved[0] ),
773 FT_FRAME_SHORT( TT_HoriHeader, Reserved[1] ),
774 FT_FRAME_SHORT( TT_HoriHeader, Reserved[2] ),
775 FT_FRAME_SHORT( TT_HoriHeader, Reserved[3] ),
776 FT_FRAME_SHORT( TT_HoriHeader, Reserved[4] ),
777 FT_FRAME_SHORT( TT_HoriHeader, metric_Data_Format ),
778 FT_FRAME_USHORT( TT_HoriHeader, number_Of_HMetrics ),
779 FT_FRAME_END
780 };
781
David Turnerb1677a82000-05-29 20:37:41 +0000782
David Turnerd2b1f351999-12-16 23:11:37 +0000783 FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
784
785 if ( vertical )
786 {
787 face->vertical_info = 0;
788
789 /* The vertical header table is optional, so return quietly if */
790 /* we don't find it. */
791 error = face->goto_table( face, TTAG_vhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000792 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000793 {
794 error = TT_Err_Ok;
795 goto Exit;
796 }
797
798 face->vertical_info = 1;
799 header = (TT_HoriHeader*)&face->vertical;
800 }
801 else
802 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000803 /* The horizontal header is mandatory; return an error if we */
David Turnerd2b1f351999-12-16 23:11:37 +0000804 /* don't find it. */
805 error = face->goto_table( face, TTAG_hhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000806 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000807 {
808 error = TT_Err_Horiz_Header_Missing;
809 goto Exit;
810 }
811
812 header = &face->horizontal;
813 }
814
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000815 if ( READ_Fields( metrics_header_fields, header ) )
816 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000817
818 header->long_metrics = NULL;
819 header->short_metrics = NULL;
820
821 FT_TRACE2(( "loaded\n" ));
822
823 /* Now try to load the corresponding metrics */
824
825 error = TT_Load_Metrics( face, stream, vertical );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000826
David Turnerd2b1f351999-12-16 23:11:37 +0000827 Exit:
828 return error;
829 }
830
831
832 /*************************************************************************/
833 /* */
834 /* <Function> */
835 /* TT_Load_Names */
836 /* */
837 /* <Description> */
838 /* Loads the name records. */
839 /* */
840 /* <Input> */
841 /* face :: A handle to the target face object. */
842 /* stream :: The input stream. */
843 /* */
844 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000845 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000846 /* */
847 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000848 FT_Error TT_Load_Names( TT_Face face,
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000849 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000850 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000851 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000852 FT_Memory memory = stream->memory;
853
David Turnerf9b8dec2000-06-16 19:34:52 +0000854 FT_ULong table_pos, table_len;
855 FT_ULong storageSize;
David Turnerd2b1f351999-12-16 23:11:37 +0000856
857 TT_NameTable* names;
David Turnerb1677a82000-05-29 20:37:41 +0000858
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000859 const FT_Frame_Field name_table_fields[] =
860 {
861 FT_FRAME_START( 6 ),
862 FT_FRAME_USHORT( TT_NameTable, format ),
863 FT_FRAME_USHORT( TT_NameTable, numNameRecords ),
864 FT_FRAME_USHORT( TT_NameTable, storageOffset ),
865 FT_FRAME_END
866 };
David Turnera56489e2000-02-13 13:41:56 +0000867
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000868 const FT_Frame_Field name_record_fields[] =
869 {
870 /* no FT_FRAME_START */
871 FT_FRAME_USHORT( TT_NameRec, platformID ),
872 FT_FRAME_USHORT( TT_NameRec, encodingID ),
873 FT_FRAME_USHORT( TT_NameRec, languageID ),
874 FT_FRAME_USHORT( TT_NameRec, nameID ),
875 FT_FRAME_USHORT( TT_NameRec, stringLength ),
876 FT_FRAME_USHORT( TT_NameRec, stringOffset ),
877 FT_FRAME_END
878 };
David Turnerd2b1f351999-12-16 23:11:37 +0000879
880
881 FT_TRACE2(( "Names " ));
882
883 error = face->goto_table( face, TTAG_name, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000884 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000885 {
886 /* The name table is required so indicate failure. */
887 FT_TRACE2(( "is missing!\n" ));
888 error = TT_Err_Name_Table_Missing;
889 goto Exit;
890 }
891
892 table_pos = FILE_Pos();
893
David Turnera56489e2000-02-13 13:41:56 +0000894 names = &face->name_table;
895
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000896 if ( READ_Fields( name_table_fields, names ) )
897 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000898
899 /* Allocate the array of name records. */
900 if ( ALLOC_ARRAY( names->names,
901 names->numNameRecords,
902 TT_NameRec ) ||
903 ACCESS_Frame( names->numNameRecords * 12L ) )
904 goto Exit;
905
906 /* Load the name records and determine how much storage is needed */
907 /* to hold the strings themselves. */
908 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000909 TT_NameRec* cur = names->names;
910 TT_NameRec* limit = cur + names->numNameRecords;
911
David Turnerd2b1f351999-12-16 23:11:37 +0000912
913 storageSize = 0;
914
915 for ( ; cur < limit; cur ++ )
916 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000917 FT_ULong upper;
David Turnerd2b1f351999-12-16 23:11:37 +0000918
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000919
David Turnera56489e2000-02-13 13:41:56 +0000920 (void)READ_Fields( name_record_fields, cur );
David Turnerb1677a82000-05-29 20:37:41 +0000921
David Turnerf9b8dec2000-06-16 19:34:52 +0000922 upper = (FT_ULong)( cur->stringOffset + cur->stringLength );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000923 if ( upper > storageSize )
924 storageSize = upper;
David Turnerd2b1f351999-12-16 23:11:37 +0000925 }
926 }
927
928 FORGET_Frame();
929
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000930 if ( storageSize > 0 )
David Turnerd2b1f351999-12-16 23:11:37 +0000931 {
932 /* allocate the name storage area in memory, then read it */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000933 if ( ALLOC( names->storage, storageSize ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000934 FILE_Read_At( table_pos + names->storageOffset,
Werner Lembergbd5ae402000-07-05 04:32:02 +0000935 names->storage, storageSize ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000936 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +0000937
David Turnerd2b1f351999-12-16 23:11:37 +0000938 /* Go through and assign the string pointers to the name records. */
939 {
940 TT_NameRec* cur = names->names;
941 TT_NameRec* limit = cur + names->numNameRecords;
David Turnere49ab252000-05-16 23:44:38 +0000942
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000943
David Turnerd2b1f351999-12-16 23:11:37 +0000944 for ( ; cur < limit; cur++ )
945 cur->string = names->storage + cur->stringOffset;
946 }
947
David Turnere49ab252000-05-16 23:44:38 +0000948#ifdef FT_DEBUG_LEVEL_TRACE
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000949
David Turnerd2b1f351999-12-16 23:11:37 +0000950 /* Print Name Record Table in case of debugging */
951 {
952 TT_NameRec* cur = names->names;
953 TT_NameRec* limit = cur + names->numNameRecords;
954
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000955
David Turnerd2b1f351999-12-16 23:11:37 +0000956 for ( ; cur < limit; cur++ )
957 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000958 FT_UInt j;
David Turnere49ab252000-05-16 23:44:38 +0000959
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000960
961 FT_TRACE3(( "%d %d %x %d\n ",
David Turnerd2b1f351999-12-16 23:11:37 +0000962 cur->platformID,
963 cur->encodingID,
964 cur->languageID,
965 cur->nameID ));
David Turnere49ab252000-05-16 23:44:38 +0000966
David Turnerd2b1f351999-12-16 23:11:37 +0000967 /* I know that M$ encoded strings are Unicode, */
968 /* but this works reasonable well for debugging purposes. */
969 if ( cur->string )
970 for ( j = 0; j < cur->stringLength; j++ )
971 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000972 FT_Char c = *( cur->string + j );
David Turnere49ab252000-05-16 23:44:38 +0000973
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000974
David Turnerf9b8dec2000-06-16 19:34:52 +0000975 if ( (FT_Byte)c < 128 )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000976 FT_TRACE3(( "%c", c ));
David Turnerd2b1f351999-12-16 23:11:37 +0000977 }
978 }
979 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000980 FT_TRACE3(( "\n" ));
981
982#endif /* FT_DEBUG_LEVEL_TRACE */
983
David Turnerd2b1f351999-12-16 23:11:37 +0000984 }
985 FT_TRACE2(( "loaded\n" ));
986
David Turner49bd4f02000-07-12 16:57:37 +0000987 /* everything went well, update face->num_names */
988 face->num_names = names->numNameRecords;
989
David Turnerd2b1f351999-12-16 23:11:37 +0000990 Exit:
991 return error;
992 }
993
994
995 /*************************************************************************/
996 /* */
997 /* <Function> */
998 /* TT_Free_Names */
999 /* */
1000 /* <Description> */
1001 /* Frees the name records. */
1002 /* */
1003 /* <Input> */
1004 /* face :: A handle to the target face object. */
1005 /* */
1006 LOCAL_FUNC
1007 void TT_Free_Names( TT_Face face )
1008 {
David Turnerf0df85b2000-06-22 00:17:42 +00001009 FT_Memory memory = face->root.driver->root.memory;
David Turnerd2b1f351999-12-16 23:11:37 +00001010 TT_NameTable* names = &face->name_table;
1011
1012
1013 /* free strings table */
1014 FREE( names->names );
1015
1016 /* free strings storage */
1017 FREE( names->storage );
1018
1019 names->numNameRecords = 0;
1020 names->format = 0;
1021 names->storageOffset = 0;
1022 }
1023
1024
1025 /*************************************************************************/
1026 /* */
1027 /* <Function> */
1028 /* TT_Load_CMap */
1029 /* */
1030 /* <Description> */
1031 /* Loads the cmap directory in a face object. The cmaps itselves are */
1032 /* loaded on demand in the `ttcmap.c' module. */
1033 /* */
1034 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001035 /* face :: A handle to the target face object. */
1036 /* stream :: A handle to the input stream. */
David Turnerd2b1f351999-12-16 23:11:37 +00001037 /* */
1038 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001039 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001040 /* */
1041 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001042 FT_Error TT_Load_CMap( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001043 FT_Stream stream )
1044 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001045 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001046 FT_Memory memory = stream->memory;
David Turnerf9b8dec2000-06-16 19:34:52 +00001047 FT_Long table_start;
David Turnerd2b1f351999-12-16 23:11:37 +00001048 TT_CMapDir cmap_dir;
1049
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001050 const FT_Frame_Field cmap_fields[] =
1051 {
1052 FT_FRAME_START( 4 ),
1053 FT_FRAME_USHORT( TT_CMapDir, tableVersionNumber ),
1054 FT_FRAME_USHORT( TT_CMapDir, numCMaps ),
1055 FT_FRAME_END
1056 };
David Turnera56489e2000-02-13 13:41:56 +00001057
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001058 const FT_Frame_Field cmap_rec_fields[] =
1059 {
1060 FT_FRAME_START( 6 ),
1061 FT_FRAME_USHORT( TT_CMapTable, format ),
1062 FT_FRAME_USHORT( TT_CMapTable, length ),
1063 FT_FRAME_USHORT( TT_CMapTable, version ),
1064 FT_FRAME_END
1065 };
1066
David Turnera56489e2000-02-13 13:41:56 +00001067
David Turnerd2b1f351999-12-16 23:11:37 +00001068 FT_TRACE2(( "CMaps " ));
1069
1070 error = face->goto_table( face, TTAG_cmap, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001071 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001072 {
1073 error = TT_Err_CMap_Table_Missing;
1074 goto Exit;
1075 }
1076
1077 table_start = FILE_Pos();
1078
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001079 if ( READ_Fields( cmap_fields, &cmap_dir ) )
1080 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001081
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001082 /* reserve space in face table for cmap tables */
David Turnerd2b1f351999-12-16 23:11:37 +00001083 if ( ALLOC_ARRAY( face->charmaps,
1084 cmap_dir.numCMaps,
1085 TT_CharMapRec ) )
1086 goto Exit;
1087
1088 face->num_charmaps = cmap_dir.numCMaps;
1089 {
1090 TT_CharMap charmap = face->charmaps;
1091 TT_CharMap limit = charmap + face->num_charmaps;
1092
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001093
David Turnera56489e2000-02-13 13:41:56 +00001094 /* read the header of each charmap first */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001095 if ( ACCESS_Frame( face->num_charmaps * 8L ) )
1096 goto Exit;
1097
David Turnerd2b1f351999-12-16 23:11:37 +00001098 for ( ; charmap < limit; charmap++ )
1099 {
1100 TT_CMapTable* cmap;
1101
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001102
David Turnerd2b1f351999-12-16 23:11:37 +00001103 charmap->root.face = (FT_Face)face;
1104 cmap = &charmap->cmap;
1105
David Turnerd2b1f351999-12-16 23:11:37 +00001106 cmap->loaded = FALSE;
1107 cmap->platformID = GET_UShort();
1108 cmap->platformEncodingID = GET_UShort();
David Turnerf9b8dec2000-06-16 19:34:52 +00001109 cmap->offset = (FT_ULong)GET_Long();
David Turnera56489e2000-02-13 13:41:56 +00001110 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001111
David Turnera56489e2000-02-13 13:41:56 +00001112 FORGET_Frame();
David Turnere49ab252000-05-16 23:44:38 +00001113
David Turnera56489e2000-02-13 13:41:56 +00001114 /* now read the rest of each table */
1115 for ( charmap = face->charmaps; charmap < limit; charmap++ )
1116 {
1117 TT_CMapTable* cmap = &charmap->cmap;
David Turnere49ab252000-05-16 23:44:38 +00001118
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001119
David Turnerf9b8dec2000-06-16 19:34:52 +00001120 if ( FILE_Seek( table_start + (FT_Long)cmap->offset ) ||
David Turnera56489e2000-02-13 13:41:56 +00001121 READ_Fields( cmap_rec_fields, cmap ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001122 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001123
David Turnerd2b1f351999-12-16 23:11:37 +00001124 cmap->offset = FILE_Pos();
David Turnerd2b1f351999-12-16 23:11:37 +00001125 }
1126 }
1127
1128 FT_TRACE2(( "loaded\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001129
David Turnerd2b1f351999-12-16 23:11:37 +00001130 Exit:
1131 return error;
1132 }
1133
1134
1135 /*************************************************************************/
1136 /* */
1137 /* <Function> */
1138 /* TT_Load_OS2 */
1139 /* */
1140 /* <Description> */
1141 /* Loads the OS2 table. */
1142 /* */
1143 /* <Input> */
1144 /* face :: A handle to the target face object. */
1145 /* stream :: A handle to the input stream. */
1146 /* */
1147 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001148 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001149 /* */
1150 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001151 FT_Error TT_Load_OS2( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001152 FT_Stream stream )
1153 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001154 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001155 TT_OS2* os2;
David Turnerb1677a82000-05-29 20:37:41 +00001156
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001157 const FT_Frame_Field os2_fields[] =
1158 {
1159 FT_FRAME_START( 78 ),
1160 FT_FRAME_USHORT( TT_OS2, version ),
1161 FT_FRAME_SHORT( TT_OS2, xAvgCharWidth ),
1162 FT_FRAME_USHORT( TT_OS2, usWeightClass ),
1163 FT_FRAME_USHORT( TT_OS2, usWidthClass ),
1164 FT_FRAME_SHORT( TT_OS2, fsType ),
1165 FT_FRAME_SHORT( TT_OS2, ySubscriptXSize ),
1166 FT_FRAME_SHORT( TT_OS2, ySubscriptYSize ),
1167 FT_FRAME_SHORT( TT_OS2, ySubscriptXOffset ),
1168 FT_FRAME_SHORT( TT_OS2, ySubscriptYOffset ),
1169 FT_FRAME_SHORT( TT_OS2, ySuperscriptXSize ),
1170 FT_FRAME_SHORT( TT_OS2, ySuperscriptYSize ),
1171 FT_FRAME_SHORT( TT_OS2, ySuperscriptXOffset ),
1172 FT_FRAME_SHORT( TT_OS2, ySuperscriptYOffset ),
1173 FT_FRAME_SHORT( TT_OS2, yStrikeoutSize ),
1174 FT_FRAME_SHORT( TT_OS2, yStrikeoutPosition ),
1175 FT_FRAME_SHORT( TT_OS2, sFamilyClass ),
1176 FT_FRAME_BYTE( TT_OS2, panose[0] ),
1177 FT_FRAME_BYTE( TT_OS2, panose[1] ),
1178 FT_FRAME_BYTE( TT_OS2, panose[2] ),
1179 FT_FRAME_BYTE( TT_OS2, panose[3] ),
1180 FT_FRAME_BYTE( TT_OS2, panose[4] ),
1181 FT_FRAME_BYTE( TT_OS2, panose[5] ),
1182 FT_FRAME_BYTE( TT_OS2, panose[6] ),
1183 FT_FRAME_BYTE( TT_OS2, panose[7] ),
1184 FT_FRAME_BYTE( TT_OS2, panose[8] ),
1185 FT_FRAME_BYTE( TT_OS2, panose[9] ),
1186 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange1 ),
1187 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange2 ),
1188 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange3 ),
1189 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange4 ),
1190 FT_FRAME_BYTE( TT_OS2, achVendID[0] ),
1191 FT_FRAME_BYTE( TT_OS2, achVendID[1] ),
1192 FT_FRAME_BYTE( TT_OS2, achVendID[2] ),
1193 FT_FRAME_BYTE( TT_OS2, achVendID[3] ),
David Turnera56489e2000-02-13 13:41:56 +00001194
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001195 FT_FRAME_USHORT( TT_OS2, fsSelection ),
1196 FT_FRAME_USHORT( TT_OS2, usFirstCharIndex ),
1197 FT_FRAME_USHORT( TT_OS2, usLastCharIndex ),
1198 FT_FRAME_SHORT( TT_OS2, sTypoAscender ),
1199 FT_FRAME_SHORT( TT_OS2, sTypoDescender ),
1200 FT_FRAME_SHORT( TT_OS2, sTypoLineGap ),
1201 FT_FRAME_USHORT( TT_OS2, usWinAscent ),
1202 FT_FRAME_USHORT( TT_OS2, usWinDescent ),
1203 FT_FRAME_END
1204 };
David Turnere49ab252000-05-16 23:44:38 +00001205
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001206 const FT_Frame_Field os2_fields_extra[] =
1207 {
1208 FT_FRAME_START( 8 ),
1209 FT_FRAME_ULONG( TT_OS2, ulCodePageRange1 ),
1210 FT_FRAME_ULONG( TT_OS2, ulCodePageRange2 ),
1211 FT_FRAME_END
1212 };
David Turner1119bae2000-05-02 11:01:49 +00001213
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001214 const FT_Frame_Field os2_fields_extra2[] =
1215 {
1216 FT_FRAME_START( 10 ),
1217 FT_FRAME_SHORT( TT_OS2, sxHeight ),
1218 FT_FRAME_SHORT( TT_OS2, sCapHeight ),
1219 FT_FRAME_USHORT( TT_OS2, usDefaultChar ),
1220 FT_FRAME_USHORT( TT_OS2, usBreakChar ),
1221 FT_FRAME_USHORT( TT_OS2, usMaxContext ),
1222 FT_FRAME_END
1223 };
1224
David Turnerd2b1f351999-12-16 23:11:37 +00001225
1226 FT_TRACE2(( "OS/2 Table " ));
1227
1228 /* We now support old Mac fonts where the OS/2 table doesn't */
1229 /* exist. Simply put, we set the `version' field to 0xFFFF */
1230 /* and test this value each time we need to access the table. */
1231 error = face->goto_table( face, TTAG_OS2, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001232 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001233 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001234 FT_TRACE2(( "is missing!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +00001235 face->os2.version = 0xFFFF;
1236 error = TT_Err_Ok;
1237 goto Exit;
1238 }
1239
David Turnera56489e2000-02-13 13:41:56 +00001240 os2 = &face->os2;
1241
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001242 if ( READ_Fields( os2_fields, os2 ) )
1243 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001244
1245 os2->ulCodePageRange1 = 0;
1246 os2->ulCodePageRange2 = 0;
1247
1248 if ( os2->version >= 0x0001 )
1249 {
1250 /* only version 1 tables */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001251 if ( READ_Fields( os2_fields_extra, os2 ) )
1252 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001253
1254 if ( os2->version >= 0x0002 )
1255 {
1256 /* only version 2 tables */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001257 if ( READ_Fields( os2_fields_extra2, os2 ) )
1258 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001259 }
David Turnerd2b1f351999-12-16 23:11:37 +00001260 }
1261
1262 FT_TRACE2(( "loaded\n" ));
1263
1264 Exit:
1265 return error;
1266 }
1267
1268
1269 /*************************************************************************/
1270 /* */
1271 /* <Function> */
1272 /* TT_Load_Postscript */
1273 /* */
1274 /* <Description> */
1275 /* Loads the Postscript table. */
1276 /* */
1277 /* <Input> */
1278 /* face :: A handle to the target face object. */
1279 /* stream :: A handle to the input stream. */
1280 /* */
1281 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001282 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001283 /* */
1284 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001285 FT_Error TT_Load_PostScript( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001286 FT_Stream stream )
1287 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001288 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001289 TT_Postscript* post = &face->postscript;
David Turnerb1677a82000-05-29 20:37:41 +00001290
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001291 static const FT_Frame_Field post_fields[] =
1292 {
1293 FT_FRAME_START( 32 ),
1294 FT_FRAME_ULONG( TT_Postscript, FormatType ),
1295 FT_FRAME_ULONG( TT_Postscript, italicAngle ),
1296 FT_FRAME_SHORT( TT_Postscript, underlinePosition ),
1297 FT_FRAME_SHORT( TT_Postscript, underlineThickness ),
1298 FT_FRAME_ULONG( TT_Postscript, isFixedPitch ),
1299 FT_FRAME_ULONG( TT_Postscript, minMemType42 ),
1300 FT_FRAME_ULONG( TT_Postscript, maxMemType42 ),
1301 FT_FRAME_ULONG( TT_Postscript, minMemType1 ),
1302 FT_FRAME_ULONG( TT_Postscript, maxMemType1 ),
1303 FT_FRAME_END
1304 };
1305
David Turnerd2b1f351999-12-16 23:11:37 +00001306
1307 FT_TRACE2(( "PostScript " ));
1308
1309 error = face->goto_table( face, TTAG_post, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001310 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001311 return TT_Err_Post_Table_Missing;
1312
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001313 if ( READ_Fields( post_fields, post ) )
1314 return error;
David Turnerd2b1f351999-12-16 23:11:37 +00001315
David Turnerd2b1f351999-12-16 23:11:37 +00001316 /* we don't load the glyph names, we do that in another */
1317 /* module (ttpost). */
1318 FT_TRACE2(( "loaded\n" ));
1319
1320 return TT_Err_Ok;
1321 }
1322
1323
1324 /*************************************************************************/
1325 /* */
1326 /* <Function> */
David Turner51179f02000-05-18 16:18:05 +00001327 /* TT_Load_PCLT */
1328 /* */
1329 /* <Description> */
1330 /* Loads the PCL 5 Table. */
1331 /* */
1332 /* <Input> */
1333 /* face :: A handle to the target face object. */
1334 /* stream :: A handle to the input stream. */
1335 /* */
1336 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001337 /* FreeType error code. 0 means success. */
David Turner51179f02000-05-18 16:18:05 +00001338 /* */
1339 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001340 FT_Error TT_Load_PCLT( TT_Face face,
David Turner51179f02000-05-18 16:18:05 +00001341 FT_Stream stream )
1342 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001343 static const FT_Frame_Field pclt_fields[] =
1344 {
David Turnerd18388e2000-07-03 15:00:49 +00001345 FT_FRAME_START( 54 ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001346 FT_FRAME_ULONG ( TT_PCLT, Version ),
1347 FT_FRAME_ULONG ( TT_PCLT, FontNumber ),
1348 FT_FRAME_USHORT( TT_PCLT, Pitch ),
1349 FT_FRAME_USHORT( TT_PCLT, xHeight ),
1350 FT_FRAME_USHORT( TT_PCLT, Style ),
1351 FT_FRAME_USHORT( TT_PCLT, TypeFamily ),
1352 FT_FRAME_USHORT( TT_PCLT, CapHeight ),
David Turnerd18388e2000-07-03 15:00:49 +00001353 FT_FRAME_BYTES ( TT_PCLT, TypeFace, 16 ),
1354 FT_FRAME_BYTES ( TT_PCLT, CharacterComplement, 8 ),
1355 FT_FRAME_BYTES ( TT_PCLT, FileName, 6 ),
1356 FT_FRAME_CHAR ( TT_PCLT, StrokeWeight ),
1357 FT_FRAME_CHAR ( TT_PCLT, WidthType ),
1358 FT_FRAME_BYTE ( TT_PCLT, SerifStyle ),
1359 FT_FRAME_BYTE ( TT_PCLT, Reserved ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001360 FT_FRAME_END
1361 };
Werner Lemberg920d41e2000-06-05 14:32:32 +00001362
David Turnerf9b8dec2000-06-16 19:34:52 +00001363 FT_Error error;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001364 TT_PCLT* pclt = &face->pclt;
1365
Werner Lemberg920d41e2000-06-05 14:32:32 +00001366
David Turner51179f02000-05-18 16:18:05 +00001367 FT_TRACE2(( "PCLT " ));
1368
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001369 /* optional table */
1370 error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1371 if ( error )
1372 {
1373 FT_TRACE2(( "missing (optional)\n" ));
1374 pclt->Version = 0;
1375 return TT_Err_Ok;
1376 }
Werner Lemberg920d41e2000-06-05 14:32:32 +00001377
David Turnerd18388e2000-07-03 15:00:49 +00001378 if ( READ_Fields( pclt_fields, pclt ) )
David Turner51179f02000-05-18 16:18:05 +00001379 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +00001380
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001381 FT_TRACE2(( "loaded\n" ));
1382
Werner Lemberg920d41e2000-06-05 14:32:32 +00001383 Exit:
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001384 return error;
1385 }
1386
David Turner51179f02000-05-18 16:18:05 +00001387
1388 /*************************************************************************/
1389 /* */
1390 /* <Function> */
David Turnerd2b1f351999-12-16 23:11:37 +00001391 /* TT_Load_Gasp */
1392 /* */
1393 /* <Description> */
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001394 /* Loads the `gasp' table into a face object. */
David Turnerd2b1f351999-12-16 23:11:37 +00001395 /* */
1396 /* <Input> */
1397 /* face :: A handle to the target face object. */
1398 /* stream :: The input stream. */
1399 /* */
1400 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001401 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001402 /* */
1403 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001404 FT_Error TT_Load_Gasp( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001405 FT_Stream stream )
1406 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001407 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001408 FT_Memory memory = stream->memory;
1409
David Turnerf9b8dec2000-06-16 19:34:52 +00001410 FT_UInt j,num_ranges;
David Turnerd2b1f351999-12-16 23:11:37 +00001411 TT_GaspRange* gaspranges;
1412
1413
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001414 FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +00001415
1416 /* the gasp table is optional */
1417 error = face->goto_table( face, TTAG_gasp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001418 if ( error )
1419 return TT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001420
1421 if ( ACCESS_Frame( 4L ) )
1422 goto Exit;
1423
1424 face->gasp.version = GET_UShort();
1425 face->gasp.numRanges = GET_UShort();
1426
1427 FORGET_Frame();
1428
1429 num_ranges = face->gasp.numRanges;
1430 FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
1431
1432 if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRange ) ||
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001433 ACCESS_Frame( num_ranges * 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001434 goto Exit;
1435
1436 face->gasp.gaspRanges = gaspranges;
1437
1438 for ( j = 0; j < num_ranges; j++ )
1439 {
1440 gaspranges[j].maxPPEM = GET_UShort();
1441 gaspranges[j].gaspFlag = GET_UShort();
1442
1443 FT_TRACE3(( " [max:%d flag:%d]",
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001444 gaspranges[j].maxPPEM,
1445 gaspranges[j].gaspFlag ));
David Turnerd2b1f351999-12-16 23:11:37 +00001446 }
1447 FT_TRACE3(( "\n" ));
1448
1449 FORGET_Frame();
1450 FT_TRACE2(( "GASP loaded\n" ));
1451
1452 Exit:
1453 return error;
1454 }
1455
1456
1457 /*************************************************************************/
1458 /* */
1459 /* <Function> */
1460 /* TT_Load_Kern */
1461 /* */
1462 /* <Description> */
1463 /* Loads the first kerning table with format 0 in the font. Only */
1464 /* accepts the first horizontal kerning table. Developers should use */
1465 /* the `ftxkern' extension to access other kerning tables in the font */
1466 /* file, if they really want to. */
1467 /* */
1468 /* <Input> */
1469 /* face :: A handle to the target face object. */
1470 /* stream :: The input stream. */
1471 /* */
1472 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001473 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001474 /* */
1475 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001476 FT_Error TT_Load_Kern( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001477 FT_Stream stream )
1478 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001479 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001480 FT_Memory memory = stream->memory;
1481
David Turnerf9b8dec2000-06-16 19:34:52 +00001482 FT_UInt n, num_tables, version;
David Turnerd2b1f351999-12-16 23:11:37 +00001483
David Turnerd2b1f351999-12-16 23:11:37 +00001484
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001485 /* the kern table is optional; exit silently if it is missing */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001486 error = face->goto_table( face, TTAG_kern, stream, 0 );
1487 if ( error )
1488 return TT_Err_Ok;
1489
1490 if ( ACCESS_Frame( 4L ) )
1491 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001492
1493 version = GET_UShort();
1494 num_tables = GET_UShort();
1495
1496 FORGET_Frame();
1497
1498 for ( n = 0; n < num_tables; n++ )
1499 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001500 FT_UInt coverage;
1501 FT_UInt length;
David Turnerd2b1f351999-12-16 23:11:37 +00001502
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001503
1504 if ( ACCESS_Frame( 6L ) )
1505 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001506
1507 version = GET_UShort(); /* version */
1508 length = GET_UShort() - 6; /* substract header length */
1509 coverage = GET_UShort();
1510
1511 FORGET_Frame();
David Turnere49ab252000-05-16 23:44:38 +00001512
David Turnerd2b1f351999-12-16 23:11:37 +00001513 if ( coverage == 0x0001 )
1514 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001515 FT_UInt num_pairs;
David Turnerd2b1f351999-12-16 23:11:37 +00001516 TT_Kern_0_Pair* pair;
1517 TT_Kern_0_Pair* limit;
1518
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001519
1520 /* found a horizontal format 0 kerning table! */
1521 if ( ACCESS_Frame( 8L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001522 goto Exit;
1523
1524 num_pairs = GET_UShort();
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001525
David Turnerd2b1f351999-12-16 23:11:37 +00001526 /* skip the rest */
1527
1528 FORGET_Frame();
1529
1530 /* allocate array of kerning pairs */
1531 if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) ||
1532 ACCESS_Frame( 6L * num_pairs ) )
1533 goto Exit;
1534
1535 pair = face->kern_pairs;
1536 limit = pair + num_pairs;
1537 for ( ; pair < limit; pair++ )
1538 {
1539 pair->left = GET_UShort();
1540 pair->right = GET_UShort();
1541 pair->value = GET_UShort();
1542 }
1543
1544 FORGET_Frame();
1545
1546 face->num_kern_pairs = num_pairs;
1547 face->kern_table_index = n;
1548 goto Exit;
1549 }
David Turnere49ab252000-05-16 23:44:38 +00001550
David Turnerd2b1f351999-12-16 23:11:37 +00001551 if ( FILE_Skip( length ) )
1552 goto Exit;
1553 }
1554
1555 /* no kern table found -- doesn't matter */
1556 face->kern_table_index = -1;
1557 face->num_kern_pairs = 0;
1558 face->kern_pairs = NULL;
1559
1560 Exit:
1561 return error;
1562 }
1563
1564
1565 /*************************************************************************/
1566 /* */
1567 /* <Function> */
1568 /* TT_Load_Hdmx */
1569 /* */
1570 /* <Description> */
1571 /* Loads the horizontal device metrics table. */
1572 /* */
1573 /* <Input> */
1574 /* face :: A handle to the target face object. */
1575 /* stream :: A handle to the input stream. */
1576 /* */
1577 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001578 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001579 /* */
1580 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001581 FT_Error TT_Load_Hdmx( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001582 FT_Stream stream )
1583 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001584 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001585 FT_Memory memory = stream->memory;
1586
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001587 TT_Hdmx* hdmx = &face->hdmx;
David Turnerf9b8dec2000-06-16 19:34:52 +00001588 FT_Long num_glyphs;
1589 FT_Long record_size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001590
David Turnerd2b1f351999-12-16 23:11:37 +00001591
1592 hdmx->version = 0;
1593 hdmx->num_records = 0;
1594 hdmx->records = 0;
1595
1596 /* this table is optional */
1597 error = face->goto_table( face, TTAG_hdmx, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001598 if ( error )
1599 return TT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001600
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001601 if ( ACCESS_Frame( 8L ) )
1602 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001603
1604 hdmx->version = GET_UShort();
1605 hdmx->num_records = GET_Short();
1606 record_size = GET_Long();
1607
1608 FORGET_Frame();
1609
1610 /* Only recognize format 0 */
1611 if ( hdmx->version != 0 )
1612 goto Exit;
1613
1614 if ( ALLOC_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxRec ) )
1615 goto Exit;
1616
1617 num_glyphs = face->root.num_glyphs;
1618 record_size -= num_glyphs + 2;
1619
1620 {
1621 TT_HdmxRec* cur = hdmx->records;
1622 TT_HdmxRec* limit = cur + hdmx->num_records;
1623
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001624
David Turnerd2b1f351999-12-16 23:11:37 +00001625 for ( ; cur < limit; cur++ )
1626 {
1627 /* read record */
1628 if ( READ_Byte( cur->ppem ) ||
1629 READ_Byte( cur->max_width ) )
1630 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001631
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001632 if ( ALLOC( cur->widths, num_glyphs ) ||
David Turnerd2b1f351999-12-16 23:11:37 +00001633 FILE_Read( cur->widths, num_glyphs ) )
1634 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001635
David Turnerd2b1f351999-12-16 23:11:37 +00001636 /* skip padding bytes */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001637 if ( record_size > 0 && FILE_Skip( record_size ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001638 goto Exit;
1639 }
1640 }
1641
1642 Exit:
1643 return error;
1644 }
1645
1646
1647 /*************************************************************************/
1648 /* */
1649 /* <Function> */
1650 /* TT_Free_Hdmx */
1651 /* */
1652 /* <Description> */
1653 /* Frees the horizontal device metrics table. */
1654 /* */
1655 /* <Input> */
1656 /* face :: A handle to the target face object. */
1657 /* */
1658 LOCAL_FUNC
1659 void TT_Free_Hdmx( TT_Face face )
1660 {
1661 if ( face )
1662 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001663 FT_Int n;
David Turnerf0df85b2000-06-22 00:17:42 +00001664 FT_Memory memory = face->root.driver->root.memory;
David Turnerd2b1f351999-12-16 23:11:37 +00001665
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001666
David Turnerd2b1f351999-12-16 23:11:37 +00001667 for ( n = 0; n < face->hdmx.num_records; n++ )
1668 FREE( face->hdmx.records[n].widths );
1669
1670 FREE( face->hdmx.records );
1671 face->hdmx.num_records = 0;
1672 }
1673 }
1674
1675
1676/* END */