blob: 0b729e730ea3af263df73832d9cef37f4d9aa692 [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 Lemberg415235d2001-06-28 17:49:10 +00008/* Copyright 1996-2001 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
Werner Lembergcc069be2000-12-08 16:17:16 +000019
David Turner19ed8af2000-12-08 02:42:29 +000020#include <ft2build.h>
21#include FT_INTERNAL_DEBUG_H
David Turner19ed8af2000-12-08 02:42:29 +000022#include FT_INTERNAL_STREAM_H
23#include FT_TRUETYPE_TAGS_H
David Turner8d3a4012001-03-20 11:14:24 +000024#include "ttload.h"
25#include "ttcmap.h"
David Turnera90663f2000-07-08 00:41:13 +000026
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000027#include "sferrors.h"
28
David Turner9a554eb2001-06-27 12:40:46 +000029#include <stdlib.h> /* for qsort */
Werner Lembergcc069be2000-12-08 16:17:16 +000030
Werner Lemberg4e6dd852000-06-05 05:26:15 +000031 /*************************************************************************/
32 /* */
33 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
34 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
35 /* messages during execution. */
36 /* */
37#undef FT_COMPONENT
38#define FT_COMPONENT trace_ttload
David Turnera56489e2000-02-13 13:41:56 +000039
David Turnerd2b1f351999-12-16 23:11:37 +000040
41 /*************************************************************************/
42 /* */
43 /* <Function> */
44 /* TT_LookUp_Table */
45 /* */
46 /* <Description> */
47 /* Looks for a TrueType table by name. */
48 /* */
49 /* <Input> */
50 /* face :: A face object handle. */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000051 /* tag :: The searched tag. */
David Turnerd2b1f351999-12-16 23:11:37 +000052 /* */
53 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000054 /* A pointer to the table directory entry. 0 if not found. */
David Turnerd2b1f351999-12-16 23:11:37 +000055 /* */
David Turnerb5713c52002-03-14 11:26:29 +000056 FT_LOCAL_DEF( TT_Table )
Werner Lemberg52005c32001-06-27 23:25:46 +000057 TT_LookUp_Table( TT_Face face,
58 FT_ULong tag )
David Turnerd2b1f351999-12-16 23:11:37 +000059 {
David Turnerb5713c52002-03-14 11:26:29 +000060 TT_Table entry;
61 TT_Table limit;
David Turnere49ab252000-05-16 23:44:38 +000062
Werner Lemberg4e6dd852000-06-05 05:26:15 +000063
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000064 FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c' -- ",
Werner Lemberg34e52702000-11-13 16:58:01 +000065 face,
66 (FT_Char)( tag >> 24 ),
67 (FT_Char)( tag >> 16 ),
68 (FT_Char)( tag >> 8 ),
69 (FT_Char)( tag ) ));
David Turnerd2b1f351999-12-16 23:11:37 +000070
71 entry = face->dir_tables;
72 limit = entry + face->num_tables;
Werner Lemberg4e6dd852000-06-05 05:26:15 +000073
David Turnerd2b1f351999-12-16 23:11:37 +000074 for ( ; entry < limit; entry++ )
75 {
76 if ( entry->Tag == tag )
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000077 {
Werner Lemberg34e52702000-11-13 16:58:01 +000078 FT_TRACE3(( "found table.\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +000079 return entry;
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000080 }
David Turnere49ab252000-05-16 23:44:38 +000081 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +000082
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000083 FT_TRACE3(( "could not find table!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +000084 return 0;
85 }
86
Werner Lemberg4e6dd852000-06-05 05:26:15 +000087
David Turnerd2b1f351999-12-16 23:11:37 +000088 /*************************************************************************/
89 /* */
90 /* <Function> */
91 /* TT_Goto_Table */
92 /* */
93 /* <Description> */
94 /* Looks for a TrueType table by name, then seek a stream to it. */
95 /* */
96 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000097 /* face :: A face object handle. */
98 /* tag :: The searched tag. */
99 /* stream :: The stream to seek when the table is found. */
100 /* */
101 /* <Output> */
102 /* length :: The length of the table if found, undefined otherwise. */
David Turnerd2b1f351999-12-16 23:11:37 +0000103 /* */
104 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000105 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000106 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000107 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000108 TT_Goto_Table( TT_Face face,
109 FT_ULong tag,
110 FT_Stream stream,
111 FT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000112 {
David Turnerb5713c52002-03-14 11:26:29 +0000113 TT_Table table;
David Turnerf9b8dec2000-06-16 19:34:52 +0000114 FT_Error error;
David Turnere49ab252000-05-16 23:44:38 +0000115
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000116
David Turnerd2b1f351999-12-16 23:11:37 +0000117 table = TT_LookUp_Table( face, tag );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000118 if ( table )
David Turnerd2b1f351999-12-16 23:11:37 +0000119 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000120 if ( length )
David Turnerd2b1f351999-12-16 23:11:37 +0000121 *length = table->Length;
David Turnere49ab252000-05-16 23:44:38 +0000122
David Turner7d3a2642002-03-20 10:49:31 +0000123 if ( FT_STREAM_SEEK( table->Offset ) )
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000124 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000125 }
126 else
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000127 error = SFNT_Err_Table_Missing;
David Turnere49ab252000-05-16 23:44:38 +0000128
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000129 Exit:
David Turnerd2b1f351999-12-16 23:11:37 +0000130 return error;
131 }
132
133
134 /*************************************************************************/
135 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000136 /* <Function> */
David Turnerb5713c52002-03-14 11:26:29 +0000137 /* TT_Load_SFNT_HeaderRec */
David Turnerd2b1f351999-12-16 23:11:37 +0000138 /* */
139 /* <Description> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000140 /* Loads the header of a SFNT font file. Supports collections. */
David Turnerd2b1f351999-12-16 23:11:37 +0000141 /* */
142 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000143 /* face :: A handle to the target face object. */
144 /* stream :: The input stream. */
145 /* face_index :: If the font is a collection, the number of the font */
146 /* in the collection, ignored otherwise. */
David Turnerb1677a82000-05-29 20:37:41 +0000147 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000148 /* <Output> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000149 /* sfnt :: The SFNT header. */
David Turnerd2b1f351999-12-16 23:11:37 +0000150 /* */
151 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000152 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000153 /* */
154 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000155 /* The stream cursor must be at the font file's origin. */
David Turnerd2b1f351999-12-16 23:11:37 +0000156 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000157 /* This function recognizes fonts embedded in a `TrueType collection' */
158 /* */
159 /* The header will be checked whether it is valid by looking at the */
160 /* values of `search_range', `entry_selector', and `range_shift'. */
David Turnerb1677a82000-05-29 20:37:41 +0000161 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000162 FT_LOCAL_DEF( FT_Error )
David Turnerb5713c52002-03-14 11:26:29 +0000163 TT_Load_SFNT_HeaderRec( TT_Face face,
Werner Lemberg52005c32001-06-27 23:25:46 +0000164 FT_Stream stream,
165 FT_Long face_index,
David Turnerb5713c52002-03-14 11:26:29 +0000166 SFNT_Header sfnt )
David Turnerd2b1f351999-12-16 23:11:37 +0000167 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000168 FT_Error error;
169 FT_ULong format_tag;
Werner Lemberg7a4fda82000-06-13 23:21:00 +0000170 FT_Memory memory = stream->memory;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000171
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000172 const FT_Frame_Field sfnt_header_fields[] =
173 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000174#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000175#define FT_STRUCTURE SFNT_HeaderRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000176
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000177 FT_FRAME_START( 8 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000178 FT_FRAME_USHORT( num_tables ),
179 FT_FRAME_USHORT( search_range ),
180 FT_FRAME_USHORT( entry_selector ),
181 FT_FRAME_USHORT( range_shift ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000182 FT_FRAME_END
183 };
Werner Lemberg920d41e2000-06-05 14:32:32 +0000184
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000185 const FT_Frame_Field ttc_header_fields[] =
186 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000187#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000188#define FT_STRUCTURE TTC_HeaderRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000189
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000190 FT_FRAME_START( 8 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000191 FT_FRAME_LONG( version ),
192 FT_FRAME_LONG( count ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000193 FT_FRAME_END };
David Turnerd2b1f351999-12-16 23:11:37 +0000194
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000195
David Turnerb5713c52002-03-14 11:26:29 +0000196 FT_TRACE2(( "TT_Load_SFNT_HeaderRec: %08p, %ld\n",
David Turner3581d062000-06-01 03:26:58 +0000197 face, face_index ));
David Turnerd2b1f351999-12-16 23:11:37 +0000198
Werner Lemberge1bbc012000-07-19 06:25:56 +0000199 face->ttc_header.tag = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000200 face->ttc_header.version = 0;
Werner Lemberge1bbc012000-07-19 06:25:56 +0000201 face->ttc_header.count = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000202
203 face->num_tables = 0;
204
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000205 /* first of all, read the first 4 bytes. If it is `ttcf', then the */
206 /* file is a TrueType collection, otherwise it can be any other */
207 /* kind of font. */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000208 if ( READ_ULong( format_tag ) )
209 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000210
David Turnerb1677a82000-05-29 20:37:41 +0000211 if ( format_tag == TTAG_ttcf )
David Turnerd2b1f351999-12-16 23:11:37 +0000212 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000213 FT_Int n;
David Turnere49ab252000-05-16 23:44:38 +0000214
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000215
David Turnerb5713c52002-03-14 11:26:29 +0000216 FT_TRACE3(( "TT_Load_SFNT_HeaderRec: file is a collection\n" ));
David Turnere49ab252000-05-16 23:44:38 +0000217
David Turnerd2b1f351999-12-16 23:11:37 +0000218 /* it's a TrueType collection, i.e. a file containing several */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000219 /* font files. Read the font directory now */
David Turner7d3a2642002-03-20 10:49:31 +0000220 if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
David Turnera56489e2000-02-13 13:41:56 +0000221 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000222
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000223 /* now read the offsets of each font in the file */
Werner Lemberge1bbc012000-07-19 06:25:56 +0000224 if ( ALLOC_ARRAY( face->ttc_header.offsets,
225 face->ttc_header.count,
226 FT_ULong ) ||
David Turner7d3a2642002-03-20 10:49:31 +0000227 FT_FRAME_ENTER( face->ttc_header.count * 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000228 goto Exit;
229
Werner Lemberge1bbc012000-07-19 06:25:56 +0000230 for ( n = 0; n < face->ttc_header.count; n++ )
231 face->ttc_header.offsets[n] = GET_ULong();
David Turnerd2b1f351999-12-16 23:11:37 +0000232
David Turner7d3a2642002-03-20 10:49:31 +0000233 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000234
235 /* check face index */
Werner Lemberge1bbc012000-07-19 06:25:56 +0000236 if ( face_index >= face->ttc_header.count )
David Turnerd2b1f351999-12-16 23:11:37 +0000237 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000238 error = SFNT_Err_Bad_Argument;
David Turnerd2b1f351999-12-16 23:11:37 +0000239 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +0000240 }
241
David Turnerd2b1f351999-12-16 23:11:37 +0000242 /* seek to the appropriate TrueType file, then read tag */
David Turner7d3a2642002-03-20 10:49:31 +0000243 if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ||
Werner Lemberge1bbc012000-07-19 06:25:56 +0000244 READ_Long( format_tag ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000245 goto Exit;
246 }
David Turnerd2b1f351999-12-16 23:11:37 +0000247
David Turnerb1677a82000-05-29 20:37:41 +0000248 /* the format tag was read, now check the rest of the header */
249 sfnt->format_tag = format_tag;
David Turner7d3a2642002-03-20 10:49:31 +0000250 if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
David Turnerb1677a82000-05-29 20:37:41 +0000251 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000252
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000253 /* now, check the values of `num_tables', `seach_range', etc. */
David Turnerb1677a82000-05-29 20:37:41 +0000254 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000255 FT_UInt num_tables = sfnt->num_tables;
256 FT_ULong entry_selector = 1L << sfnt->entry_selector;
David Turner3581d062000-06-01 03:26:58 +0000257
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000258
259 /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
260 /* we only check the `entry_selector' correctness here. */
261 /* */
262 if ( num_tables == 0 ||
263 entry_selector > num_tables ||
264 entry_selector * 2 <= num_tables )
David Turner3581d062000-06-01 03:26:58 +0000265 {
David Turnerb5713c52002-03-14 11:26:29 +0000266 FT_TRACE2(( "TT_Load_SFNT_HeaderRec: file is not SFNT!\n" ));
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000267 error = SFNT_Err_Unknown_File_Format;
David Turnerb1677a82000-05-29 20:37:41 +0000268 }
269 }
270
David Turnerd42c68e2000-01-27 13:56:02 +0000271 Exit:
272 return error;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000273 }
David Turnerb1677a82000-05-29 20:37:41 +0000274
David Turnerd2b1f351999-12-16 23:11:37 +0000275
David Turnerd42c68e2000-01-27 13:56:02 +0000276 /*************************************************************************/
277 /* */
278 /* <Function> */
279 /* TT_Load_Directory */
280 /* */
281 /* <Description> */
282 /* Loads the table directory into a face object. */
283 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000284 /* <InOut> */
285 /* face :: A handle to the target face object. */
286 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000287 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000288 /* stream :: The input stream. */
289 /* sfnt :: The SFNT directory header. */
David Turnerd42c68e2000-01-27 13:56:02 +0000290 /* */
291 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000292 /* FreeType error code. 0 means success. */
David Turnerd42c68e2000-01-27 13:56:02 +0000293 /* */
294 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000295 /* The stream cursor must be at the font file's origin. */
David Turnerd42c68e2000-01-27 13:56:02 +0000296 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000297 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000298 TT_Load_Directory( TT_Face face,
299 FT_Stream stream,
David Turnerb5713c52002-03-14 11:26:29 +0000300 SFNT_Header sfnt )
David Turnerd42c68e2000-01-27 13:56:02 +0000301 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000302 FT_Error error;
David Turnerd42c68e2000-01-27 13:56:02 +0000303 FT_Memory memory = stream->memory;
David Turnerd42c68e2000-01-27 13:56:02 +0000304
David Turnerb5713c52002-03-14 11:26:29 +0000305 TT_TableRec *entry, *limit;
David Turnerd42c68e2000-01-27 13:56:02 +0000306
David Turnerd42c68e2000-01-27 13:56:02 +0000307
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000308 FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
309
310 FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
311 FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
David Turnerd42c68e2000-01-27 13:56:02 +0000312
David Turnerb1677a82000-05-29 20:37:41 +0000313 face->num_tables = sfnt->num_tables;
David Turnerd2b1f351999-12-16 23:11:37 +0000314
315 if ( ALLOC_ARRAY( face->dir_tables,
316 face->num_tables,
David Turnerb5713c52002-03-14 11:26:29 +0000317 TT_TableRec ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000318 goto Exit;
319
David Turner7d3a2642002-03-20 10:49:31 +0000320 if ( FT_FRAME_ENTER( face->num_tables * 16L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000321 goto Exit;
322
323 entry = face->dir_tables;
324 limit = entry + face->num_tables;
325
326 for ( ; entry < limit; entry++ )
David Turnerd42c68e2000-01-27 13:56:02 +0000327 { /* loop through the tables and get all entries */
David Turnerd2b1f351999-12-16 23:11:37 +0000328 entry->Tag = GET_Tag4();
329 entry->CheckSum = GET_ULong();
330 entry->Offset = GET_Long();
331 entry->Length = GET_Long();
332
333 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
David Turnerf9b8dec2000-06-16 19:34:52 +0000334 (FT_Char)( entry->Tag >> 24 ),
335 (FT_Char)( entry->Tag >> 16 ),
336 (FT_Char)( entry->Tag >> 8 ),
337 (FT_Char)( entry->Tag ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000338 entry->Offset,
339 entry->Length ));
David Turnerd2b1f351999-12-16 23:11:37 +0000340 }
341
David Turner7d3a2642002-03-20 10:49:31 +0000342 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000343
344 FT_TRACE2(( "Directory loaded\n\n" ));
345
346 Exit:
347 return error;
348 }
349
350
351 /*************************************************************************/
352 /* */
353 /* <Function> */
354 /* TT_Load_Any */
355 /* */
356 /* <Description> */
Werner Lembergc8f9cf32000-07-19 02:59:31 +0000357 /* Loads any font table into client memory. */
David Turnerd2b1f351999-12-16 23:11:37 +0000358 /* */
359 /* <Input> */
360 /* face :: The face object to look for. */
361 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000362 /* tag :: The tag of table to load. Use the value 0 if you want */
David Turnerd2b1f351999-12-16 23:11:37 +0000363 /* to access the whole font file, else set this parameter */
364 /* to a valid TrueType table tag that you can forge with */
365 /* the MAKE_TT_TAG macro. */
366 /* */
367 /* offset :: The starting offset in the table (or the file if */
368 /* tag == 0). */
369 /* */
370 /* length :: The address of the decision variable: */
371 /* */
372 /* If length == NULL: */
373 /* Loads the whole table. Returns an error if */
374 /* `offset' == 0! */
375 /* */
376 /* If *length == 0: */
377 /* Exits immediately; returning the length of the given */
378 /* table or of the font file, depending on the value of */
379 /* `tag'. */
380 /* */
381 /* If *length != 0: */
382 /* Loads the next `length' bytes of table or font, */
383 /* starting at offset `offset' (in table or font too). */
384 /* */
385 /* <Output> */
386 /* buffer :: The address of target buffer. */
387 /* */
388 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000389 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000390 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000391 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000392 TT_Load_Any( TT_Face face,
393 FT_ULong tag,
394 FT_Long offset,
395 FT_Byte* buffer,
396 FT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000397 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000398 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000399 FT_Stream stream;
David Turnerb5713c52002-03-14 11:26:29 +0000400 TT_Table table;
David Turnerf9b8dec2000-06-16 19:34:52 +0000401 FT_ULong size;
David Turnerd2b1f351999-12-16 23:11:37 +0000402
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000403
David Turnerd2b1f351999-12-16 23:11:37 +0000404 if ( tag != 0 )
405 {
406 /* look for tag in font directory */
407 table = TT_LookUp_Table( face, tag );
408 if ( !table )
409 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000410 error = SFNT_Err_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000411 goto Exit;
412 }
413
414 offset += table->Offset;
415 size = table->Length;
416 }
417 else
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000418 /* tag == 0 -- the user wants to access the font file directly */
David Turnerd2b1f351999-12-16 23:11:37 +0000419 size = face->root.stream->size;
David Turnerd2b1f351999-12-16 23:11:37 +0000420
421 if ( length && *length == 0 )
422 {
423 *length = size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000424
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000425 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000426 }
427
428 if ( length )
429 size = *length;
430
431 stream = face->root.stream;
Werner Lembergb1dd3532000-07-31 22:51:00 +0000432 /* the `if' is syntactic sugar for picky compilers */
David Turner7d3a2642002-03-20 10:49:31 +0000433 if ( FT_STREAM_READ_AT( offset, buffer, size ) )
David Turner24d70242000-08-17 01:09:06 +0000434 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000435
436 Exit:
437 return error;
438 }
439
440
441 /*************************************************************************/
442 /* */
443 /* <Function> */
Tom Kacvinsky200a1a42000-11-13 07:31:21 +0000444 /* TT_Load_Generic_Header */
David Turnerd2b1f351999-12-16 23:11:37 +0000445 /* */
446 /* <Description> */
Tom Kacvinsky200a1a42000-11-13 07:31:21 +0000447 /* Loads the TrueType table `head' or `bhed'. */
David Turnerd2b1f351999-12-16 23:11:37 +0000448 /* */
449 /* <Input> */
450 /* face :: A handle to the target face object. */
451 /* stream :: The input stream. */
452 /* */
453 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000454 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000455 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000456 static FT_Error
457 TT_Load_Generic_Header( TT_Face face,
458 FT_Stream stream,
459 FT_ULong tag )
David Turnerd2b1f351999-12-16 23:11:37 +0000460 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000461 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000462 TT_Header* header;
David Turnerb1677a82000-05-29 20:37:41 +0000463
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000464 static const FT_Frame_Field header_fields[] =
465 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000466#undef FT_STRUCTURE
467#define FT_STRUCTURE TT_Header
468
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000469 FT_FRAME_START( 54 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000470 FT_FRAME_ULONG ( Table_Version ),
471 FT_FRAME_ULONG ( Font_Revision ),
472 FT_FRAME_LONG ( CheckSum_Adjust ),
473 FT_FRAME_LONG ( Magic_Number ),
474 FT_FRAME_USHORT( Flags ),
475 FT_FRAME_USHORT( Units_Per_EM ),
476 FT_FRAME_LONG ( Created[0] ),
477 FT_FRAME_LONG ( Created[1] ),
478 FT_FRAME_LONG ( Modified[0] ),
479 FT_FRAME_LONG ( Modified[1] ),
480 FT_FRAME_SHORT ( xMin ),
481 FT_FRAME_SHORT ( yMin ),
482 FT_FRAME_SHORT ( xMax ),
483 FT_FRAME_SHORT ( yMax ),
484 FT_FRAME_USHORT( Mac_Style ),
485 FT_FRAME_USHORT( Lowest_Rec_PPEM ),
486 FT_FRAME_SHORT ( Font_Direction ),
487 FT_FRAME_SHORT ( Index_To_Loc_Format ),
488 FT_FRAME_SHORT ( Glyph_Data_Format ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000489 FT_FRAME_END
490 };
David Turnerd2b1f351999-12-16 23:11:37 +0000491
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000492
Werner Lemberg34e52702000-11-13 16:58:01 +0000493 FT_TRACE2(( "TT_Load_Generic_Header: "
494 "%08p, looking up font table `%c%c%c%c'.\n",
495 face,
496 (FT_Char)( tag >> 24 ),
497 (FT_Char)( tag >> 16 ),
498 (FT_Char)( tag >> 8 ),
499 (FT_Char)( tag ) ));
David Turnerd2b1f351999-12-16 23:11:37 +0000500
David Turnerf96594f2000-11-06 23:07:51 +0000501 error = face->goto_table( face, tag, stream, 0 );
David Turnerd2b1f351999-12-16 23:11:37 +0000502 if ( error )
503 {
Werner Lemberg04bfe312001-12-11 14:09:06 +0000504 FT_TRACE2(( "TT_Load_Generic_Header: Font table is missing!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000505 goto Exit;
506 }
507
David Turnera56489e2000-02-13 13:41:56 +0000508 header = &face->header;
509
David Turner7d3a2642002-03-20 10:49:31 +0000510 if ( FT_STREAM_READ_FIELDS( header_fields, header ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000511 goto Exit;
512
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000513 FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
514 FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
Werner Lemberg04bfe312001-12-11 14:09:06 +0000515 FT_TRACE2(( "TT_Load_Generic_Header: Font table loaded.\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000516
517 Exit:
518 return error;
519 }
520
Werner Lemberg4b680072000-11-07 06:30:29 +0000521
David Turnerbc82f1b2002-03-01 02:26:22 +0000522 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000523 TT_Load_Header( TT_Face face,
524 FT_Stream stream )
David Turnerf96594f2000-11-06 23:07:51 +0000525 {
526 return TT_Load_Generic_Header( face, stream, TTAG_head );
527 }
528
Werner Lemberg4b680072000-11-07 06:30:29 +0000529
David Turnerf96594f2000-11-06 23:07:51 +0000530#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
Werner Lemberg4b680072000-11-07 06:30:29 +0000531
David Turnerbc82f1b2002-03-01 02:26:22 +0000532 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000533 TT_Load_Bitmap_Header( TT_Face face,
534 FT_Stream stream )
David Turnerf96594f2000-11-06 23:07:51 +0000535 {
536 return TT_Load_Generic_Header( face, stream, TTAG_bhed );
537 }
Werner Lemberg4b680072000-11-07 06:30:29 +0000538
539#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
540
David Turnerd2b1f351999-12-16 23:11:37 +0000541
542 /*************************************************************************/
543 /* */
544 /* <Function> */
545 /* TT_Load_MaxProfile */
546 /* */
547 /* <Description> */
548 /* Loads the maximum profile into a face object. */
549 /* */
550 /* <Input> */
551 /* face :: A handle to the target face object. */
552 /* stream :: The input stream. */
553 /* */
554 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000555 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000556 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000557 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000558 TT_Load_MaxProfile( TT_Face face,
559 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000560 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000561 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000562 TT_MaxProfile* maxProfile = &face->max_profile;
David Turnerb1677a82000-05-29 20:37:41 +0000563
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000564 const FT_Frame_Field maxp_fields[] =
565 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000566#undef FT_STRUCTURE
567#define FT_STRUCTURE TT_MaxProfile
568
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000569 FT_FRAME_START( 6 ),
570 FT_FRAME_LONG ( version ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000571 FT_FRAME_USHORT( numGlyphs ),
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000572 FT_FRAME_END
573 };
574
575 const FT_Frame_Field maxp_fields_extra[] =
576 {
577 FT_FRAME_START( 26 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000578 FT_FRAME_USHORT( maxPoints ),
579 FT_FRAME_USHORT( maxContours ),
580 FT_FRAME_USHORT( maxCompositePoints ),
581 FT_FRAME_USHORT( maxCompositeContours ),
582 FT_FRAME_USHORT( maxZones ),
583 FT_FRAME_USHORT( maxTwilightPoints ),
584 FT_FRAME_USHORT( maxStorage ),
585 FT_FRAME_USHORT( maxFunctionDefs ),
586 FT_FRAME_USHORT( maxInstructionDefs ),
587 FT_FRAME_USHORT( maxStackElements ),
588 FT_FRAME_USHORT( maxSizeOfInstructions ),
589 FT_FRAME_USHORT( maxComponentElements ),
590 FT_FRAME_USHORT( maxComponentDepth ),
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000591 FT_FRAME_END
592 };
David Turnerd2b1f351999-12-16 23:11:37 +0000593
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000594
595 FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000596
597 error = face->goto_table( face, TTAG_maxp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000598 if ( error )
599 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000600
David Turner7d3a2642002-03-20 10:49:31 +0000601 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000602 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000603
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000604 maxProfile->maxPoints = 0;
605 maxProfile->maxContours = 0;
606 maxProfile->maxCompositePoints = 0;
607 maxProfile->maxCompositeContours = 0;
608 maxProfile->maxZones = 0;
609 maxProfile->maxTwilightPoints = 0;
610 maxProfile->maxStorage = 0;
611 maxProfile->maxFunctionDefs = 0;
612 maxProfile->maxInstructionDefs = 0;
613 maxProfile->maxStackElements = 0;
614 maxProfile->maxSizeOfInstructions = 0;
615 maxProfile->maxComponentElements = 0;
616 maxProfile->maxComponentDepth = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000617
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000618 if ( maxProfile->version >= 0x10000L )
619 {
David Turner7d3a2642002-03-20 10:49:31 +0000620 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) )
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000621 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000622
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000623 /* XXX: an adjustment that is necessary to load certain */
624 /* broken fonts like `Keystrokes MT' :-( */
625 /* */
626 /* We allocate 64 function entries by default when */
627 /* the maxFunctionDefs field is null. */
David Turnerd2b1f351999-12-16 23:11:37 +0000628
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000629 if ( maxProfile->maxFunctionDefs == 0 )
630 maxProfile->maxFunctionDefs = 64;
David Turnerd2b1f351999-12-16 23:11:37 +0000631
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000632 face->root.num_glyphs = maxProfile->numGlyphs;
David Turnerd2b1f351999-12-16 23:11:37 +0000633
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000634 face->root.internal->max_points =
635 (FT_UShort)MAX( maxProfile->maxCompositePoints,
636 maxProfile->maxPoints );
David Turnerd2b1f351999-12-16 23:11:37 +0000637
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000638 face->root.internal->max_contours =
639 (FT_Short)MAX( maxProfile->maxCompositeContours,
640 maxProfile->maxContours );
David Turnerd2b1f351999-12-16 23:11:37 +0000641
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000642 face->max_components = (FT_ULong)maxProfile->maxComponentElements +
643 maxProfile->maxComponentDepth;
644
645 /* XXX: some fonts have maxComponents set to 0; we will */
646 /* then use 16 of them by default. */
647 if ( face->max_components == 0 )
648 face->max_components = 16;
649
650 /* We also increase maxPoints and maxContours in order to support */
651 /* some broken fonts. */
Werner Lemberg3975e2e2002-01-09 21:01:18 +0000652 face->root.internal->max_points += (FT_UShort)8;
653 face->root.internal->max_contours += (FT_Short) 4;
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000654 }
David Turnerd2b1f351999-12-16 23:11:37 +0000655
656 FT_TRACE2(( "MAXP loaded.\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000657
David Turnerd2b1f351999-12-16 23:11:37 +0000658 Exit:
659 return error;
660 }
661
662
663 /*************************************************************************/
664 /* */
665 /* <Function> */
666 /* TT_Load_Metrics */
667 /* */
668 /* <Description> */
669 /* Loads the horizontal or vertical metrics table into a face object. */
670 /* */
671 /* <Input> */
672 /* face :: A handle to the target face object. */
673 /* stream :: The input stream. */
674 /* vertical :: A boolean flag. If set, load vertical metrics. */
675 /* */
676 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000677 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000678 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000679 static FT_Error
680 TT_Load_Metrics( TT_Face face,
681 FT_Stream stream,
682 FT_Bool vertical )
David Turnerd2b1f351999-12-16 23:11:37 +0000683 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000684 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000685 FT_Memory memory = stream->memory;
686
David Turnerf9b8dec2000-06-16 19:34:52 +0000687 FT_ULong table_len;
688 FT_Long num_shorts, num_longs, num_shorts_checked;
David Turnerd2b1f351999-12-16 23:11:37 +0000689
David Turnerb5713c52002-03-14 11:26:29 +0000690 TT_LongMetrics * longs;
David Turnerd2b1f351999-12-16 23:11:37 +0000691 TT_ShortMetrics** shorts;
692
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000693
694 FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
695 : "Horizontal",
696 face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000697
698 if ( vertical )
699 {
700 /* The table is optional, quit silently if it wasn't found */
701 /* XXX: Some fonts have a valid vertical header with a non-null */
702 /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
703 /* table to get the metrics from (e.g. mingliu). */
704 /* */
705 /* For safety, we set the field to 0! */
706 /* */
707 error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
708 if ( error )
709 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000710 /* Set number_Of_VMetrics to 0! */
David Turnerd2b1f351999-12-16 23:11:37 +0000711 FT_TRACE2(( " no vertical header in file.\n" ));
712 face->vertical.number_Of_VMetrics = 0;
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000713 error = SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000714 goto Exit;
715 }
716
717 num_longs = face->vertical.number_Of_VMetrics;
David Turnerb5713c52002-03-14 11:26:29 +0000718 longs = (TT_LongMetrics *)&face->vertical.long_metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000719 shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
720 }
721 else
722 {
723 error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000724 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000725 {
726 FT_ERROR(( " no horizontal metrics in file!\n" ));
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000727 error = SFNT_Err_Hmtx_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000728 goto Exit;
729 }
730
731 num_longs = face->horizontal.number_Of_HMetrics;
David Turnerb5713c52002-03-14 11:26:29 +0000732 longs = (TT_LongMetrics *)&face->horizontal.long_metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000733 shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
734 }
735
736 /* never trust derived values */
737
738 num_shorts = face->max_profile.numGlyphs - num_longs;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000739 num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000740
741 if ( num_shorts < 0 )
742 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000743 FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
744 vertical ? "Vertical"
745 : "Horizontal" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000746
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000747 error = vertical ? SFNT_Err_Invalid_Vert_Metrics
748 : SFNT_Err_Invalid_Horiz_Metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000749 goto Exit;
750 }
751
David Turnerb5713c52002-03-14 11:26:29 +0000752 if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetricsRec ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000753 ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
754 goto Exit;
755
David Turner7d3a2642002-03-20 10:49:31 +0000756 if ( FT_FRAME_ENTER( table_len ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000757 goto Exit;
758
759 {
David Turnerb5713c52002-03-14 11:26:29 +0000760 TT_LongMetrics cur = *longs;
761 TT_LongMetrics limit = cur + num_longs;
David Turnerd2b1f351999-12-16 23:11:37 +0000762
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000763
David Turnerd2b1f351999-12-16 23:11:37 +0000764 for ( ; cur < limit; cur++ )
765 {
766 cur->advance = GET_UShort();
767 cur->bearing = GET_Short();
768 }
769 }
770
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000771 /* do we have an inconsistent number of metric values? */
David Turnerd2b1f351999-12-16 23:11:37 +0000772 {
773 TT_ShortMetrics* cur = *shorts;
774 TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
775
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000776
David Turnerd2b1f351999-12-16 23:11:37 +0000777 for ( ; cur < limit; cur++ )
778 *cur = GET_Short();
779
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000780 /* we fill up the missing left side bearings with the */
781 /* last valid value. Since this will occur for buggy CJK */
782 /* fonts usually only, nothing serious will happen */
David Turnerd2b1f351999-12-16 23:11:37 +0000783 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
784 {
Tom Kacvinsky4a1bc8f2001-04-02 17:47:16 +0000785 FT_Short val = (*shorts)[num_shorts_checked - 1];
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000786
David Turnerd2b1f351999-12-16 23:11:37 +0000787
788 limit = *shorts + num_shorts;
789 for ( ; cur < limit; cur++ )
790 *cur = val;
791 }
792 }
793
David Turner7d3a2642002-03-20 10:49:31 +0000794 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000795
796 FT_TRACE2(( "loaded\n" ));
797
798 Exit:
799 return error;
800 }
801
802
803 /*************************************************************************/
804 /* */
805 /* <Function> */
806 /* TT_Load_Metrics_Header */
807 /* */
808 /* <Description> */
809 /* Loads the horizontal or vertical header in a face object. */
810 /* */
811 /* <Input> */
812 /* face :: A handle to the target face object. */
813 /* stream :: The input stream. */
814 /* vertical :: A boolean flag. If set, load vertical metrics. */
815 /* */
816 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000817 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000818 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000819 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000820 TT_Load_Metrics_Header( TT_Face face,
821 FT_Stream stream,
822 FT_Bool vertical )
David Turnerd2b1f351999-12-16 23:11:37 +0000823 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000824 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000825 TT_HoriHeader* header;
David Turnerb1677a82000-05-29 20:37:41 +0000826
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000827 const FT_Frame_Field metrics_header_fields[] =
828 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000829#undef FT_STRUCTURE
830#define FT_STRUCTURE TT_HoriHeader
831
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000832 FT_FRAME_START( 36 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000833 FT_FRAME_ULONG ( Version ),
834 FT_FRAME_SHORT ( Ascender ),
835 FT_FRAME_SHORT ( Descender ),
836 FT_FRAME_SHORT ( Line_Gap ),
837 FT_FRAME_USHORT( advance_Width_Max ),
838 FT_FRAME_SHORT ( min_Left_Side_Bearing ),
839 FT_FRAME_SHORT ( min_Right_Side_Bearing ),
840 FT_FRAME_SHORT ( xMax_Extent ),
841 FT_FRAME_SHORT ( caret_Slope_Rise ),
842 FT_FRAME_SHORT ( caret_Slope_Run ),
Werner Lemberg5dea4442001-08-13 11:44:29 +0000843 FT_FRAME_SHORT ( caret_Offset ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000844 FT_FRAME_SHORT ( Reserved[0] ),
845 FT_FRAME_SHORT ( Reserved[1] ),
846 FT_FRAME_SHORT ( Reserved[2] ),
847 FT_FRAME_SHORT ( Reserved[3] ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000848 FT_FRAME_SHORT ( metric_Data_Format ),
849 FT_FRAME_USHORT( number_Of_HMetrics ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000850 FT_FRAME_END
851 };
852
David Turnerb1677a82000-05-29 20:37:41 +0000853
David Turnerd2b1f351999-12-16 23:11:37 +0000854 FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
855
856 if ( vertical )
857 {
858 face->vertical_info = 0;
859
860 /* The vertical header table is optional, so return quietly if */
861 /* we don't find it. */
862 error = face->goto_table( face, TTAG_vhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000863 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000864 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000865 error = SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000866 goto Exit;
867 }
868
869 face->vertical_info = 1;
870 header = (TT_HoriHeader*)&face->vertical;
871 }
872 else
873 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000874 /* The horizontal header is mandatory; return an error if we */
David Turnerd2b1f351999-12-16 23:11:37 +0000875 /* don't find it. */
876 error = face->goto_table( face, TTAG_hhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000877 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000878 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000879 error = SFNT_Err_Horiz_Header_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000880 goto Exit;
881 }
882
883 header = &face->horizontal;
884 }
885
David Turner7d3a2642002-03-20 10:49:31 +0000886 if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000887 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000888
889 header->long_metrics = NULL;
890 header->short_metrics = NULL;
891
892 FT_TRACE2(( "loaded\n" ));
893
894 /* Now try to load the corresponding metrics */
895
896 error = TT_Load_Metrics( face, stream, vertical );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000897
David Turnerd2b1f351999-12-16 23:11:37 +0000898 Exit:
899 return error;
900 }
901
902
903 /*************************************************************************/
904 /* */
905 /* <Function> */
906 /* TT_Load_Names */
907 /* */
908 /* <Description> */
909 /* Loads the name records. */
910 /* */
911 /* <Input> */
912 /* face :: A handle to the target face object. */
913 /* stream :: The input stream. */
914 /* */
915 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000916 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000917 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000918 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000919 TT_Load_Names( TT_Face face,
920 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000921 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000922 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000923 FT_Memory memory = stream->memory;
924
David Turnerf9b8dec2000-06-16 19:34:52 +0000925 FT_ULong table_pos, table_len;
David Turnerc03d9cf2002-02-27 23:10:19 +0000926 FT_ULong storageOffset, storageSize;
927 FT_Byte* storage;
David Turnerd2b1f351999-12-16 23:11:37 +0000928
David Turnerb5713c52002-03-14 11:26:29 +0000929 TT_NameTable names;
David Turnerb1677a82000-05-29 20:37:41 +0000930
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000931 const FT_Frame_Field name_table_fields[] =
932 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000933#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000934#define FT_STRUCTURE TT_NameTableRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000935
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000936 FT_FRAME_START( 6 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000937 FT_FRAME_USHORT( format ),
938 FT_FRAME_USHORT( numNameRecords ),
939 FT_FRAME_USHORT( storageOffset ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000940 FT_FRAME_END
941 };
David Turnera56489e2000-02-13 13:41:56 +0000942
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000943 const FT_Frame_Field name_record_fields[] =
944 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000945#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000946#define FT_STRUCTURE TT_NameEntryRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000947
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000948 /* no FT_FRAME_START */
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000949 FT_FRAME_USHORT( platformID ),
950 FT_FRAME_USHORT( encodingID ),
951 FT_FRAME_USHORT( languageID ),
952 FT_FRAME_USHORT( nameID ),
953 FT_FRAME_USHORT( stringLength ),
954 FT_FRAME_USHORT( stringOffset ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000955 FT_FRAME_END
956 };
David Turnerd2b1f351999-12-16 23:11:37 +0000957
958
959 FT_TRACE2(( "Names " ));
960
961 error = face->goto_table( face, TTAG_name, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000962 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000963 {
964 /* The name table is required so indicate failure. */
965 FT_TRACE2(( "is missing!\n" ));
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000966 error = SFNT_Err_Name_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000967 goto Exit;
968 }
969
David Turner7d3a2642002-03-20 10:49:31 +0000970 table_pos = FT_STREAM_POS();
David Turnerd2b1f351999-12-16 23:11:37 +0000971
David Turnera56489e2000-02-13 13:41:56 +0000972 names = &face->name_table;
973
David Turner7d3a2642002-03-20 10:49:31 +0000974 if ( FT_STREAM_READ_FIELDS( name_table_fields, names ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000975 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000976
David Turnerc03d9cf2002-02-27 23:10:19 +0000977 /* check the 'storageOffset' field */
978 storageOffset = names->storageOffset;
979 if ( storageOffset < (FT_ULong)(6 + 12*names->numNameRecords) ||
980 table_len <= storageOffset )
981 {
982 FT_ERROR(( "TT.load_names: invalid 'name' table\n" ));
983 error = SFNT_Err_Name_Table_Missing;
984 goto Exit;
985 }
986
987 storageSize = (FT_ULong)(table_len - storageOffset);
988
David Turnerd2b1f351999-12-16 23:11:37 +0000989 /* Allocate the array of name records. */
David Turnerc03d9cf2002-02-27 23:10:19 +0000990 if ( ALLOC( names->names,
David Turnerb5713c52002-03-14 11:26:29 +0000991 names->numNameRecords*sizeof(TT_NameEntryRec) + storageSize ) ||
David Turner7d3a2642002-03-20 10:49:31 +0000992 FT_FRAME_ENTER( names->numNameRecords * 12L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000993 goto Exit;
994
David Turnerc03d9cf2002-02-27 23:10:19 +0000995 storage = (FT_Byte*)(names->names + names->numNameRecords);
996
David Turnerd2b1f351999-12-16 23:11:37 +0000997 /* Load the name records and determine how much storage is needed */
998 /* to hold the strings themselves. */
999 {
David Turnerb5713c52002-03-14 11:26:29 +00001000 TT_NameEntryRec* cur = names->names;
1001 TT_NameEntryRec* limit = cur + names->numNameRecords;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001002
David Turnerd2b1f351999-12-16 23:11:37 +00001003
David Turnerd2b1f351999-12-16 23:11:37 +00001004 for ( ; cur < limit; cur ++ )
1005 {
David Turner7d3a2642002-03-20 10:49:31 +00001006 if ( FT_STREAM_READ_FIELDS( name_record_fields, cur ) )
Werner Lembergb1dd3532000-07-31 22:51:00 +00001007 break;
David Turnerb1677a82000-05-29 20:37:41 +00001008
David Turnerc03d9cf2002-02-27 23:10:19 +00001009 /* invalid name entries will have "cur->string" set to NULL !! */
1010 if ( (FT_ULong)(cur->stringOffset + cur->stringLength) < storageSize )
1011 cur->string = storage + cur->stringOffset;
David Turner28ea6f62002-03-05 16:12:57 +00001012 else
1013 {
1014 /* that's an invalid entry */
1015 cur->stringOffset = 0;
1016 cur->string = NULL;
1017 }
David Turnerd2b1f351999-12-16 23:11:37 +00001018 }
1019 }
1020
David Turner7d3a2642002-03-20 10:49:31 +00001021 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001022
David Turnerc03d9cf2002-02-27 23:10:19 +00001023 if (error)
1024 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001025
David Turner28ea6f62002-03-05 16:12:57 +00001026 storageOffset -= 6 + 12*names->numNameRecords;
David Turner7d3a2642002-03-20 10:49:31 +00001027 if ( FT_STREAM_SKIP( storageOffset ) ||
1028 FT_STREAM_READ( storage, storageSize ) )
David Turner28ea6f62002-03-05 16:12:57 +00001029 goto Exit;
1030
1031
David Turnere49ab252000-05-16 23:44:38 +00001032#ifdef FT_DEBUG_LEVEL_TRACE
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001033
David Turnerd2b1f351999-12-16 23:11:37 +00001034 /* Print Name Record Table in case of debugging */
1035 {
David Turnerb5713c52002-03-14 11:26:29 +00001036 TT_NameEntryRec* cur = names->names;
1037 TT_NameEntryRec* limit = cur + names->numNameRecords;
David Turnerd2b1f351999-12-16 23:11:37 +00001038
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001039
David Turnerd2b1f351999-12-16 23:11:37 +00001040 for ( ; cur < limit; cur++ )
1041 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001042 FT_UInt j;
David Turnere49ab252000-05-16 23:44:38 +00001043
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001044
David Turnerc03d9cf2002-02-27 23:10:19 +00001045 FT_TRACE3(( "(%2d %2d %4x %2d) ",
David Turnerd2b1f351999-12-16 23:11:37 +00001046 cur->platformID,
1047 cur->encodingID,
1048 cur->languageID,
1049 cur->nameID ));
David Turnere49ab252000-05-16 23:44:38 +00001050
David Turnerd2b1f351999-12-16 23:11:37 +00001051 /* I know that M$ encoded strings are Unicode, */
1052 /* but this works reasonable well for debugging purposes. */
1053 if ( cur->string )
David Turnerd3c8e062000-12-04 22:53:55 +00001054 for ( j = 0; j < (FT_UInt)cur->stringLength; j++ )
David Turnerd2b1f351999-12-16 23:11:37 +00001055 {
David Turnerc03d9cf2002-02-27 23:10:19 +00001056 FT_Byte c = *(FT_Byte*)(cur->string + j);
David Turnere49ab252000-05-16 23:44:38 +00001057
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001058
David Turnerc03d9cf2002-02-27 23:10:19 +00001059 if ( c >= 32 && c < 128 )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001060 FT_TRACE3(( "%c", c ));
David Turnerd2b1f351999-12-16 23:11:37 +00001061 }
David Turnerc03d9cf2002-02-27 23:10:19 +00001062 else
1063 FT_TRACE3(( "INVALID ENTRY !!\n" ));
1064
1065 FT_TRACE3(( "\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +00001066 }
1067 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001068
1069#endif /* FT_DEBUG_LEVEL_TRACE */
1070
David Turnerd2b1f351999-12-16 23:11:37 +00001071 FT_TRACE2(( "loaded\n" ));
1072
David Turner49bd4f02000-07-12 16:57:37 +00001073 /* everything went well, update face->num_names */
1074 face->num_names = names->numNameRecords;
1075
David Turnerd2b1f351999-12-16 23:11:37 +00001076 Exit:
1077 return error;
1078 }
1079
1080
1081 /*************************************************************************/
1082 /* */
1083 /* <Function> */
1084 /* TT_Free_Names */
1085 /* */
1086 /* <Description> */
1087 /* Frees the name records. */
1088 /* */
1089 /* <Input> */
1090 /* face :: A handle to the target face object. */
1091 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001092 FT_LOCAL_DEF( void )
Werner Lemberg52005c32001-06-27 23:25:46 +00001093 TT_Free_Names( TT_Face face )
David Turnerd2b1f351999-12-16 23:11:37 +00001094 {
David Turnerf0df85b2000-06-22 00:17:42 +00001095 FT_Memory memory = face->root.driver->root.memory;
David Turnerb5713c52002-03-14 11:26:29 +00001096 TT_NameTable names = &face->name_table;
David Turnerd2b1f351999-12-16 23:11:37 +00001097
1098
1099 /* free strings table */
1100 FREE( names->names );
1101
1102 /* free strings storage */
1103 FREE( names->storage );
1104
1105 names->numNameRecords = 0;
1106 names->format = 0;
1107 names->storageOffset = 0;
1108 }
1109
1110
1111 /*************************************************************************/
1112 /* */
1113 /* <Function> */
1114 /* TT_Load_CMap */
1115 /* */
1116 /* <Description> */
1117 /* Loads the cmap directory in a face object. The cmaps itselves are */
1118 /* loaded on demand in the `ttcmap.c' module. */
1119 /* */
1120 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001121 /* face :: A handle to the target face object. */
1122 /* stream :: A handle to the input stream. */
David Turnerd2b1f351999-12-16 23:11:37 +00001123 /* */
1124 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001125 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001126 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001127 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001128 TT_Load_CMap( TT_Face face,
1129 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001130 {
David Turnerb5713c52002-03-14 11:26:29 +00001131 FT_Error error;
1132 FT_Memory memory = stream->memory;
1133 FT_Long table_start;
1134 TT_CMapDirRec cmap_dir;
David Turnerd2b1f351999-12-16 23:11:37 +00001135
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001136 const FT_Frame_Field cmap_fields[] =
1137 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001138#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +00001139#define FT_STRUCTURE TT_CMapDirRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001140
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001141 FT_FRAME_START( 4 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001142 FT_FRAME_USHORT( tableVersionNumber ),
1143 FT_FRAME_USHORT( numCMaps ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001144 FT_FRAME_END
1145 };
David Turnera56489e2000-02-13 13:41:56 +00001146
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001147 const FT_Frame_Field cmap_rec_fields[] =
1148 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001149#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +00001150#define FT_STRUCTURE TT_CMapTableRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001151
Werner Lembergbcf8d4b2001-08-24 23:11:34 +00001152 FT_FRAME_START( 4 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001153 FT_FRAME_USHORT( format ),
1154 FT_FRAME_USHORT( length ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001155 FT_FRAME_END
1156 };
1157
David Turnera56489e2000-02-13 13:41:56 +00001158
David Turnerd2b1f351999-12-16 23:11:37 +00001159 FT_TRACE2(( "CMaps " ));
1160
1161 error = face->goto_table( face, TTAG_cmap, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001162 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001163 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001164 error = SFNT_Err_CMap_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +00001165 goto Exit;
1166 }
1167
David Turner7d3a2642002-03-20 10:49:31 +00001168 table_start = FT_STREAM_POS();
David Turnerd2b1f351999-12-16 23:11:37 +00001169
David Turner7d3a2642002-03-20 10:49:31 +00001170 if ( FT_STREAM_READ_FIELDS( cmap_fields, &cmap_dir ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001171 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001172
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001173 /* reserve space in face table for cmap tables */
David Turnerd2b1f351999-12-16 23:11:37 +00001174 if ( ALLOC_ARRAY( face->charmaps,
1175 cmap_dir.numCMaps,
1176 TT_CharMapRec ) )
1177 goto Exit;
1178
1179 face->num_charmaps = cmap_dir.numCMaps;
1180 {
1181 TT_CharMap charmap = face->charmaps;
1182 TT_CharMap limit = charmap + face->num_charmaps;
1183
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001184
David Turnera56489e2000-02-13 13:41:56 +00001185 /* read the header of each charmap first */
David Turner7d3a2642002-03-20 10:49:31 +00001186 if ( FT_FRAME_ENTER( face->num_charmaps * 8L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001187 goto Exit;
1188
David Turnerd2b1f351999-12-16 23:11:37 +00001189 for ( ; charmap < limit; charmap++ )
1190 {
David Turnerb5713c52002-03-14 11:26:29 +00001191 TT_CMapTable cmap;
David Turnerd2b1f351999-12-16 23:11:37 +00001192
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001193
David Turnerd2b1f351999-12-16 23:11:37 +00001194 charmap->root.face = (FT_Face)face;
1195 cmap = &charmap->cmap;
1196
David Turnerd2b1f351999-12-16 23:11:37 +00001197 cmap->loaded = FALSE;
1198 cmap->platformID = GET_UShort();
1199 cmap->platformEncodingID = GET_UShort();
David Turnerf9b8dec2000-06-16 19:34:52 +00001200 cmap->offset = (FT_ULong)GET_Long();
David Turnera56489e2000-02-13 13:41:56 +00001201 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001202
David Turner7d3a2642002-03-20 10:49:31 +00001203 FT_FRAME_EXIT();
David Turnere49ab252000-05-16 23:44:38 +00001204
David Turnera56489e2000-02-13 13:41:56 +00001205 /* now read the rest of each table */
1206 for ( charmap = face->charmaps; charmap < limit; charmap++ )
1207 {
David Turnerb5713c52002-03-14 11:26:29 +00001208 TT_CMapTable cmap = &charmap->cmap;
David Turnere49ab252000-05-16 23:44:38 +00001209
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001210
David Turner7d3a2642002-03-20 10:49:31 +00001211 if ( FT_STREAM_SEEK( table_start + (FT_Long)cmap->offset ) ||
1212 FT_STREAM_READ_FIELDS( cmap_rec_fields, cmap ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001213 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001214
David Turner7d3a2642002-03-20 10:49:31 +00001215 cmap->offset = FT_STREAM_POS();
David Turnerd2b1f351999-12-16 23:11:37 +00001216 }
1217 }
1218
1219 FT_TRACE2(( "loaded\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001220
David Turnerd2b1f351999-12-16 23:11:37 +00001221 Exit:
1222 return error;
1223 }
1224
1225
1226 /*************************************************************************/
1227 /* */
1228 /* <Function> */
1229 /* TT_Load_OS2 */
1230 /* */
1231 /* <Description> */
1232 /* Loads the OS2 table. */
1233 /* */
1234 /* <Input> */
1235 /* face :: A handle to the target face object. */
1236 /* stream :: A handle to the input stream. */
1237 /* */
1238 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001239 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001240 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001241 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001242 TT_Load_OS2( TT_Face face,
1243 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001244 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001245 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001246 TT_OS2* os2;
David Turnerb1677a82000-05-29 20:37:41 +00001247
Werner Lemberg36af3ea2001-07-17 12:37:54 +00001248 const FT_Frame_Field os2_fields[] =
1249 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001250#undef FT_STRUCTURE
1251#define FT_STRUCTURE TT_OS2
1252
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001253 FT_FRAME_START( 78 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001254 FT_FRAME_USHORT( version ),
1255 FT_FRAME_SHORT ( xAvgCharWidth ),
1256 FT_FRAME_USHORT( usWeightClass ),
1257 FT_FRAME_USHORT( usWidthClass ),
1258 FT_FRAME_SHORT ( fsType ),
1259 FT_FRAME_SHORT ( ySubscriptXSize ),
1260 FT_FRAME_SHORT ( ySubscriptYSize ),
1261 FT_FRAME_SHORT ( ySubscriptXOffset ),
1262 FT_FRAME_SHORT ( ySubscriptYOffset ),
1263 FT_FRAME_SHORT ( ySuperscriptXSize ),
1264 FT_FRAME_SHORT ( ySuperscriptYSize ),
1265 FT_FRAME_SHORT ( ySuperscriptXOffset ),
1266 FT_FRAME_SHORT ( ySuperscriptYOffset ),
1267 FT_FRAME_SHORT ( yStrikeoutSize ),
1268 FT_FRAME_SHORT ( yStrikeoutPosition ),
1269 FT_FRAME_SHORT ( sFamilyClass ),
1270 FT_FRAME_BYTE ( panose[0] ),
1271 FT_FRAME_BYTE ( panose[1] ),
1272 FT_FRAME_BYTE ( panose[2] ),
1273 FT_FRAME_BYTE ( panose[3] ),
1274 FT_FRAME_BYTE ( panose[4] ),
1275 FT_FRAME_BYTE ( panose[5] ),
1276 FT_FRAME_BYTE ( panose[6] ),
1277 FT_FRAME_BYTE ( panose[7] ),
1278 FT_FRAME_BYTE ( panose[8] ),
1279 FT_FRAME_BYTE ( panose[9] ),
1280 FT_FRAME_ULONG ( ulUnicodeRange1 ),
1281 FT_FRAME_ULONG ( ulUnicodeRange2 ),
1282 FT_FRAME_ULONG ( ulUnicodeRange3 ),
1283 FT_FRAME_ULONG ( ulUnicodeRange4 ),
1284 FT_FRAME_BYTE ( achVendID[0] ),
1285 FT_FRAME_BYTE ( achVendID[1] ),
1286 FT_FRAME_BYTE ( achVendID[2] ),
1287 FT_FRAME_BYTE ( achVendID[3] ),
David Turnera56489e2000-02-13 13:41:56 +00001288
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001289 FT_FRAME_USHORT( fsSelection ),
1290 FT_FRAME_USHORT( usFirstCharIndex ),
1291 FT_FRAME_USHORT( usLastCharIndex ),
1292 FT_FRAME_SHORT ( sTypoAscender ),
1293 FT_FRAME_SHORT ( sTypoDescender ),
1294 FT_FRAME_SHORT ( sTypoLineGap ),
1295 FT_FRAME_USHORT( usWinAscent ),
1296 FT_FRAME_USHORT( usWinDescent ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001297 FT_FRAME_END
1298 };
David Turnere49ab252000-05-16 23:44:38 +00001299
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001300 const FT_Frame_Field os2_fields_extra[] =
1301 {
1302 FT_FRAME_START( 8 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001303 FT_FRAME_ULONG( ulCodePageRange1 ),
1304 FT_FRAME_ULONG( ulCodePageRange2 ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001305 FT_FRAME_END
1306 };
David Turner1119bae2000-05-02 11:01:49 +00001307
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001308 const FT_Frame_Field os2_fields_extra2[] =
1309 {
1310 FT_FRAME_START( 10 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001311 FT_FRAME_SHORT ( sxHeight ),
1312 FT_FRAME_SHORT ( sCapHeight ),
1313 FT_FRAME_USHORT( usDefaultChar ),
1314 FT_FRAME_USHORT( usBreakChar ),
1315 FT_FRAME_USHORT( usMaxContext ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001316 FT_FRAME_END
1317 };
1318
David Turnerd2b1f351999-12-16 23:11:37 +00001319
1320 FT_TRACE2(( "OS/2 Table " ));
1321
1322 /* We now support old Mac fonts where the OS/2 table doesn't */
1323 /* exist. Simply put, we set the `version' field to 0xFFFF */
1324 /* and test this value each time we need to access the table. */
1325 error = face->goto_table( face, TTAG_OS2, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001326 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001327 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001328 FT_TRACE2(( "is missing!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +00001329 face->os2.version = 0xFFFF;
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001330 error = SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001331 goto Exit;
1332 }
1333
David Turnera56489e2000-02-13 13:41:56 +00001334 os2 = &face->os2;
1335
David Turner7d3a2642002-03-20 10:49:31 +00001336 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001337 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001338
1339 os2->ulCodePageRange1 = 0;
1340 os2->ulCodePageRange2 = 0;
Werner Lemberg36af3ea2001-07-17 12:37:54 +00001341 os2->sxHeight = 0;
1342 os2->sCapHeight = 0;
1343 os2->usDefaultChar = 0;
1344 os2->usBreakChar = 0;
1345 os2->usMaxContext = 0;
David Turnerd2b1f351999-12-16 23:11:37 +00001346
1347 if ( os2->version >= 0x0001 )
1348 {
1349 /* only version 1 tables */
David Turner7d3a2642002-03-20 10:49:31 +00001350 if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001351 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001352
1353 if ( os2->version >= 0x0002 )
1354 {
1355 /* only version 2 tables */
David Turner7d3a2642002-03-20 10:49:31 +00001356 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001357 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001358 }
David Turnerd2b1f351999-12-16 23:11:37 +00001359 }
1360
1361 FT_TRACE2(( "loaded\n" ));
1362
1363 Exit:
1364 return error;
1365 }
1366
1367
1368 /*************************************************************************/
1369 /* */
1370 /* <Function> */
1371 /* TT_Load_Postscript */
1372 /* */
1373 /* <Description> */
1374 /* Loads the Postscript table. */
1375 /* */
1376 /* <Input> */
1377 /* face :: A handle to the target face object. */
1378 /* stream :: A handle to the input stream. */
1379 /* */
1380 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001381 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001382 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001383 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001384 TT_Load_PostScript( TT_Face face,
1385 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001386 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001387 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001388 TT_Postscript* post = &face->postscript;
David Turnerb1677a82000-05-29 20:37:41 +00001389
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001390 static const FT_Frame_Field post_fields[] =
1391 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001392#undef FT_STRUCTURE
1393#define FT_STRUCTURE TT_Postscript
1394
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001395 FT_FRAME_START( 32 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001396 FT_FRAME_ULONG( FormatType ),
1397 FT_FRAME_ULONG( italicAngle ),
1398 FT_FRAME_SHORT( underlinePosition ),
1399 FT_FRAME_SHORT( underlineThickness ),
1400 FT_FRAME_ULONG( isFixedPitch ),
1401 FT_FRAME_ULONG( minMemType42 ),
1402 FT_FRAME_ULONG( maxMemType42 ),
1403 FT_FRAME_ULONG( minMemType1 ),
1404 FT_FRAME_ULONG( maxMemType1 ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001405 FT_FRAME_END
1406 };
1407
David Turnerd2b1f351999-12-16 23:11:37 +00001408
1409 FT_TRACE2(( "PostScript " ));
1410
1411 error = face->goto_table( face, TTAG_post, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001412 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001413 return SFNT_Err_Post_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +00001414
David Turner7d3a2642002-03-20 10:49:31 +00001415 if ( FT_STREAM_READ_FIELDS( post_fields, post ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001416 return error;
David Turnerd2b1f351999-12-16 23:11:37 +00001417
David Turnerd2b1f351999-12-16 23:11:37 +00001418 /* we don't load the glyph names, we do that in another */
1419 /* module (ttpost). */
1420 FT_TRACE2(( "loaded\n" ));
1421
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001422 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001423 }
1424
1425
1426 /*************************************************************************/
1427 /* */
1428 /* <Function> */
David Turner51179f02000-05-18 16:18:05 +00001429 /* TT_Load_PCLT */
1430 /* */
1431 /* <Description> */
1432 /* Loads the PCL 5 Table. */
1433 /* */
1434 /* <Input> */
1435 /* face :: A handle to the target face object. */
1436 /* stream :: A handle to the input stream. */
1437 /* */
1438 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001439 /* FreeType error code. 0 means success. */
David Turner51179f02000-05-18 16:18:05 +00001440 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001441 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001442 TT_Load_PCLT( TT_Face face,
1443 FT_Stream stream )
David Turner51179f02000-05-18 16:18:05 +00001444 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001445 static const FT_Frame_Field pclt_fields[] =
1446 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001447#undef FT_STRUCTURE
1448#define FT_STRUCTURE TT_PCLT
1449
David Turnerd18388e2000-07-03 15:00:49 +00001450 FT_FRAME_START( 54 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001451 FT_FRAME_ULONG ( Version ),
1452 FT_FRAME_ULONG ( FontNumber ),
1453 FT_FRAME_USHORT( Pitch ),
1454 FT_FRAME_USHORT( xHeight ),
1455 FT_FRAME_USHORT( Style ),
1456 FT_FRAME_USHORT( TypeFamily ),
1457 FT_FRAME_USHORT( CapHeight ),
1458 FT_FRAME_BYTES ( TypeFace, 16 ),
1459 FT_FRAME_BYTES ( CharacterComplement, 8 ),
1460 FT_FRAME_BYTES ( FileName, 6 ),
1461 FT_FRAME_CHAR ( StrokeWeight ),
1462 FT_FRAME_CHAR ( WidthType ),
1463 FT_FRAME_BYTE ( SerifStyle ),
1464 FT_FRAME_BYTE ( Reserved ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001465 FT_FRAME_END
1466 };
Werner Lemberg920d41e2000-06-05 14:32:32 +00001467
David Turnerf9b8dec2000-06-16 19:34:52 +00001468 FT_Error error;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001469 TT_PCLT* pclt = &face->pclt;
1470
Werner Lemberg920d41e2000-06-05 14:32:32 +00001471
David Turner51179f02000-05-18 16:18:05 +00001472 FT_TRACE2(( "PCLT " ));
1473
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001474 /* optional table */
1475 error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1476 if ( error )
1477 {
1478 FT_TRACE2(( "missing (optional)\n" ));
1479 pclt->Version = 0;
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001480 return SFNT_Err_Ok;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001481 }
Werner Lemberg920d41e2000-06-05 14:32:32 +00001482
David Turner7d3a2642002-03-20 10:49:31 +00001483 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) )
David Turner51179f02000-05-18 16:18:05 +00001484 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +00001485
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001486 FT_TRACE2(( "loaded\n" ));
1487
Werner Lemberg920d41e2000-06-05 14:32:32 +00001488 Exit:
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001489 return error;
1490 }
1491
David Turner51179f02000-05-18 16:18:05 +00001492
1493 /*************************************************************************/
1494 /* */
1495 /* <Function> */
David Turnerd2b1f351999-12-16 23:11:37 +00001496 /* TT_Load_Gasp */
1497 /* */
1498 /* <Description> */
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001499 /* Loads the `gasp' table into a face object. */
David Turnerd2b1f351999-12-16 23:11:37 +00001500 /* */
1501 /* <Input> */
1502 /* face :: A handle to the target face object. */
1503 /* stream :: The input stream. */
1504 /* */
1505 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001506 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001507 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001508 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001509 TT_Load_Gasp( TT_Face face,
1510 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001511 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001512 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001513 FT_Memory memory = stream->memory;
1514
David Turnerf9b8dec2000-06-16 19:34:52 +00001515 FT_UInt j,num_ranges;
David Turnerb5713c52002-03-14 11:26:29 +00001516 TT_GaspRange gaspranges;
David Turnerd2b1f351999-12-16 23:11:37 +00001517
1518
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001519 FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +00001520
1521 /* the gasp table is optional */
1522 error = face->goto_table( face, TTAG_gasp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001523 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001524 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001525
David Turner7d3a2642002-03-20 10:49:31 +00001526 if ( FT_FRAME_ENTER( 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001527 goto Exit;
1528
1529 face->gasp.version = GET_UShort();
1530 face->gasp.numRanges = GET_UShort();
1531
David Turner7d3a2642002-03-20 10:49:31 +00001532 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001533
1534 num_ranges = face->gasp.numRanges;
1535 FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
1536
David Turnerb5713c52002-03-14 11:26:29 +00001537 if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRangeRec ) ||
David Turner7d3a2642002-03-20 10:49:31 +00001538 FT_FRAME_ENTER( num_ranges * 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001539 goto Exit;
1540
1541 face->gasp.gaspRanges = gaspranges;
1542
1543 for ( j = 0; j < num_ranges; j++ )
1544 {
1545 gaspranges[j].maxPPEM = GET_UShort();
1546 gaspranges[j].gaspFlag = GET_UShort();
1547
1548 FT_TRACE3(( " [max:%d flag:%d]",
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001549 gaspranges[j].maxPPEM,
1550 gaspranges[j].gaspFlag ));
David Turnerd2b1f351999-12-16 23:11:37 +00001551 }
1552 FT_TRACE3(( "\n" ));
1553
David Turner7d3a2642002-03-20 10:49:31 +00001554 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001555 FT_TRACE2(( "GASP loaded\n" ));
1556
1557 Exit:
1558 return error;
1559 }
1560
1561
Werner Lemberg52005c32001-06-27 23:25:46 +00001562 FT_CALLBACK_DEF( int )
1563 tt_kern_pair_compare( const void* a,
1564 const void* b );
1565
1566
David Turnerd2b1f351999-12-16 23:11:37 +00001567 /*************************************************************************/
1568 /* */
1569 /* <Function> */
1570 /* TT_Load_Kern */
1571 /* */
1572 /* <Description> */
1573 /* Loads the first kerning table with format 0 in the font. Only */
1574 /* accepts the first horizontal kerning table. Developers should use */
1575 /* the `ftxkern' extension to access other kerning tables in the font */
1576 /* file, if they really want to. */
1577 /* */
1578 /* <Input> */
1579 /* face :: A handle to the target face object. */
1580 /* stream :: The input stream. */
1581 /* */
1582 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001583 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001584 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001585 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001586 TT_Load_Kern( TT_Face face,
1587 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001588 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001589 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001590 FT_Memory memory = stream->memory;
1591
Werner Lembergcf24d512001-06-18 14:23:45 +00001592 FT_UInt n, num_tables;
David Turnerd2b1f351999-12-16 23:11:37 +00001593
David Turnerd2b1f351999-12-16 23:11:37 +00001594
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001595 /* the kern table is optional; exit silently if it is missing */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001596 error = face->goto_table( face, TTAG_kern, stream, 0 );
1597 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001598 return SFNT_Err_Ok;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001599
David Turner7d3a2642002-03-20 10:49:31 +00001600 if ( FT_FRAME_ENTER( 4L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001601 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001602
Werner Lembergcf24d512001-06-18 14:23:45 +00001603 (void)GET_UShort(); /* version */
David Turnerd2b1f351999-12-16 23:11:37 +00001604 num_tables = GET_UShort();
1605
David Turner7d3a2642002-03-20 10:49:31 +00001606 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001607
1608 for ( n = 0; n < num_tables; n++ )
1609 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001610 FT_UInt coverage;
1611 FT_UInt length;
David Turnerd2b1f351999-12-16 23:11:37 +00001612
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001613
David Turner7d3a2642002-03-20 10:49:31 +00001614 if ( FT_FRAME_ENTER( 6L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001615 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001616
Werner Lembergcf24d512001-06-18 14:23:45 +00001617 (void)GET_UShort(); /* version */
David Turnerd2b1f351999-12-16 23:11:37 +00001618 length = GET_UShort() - 6; /* substract header length */
1619 coverage = GET_UShort();
1620
David Turner7d3a2642002-03-20 10:49:31 +00001621 FT_FRAME_EXIT();
David Turnere49ab252000-05-16 23:44:38 +00001622
David Turnerd2b1f351999-12-16 23:11:37 +00001623 if ( coverage == 0x0001 )
1624 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001625 FT_UInt num_pairs;
David Turnerb5713c52002-03-14 11:26:29 +00001626 TT_Kern0_Pair pair;
1627 TT_Kern0_Pair limit;
David Turnerd2b1f351999-12-16 23:11:37 +00001628
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001629
1630 /* found a horizontal format 0 kerning table! */
David Turner7d3a2642002-03-20 10:49:31 +00001631 if ( FT_FRAME_ENTER( 8L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001632 goto Exit;
1633
1634 num_pairs = GET_UShort();
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001635
David Turnerd2b1f351999-12-16 23:11:37 +00001636 /* skip the rest */
1637
David Turner7d3a2642002-03-20 10:49:31 +00001638 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001639
1640 /* allocate array of kerning pairs */
David Turnerb5713c52002-03-14 11:26:29 +00001641 if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern0_PairRec ) ||
David Turner7d3a2642002-03-20 10:49:31 +00001642 FT_FRAME_ENTER( 6L * num_pairs ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001643 goto Exit;
1644
1645 pair = face->kern_pairs;
1646 limit = pair + num_pairs;
1647 for ( ; pair < limit; pair++ )
1648 {
1649 pair->left = GET_UShort();
1650 pair->right = GET_UShort();
1651 pair->value = GET_UShort();
1652 }
1653
David Turner7d3a2642002-03-20 10:49:31 +00001654 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001655
1656 face->num_kern_pairs = num_pairs;
1657 face->kern_table_index = n;
Werner Lemberg415235d2001-06-28 17:49:10 +00001658
David Turner9a554eb2001-06-27 12:40:46 +00001659 /* ensure that the kerning pair table is sorted (yes, some */
Werner Lembergf814d0f2001-06-27 16:18:10 +00001660 /* fonts have unsorted tables!) */
David Turner9a554eb2001-06-27 12:40:46 +00001661 {
1662 FT_UInt i;
David Turnerb5713c52002-03-14 11:26:29 +00001663 TT_Kern0_Pair pair0;
Werner Lemberg415235d2001-06-28 17:49:10 +00001664
David Turner9a554eb2001-06-27 12:40:46 +00001665
Werner Lembergf814d0f2001-06-27 16:18:10 +00001666 pair0 = face->kern_pairs;
1667
1668 for ( i = 1; i < num_pairs; i++, pair0++ )
David Turner9a554eb2001-06-27 12:40:46 +00001669 {
Werner Lembergf814d0f2001-06-27 16:18:10 +00001670 if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
David Turner9a554eb2001-06-27 12:40:46 +00001671 {
1672 qsort( (void*)face->kern_pairs, (int)num_pairs,
David Turnerb5713c52002-03-14 11:26:29 +00001673 sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare );
David Turner9a554eb2001-06-27 12:40:46 +00001674 break;
1675 }
1676 }
1677 }
Werner Lemberg415235d2001-06-28 17:49:10 +00001678
David Turnerd2b1f351999-12-16 23:11:37 +00001679 goto Exit;
1680 }
David Turnere49ab252000-05-16 23:44:38 +00001681
David Turner7d3a2642002-03-20 10:49:31 +00001682 if ( FT_STREAM_SKIP( length ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001683 goto Exit;
1684 }
1685
1686 /* no kern table found -- doesn't matter */
1687 face->kern_table_index = -1;
1688 face->num_kern_pairs = 0;
1689 face->kern_pairs = NULL;
1690
1691 Exit:
1692 return error;
1693 }
1694
Werner Lembergf814d0f2001-06-27 16:18:10 +00001695
David Turner9a554eb2001-06-27 12:40:46 +00001696#undef TT_KERN_INDEX
Werner Lembergf814d0f2001-06-27 16:18:10 +00001697#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
David Turner9a554eb2001-06-27 12:40:46 +00001698
Werner Lemberg52005c32001-06-27 23:25:46 +00001699 FT_CALLBACK_DEF( int )
Werner Lembergf814d0f2001-06-27 16:18:10 +00001700 tt_kern_pair_compare( const void* a,
1701 const void* b )
David Turner9a554eb2001-06-27 12:40:46 +00001702 {
David Turnerb5713c52002-03-14 11:26:29 +00001703 TT_Kern0_Pair pair1 = (TT_Kern0_Pair)a;
1704 TT_Kern0_Pair pair2 = (TT_Kern0_Pair)b;
David Turner9a554eb2001-06-27 12:40:46 +00001705
1706 FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right );
1707 FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right );
1708
Werner Lembergf814d0f2001-06-27 16:18:10 +00001709
David Turner9a554eb2001-06-27 12:40:46 +00001710 return ( index1 < index2 ? -1 :
1711 ( index1 > index2 ? 1 : 0 ));
1712 }
1713
1714#undef TT_KERN_INDEX
David Turnerd2b1f351999-12-16 23:11:37 +00001715
Werner Lembergf814d0f2001-06-27 16:18:10 +00001716
David Turnerd2b1f351999-12-16 23:11:37 +00001717 /*************************************************************************/
1718 /* */
1719 /* <Function> */
1720 /* TT_Load_Hdmx */
1721 /* */
1722 /* <Description> */
1723 /* Loads the horizontal device metrics table. */
1724 /* */
1725 /* <Input> */
1726 /* face :: A handle to the target face object. */
1727 /* stream :: A handle to the input stream. */
1728 /* */
1729 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001730 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001731 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001732 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001733 TT_Load_Hdmx( TT_Face face,
1734 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001735 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001736 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001737 FT_Memory memory = stream->memory;
1738
David Turnerb5713c52002-03-14 11:26:29 +00001739 TT_Hdmx hdmx = &face->hdmx;
David Turnerf9b8dec2000-06-16 19:34:52 +00001740 FT_Long num_glyphs;
1741 FT_Long record_size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001742
David Turnerd2b1f351999-12-16 23:11:37 +00001743
1744 hdmx->version = 0;
1745 hdmx->num_records = 0;
1746 hdmx->records = 0;
1747
1748 /* this table is optional */
1749 error = face->goto_table( face, TTAG_hdmx, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001750 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001751 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001752
David Turner7d3a2642002-03-20 10:49:31 +00001753 if ( FT_FRAME_ENTER( 8L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001754 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001755
1756 hdmx->version = GET_UShort();
1757 hdmx->num_records = GET_Short();
1758 record_size = GET_Long();
1759
David Turner7d3a2642002-03-20 10:49:31 +00001760 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001761
1762 /* Only recognize format 0 */
1763 if ( hdmx->version != 0 )
1764 goto Exit;
1765
David Turnerb5713c52002-03-14 11:26:29 +00001766 if ( ALLOC_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxEntryRec ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001767 goto Exit;
1768
1769 num_glyphs = face->root.num_glyphs;
1770 record_size -= num_glyphs + 2;
1771
1772 {
David Turnerb5713c52002-03-14 11:26:29 +00001773 TT_HdmxEntry cur = hdmx->records;
1774 TT_HdmxEntry limit = cur + hdmx->num_records;
David Turnerd2b1f351999-12-16 23:11:37 +00001775
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001776
David Turnerd2b1f351999-12-16 23:11:37 +00001777 for ( ; cur < limit; cur++ )
1778 {
1779 /* read record */
1780 if ( READ_Byte( cur->ppem ) ||
1781 READ_Byte( cur->max_width ) )
1782 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001783
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001784 if ( ALLOC( cur->widths, num_glyphs ) ||
David Turner7d3a2642002-03-20 10:49:31 +00001785 FT_STREAM_READ( cur->widths, num_glyphs ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001786 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001787
David Turnerd2b1f351999-12-16 23:11:37 +00001788 /* skip padding bytes */
David Turner7d3a2642002-03-20 10:49:31 +00001789 if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001790 goto Exit;
1791 }
1792 }
1793
1794 Exit:
1795 return error;
1796 }
1797
1798
1799 /*************************************************************************/
1800 /* */
1801 /* <Function> */
1802 /* TT_Free_Hdmx */
1803 /* */
1804 /* <Description> */
1805 /* Frees the horizontal device metrics table. */
1806 /* */
1807 /* <Input> */
1808 /* face :: A handle to the target face object. */
1809 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001810 FT_LOCAL_DEF( void )
Werner Lemberg52005c32001-06-27 23:25:46 +00001811 TT_Free_Hdmx( TT_Face face )
David Turnerd2b1f351999-12-16 23:11:37 +00001812 {
1813 if ( face )
1814 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001815 FT_Int n;
David Turnerf0df85b2000-06-22 00:17:42 +00001816 FT_Memory memory = face->root.driver->root.memory;
David Turnerd2b1f351999-12-16 23:11:37 +00001817
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001818
David Turnerd2b1f351999-12-16 23:11:37 +00001819 for ( n = 0; n < face->hdmx.num_records; n++ )
1820 FREE( face->hdmx.records[n].widths );
1821
1822 FREE( face->hdmx.records );
1823 face->hdmx.num_records = 0;
1824 }
1825 }
1826
1827
1828/* END */