blob: 40d8c5737d66185336c3ffd558adb4e46f5f58f5 [file] [log] [blame]
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001/***************************************************************************/
2/* */
Werner Lembergb5084e12000-10-28 17:10:06 +00003/* t1load.c */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00004/* */
Werner Lembergb5084e12000-10-28 17:10:06 +00005/* Type 1 font loader (body). */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00006/* */
Werner Lemberg415235d2001-06-28 17:49:10 +00007/* Copyright 1996-2001 by */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
10/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
12/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18
19 /*************************************************************************/
20 /* */
21 /* This is the new and improved Type 1 data loader for FreeType 2. The */
22 /* old loader has several problems: it is slow, complex, difficult to */
23 /* maintain, and contains incredible hacks to make it accept some */
24 /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */
25 /* the Type 1 fonts on my machine still aren't loaded correctly by it. */
26 /* */
27 /* This version is much simpler, much faster and also easier to read and */
28 /* maintain by a great order of magnitude. The idea behind it is to */
29 /* _not_ try to read the Type 1 token stream with a state machine (i.e. */
30 /* a Postscript-like interpreter) but rather to perform simple pattern */
31 /* matching. */
32 /* */
33 /* Indeed, nearly all data definitions follow a simple pattern like */
34 /* */
35 /* ... /Field <data> ... */
36 /* */
37 /* where <data> can be a number, a boolean, a string, or an array of */
38 /* numbers. There are a few exceptions, namely the encoding, font name, */
39 /* charstrings, and subrs; they are handled with a special pattern */
40 /* matching routine. */
41 /* */
42 /* All other common cases are handled very simply. The matching rules */
43 /* are defined in the file `t1tokens.h' through the use of several */
44 /* macros calls PARSE_XXX. */
45 /* */
46 /* This file is included twice here; the first time to generate parsing */
47 /* callback functions, the second to generate a table of keywords (with */
48 /* pointers to the associated callback). */
49 /* */
50 /* The function `parse_dict' simply scans *linearly* a given dictionary */
51 /* (either the top-level or private one) and calls the appropriate */
52 /* callback when it encounters an immediate keyword. */
53 /* */
54 /* This is by far the fastest way one can find to parse and read all */
55 /* data. */
56 /* */
57 /* This led to tremendous code size reduction. Note that later, the */
58 /* glyph loader will also be _greatly_ simplified, and the automatic */
59 /* hinter will replace the clumsy `t1hinter'. */
60 /* */
61 /*************************************************************************/
62
Werner Lembergcc069be2000-12-08 16:17:16 +000063
David Turner19ed8af2000-12-08 02:42:29 +000064#include <ft2build.h>
65#include FT_INTERNAL_DEBUG_H
66#include FT_CONFIG_CONFIG_H
67#include FT_MULTIPLE_MASTERS_H
68#include FT_INTERNAL_TYPE1_TYPES_H
David Turner2dfb5ac2000-01-27 14:02:04 +000069
David Turner8d3a4012001-03-20 11:14:24 +000070#include "t1load.h"
Werner Lembergcc069be2000-12-08 16:17:16 +000071
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000072#include "t1errors.h"
73
Werner Lemberg681e8ee2000-07-09 00:48:37 +000074#include <string.h> /* for strncmp(), strcmp() */
75#include <ctype.h> /* for isalnum() */
76
77
78 /*************************************************************************/
79 /* */
80 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
81 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
82 /* messages during execution. */
83 /* */
David Turner2dfb5ac2000-01-27 14:02:04 +000084#undef FT_COMPONENT
Werner Lembergb5084e12000-10-28 17:10:06 +000085#define FT_COMPONENT trace_t1load
Werner Lemberg681e8ee2000-07-09 00:48:37 +000086
David Turner2dfb5ac2000-01-27 14:02:04 +000087
Werner Lembergb5084e12000-10-28 17:10:06 +000088#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
David Turner1c9a1ca2000-05-24 21:12:02 +000089
David Turner11187202000-05-26 17:13:23 +000090
Werner Lemberg681e8ee2000-07-09 00:48:37 +000091 /*************************************************************************/
92 /*************************************************************************/
93 /***** *****/
94 /***** MULTIPLE MASTERS SUPPORT *****/
95 /***** *****/
96 /*************************************************************************/
97 /*************************************************************************/
Werner Lembergb48a6092000-07-09 19:15:30 +000098
Werner Lemberg4a2305c2001-06-28 07:17:51 +000099 static FT_Error
100 t1_allocate_blend( T1_Face face,
101 FT_UInt num_designs,
102 FT_UInt num_axis )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000103 {
David Turner29644172002-02-28 18:59:37 +0000104 PS_Blend blend;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000105 FT_Memory memory = face->root.memory;
106 FT_Error error = 0;
Werner Lembergb48a6092000-07-09 19:15:30 +0000107
108
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000109 blend = face->blend;
110 if ( !blend )
111 {
David Turnere459d742002-03-22 13:52:37 +0000112 if ( FT_NEW( blend ) )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000113 goto Exit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000114
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000115 face->blend = blend;
116 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000117
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000118 /* allocate design data if needed */
119 if ( num_designs > 0 )
120 {
121 if ( blend->num_designs == 0 )
122 {
David Turnere208f4e2000-07-10 20:30:59 +0000123 FT_UInt nn;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000124
Werner Lemberg93ac3e32000-07-10 21:41:32 +0000125
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000126 /* allocate the blend `private' and `font_info' dictionaries */
David Turnere459d742002-03-22 13:52:37 +0000127 if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) ||
128 FT_NEW_ARRAY( blend->privates[1], num_designs ) ||
129 FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000130 goto Exit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000131
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000132 blend->default_weight_vector = blend->weight_vector + num_designs;
Werner Lembergb48a6092000-07-09 19:15:30 +0000133
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000134 blend->font_infos[0] = &face->type1.font_info;
135 blend->privates [0] = &face->type1.private_dict;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000136
David Turnere208f4e2000-07-10 20:30:59 +0000137 for ( nn = 2; nn <= num_designs; nn++ )
138 {
Werner Lemberg93ac3e32000-07-10 21:41:32 +0000139 blend->privates[nn] = blend->privates [nn - 1] + 1;
140 blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
David Turnere208f4e2000-07-10 20:30:59 +0000141 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000142
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000143 blend->num_designs = num_designs;
144 }
145 else if ( blend->num_designs != num_designs )
146 goto Fail;
147 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000148
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000149 /* allocate axis data if needed */
150 if ( num_axis > 0 )
151 {
152 if ( blend->num_axis != 0 && blend->num_axis != num_axis )
153 goto Fail;
Werner Lembergb48a6092000-07-09 19:15:30 +0000154
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000155 blend->num_axis = num_axis;
156 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000157
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000158 /* allocate the blend design pos table if needed */
159 num_designs = blend->num_designs;
160 num_axis = blend->num_axis;
161 if ( num_designs && num_axis && blend->design_pos[0] == 0 )
162 {
163 FT_UInt n;
Werner Lembergb48a6092000-07-09 19:15:30 +0000164
165
David Turnere459d742002-03-22 13:52:37 +0000166 if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000167 goto Exit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000168
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000169 for ( n = 1; n < num_designs; n++ )
170 blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
171 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000172
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000173 Exit:
174 return error;
Werner Lembergb48a6092000-07-09 19:15:30 +0000175
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000176 Fail:
177 error = -1;
178 goto Exit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000179 }
180
181
David Turnerbc82f1b2002-03-01 02:26:22 +0000182 FT_LOCAL_DEF( FT_Error )
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000183 T1_Get_Multi_Master( T1_Face face,
184 FT_Multi_Master* master )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000185 {
David Turner29644172002-02-28 18:59:37 +0000186 PS_Blend blend = face->blend;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000187 FT_UInt n;
188 FT_Error error;
Werner Lembergb48a6092000-07-09 19:15:30 +0000189
190
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000191 error = T1_Err_Invalid_Argument;
Werner Lembergb48a6092000-07-09 19:15:30 +0000192
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000193 if ( blend )
194 {
195 master->num_axis = blend->num_axis;
196 master->num_designs = blend->num_designs;
Werner Lembergb48a6092000-07-09 19:15:30 +0000197
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000198 for ( n = 0; n < blend->num_axis; n++ )
199 {
David Turner29644172002-02-28 18:59:37 +0000200 FT_MM_Axis* axis = master->axis + n;
201 PS_DesignMap map = blend->design_map + n;
Werner Lembergb48a6092000-07-09 19:15:30 +0000202
203
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000204 axis->name = blend->axis_names[n];
205 axis->minimum = map->design_points[0];
206 axis->maximum = map->design_points[map->num_points - 1];
207 }
208 error = 0;
209 }
210 return error;
Werner Lembergb48a6092000-07-09 19:15:30 +0000211 }
212
213
David Turnerbc82f1b2002-03-01 02:26:22 +0000214 FT_LOCAL_DEF( FT_Error )
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000215 T1_Set_MM_Blend( T1_Face face,
216 FT_UInt num_coords,
217 FT_Fixed* coords )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000218 {
David Turner29644172002-02-28 18:59:37 +0000219 PS_Blend blend = face->blend;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000220 FT_Error error;
221 FT_UInt n, m;
Werner Lembergb48a6092000-07-09 19:15:30 +0000222
David Turner11187202000-05-26 17:13:23 +0000223
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000224 error = T1_Err_Invalid_Argument;
225
226 if ( blend && blend->num_axis == num_coords )
227 {
228 /* recompute the weight vector from the blend coordinates */
Werner Lemberg1429db62001-04-02 23:54:01 +0000229 error = T1_Err_Ok;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000230
231 for ( n = 0; n < blend->num_designs; n++ )
232 {
233 FT_Fixed result = 0x10000L; /* 1.0 fixed */
234
235
236 for ( m = 0; m < blend->num_axis; m++ )
237 {
238 FT_Fixed factor;
Werner Lembergb48a6092000-07-09 19:15:30 +0000239
David Turner11187202000-05-26 17:13:23 +0000240
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000241 /* get current blend axis position */
242 factor = coords[m];
243 if ( factor < 0 ) factor = 0;
244 if ( factor > 0x10000L ) factor = 0x10000L;
Werner Lembergb48a6092000-07-09 19:15:30 +0000245
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000246 if ( ( n & ( 1 << m ) ) == 0 )
247 factor = 0x10000L - factor;
Werner Lembergb48a6092000-07-09 19:15:30 +0000248
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000249 result = FT_MulFix( result, factor );
250 }
251 blend->weight_vector[n] = result;
252 }
David Turner1c9a1ca2000-05-24 21:12:02 +0000253
Werner Lemberg1429db62001-04-02 23:54:01 +0000254 error = T1_Err_Ok;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000255 }
256 return error;
257 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000258
259
David Turnerbc82f1b2002-03-01 02:26:22 +0000260 FT_LOCAL_DEF( FT_Error )
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000261 T1_Set_MM_Design( T1_Face face,
262 FT_UInt num_coords,
263 FT_Long* coords )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000264 {
David Turner29644172002-02-28 18:59:37 +0000265 PS_Blend blend = face->blend;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000266 FT_Error error;
267 FT_UInt n, p;
David Turner1c9a1ca2000-05-24 21:12:02 +0000268
Werner Lembergb48a6092000-07-09 19:15:30 +0000269
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000270 error = T1_Err_Invalid_Argument;
271 if ( blend && blend->num_axis == num_coords )
272 {
273 /* compute the blend coordinates through the blend design map */
274 FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
Werner Lembergb48a6092000-07-09 19:15:30 +0000275
David Turner7c388ba2000-05-26 02:07:40 +0000276
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000277 for ( n = 0; n < blend->num_axis; n++ )
278 {
279 FT_Long design = coords[n];
280 FT_Fixed the_blend;
David Turner29644172002-02-28 18:59:37 +0000281 PS_DesignMap map = blend->design_map + n;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000282 FT_Fixed* designs = map->design_points;
283 FT_Fixed* blends = map->blend_points;
284 FT_Int before = -1, after = -1;
Werner Lembergb48a6092000-07-09 19:15:30 +0000285
David Turnerefa80f22000-12-01 21:43:05 +0000286 for ( p = 0; p < (FT_UInt)map->num_points; p++ )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000287 {
288 FT_Fixed p_design = designs[p];
Werner Lembergb48a6092000-07-09 19:15:30 +0000289
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000290
291 /* exact match ? */
292 if ( design == p_design )
293 {
294 the_blend = blends[p];
295 goto Found;
296 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000297
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000298 if ( design < p_design )
299 {
300 after = p;
301 break;
302 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000303
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000304 before = p;
305 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000306
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000307 /* now, interpolate if needed */
308 if ( before < 0 )
309 the_blend = blends[0];
Werner Lembergb48a6092000-07-09 19:15:30 +0000310
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000311 else if ( after < 0 )
312 the_blend = blends[map->num_points - 1];
Werner Lembergb48a6092000-07-09 19:15:30 +0000313
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000314 else
315 the_blend = FT_MulDiv( design - designs[before],
316 blends [after] - blends [before],
317 designs[after] - designs[before] );
318
319 Found:
320 final_blends[n] = the_blend;
321 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000322
Werner Lembergb5084e12000-10-28 17:10:06 +0000323 error = T1_Set_MM_Blend( face, num_coords, final_blends );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000324 }
325
326 return error;
327 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000328
329
David Turnerbc82f1b2002-03-01 02:26:22 +0000330 FT_LOCAL_DEF( void )
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000331 T1_Done_Blend( T1_Face face )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000332 {
333 FT_Memory memory = face->root.memory;
David Turner29644172002-02-28 18:59:37 +0000334 PS_Blend blend = face->blend;
Werner Lembergb48a6092000-07-09 19:15:30 +0000335
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000336
337 if ( blend )
338 {
339 FT_UInt num_designs = blend->num_designs;
340 FT_UInt num_axis = blend->num_axis;
341 FT_UInt n;
Werner Lembergb48a6092000-07-09 19:15:30 +0000342
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000343
344 /* release design pos table */
David Turnere459d742002-03-22 13:52:37 +0000345 FT_FREE( blend->design_pos[0] );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000346 for ( n = 1; n < num_designs; n++ )
347 blend->design_pos[n] = 0;
Werner Lembergb48a6092000-07-09 19:15:30 +0000348
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000349 /* release blend `private' and `font info' dictionaries */
David Turnere459d742002-03-22 13:52:37 +0000350 FT_FREE( blend->privates[1] );
351 FT_FREE( blend->font_infos[1] );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000352
353 for ( n = 0; n < num_designs; n++ )
354 {
355 blend->privates [n] = 0;
356 blend->font_infos[n] = 0;
357 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000358
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000359 /* release weight vectors */
David Turnere459d742002-03-22 13:52:37 +0000360 FT_FREE( blend->weight_vector );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000361 blend->default_weight_vector = 0;
Werner Lembergb48a6092000-07-09 19:15:30 +0000362
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000363 /* release axis names */
364 for ( n = 0; n < num_axis; n++ )
David Turnere459d742002-03-22 13:52:37 +0000365 FT_FREE( blend->axis_names[n] );
Werner Lembergb48a6092000-07-09 19:15:30 +0000366
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000367 /* release design map */
368 for ( n = 0; n < num_axis; n++ )
369 {
David Turner29644172002-02-28 18:59:37 +0000370 PS_DesignMap dmap = blend->design_map + n;
David Turner1c9a1ca2000-05-24 21:12:02 +0000371
David Turner7c388ba2000-05-26 02:07:40 +0000372
David Turnere459d742002-03-22 13:52:37 +0000373 FT_FREE( dmap->design_points );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000374 dmap->num_points = 0;
375 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000376
David Turnere459d742002-03-22 13:52:37 +0000377 FT_FREE( face->blend );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000378 }
379 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000380
381
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000382 static void
383 parse_blend_axis_types( T1_Face face,
384 T1_Loader* loader )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000385 {
David Turner4e7eeee2002-02-28 16:10:29 +0000386 T1_TokenRec axis_tokens[ T1_MAX_MM_AXIS ];
387 FT_Int n, num_axis;
388 FT_Error error = 0;
David Turner29644172002-02-28 18:59:37 +0000389 PS_Blend blend;
David Turner4e7eeee2002-02-28 16:10:29 +0000390 FT_Memory memory;
Werner Lembergb48a6092000-07-09 19:15:30 +0000391
David Turner1c9a1ca2000-05-24 21:12:02 +0000392
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000393 /* take an array of objects */
Werner Lembergb5084e12000-10-28 17:10:06 +0000394 T1_ToTokenArray( &loader->parser, axis_tokens,
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000395 T1_MAX_MM_AXIS, &num_axis );
396 if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
397 {
398 FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
399 num_axis ));
400 error = T1_Err_Invalid_File_Format;
401 goto Exit;
402 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000403
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000404 /* allocate blend if necessary */
405 error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
406 if ( error )
407 goto Exit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000408
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000409 blend = face->blend;
410 memory = face->root.memory;
Werner Lembergb48a6092000-07-09 19:15:30 +0000411
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000412 /* each token is an immediate containing the name of the axis */
413 for ( n = 0; n < num_axis; n++ )
414 {
David Turner4e7eeee2002-02-28 16:10:29 +0000415 T1_Token token = axis_tokens + n;
Werner Lemberg8728f292000-08-23 17:32:42 +0000416 FT_Byte* name;
417 FT_Int len;
Werner Lembergb48a6092000-07-09 19:15:30 +0000418
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000419 /* skip first slash, if any */
420 if (token->start[0] == '/')
421 token->start++;
Werner Lembergb48a6092000-07-09 19:15:30 +0000422
Werner Lemberg914b2892001-03-10 17:07:42 +0000423 len = (FT_Int)( token->limit - token->start );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000424 if ( len <= 0 )
425 {
426 error = T1_Err_Invalid_File_Format;
427 goto Exit;
428 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000429
David Turnere459d742002-03-22 13:52:37 +0000430 if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000431 goto Exit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000432
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000433 name = (FT_Byte*)blend->axis_names[n];
David Turnere459d742002-03-22 13:52:37 +0000434 FT_MEM_COPY( name, token->start, len );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000435 name[len] = 0;
436 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000437
438 Exit:
David Turnera39acf52000-08-23 02:47:57 +0000439 loader->parser.root.error = error;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000440 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000441
442
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000443 static void
444 parse_blend_design_positions( T1_Face face,
445 T1_Loader* loader )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000446 {
David Turner4e7eeee2002-02-28 16:10:29 +0000447 T1_TokenRec design_tokens[ T1_MAX_MM_DESIGNS ];
Werner Lembergb5084e12000-10-28 17:10:06 +0000448 FT_Int num_designs;
449 FT_Int num_axis;
David Turner4e7eeee2002-02-28 16:10:29 +0000450 T1_Parser parser = &loader->parser;
Werner Lembergb48a6092000-07-09 19:15:30 +0000451
Werner Lembergb5084e12000-10-28 17:10:06 +0000452 FT_Error error = 0;
David Turner29644172002-02-28 18:59:37 +0000453 PS_Blend blend;
David Turner1c9a1ca2000-05-24 21:12:02 +0000454
Werner Lembergb48a6092000-07-09 19:15:30 +0000455
456 /* get the array of design tokens - compute number of designs */
Werner Lembergb5084e12000-10-28 17:10:06 +0000457 T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000458 if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
459 {
460 FT_ERROR(( "parse_blend_design_positions:" ));
461 FT_ERROR(( " incorrect number of designs: %d\n",
462 num_designs ));
463 error = T1_Err_Invalid_File_Format;
464 goto Exit;
465 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000466
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000467 {
David Turnera39acf52000-08-23 02:47:57 +0000468 FT_Byte* old_cursor = parser->root.cursor;
469 FT_Byte* old_limit = parser->root.limit;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000470 FT_UInt n;
Werner Lembergb48a6092000-07-09 19:15:30 +0000471
David Turner1c9a1ca2000-05-24 21:12:02 +0000472
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000473 blend = face->blend;
474 num_axis = 0; /* make compiler happy */
475
476 for ( n = 0; n < (FT_UInt)num_designs; n++ )
477 {
David Turner4e7eeee2002-02-28 16:10:29 +0000478 T1_TokenRec axis_tokens[ T1_MAX_MM_DESIGNS ];
479 T1_Token token;
David Turnera39acf52000-08-23 02:47:57 +0000480 FT_Int axis, n_axis;
Werner Lembergb48a6092000-07-09 19:15:30 +0000481
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000482
483 /* read axis/coordinates tokens */
484 token = design_tokens + n;
David Turnera39acf52000-08-23 02:47:57 +0000485 parser->root.cursor = token->start - 1;
486 parser->root.limit = token->limit + 1;
Werner Lembergb5084e12000-10-28 17:10:06 +0000487 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
Werner Lembergb48a6092000-07-09 19:15:30 +0000488
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000489 if ( n == 0 )
490 {
491 num_axis = n_axis;
492 error = t1_allocate_blend( face, num_designs, num_axis );
493 if ( error )
494 goto Exit;
495 blend = face->blend;
496 }
497 else if ( n_axis != num_axis )
498 {
499 FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
500 error = T1_Err_Invalid_File_Format;
501 goto Exit;
502 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000503
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000504 /* now, read each axis token into the design position */
505 for ( axis = 0; axis < n_axis; axis++ )
506 {
David Turner4e7eeee2002-02-28 16:10:29 +0000507 T1_Token token2 = axis_tokens + axis;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000508
509
David Turnera39acf52000-08-23 02:47:57 +0000510 parser->root.cursor = token2->start;
511 parser->root.limit = token2->limit;
Werner Lembergb5084e12000-10-28 17:10:06 +0000512 blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000513 }
514 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000515
David Turnera39acf52000-08-23 02:47:57 +0000516 loader->parser.root.cursor = old_cursor;
517 loader->parser.root.limit = old_limit;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000518 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000519
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000520 Exit:
David Turnera39acf52000-08-23 02:47:57 +0000521 loader->parser.root.error = error;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000522 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000523
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000524
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000525 static void
526 parse_blend_design_map( T1_Face face,
527 T1_Loader* loader )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000528 {
Werner Lembergb5084e12000-10-28 17:10:06 +0000529 FT_Error error = 0;
David Turner4e7eeee2002-02-28 16:10:29 +0000530 T1_Parser parser = &loader->parser;
David Turner29644172002-02-28 18:59:37 +0000531 PS_Blend blend;
David Turner4e7eeee2002-02-28 16:10:29 +0000532 T1_TokenRec axis_tokens[ T1_MAX_MM_AXIS ];
Werner Lembergb5084e12000-10-28 17:10:06 +0000533 FT_Int n, num_axis;
534 FT_Byte* old_cursor;
535 FT_Byte* old_limit;
536 FT_Memory memory = face->root.memory;
Werner Lembergb48a6092000-07-09 19:15:30 +0000537
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000538
Werner Lembergb5084e12000-10-28 17:10:06 +0000539 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000540 if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
541 {
542 FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
543 num_axis ));
544 error = T1_Err_Invalid_File_Format;
545 goto Exit;
546 }
David Turnera39acf52000-08-23 02:47:57 +0000547 old_cursor = parser->root.cursor;
548 old_limit = parser->root.limit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000549
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000550 error = t1_allocate_blend( face, 0, num_axis );
551 if ( error )
552 goto Exit;
553 blend = face->blend;
Werner Lembergb48a6092000-07-09 19:15:30 +0000554
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000555 /* now, read each axis design map */
556 for ( n = 0; n < num_axis; n++ )
557 {
David Turner29644172002-02-28 18:59:37 +0000558 PS_DesignMap map = blend->design_map + n;
David Turner4e7eeee2002-02-28 16:10:29 +0000559 T1_Token token;
Werner Lemberg8728f292000-08-23 17:32:42 +0000560 FT_Int p, num_points;
Werner Lembergb48a6092000-07-09 19:15:30 +0000561
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000562
563 token = axis_tokens + n;
David Turnera39acf52000-08-23 02:47:57 +0000564 parser->root.cursor = token->start;
565 parser->root.limit = token->limit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000566
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000567 /* count the number of map points */
568 {
Werner Lembergb1dd3532000-07-31 22:51:00 +0000569 FT_Byte* ptr = token->start;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000570 FT_Byte* limit = token->limit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000571
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000572
573 num_points = 0;
Werner Lembergb1dd3532000-07-31 22:51:00 +0000574 for ( ; ptr < limit; ptr++ )
575 if ( ptr[0] == '[' )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000576 num_points++;
577 }
578 if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
579 {
580 FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
581 error = T1_Err_Invalid_File_Format;
582 goto Exit;
583 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000584
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000585 /* allocate design map data */
David Turnere459d742002-03-22 13:52:37 +0000586 if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000587 goto Exit;
588 map->blend_points = map->design_points + num_points;
589 map->num_points = (FT_Byte)num_points;
Werner Lembergb48a6092000-07-09 19:15:30 +0000590
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000591 for ( p = 0; p < num_points; p++ )
592 {
Werner Lembergb5084e12000-10-28 17:10:06 +0000593 map->design_points[p] = T1_ToInt( parser );
594 map->blend_points [p] = T1_ToFixed( parser, 0 );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000595 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000596 }
597
David Turnera39acf52000-08-23 02:47:57 +0000598 parser->root.cursor = old_cursor;
599 parser->root.limit = old_limit;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000600
601 Exit:
David Turnera39acf52000-08-23 02:47:57 +0000602 parser->root.error = error;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000603 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000604
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000605
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000606 static void
607 parse_weight_vector( T1_Face face,
608 T1_Loader* loader )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000609 {
Werner Lembergb5084e12000-10-28 17:10:06 +0000610 FT_Error error = 0;
David Turner4e7eeee2002-02-28 16:10:29 +0000611 T1_Parser parser = &loader->parser;
David Turner29644172002-02-28 18:59:37 +0000612 PS_Blend blend = face->blend;
David Turner4e7eeee2002-02-28 16:10:29 +0000613 T1_TokenRec master;
Werner Lembergb5084e12000-10-28 17:10:06 +0000614 FT_UInt n;
615 FT_Byte* old_cursor;
616 FT_Byte* old_limit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000617
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000618
619 if ( !blend || blend->num_designs == 0 )
620 {
621 FT_ERROR(( "parse_weight_vector: too early!\n" ));
622 error = T1_Err_Invalid_File_Format;
623 goto Exit;
624 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000625
Werner Lembergb5084e12000-10-28 17:10:06 +0000626 T1_ToToken( parser, &master );
David Turner4e7eeee2002-02-28 16:10:29 +0000627 if ( master.type != T1_TOKEN_TYPE_ARRAY )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000628 {
629 FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
630 error = T1_Err_Invalid_File_Format;
631 goto Exit;
632 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000633
David Turnera39acf52000-08-23 02:47:57 +0000634 old_cursor = parser->root.cursor;
635 old_limit = parser->root.limit;
Werner Lembergb48a6092000-07-09 19:15:30 +0000636
David Turnera39acf52000-08-23 02:47:57 +0000637 parser->root.cursor = master.start;
638 parser->root.limit = master.limit;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000639
640 for ( n = 0; n < blend->num_designs; n++ )
641 {
642 blend->default_weight_vector[n] =
Werner Lembergb5084e12000-10-28 17:10:06 +0000643 blend->weight_vector[n] = T1_ToFixed( parser, 0 );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000644 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000645
David Turnera39acf52000-08-23 02:47:57 +0000646 parser->root.cursor = old_cursor;
647 parser->root.limit = old_limit;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000648
649 Exit:
David Turnera39acf52000-08-23 02:47:57 +0000650 parser->root.error = error;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000651 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000652
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000653
654 /* the keyword `/shareddict' appears in some multiple master fonts */
655 /* with a lot of Postscript garbage behind it (that's completely out */
656 /* of spec!); we detect it and terminate the parsing */
657 /* */
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000658 static void
659 parse_shared_dict( T1_Face face,
660 T1_Loader* loader )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000661 {
David Turner4e7eeee2002-02-28 16:10:29 +0000662 T1_Parser parser = &loader->parser;
Werner Lembergb48a6092000-07-09 19:15:30 +0000663
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000664 FT_UNUSED( face );
Werner Lembergb48a6092000-07-09 19:15:30 +0000665
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000666
David Turnera39acf52000-08-23 02:47:57 +0000667 parser->root.cursor = parser->root.limit;
668 parser->root.error = 0;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000669 }
670
Werner Lembergb5084e12000-10-28 17:10:06 +0000671#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000672
Werner Lembergb48a6092000-07-09 19:15:30 +0000673
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000674 /*************************************************************************/
675 /*************************************************************************/
676 /***** *****/
677 /***** TYPE 1 SYMBOL PARSING *****/
678 /***** *****/
679 /*************************************************************************/
680 /*************************************************************************/
681
682
683 /*************************************************************************/
684 /* */
685 /* First of all, define the token field static variables. This is a set */
David Turner4e7eeee2002-02-28 16:10:29 +0000686 /* of T1_FieldRec variables used later. */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000687 /* */
688 /*************************************************************************/
689
David Turner1c9a1ca2000-05-24 21:12:02 +0000690
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000691 static FT_Error
692 t1_load_keyword( T1_Face face,
693 T1_Loader* loader,
David Turner4e7eeee2002-02-28 16:10:29 +0000694 T1_Field field )
David Turner1c9a1ca2000-05-24 21:12:02 +0000695 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000696 FT_Error error;
697 void* dummy_object;
698 void** objects;
699 FT_UInt max_objects;
David Turner29644172002-02-28 18:59:37 +0000700 PS_Blend blend = face->blend;
Werner Lembergb48a6092000-07-09 19:15:30 +0000701
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000702
David Turner1c9a1ca2000-05-24 21:12:02 +0000703 /* if the keyword has a dedicated callback, call it */
David Turner4e7eeee2002-02-28 16:10:29 +0000704 if ( field->type == T1_FIELD_TYPE_CALLBACK )
David Turner1c9a1ca2000-05-24 21:12:02 +0000705 {
David Turner34f1c2f2000-08-23 22:47:44 +0000706 field->reader( (FT_Face)face, loader );
David Turnera39acf52000-08-23 02:47:57 +0000707 error = loader->parser.root.error;
David Turner1c9a1ca2000-05-24 21:12:02 +0000708 goto Exit;
709 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000710
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000711 /* now, the keyword is either a simple field, or a table of fields; */
712 /* we are now going to take care of it */
David Turner34f1c2f2000-08-23 22:47:44 +0000713 switch ( field->location )
David Turner1c9a1ca2000-05-24 21:12:02 +0000714 {
David Turner429978b2002-03-14 10:09:35 +0000715 case T1_FIELD_LOCATION_FONT_INFO:
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000716 dummy_object = &face->type1.font_info;
717 objects = &dummy_object;
718 max_objects = 0;
719
720 if ( blend )
721 {
722 objects = (void**)blend->font_infos;
723 max_objects = blend->num_designs;
724 }
725 break;
Werner Lembergb48a6092000-07-09 19:15:30 +0000726
David Turner429978b2002-03-14 10:09:35 +0000727 case T1_FIELD_LOCATION_PRIVATE:
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000728 dummy_object = &face->type1.private_dict;
729 objects = &dummy_object;
730 max_objects = 0;
731
732 if ( blend )
733 {
734 objects = (void**)blend->privates;
735 max_objects = blend->num_designs;
736 }
737 break;
Werner Lembergb48a6092000-07-09 19:15:30 +0000738
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000739 default:
740 dummy_object = &face->type1;
741 objects = &dummy_object;
742 max_objects = 0;
David Turner1c9a1ca2000-05-24 21:12:02 +0000743 }
Werner Lembergb48a6092000-07-09 19:15:30 +0000744
David Turner4e7eeee2002-02-28 16:10:29 +0000745 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
746 field->type == T1_FIELD_TYPE_FIXED_ARRAY )
Werner Lembergb5084e12000-10-28 17:10:06 +0000747 error = T1_Load_Field_Table( &loader->parser, field,
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000748 objects, max_objects, 0 );
David Turner1c9a1ca2000-05-24 21:12:02 +0000749 else
Werner Lembergb5084e12000-10-28 17:10:06 +0000750 error = T1_Load_Field( &loader->parser, field,
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000751 objects, max_objects, 0 );
Werner Lembergb48a6092000-07-09 19:15:30 +0000752
David Turner1c9a1ca2000-05-24 21:12:02 +0000753 Exit:
754 return error;
Werner Lembergb48a6092000-07-09 19:15:30 +0000755 }
David Turner2dfb5ac2000-01-27 14:02:04 +0000756
757
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000758 static int
759 is_space( FT_Byte c )
David Turner2dfb5ac2000-01-27 14:02:04 +0000760 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000761 return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
David Turner2dfb5ac2000-01-27 14:02:04 +0000762 }
763
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000764
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000765 static int
766 is_alpha( FT_Byte c )
David Turner2dfb5ac2000-01-27 14:02:04 +0000767 {
David Turner8ab0add2001-08-30 07:59:28 +0000768 /* Note: we must accept "+" as a valid character, as it is used in */
Werner Lembergec342902001-09-10 06:55:43 +0000769 /* embedded type1 fonts in PDF documents. */
David Turner8ab0add2001-08-30 07:59:28 +0000770 /* */
771 return ( isalnum( c ) || c == '.' || c == '_' || c == '-' || c == '+' );
David Turner2dfb5ac2000-01-27 14:02:04 +0000772 }
773
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000774
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000775 static int
David Turner4e7eeee2002-02-28 16:10:29 +0000776 read_binary_data( T1_Parser parser,
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000777 FT_Int* size,
778 FT_Byte** base )
David Turner2dfb5ac2000-01-27 14:02:04 +0000779 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000780 FT_Byte* cur;
David Turnera39acf52000-08-23 02:47:57 +0000781 FT_Byte* limit = parser->root.limit;
David Turnere49ab252000-05-16 23:44:38 +0000782
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000783
David Turner2dfb5ac2000-01-27 14:02:04 +0000784 /* the binary data has the following format */
785 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000786 /* `size' [white*] RD white ....... ND */
David Turner2dfb5ac2000-01-27 14:02:04 +0000787 /* */
David Turnere49ab252000-05-16 23:44:38 +0000788
Werner Lembergb5084e12000-10-28 17:10:06 +0000789 T1_Skip_Spaces( parser );
David Turnera39acf52000-08-23 02:47:57 +0000790 cur = parser->root.cursor;
David Turnere49ab252000-05-16 23:44:38 +0000791
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000792 if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
David Turner2dfb5ac2000-01-27 14:02:04 +0000793 {
Werner Lembergb5084e12000-10-28 17:10:06 +0000794 *size = T1_ToInt( parser );
David Turnere49ab252000-05-16 23:44:38 +0000795
Werner Lembergb5084e12000-10-28 17:10:06 +0000796 T1_Skip_Spaces( parser );
797 T1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */
David Turnere49ab252000-05-16 23:44:38 +0000798
David Turner2dfb5ac2000-01-27 14:02:04 +0000799 /* there is only one whitespace char after the */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000800 /* `RD' or `-|' token */
David Turnera39acf52000-08-23 02:47:57 +0000801 *base = parser->root.cursor + 1;
David Turnere49ab252000-05-16 23:44:38 +0000802
Werner Lemberg8728f292000-08-23 17:32:42 +0000803 parser->root.cursor += *size + 1;
David Turner2dfb5ac2000-01-27 14:02:04 +0000804 return 1;
805 }
806
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000807 FT_ERROR(( "read_binary_data: invalid size field\n" ));
David Turnera39acf52000-08-23 02:47:57 +0000808 parser->root.error = T1_Err_Invalid_File_Format;
David Turner2dfb5ac2000-01-27 14:02:04 +0000809 return 0;
810 }
811
812
813 /* we will now define the routines used to handle */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000814 /* the `/Encoding', `/Subrs', and `/CharStrings' */
815 /* dictionaries */
David Turner2dfb5ac2000-01-27 14:02:04 +0000816
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000817 static void
818 parse_font_name( T1_Face face,
819 T1_Loader* loader )
David Turner2dfb5ac2000-01-27 14:02:04 +0000820 {
David Turner4e7eeee2002-02-28 16:10:29 +0000821 T1_Parser parser = &loader->parser;
Werner Lembergb5084e12000-10-28 17:10:06 +0000822 FT_Error error;
823 FT_Memory memory = parser->root.memory;
824 FT_Int len;
825 FT_Byte* cur;
826 FT_Byte* cur2;
827 FT_Byte* limit;
David Turnere49ab252000-05-16 23:44:38 +0000828
Werner Lembergc3b21602001-12-05 01:22:05 +0000829
Tom Kacvinsky48f26bc2001-10-20 17:44:48 +0000830 if ( face->type1.font_name )
831 /* with synthetic fonts, it's possible we get here twice */
832 return;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000833
Werner Lembergb5084e12000-10-28 17:10:06 +0000834 T1_Skip_Spaces( parser );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000835
David Turnera39acf52000-08-23 02:47:57 +0000836 cur = parser->root.cursor;
837 limit = parser->root.limit;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000838
839 if ( cur >= limit - 1 || *cur != '/' )
840 return;
David Turnere49ab252000-05-16 23:44:38 +0000841
David Turner2dfb5ac2000-01-27 14:02:04 +0000842 cur++;
843 cur2 = cur;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000844 while ( cur2 < limit && is_alpha( *cur2 ) )
845 cur2++;
846
Werner Lemberg914b2892001-03-10 17:07:42 +0000847 len = (FT_Int)( cur2 - cur );
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000848 if ( len > 0 )
David Turner2dfb5ac2000-01-27 14:02:04 +0000849 {
David Turnere459d742002-03-22 13:52:37 +0000850 if ( FT_ALLOC( face->type1.font_name, len + 1 ) )
David Turner2dfb5ac2000-01-27 14:02:04 +0000851 {
David Turnera39acf52000-08-23 02:47:57 +0000852 parser->root.error = error;
David Turner2dfb5ac2000-01-27 14:02:04 +0000853 return;
854 }
David Turnere49ab252000-05-16 23:44:38 +0000855
David Turnere459d742002-03-22 13:52:37 +0000856 FT_MEM_COPY( face->type1.font_name, cur, len );
David Turner2dfb5ac2000-01-27 14:02:04 +0000857 face->type1.font_name[len] = '\0';
858 }
David Turnera39acf52000-08-23 02:47:57 +0000859 parser->root.cursor = cur2;
David Turner2dfb5ac2000-01-27 14:02:04 +0000860 }
861
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000862
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000863 static void
864 parse_font_bbox( T1_Face face,
865 T1_Loader* loader )
David Turner2dfb5ac2000-01-27 14:02:04 +0000866 {
David Turner4e7eeee2002-02-28 16:10:29 +0000867 T1_Parser parser = &loader->parser;
Tom Kacvinsky5d362b62001-03-10 19:08:44 +0000868 FT_Fixed temp[4];
Werner Lembergb5084e12000-10-28 17:10:06 +0000869 FT_BBox* bbox = &face->type1.font_bbox;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000870
David Turnere49ab252000-05-16 23:44:38 +0000871
Tom Kacvinsky5d362b62001-03-10 19:08:44 +0000872 (void)T1_ToFixedArray( parser, 4, temp, 0 );
873 bbox->xMin = FT_RoundFix( temp[0] );
874 bbox->yMin = FT_RoundFix( temp[1] );
875 bbox->xMax = FT_RoundFix( temp[2] );
876 bbox->yMax = FT_RoundFix( temp[3] );
David Turner2dfb5ac2000-01-27 14:02:04 +0000877 }
878
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000879
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000880 static void
881 parse_font_matrix( T1_Face face,
882 T1_Loader* loader )
David Turner1c9a1ca2000-05-24 21:12:02 +0000883 {
David Turner4e7eeee2002-02-28 16:10:29 +0000884 T1_Parser parser = &loader->parser;
Werner Lembergb5084e12000-10-28 17:10:06 +0000885 FT_Matrix* matrix = &face->type1.font_matrix;
886 FT_Vector* offset = &face->type1.font_offset;
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +0000887 FT_Face root = (FT_Face)&face->root;
Werner Lembergb5084e12000-10-28 17:10:06 +0000888 FT_Fixed temp[6];
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +0000889 FT_Fixed temp_scale;
David Turner1c9a1ca2000-05-24 21:12:02 +0000890
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000891
Just van Rossum7c644092000-08-01 04:29:25 +0000892 if ( matrix->xx || matrix->yx )
893 /* with synthetic fonts, it's possible we get here twice */
894 return;
895
Werner Lembergb5084e12000-10-28 17:10:06 +0000896 (void)T1_ToFixedArray( parser, 6, temp, 3 );
David Turner24d70242000-08-17 01:09:06 +0000897
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +0000898 temp_scale = ABS( temp[3] );
899
Werner Lembergec342902001-09-10 06:55:43 +0000900 /* Set Units per EM based on FontMatrix values. We set the value to */
901 /* 1000 / temp_scale, because temp_scale was already multiplied by */
902 /* 1000 (in t1_tofixed, from psobjs.c). */
Tom Kacvinskyf3dad682001-03-19 13:52:31 +0000903
Werner Lembergec342902001-09-10 06:55:43 +0000904 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
905 temp_scale ) >> 16 );
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +0000906
907 /* we need to scale the values by 1.0/temp_scale */
908 if ( temp_scale != 0x10000L )
David Turner24d70242000-08-17 01:09:06 +0000909 {
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +0000910 temp[0] = FT_DivFix( temp[0], temp_scale );
911 temp[1] = FT_DivFix( temp[1], temp_scale );
912 temp[2] = FT_DivFix( temp[2], temp_scale );
913 temp[4] = FT_DivFix( temp[4], temp_scale );
914 temp[5] = FT_DivFix( temp[5], temp_scale );
Werner Lembergb1c8bf02000-08-17 07:18:04 +0000915 temp[3] = 0x10000L;
David Turner24d70242000-08-17 01:09:06 +0000916 }
917
David Turner1c9a1ca2000-05-24 21:12:02 +0000918 matrix->xx = temp[0];
919 matrix->yx = temp[1];
920 matrix->xy = temp[2];
921 matrix->yy = temp[3];
Werner Lemberge4b32a52000-10-31 20:42:18 +0000922
Werner Lemberg6fbe4db2000-10-05 04:53:31 +0000923 /* note that the offsets must be expressed in integer font units */
David Turnerf00a4de2000-10-03 22:03:09 +0000924 offset->x = temp[4] >> 16;
925 offset->y = temp[5] >> 16;
David Turner1c9a1ca2000-05-24 21:12:02 +0000926 }
927
928
Werner Lemberg4a2305c2001-06-28 07:17:51 +0000929 static void
930 parse_encoding( T1_Face face,
931 T1_Loader* loader )
David Turner2dfb5ac2000-01-27 14:02:04 +0000932 {
David Turner4e7eeee2002-02-28 16:10:29 +0000933 T1_Parser parser = &loader->parser;
Werner Lembergb5084e12000-10-28 17:10:06 +0000934 FT_Byte* cur = parser->root.cursor;
935 FT_Byte* limit = parser->root.limit;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000936
David Turner4e7eeee2002-02-28 16:10:29 +0000937 PSAux_Service psaux = (PSAux_Service)face->psaux;
David Turnere49ab252000-05-16 23:44:38 +0000938
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000939
David Turner2dfb5ac2000-01-27 14:02:04 +0000940 /* skip whitespace */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000941 while ( is_space( *cur ) )
David Turner2dfb5ac2000-01-27 14:02:04 +0000942 {
943 cur++;
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000944 if ( cur >= limit )
David Turner2dfb5ac2000-01-27 14:02:04 +0000945 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000946 FT_ERROR(( "parse_encoding: out of bounds!\n" ));
David Turnera39acf52000-08-23 02:47:57 +0000947 parser->root.error = T1_Err_Invalid_File_Format;
David Turner2dfb5ac2000-01-27 14:02:04 +0000948 return;
949 }
950 }
David Turnere49ab252000-05-16 23:44:38 +0000951
David Turner2dfb5ac2000-01-27 14:02:04 +0000952 /* if we have a number, then the encoding is an array, */
953 /* and we must load it now */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000954 if ( (FT_Byte)( *cur - '0' ) < 10 )
David Turner2dfb5ac2000-01-27 14:02:04 +0000955 {
David Turner29644172002-02-28 18:59:37 +0000956 T1_Encoding encode = &face->type1.encoding;
David Turnerf9b8dec2000-06-16 19:34:52 +0000957 FT_Int count, n;
David Turner4e7eeee2002-02-28 16:10:29 +0000958 PS_Table char_table = &loader->encoding_table;
David Turnera39acf52000-08-23 02:47:57 +0000959 FT_Memory memory = parser->root.memory;
David Turnerf9b8dec2000-06-16 19:34:52 +0000960 FT_Error error;
David Turnere49ab252000-05-16 23:44:38 +0000961
Werner Lembergc3b21602001-12-05 01:22:05 +0000962
Tom Kacvinsky629bf282001-10-20 20:46:36 +0000963 if ( encode->char_index )
964 /* with synthetic fonts, it's possible we get here twice */
965 return;
966
David Turner2dfb5ac2000-01-27 14:02:04 +0000967 /* read the number of entries in the encoding, should be 256 */
Werner Lembergb5084e12000-10-28 17:10:06 +0000968 count = T1_ToInt( parser );
David Turnera39acf52000-08-23 02:47:57 +0000969 if ( parser->root.error )
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000970 return;
David Turner2dfb5ac2000-01-27 14:02:04 +0000971
Werner Lembergb5084e12000-10-28 17:10:06 +0000972 /* we use a T1_Table to store our charnames */
Werner Lemberg556ad082002-01-28 13:34:52 +0000973 loader->num_chars = encode->num_chars = count;
David Turnere459d742002-03-22 13:52:37 +0000974 if ( FT_NEW_ARRAY( encode->char_index, count ) ||
975 FT_NEW_ARRAY( encode->char_name, count ) ||
976 FT_SET_ERROR( psaux->ps_table_funcs->init(
977 char_table, count, memory ) ) )
David Turner2dfb5ac2000-01-27 14:02:04 +0000978 {
David Turnera39acf52000-08-23 02:47:57 +0000979 parser->root.error = error;
David Turner2dfb5ac2000-01-27 14:02:04 +0000980 return;
981 }
David Turnere49ab252000-05-16 23:44:38 +0000982
Tom Kacvinsky40822002000-10-17 20:25:30 +0000983 /* We need to `zero' out encoding_table.elements */
Werner Lemberg05f0ad02000-10-19 05:12:00 +0000984 for ( n = 0; n < count; n++ )
Tom Kacvinsky40822002000-10-17 20:25:30 +0000985 {
Werner Lemberga13a4732000-11-02 15:14:38 +0000986 char* notdef = (char *)".notdef";
Werner Lemberg05f0ad02000-10-19 05:12:00 +0000987
988
Werner Lembergb5084e12000-10-28 17:10:06 +0000989 T1_Add_Table( char_table, n, notdef, 8 );
Tom Kacvinsky40822002000-10-17 20:25:30 +0000990 }
991
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000992 /* Now, we will need to read a record of the form */
David Turner2dfb5ac2000-01-27 14:02:04 +0000993 /* ... charcode /charname ... for each entry in our table */
994 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +0000995 /* We simply look for a number followed by an immediate */
996 /* name. Note that this ignores correctly the sequence */
997 /* that is often seen in type1 fonts: */
David Turner2dfb5ac2000-01-27 14:02:04 +0000998 /* */
999 /* 0 1 255 { 1 index exch /.notdef put } for dup */
1000 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001001 /* used to clean the encoding array before anything else. */
David Turner2dfb5ac2000-01-27 14:02:04 +00001002 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001003 /* We stop when we encounter a `def'. */
David Turner2dfb5ac2000-01-27 14:02:04 +00001004
David Turnera39acf52000-08-23 02:47:57 +00001005 cur = parser->root.cursor;
1006 limit = parser->root.limit;
David Turner2dfb5ac2000-01-27 14:02:04 +00001007 n = 0;
1008
1009 for ( ; cur < limit; )
1010 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001011 FT_Byte c;
David Turnere49ab252000-05-16 23:44:38 +00001012
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001013
David Turner2dfb5ac2000-01-27 14:02:04 +00001014 c = *cur;
David Turnere49ab252000-05-16 23:44:38 +00001015
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001016 /* we stop when we encounter a `def' */
1017 if ( c == 'd' && cur + 3 < limit )
David Turner2dfb5ac2000-01-27 14:02:04 +00001018 {
1019 if ( cur[1] == 'e' &&
1020 cur[2] == 'f' &&
David Turner95bec282000-02-15 12:55:57 +00001021 is_space(cur[-1]) &&
David Turner2dfb5ac2000-01-27 14:02:04 +00001022 is_space(cur[3]) )
David Turner95bec282000-02-15 12:55:57 +00001023 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001024 FT_TRACE6(( "encoding end\n" ));
1025 break;
David Turner95bec282000-02-15 12:55:57 +00001026 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001027 }
David Turnere49ab252000-05-16 23:44:38 +00001028
David Turner2dfb5ac2000-01-27 14:02:04 +00001029 /* otherwise, we must find a number before anything else */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001030 if ( (FT_Byte)( c - '0' ) < 10 )
David Turner2dfb5ac2000-01-27 14:02:04 +00001031 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001032 FT_Int charcode;
David Turnere49ab252000-05-16 23:44:38 +00001033
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001034
David Turnera39acf52000-08-23 02:47:57 +00001035 parser->root.cursor = cur;
Werner Lembergb5084e12000-10-28 17:10:06 +00001036 charcode = T1_ToInt( parser );
David Turnera39acf52000-08-23 02:47:57 +00001037 cur = parser->root.cursor;
David Turnere49ab252000-05-16 23:44:38 +00001038
David Turner2dfb5ac2000-01-27 14:02:04 +00001039 /* skip whitespace */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001040 while ( cur < limit && is_space( *cur ) )
1041 cur++;
David Turnere49ab252000-05-16 23:44:38 +00001042
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001043 if ( cur < limit && *cur == '/' )
David Turner2dfb5ac2000-01-27 14:02:04 +00001044 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001045 /* bingo, we have an immediate name -- it must be a */
1046 /* character name */
1047 FT_Byte* cur2 = cur + 1;
David Turnerf9b8dec2000-06-16 19:34:52 +00001048 FT_Int len;
David Turnere49ab252000-05-16 23:44:38 +00001049
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001050
1051 while ( cur2 < limit && is_alpha( *cur2 ) )
1052 cur2++;
1053
Werner Lemberg914b2892001-03-10 17:07:42 +00001054 len = (FT_Int)( cur2 - cur - 1 );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001055
Werner Lembergb5084e12000-10-28 17:10:06 +00001056 parser->root.error = T1_Add_Table( char_table, charcode,
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001057 cur + 1, len + 1 );
David Turner2dfb5ac2000-01-27 14:02:04 +00001058 char_table->elements[charcode][len] = '\0';
David Turnera39acf52000-08-23 02:47:57 +00001059 if ( parser->root.error )
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001060 return;
David Turnere49ab252000-05-16 23:44:38 +00001061
David Turner2dfb5ac2000-01-27 14:02:04 +00001062 cur = cur2;
1063 }
1064 }
1065 else
1066 cur++;
1067 }
David Turnere49ab252000-05-16 23:44:38 +00001068
David Turner29644172002-02-28 18:59:37 +00001069 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
Werner Lemberg8728f292000-08-23 17:32:42 +00001070 parser->root.cursor = cur;
David Turner2dfb5ac2000-01-27 14:02:04 +00001071 }
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001072 /* Otherwise, we should have either `StandardEncoding' or */
1073 /* `ExpertEncoding' */
David Turner2dfb5ac2000-01-27 14:02:04 +00001074 else
1075 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001076 if ( cur + 17 < limit &&
David Turner0dd34342000-02-02 12:20:53 +00001077 strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
David Turner29644172002-02-28 18:59:37 +00001078 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
David Turnere49ab252000-05-16 23:44:38 +00001079
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001080 else if ( cur + 15 < limit &&
David Turner0dd34342000-02-02 12:20:53 +00001081 strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
David Turner29644172002-02-28 18:59:37 +00001082 face->type1.encoding_type = T1_ENCODING_TYPE_EXPORT;
David Turner2dfb5ac2000-01-27 14:02:04 +00001083
Werner Lemberg66b35092002-02-10 12:33:14 +00001084 else if ( cur + 18 < limit &&
1085 strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
David Turner29644172002-02-28 18:59:37 +00001086 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
Werner Lemberg66b35092002-02-10 12:33:14 +00001087
David Turner2dfb5ac2000-01-27 14:02:04 +00001088 else
1089 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001090 FT_ERROR(( "parse_encoding: invalid token!\n" ));
David Turnera39acf52000-08-23 02:47:57 +00001091 parser->root.error = T1_Err_Invalid_File_Format;
David Turnere49ab252000-05-16 23:44:38 +00001092 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001093 }
1094 }
1095
1096
Werner Lemberg4a2305c2001-06-28 07:17:51 +00001097 static void
1098 parse_subrs( T1_Face face,
1099 T1_Loader* loader )
David Turner2dfb5ac2000-01-27 14:02:04 +00001100 {
David Turner9ddeee12002-03-06 12:36:22 +00001101 T1_Parser parser = &loader->parser;
1102 PS_Table table = &loader->subrs;
Werner Lembergb5084e12000-10-28 17:10:06 +00001103 FT_Memory memory = parser->root.memory;
1104 FT_Error error;
1105 FT_Int n;
David Turnere49ab252000-05-16 23:44:38 +00001106
David Turner4e7eeee2002-02-28 16:10:29 +00001107 PSAux_Service psaux = (PSAux_Service)face->psaux;
Werner Lemberg8728f292000-08-23 17:32:42 +00001108
Werner Lembergc3b21602001-12-05 01:22:05 +00001109
Tom Kacvinsky48f26bc2001-10-20 17:44:48 +00001110 if ( loader->num_subrs )
1111 /* with synthetic fonts, it's possible we get here twice */
1112 return;
Werner Lemberge4b32a52000-10-31 20:42:18 +00001113
Werner Lembergb5084e12000-10-28 17:10:06 +00001114 loader->num_subrs = T1_ToInt( parser );
David Turnera39acf52000-08-23 02:47:57 +00001115 if ( parser->root.error )
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001116 return;
David Turnere49ab252000-05-16 23:44:38 +00001117
Werner Lembergd082cd62000-07-25 17:25:32 +00001118 /* position the parser right before the `dup' of the first subr */
Werner Lembergb5084e12000-10-28 17:10:06 +00001119 T1_Skip_Spaces( parser );
1120 T1_Skip_Alpha( parser ); /* `array' */
1121 T1_Skip_Spaces( parser );
Just van Rossum53fb1f52000-07-25 16:20:57 +00001122
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001123 /* initialize subrs array */
David Turnera39acf52000-08-23 02:47:57 +00001124 error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001125 if ( error )
1126 goto Fail;
David Turner2dfb5ac2000-01-27 14:02:04 +00001127
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001128 /* the format is simple: */
David Turner2dfb5ac2000-01-27 14:02:04 +00001129 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001130 /* `index' + binary data */
David Turner2dfb5ac2000-01-27 14:02:04 +00001131 /* */
David Turnere49ab252000-05-16 23:44:38 +00001132
David Turner2dfb5ac2000-01-27 14:02:04 +00001133 for ( n = 0; n < loader->num_subrs; n++ )
1134 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001135 FT_Int idx, size;
David Turnerf9b8dec2000-06-16 19:34:52 +00001136 FT_Byte* base;
David Turnere49ab252000-05-16 23:44:38 +00001137
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001138
Werner Lembergd082cd62000-07-25 17:25:32 +00001139 /* If the next token isn't `dup', we are also done. This */
1140 /* happens when there are `holes' in the Subrs array. */
David Turnera39acf52000-08-23 02:47:57 +00001141 if ( strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
Just van Rossum53fb1f52000-07-25 16:20:57 +00001142 break;
1143
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001144 idx = T1_ToInt( parser );
Werner Lemberge4b32a52000-10-31 20:42:18 +00001145
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001146 if ( !read_binary_data( parser, &size, &base ) )
1147 return;
David Turnere49ab252000-05-16 23:44:38 +00001148
Werner Lembergd082cd62000-07-25 17:25:32 +00001149 /* The binary string is followed by one token, e.g. `NP' */
1150 /* (bound to `noaccess put') or by two separate tokens: */
1151 /* `noaccess' & `put'. We position the parser right */
1152 /* before the next `dup', if any. */
Werner Lembergb5084e12000-10-28 17:10:06 +00001153 T1_Skip_Spaces( parser );
1154 T1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */
1155 T1_Skip_Spaces( parser );
Werner Lembergd082cd62000-07-25 17:25:32 +00001156
David Turnera39acf52000-08-23 02:47:57 +00001157 if ( strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
Just van Rossum53fb1f52000-07-25 16:20:57 +00001158 {
Werner Lembergb5084e12000-10-28 17:10:06 +00001159 T1_Skip_Alpha( parser ); /* skip `put' */
1160 T1_Skip_Spaces( parser );
Just van Rossum53fb1f52000-07-25 16:20:57 +00001161 }
1162
David Turnerd0079e62000-06-23 00:07:06 +00001163 /* some fonts use a value of -1 for lenIV to indicate that */
Werner Lembergd082cd62000-07-25 17:25:32 +00001164 /* the charstrings are unencoded */
David Turnerd0079e62000-06-23 00:07:06 +00001165 /* */
Werner Lembergd082cd62000-07-25 17:25:32 +00001166 /* thanks to Tom Kacvinsky for pointing this out */
David Turnerd0079e62000-06-23 00:07:06 +00001167 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001168 if ( face->type1.private_dict.lenIV >= 0 )
David Turnerd0079e62000-06-23 00:07:06 +00001169 {
Werner Lemberg556ad082002-01-28 13:34:52 +00001170 FT_Byte* temp;
David Turner95bec282000-02-15 12:55:57 +00001171
Werner Lemberg556ad082002-01-28 13:34:52 +00001172
1173 /* t1_decrypt() shouldn't write to base -- make temporary copy */
David Turnere459d742002-03-22 13:52:37 +00001174 if ( FT_ALLOC( temp, size ) )
Werner Lemberg556ad082002-01-28 13:34:52 +00001175 goto Fail;
David Turnere459d742002-03-22 13:52:37 +00001176 FT_MEM_COPY( temp, base, size );
Werner Lemberg556ad082002-01-28 13:34:52 +00001177 psaux->t1_decrypt( temp, size, 4330 );
1178 size -= face->type1.private_dict.lenIV;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001179 error = T1_Add_Table( table, idx,
Werner Lemberg556ad082002-01-28 13:34:52 +00001180 temp + face->type1.private_dict.lenIV, size );
David Turnere459d742002-03-22 13:52:37 +00001181 FT_FREE( temp );
Werner Lemberg556ad082002-01-28 13:34:52 +00001182 }
1183 else
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001184 error = T1_Add_Table( table, idx, base, size );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001185 if ( error )
1186 goto Fail;
David Turner2dfb5ac2000-01-27 14:02:04 +00001187 }
1188 return;
1189
1190 Fail:
David Turnera39acf52000-08-23 02:47:57 +00001191 parser->root.error = error;
David Turner2dfb5ac2000-01-27 14:02:04 +00001192 }
1193
1194
Werner Lemberg4a2305c2001-06-28 07:17:51 +00001195 static void
1196 parse_charstrings( T1_Face face,
1197 T1_Loader* loader )
David Turner2dfb5ac2000-01-27 14:02:04 +00001198 {
David Turner4e7eeee2002-02-28 16:10:29 +00001199 T1_Parser parser = &loader->parser;
1200 PS_Table code_table = &loader->charstrings;
1201 PS_Table name_table = &loader->glyph_names;
1202 PS_Table swap_table = &loader->swap_table;
Werner Lembergb5084e12000-10-28 17:10:06 +00001203 FT_Memory memory = parser->root.memory;
1204 FT_Error error;
David Turner2dfb5ac2000-01-27 14:02:04 +00001205
David Turner4e7eeee2002-02-28 16:10:29 +00001206 PSAux_Service psaux = (PSAux_Service)face->psaux;
David Turnera39acf52000-08-23 02:47:57 +00001207
David Turnerf9b8dec2000-06-16 19:34:52 +00001208 FT_Byte* cur;
David Turnera39acf52000-08-23 02:47:57 +00001209 FT_Byte* limit = parser->root.limit;
David Turnerf9b8dec2000-06-16 19:34:52 +00001210 FT_Int n;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001211 FT_UInt notdef_index = 0;
1212 FT_Byte notdef_found = 0;
David Turnere49ab252000-05-16 23:44:38 +00001213
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001214
Just van Rossum7c644092000-08-01 04:29:25 +00001215 if ( loader->num_glyphs )
1216 /* with synthetic fonts, it's possible we get here twice */
1217 return;
1218
Werner Lembergb5084e12000-10-28 17:10:06 +00001219 loader->num_glyphs = T1_ToInt( parser );
David Turnera39acf52000-08-23 02:47:57 +00001220 if ( parser->root.error )
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001221 return;
1222
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001223 /* initialize tables (leaving room for addition of .notdef, */
David Turner09d55ce2001-05-11 18:08:58 +00001224 /* if necessary). */
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001225
Werner Lemberg8728f292000-08-23 17:32:42 +00001226 error = psaux->ps_table_funcs->init( code_table,
Tom Kacvinsky40822002000-10-17 20:25:30 +00001227 loader->num_glyphs + 1,
Werner Lemberg8728f292000-08-23 17:32:42 +00001228 memory );
1229 if ( error )
David Turnera39acf52000-08-23 02:47:57 +00001230 goto Fail;
1231
Werner Lemberg8728f292000-08-23 17:32:42 +00001232 error = psaux->ps_table_funcs->init( name_table,
Tom Kacvinsky40822002000-10-17 20:25:30 +00001233 loader->num_glyphs + 1,
Werner Lemberg8728f292000-08-23 17:32:42 +00001234 memory );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001235 if ( error )
1236 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00001237
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001238 /* Initialize table for swapping index notdef_index and */
1239 /* index 0 names and codes (if necessary). */
1240
1241 error = psaux->ps_table_funcs->init( swap_table, 4, memory );
1242
1243 if ( error )
1244 goto Fail;
1245
1246
David Turner2dfb5ac2000-01-27 14:02:04 +00001247 n = 0;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001248 for (;;)
David Turner2dfb5ac2000-01-27 14:02:04 +00001249 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001250 FT_Int size;
1251 FT_Byte* base;
David Turnere49ab252000-05-16 23:44:38 +00001252
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001253
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001254 /* the format is simple: */
1255 /* `/glyphname' + binary data */
David Turner2dfb5ac2000-01-27 14:02:04 +00001256 /* */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001257 /* note that we stop when we find a `def' */
David Turner2dfb5ac2000-01-27 14:02:04 +00001258 /* */
Werner Lembergb5084e12000-10-28 17:10:06 +00001259 T1_Skip_Spaces( parser );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001260
David Turnera39acf52000-08-23 02:47:57 +00001261 cur = parser->root.cursor;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001262 if ( cur >= limit )
David Turner2dfb5ac2000-01-27 14:02:04 +00001263 break;
1264
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001265 /* we stop when we find a `def' or `end' keyword */
1266 if ( *cur == 'd' &&
1267 cur + 3 < limit &&
1268 cur[1] == 'e' &&
1269 cur[2] == 'f' )
David Turner95bec282000-02-15 12:55:57 +00001270 break;
1271
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001272 if ( *cur == 'e' &&
1273 cur + 3 < limit &&
1274 cur[1] == 'n' &&
1275 cur[2] == 'd' )
1276 break;
1277
1278 if ( *cur != '/' )
Werner Lembergb5084e12000-10-28 17:10:06 +00001279 T1_Skip_Alpha( parser );
David Turner2dfb5ac2000-01-27 14:02:04 +00001280 else
1281 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001282 FT_Byte* cur2 = cur + 1;
David Turnerf9b8dec2000-06-16 19:34:52 +00001283 FT_Int len;
David Turnere49ab252000-05-16 23:44:38 +00001284
David Turnere49ab252000-05-16 23:44:38 +00001285
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001286 while ( cur2 < limit && is_alpha( *cur2 ) )
1287 cur2++;
Werner Lemberg914b2892001-03-10 17:07:42 +00001288 len = (FT_Int)( cur2 - cur - 1 );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001289
Werner Lembergb5084e12000-10-28 17:10:06 +00001290 error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001291 if ( error )
1292 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00001293
David Turner2dfb5ac2000-01-27 14:02:04 +00001294 /* add a trailing zero to the name table */
1295 name_table->elements[n][len] = '\0';
David Turnere49ab252000-05-16 23:44:38 +00001296
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001297 /* record index of /.notdef */
1298 if ( strcmp( (const char*)".notdef",
1299 (const char*)(name_table->elements[n]) ) == 0 )
1300 {
1301 notdef_index = n;
1302 notdef_found = 1;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001303 }
1304
David Turnera39acf52000-08-23 02:47:57 +00001305 parser->root.cursor = cur2;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001306 if ( !read_binary_data( parser, &size, &base ) )
1307 return;
David Turner95bec282000-02-15 12:55:57 +00001308
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001309 if ( face->type1.private_dict.lenIV >= 0 )
David Turnerd0079e62000-06-23 00:07:06 +00001310 {
Werner Lemberg556ad082002-01-28 13:34:52 +00001311 FT_Byte* temp;
David Turner95bec282000-02-15 12:55:57 +00001312
Werner Lemberg556ad082002-01-28 13:34:52 +00001313
1314 /* t1_decrypt() shouldn't write to base -- make temporary copy */
David Turnere459d742002-03-22 13:52:37 +00001315 if ( FT_ALLOC( temp, size ) )
Werner Lemberg556ad082002-01-28 13:34:52 +00001316 goto Fail;
David Turnere459d742002-03-22 13:52:37 +00001317 FT_MEM_COPY( temp, base, size );
Werner Lemberg556ad082002-01-28 13:34:52 +00001318 psaux->t1_decrypt( temp, size, 4330 );
1319 size -= face->type1.private_dict.lenIV;
1320 error = T1_Add_Table( code_table, n,
1321 temp + face->type1.private_dict.lenIV, size );
David Turnere459d742002-03-22 13:52:37 +00001322 FT_FREE( temp );
Werner Lemberg556ad082002-01-28 13:34:52 +00001323 }
1324 else
1325 error = T1_Add_Table( code_table, n, base, size );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001326 if ( error )
1327 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00001328
David Turner2dfb5ac2000-01-27 14:02:04 +00001329 n++;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001330 if ( n >= loader->num_glyphs )
David Turner2dfb5ac2000-01-27 14:02:04 +00001331 break;
1332 }
1333 }
Tom Kacvinsky40822002000-10-17 20:25:30 +00001334
David Turner95bec282000-02-15 12:55:57 +00001335 loader->num_glyphs = n;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001336
1337 /* if /.notdef is found but does not occupy index 0, do our magic. */
1338 if ( strcmp( (const char*)".notdef",
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001339 (const char*)name_table->elements[0] ) &&
1340 notdef_found )
Tom Kacvinsky40822002000-10-17 20:25:30 +00001341 {
Werner Lembergef6ebd62001-04-11 18:09:49 +00001342 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
Tom Kacvinsky9d770c92001-04-11 18:40:27 +00001343 /* name and code entries to swap_table. Then place notdef_index name */
1344 /* and code entries into swap_table. Then swap name and code */
Werner Lembergef6ebd62001-04-11 18:09:49 +00001345 /* entries at indices notdef_index and 0 using values stored in */
1346 /* swap_table. */
Tom Kacvinsky40822002000-10-17 20:25:30 +00001347
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001348 /* Index 0 name */
1349 error = T1_Add_Table( swap_table, 0,
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001350 name_table->elements[0],
1351 name_table->lengths [0] );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001352 if ( error )
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001353 goto Fail;
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001354
1355 /* Index 0 code */
1356 error = T1_Add_Table( swap_table, 1,
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001357 code_table->elements[0],
1358 code_table->lengths [0] );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001359 if ( error )
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001360 goto Fail;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001361
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001362 /* Index notdef_index name */
1363 error = T1_Add_Table( swap_table, 2,
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001364 name_table->elements[notdef_index],
1365 name_table->lengths [notdef_index] );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001366 if ( error )
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001367 goto Fail;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001368
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001369 /* Index notdef_index code */
1370 error = T1_Add_Table( swap_table, 3,
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001371 code_table->elements[notdef_index],
1372 code_table->lengths [notdef_index] );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001373 if ( error )
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001374 goto Fail;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001375
Werner Lembergb5084e12000-10-28 17:10:06 +00001376 error = T1_Add_Table( name_table, notdef_index,
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001377 swap_table->elements[0],
1378 swap_table->lengths [0] );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001379 if ( error )
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001380 goto Fail;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001381
Werner Lembergb5084e12000-10-28 17:10:06 +00001382 error = T1_Add_Table( code_table, notdef_index,
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001383 swap_table->elements[1],
1384 swap_table->lengths [1] );
1385 if ( error )
1386 goto Fail;
1387
1388 error = T1_Add_Table( name_table, 0,
1389 swap_table->elements[2],
1390 swap_table->lengths [2] );
1391 if ( error )
1392 goto Fail;
1393
1394 error = T1_Add_Table( code_table, 0,
1395 swap_table->elements[3],
1396 swap_table->lengths [3] );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001397 if ( error )
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001398 goto Fail;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001399
1400 }
1401 else if ( !notdef_found )
1402 {
1403
1404 /* notdef_index is already 0, or /.notdef is undefined in */
1405 /* charstrings dictionary. Worry about /.notdef undefined. */
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001406 /* We take index 0 and add it to the end of the table(s) */
Tom Kacvinsky40822002000-10-17 20:25:30 +00001407 /* and add our own /.notdef glyph to index 0. */
Werner Lemberge4b32a52000-10-31 20:42:18 +00001408
Tom Kacvinsky40822002000-10-17 20:25:30 +00001409 /* 0 333 hsbw endchar */
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001410 FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
Werner Lemberga13a4732000-11-02 15:14:38 +00001411 char* notdef_name = (char *)".notdef";
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001412
Tom Kacvinsky40822002000-10-17 20:25:30 +00001413
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001414 error = T1_Add_Table( swap_table, 0,
Tom Kacvinsky40822002000-10-17 20:25:30 +00001415 name_table->elements[0],
1416 name_table->lengths [0] );
1417 if ( error )
1418 goto Fail;
1419
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001420 error = T1_Add_Table( swap_table, 1,
Tom Kacvinsky40822002000-10-17 20:25:30 +00001421 code_table->elements[0],
1422 code_table->lengths [0] );
1423 if ( error )
1424 goto Fail;
1425
Werner Lembergb5084e12000-10-28 17:10:06 +00001426 error = T1_Add_Table( name_table, 0, notdef_name, 8 );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001427 if ( error )
1428 goto Fail;
1429
Werner Lembergb5084e12000-10-28 17:10:06 +00001430 error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
Tom Kacvinsky40822002000-10-17 20:25:30 +00001431
1432 if ( error )
1433 goto Fail;
1434
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001435 error = T1_Add_Table( name_table, n,
1436 swap_table->elements[0],
1437 swap_table->lengths [0] );
1438 if ( error )
1439 goto Fail;
1440
1441 error = T1_Add_Table( code_table, n,
1442 swap_table->elements[1],
1443 swap_table->lengths [1] );
1444 if ( error )
1445 goto Fail;
1446
Tom Kacvinsky40822002000-10-17 20:25:30 +00001447 /* we added a glyph. */
1448 loader->num_glyphs = n + 1;
Tom Kacvinsky40822002000-10-17 20:25:30 +00001449 }
1450
David Turner2dfb5ac2000-01-27 14:02:04 +00001451 return;
David Turnere49ab252000-05-16 23:44:38 +00001452
David Turner2dfb5ac2000-01-27 14:02:04 +00001453 Fail:
David Turnera39acf52000-08-23 02:47:57 +00001454 parser->root.error = error;
David Turner2dfb5ac2000-01-27 14:02:04 +00001455 }
1456
1457
David Turner2dfb5ac2000-01-27 14:02:04 +00001458 static
David Turner4e7eeee2002-02-28 16:10:29 +00001459 const T1_FieldRec t1_keywords[] =
David Turner2dfb5ac2000-01-27 14:02:04 +00001460 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001461
David Turner8d3a4012001-03-20 11:14:24 +00001462#include "t1tokens.h"
Werner Lembergb48a6092000-07-09 19:15:30 +00001463
David Turner2dfb5ac2000-01-27 14:02:04 +00001464 /* now add the special functions... */
David Turner34f1c2f2000-08-23 22:47:44 +00001465 T1_FIELD_CALLBACK( "FontName", parse_font_name )
1466 T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
1467 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
1468 T1_FIELD_CALLBACK( "Encoding", parse_encoding )
1469 T1_FIELD_CALLBACK( "Subrs", parse_subrs )
1470 T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001471
Werner Lembergb5084e12000-10-28 17:10:06 +00001472#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
David Turner34f1c2f2000-08-23 22:47:44 +00001473 T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
1474 T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
1475 T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
1476 T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
1477 T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
Werner Lembergb48a6092000-07-09 19:15:30 +00001478#endif
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001479
David Turner429978b2002-03-14 10:09:35 +00001480 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001481 };
1482
1483
Werner Lemberg4a2305c2001-06-28 07:17:51 +00001484 static FT_Error
1485 parse_dict( T1_Face face,
1486 T1_Loader* loader,
1487 FT_Byte* base,
1488 FT_Long size )
David Turner2dfb5ac2000-01-27 14:02:04 +00001489 {
David Turner4e7eeee2002-02-28 16:10:29 +00001490 T1_Parser parser = &loader->parser;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001491
David Turnere49ab252000-05-16 23:44:38 +00001492
David Turnera39acf52000-08-23 02:47:57 +00001493 parser->root.cursor = base;
1494 parser->root.limit = base + size;
1495 parser->root.error = 0;
David Turnere49ab252000-05-16 23:44:38 +00001496
David Turner2dfb5ac2000-01-27 14:02:04 +00001497 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001498 FT_Byte* cur = base;
1499 FT_Byte* limit = cur + size;
David Turnere49ab252000-05-16 23:44:38 +00001500
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001501
1502 for ( ; cur < limit; cur++ )
David Turner2dfb5ac2000-01-27 14:02:04 +00001503 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001504 /* look for `FontDirectory', which causes problems on some fonts */
1505 if ( *cur == 'F' && cur + 25 < limit &&
David Turner1c9a1ca2000-05-24 21:12:02 +00001506 strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1507 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001508 FT_Byte* cur2;
Werner Lembergb48a6092000-07-09 19:15:30 +00001509
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001510
1511 /* skip the `FontDirectory' keyword */
David Turner1c9a1ca2000-05-24 21:12:02 +00001512 cur += 13;
1513 cur2 = cur;
Werner Lembergb48a6092000-07-09 19:15:30 +00001514
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001515 /* lookup the `known' keyword */
1516 while ( cur < limit && *cur != 'k' &&
1517 strncmp( (char*)cur, "known", 5 ) )
David Turner1c9a1ca2000-05-24 21:12:02 +00001518 cur++;
Werner Lembergb48a6092000-07-09 19:15:30 +00001519
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001520 if ( cur < limit )
David Turner1c9a1ca2000-05-24 21:12:02 +00001521 {
David Turner4e7eeee2002-02-28 16:10:29 +00001522 T1_TokenRec token;
Werner Lembergb48a6092000-07-09 19:15:30 +00001523
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001524
1525 /* skip the `known' keyword and the token following it */
David Turner1c9a1ca2000-05-24 21:12:02 +00001526 cur += 5;
David Turnera39acf52000-08-23 02:47:57 +00001527 loader->parser.root.cursor = cur;
Werner Lembergb5084e12000-10-28 17:10:06 +00001528 T1_ToToken( &loader->parser, &token );
Werner Lembergb48a6092000-07-09 19:15:30 +00001529
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001530 /* if the last token was an array, skip it! */
David Turner4e7eeee2002-02-28 16:10:29 +00001531 if ( token.type == T1_TOKEN_TYPE_ARRAY )
David Turnera39acf52000-08-23 02:47:57 +00001532 cur2 = parser->root.cursor;
David Turner1c9a1ca2000-05-24 21:12:02 +00001533 }
1534 cur = cur2;
1535 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001536 /* look for immediates */
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001537 else if ( *cur == '/' && cur + 2 < limit )
David Turner2dfb5ac2000-01-27 14:02:04 +00001538 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001539 FT_Byte* cur2;
1540 FT_Int len;
David Turnere49ab252000-05-16 23:44:38 +00001541
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001542
1543 cur++;
David Turner2dfb5ac2000-01-27 14:02:04 +00001544 cur2 = cur;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001545 while ( cur2 < limit && is_alpha( *cur2 ) )
1546 cur2++;
David Turnere49ab252000-05-16 23:44:38 +00001547
Werner Lemberg914b2892001-03-10 17:07:42 +00001548 len = (FT_Int)( cur2 - cur );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001549 if ( len > 0 && len < 22 )
David Turner2dfb5ac2000-01-27 14:02:04 +00001550 {
David Turner1c9a1ca2000-05-24 21:12:02 +00001551 {
1552 /* now, compare the immediate name to the keyword table */
David Turner4e7eeee2002-02-28 16:10:29 +00001553 T1_Field keyword = (T1_Field)t1_keywords;
Werner Lembergb48a6092000-07-09 19:15:30 +00001554
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001555
David Turner1c9a1ca2000-05-24 21:12:02 +00001556 for (;;)
David Turner2dfb5ac2000-01-27 14:02:04 +00001557 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001558 FT_Byte* name;
Werner Lembergb48a6092000-07-09 19:15:30 +00001559
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001560
David Turner34f1c2f2000-08-23 22:47:44 +00001561 name = (FT_Byte*)keyword->ident;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001562 if ( !name )
1563 break;
Werner Lembergb48a6092000-07-09 19:15:30 +00001564
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001565 if ( cur[0] == name[0] &&
1566 len == (FT_Int)strlen( (const char*)name ) )
David Turner2dfb5ac2000-01-27 14:02:04 +00001567 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001568 FT_Int n;
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001569
1570
David Turner1c9a1ca2000-05-24 21:12:02 +00001571 for ( n = 1; n < len; n++ )
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001572 if ( cur[n] != name[n] )
David Turner1c9a1ca2000-05-24 21:12:02 +00001573 break;
Werner Lembergb48a6092000-07-09 19:15:30 +00001574
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001575 if ( n >= len )
David Turner1c9a1ca2000-05-24 21:12:02 +00001576 {
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001577 /* we found it -- run the parsing callback! */
David Turnera39acf52000-08-23 02:47:57 +00001578 parser->root.cursor = cur2;
Werner Lembergb5084e12000-10-28 17:10:06 +00001579 T1_Skip_Spaces( parser );
Werner Lemberg8728f292000-08-23 17:32:42 +00001580 parser->root.error = t1_load_keyword( face,
1581 loader,
1582 keyword );
David Turnera39acf52000-08-23 02:47:57 +00001583 if ( parser->root.error )
1584 return parser->root.error;
Werner Lembergb48a6092000-07-09 19:15:30 +00001585
David Turnera39acf52000-08-23 02:47:57 +00001586 cur = parser->root.cursor;
David Turner1c9a1ca2000-05-24 21:12:02 +00001587 break;
1588 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001589 }
David Turner1c9a1ca2000-05-24 21:12:02 +00001590 keyword++;
David Turner2dfb5ac2000-01-27 14:02:04 +00001591 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001592 }
1593 }
1594 }
1595 }
1596 }
David Turnera39acf52000-08-23 02:47:57 +00001597 return parser->root.error;
David Turner2dfb5ac2000-01-27 14:02:04 +00001598 }
1599
David Turnere49ab252000-05-16 23:44:38 +00001600
Werner Lemberg4a2305c2001-06-28 07:17:51 +00001601 static void
1602 t1_init_loader( T1_Loader* loader,
1603 T1_Face face )
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001604 {
1605 FT_UNUSED( face );
1606
David Turnere459d742002-03-22 13:52:37 +00001607 FT_MEM_SET( loader, 0, sizeof ( *loader ) );
David Turner2dfb5ac2000-01-27 14:02:04 +00001608 loader->num_glyphs = 0;
1609 loader->num_chars = 0;
David Turner95bec282000-02-15 12:55:57 +00001610
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001611 /* initialize the tables -- simply set their `init' field to 0 */
David Turner2dfb5ac2000-01-27 14:02:04 +00001612 loader->encoding_table.init = 0;
1613 loader->charstrings.init = 0;
1614 loader->glyph_names.init = 0;
1615 loader->subrs.init = 0;
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001616 loader->swap_table.init = 0;
David Turner1c9a1ca2000-05-24 21:12:02 +00001617 loader->fontdata = 0;
David Turner2dfb5ac2000-01-27 14:02:04 +00001618 }
David Turnere49ab252000-05-16 23:44:38 +00001619
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001620
Werner Lemberg4a2305c2001-06-28 07:17:51 +00001621 static void
1622 t1_done_loader( T1_Loader* loader )
David Turner2dfb5ac2000-01-27 14:02:04 +00001623 {
David Turner4e7eeee2002-02-28 16:10:29 +00001624 T1_Parser parser = &loader->parser;
David Turnere49ab252000-05-16 23:44:38 +00001625
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001626
David Turner2dfb5ac2000-01-27 14:02:04 +00001627 /* finalize tables */
Werner Lembergb5084e12000-10-28 17:10:06 +00001628 T1_Release_Table( &loader->encoding_table );
1629 T1_Release_Table( &loader->charstrings );
1630 T1_Release_Table( &loader->glyph_names );
Tom Kacvinskycad797e2001-04-10 18:15:17 +00001631 T1_Release_Table( &loader->swap_table );
Werner Lembergb5084e12000-10-28 17:10:06 +00001632 T1_Release_Table( &loader->subrs );
David Turnere49ab252000-05-16 23:44:38 +00001633
David Turner2dfb5ac2000-01-27 14:02:04 +00001634 /* finalize parser */
Werner Lemberg27695e52000-11-23 08:21:13 +00001635 T1_Finalize_Parser( parser );
David Turner2dfb5ac2000-01-27 14:02:04 +00001636 }
1637
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001638
David Turnerbc82f1b2002-03-01 02:26:22 +00001639 FT_LOCAL_DEF( FT_Error )
Werner Lemberg4a2305c2001-06-28 07:17:51 +00001640 T1_Open_Face( T1_Face face )
David Turner2dfb5ac2000-01-27 14:02:04 +00001641 {
David Turner4e7eeee2002-02-28 16:10:29 +00001642 T1_Loader loader;
1643 T1_Parser parser;
David Turner29644172002-02-28 18:59:37 +00001644 T1_Font type1 = &face->type1;
David Turner4e7eeee2002-02-28 16:10:29 +00001645 FT_Error error;
Werner Lemberge4b32a52000-10-31 20:42:18 +00001646
David Turner4e7eeee2002-02-28 16:10:29 +00001647 PSAux_Service psaux = (PSAux_Service)face->psaux;
David Turner2dfb5ac2000-01-27 14:02:04 +00001648
Werner Lemberg8728f292000-08-23 17:32:42 +00001649
David Turner2dfb5ac2000-01-27 14:02:04 +00001650 t1_init_loader( &loader, face );
1651
1652 /* default lenIV */
David Turner9a9315f2000-05-02 10:59:01 +00001653 type1->private_dict.lenIV = 4;
David Turnere49ab252000-05-16 23:44:38 +00001654
David Turner2dfb5ac2000-01-27 14:02:04 +00001655 parser = &loader.parser;
Werner Lembergb5084e12000-10-28 17:10:06 +00001656 error = T1_New_Parser( parser,
Werner Lemberg8728f292000-08-23 17:32:42 +00001657 face->root.stream,
1658 face->root.memory,
1659 psaux );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001660 if ( error )
1661 goto Exit;
David Turner2dfb5ac2000-01-27 14:02:04 +00001662
1663 error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001664 if ( error )
1665 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001666
Werner Lemberg27695e52000-11-23 08:21:13 +00001667 error = T1_Get_Private_Dict( parser, psaux );
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001668 if ( error )
1669 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001670
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001671 error = parse_dict( face, &loader, parser->private_dict,
1672 parser->private_len );
1673 if ( error )
1674 goto Exit;
David Turner2dfb5ac2000-01-27 14:02:04 +00001675
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001676 /* now, propagate the subrs, charstrings, and glyphnames tables */
1677 /* to the Type1 data */
David Turner2dfb5ac2000-01-27 14:02:04 +00001678 type1->num_glyphs = loader.num_glyphs;
David Turnere49ab252000-05-16 23:44:38 +00001679
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +00001680 if ( loader.subrs.init )
David Turner95bec282000-02-15 12:55:57 +00001681 {
Tom Kacvinskyb2d5fef2001-01-24 22:41:20 +00001682 loader.subrs.init = 0;
1683 type1->num_subrs = loader.num_subrs;
1684 type1->subrs_block = loader.subrs.block;
1685 type1->subrs = loader.subrs.elements;
1686 type1->subrs_len = loader.subrs.lengths;
David Turner95bec282000-02-15 12:55:57 +00001687 }
David Turnere49ab252000-05-16 23:44:38 +00001688
David Turner95bec282000-02-15 12:55:57 +00001689 if ( !loader.charstrings.init )
1690 {
Werner Lembergb5084e12000-10-28 17:10:06 +00001691 FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" ));
Werner Lemberge35cac62000-06-11 03:46:57 +00001692 error = T1_Err_Invalid_File_Format;
David Turner95bec282000-02-15 12:55:57 +00001693 }
David Turnere49ab252000-05-16 23:44:38 +00001694
David Turner2dfb5ac2000-01-27 14:02:04 +00001695 loader.charstrings.init = 0;
1696 type1->charstrings_block = loader.charstrings.block;
1697 type1->charstrings = loader.charstrings.elements;
1698 type1->charstrings_len = loader.charstrings.lengths;
David Turnere49ab252000-05-16 23:44:38 +00001699
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001700 /* we copy the glyph names `block' and `elements' fields; */
1701 /* the `lengths' field must be released later */
David Turner2dfb5ac2000-01-27 14:02:04 +00001702 type1->glyph_names_block = loader.glyph_names.block;
David Turnerf9b8dec2000-06-16 19:34:52 +00001703 type1->glyph_names = (FT_String**)loader.glyph_names.elements;
David Turner2dfb5ac2000-01-27 14:02:04 +00001704 loader.glyph_names.block = 0;
1705 loader.glyph_names.elements = 0;
1706
1707 /* we must now build type1.encoding when we have a custom */
1708 /* array.. */
David Turner29644172002-02-28 18:59:37 +00001709 if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
David Turner2dfb5ac2000-01-27 14:02:04 +00001710 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001711 FT_Int charcode, idx, min_char, max_char;
David Turnerf9b8dec2000-06-16 19:34:52 +00001712 FT_Byte* char_name;
1713 FT_Byte* glyph_name;
David Turner2dfb5ac2000-01-27 14:02:04 +00001714
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001715
1716 /* OK, we do the following: for each element in the encoding */
1717 /* table, look up the index of the glyph having the same name */
David Turner2dfb5ac2000-01-27 14:02:04 +00001718 /* the index is then stored in type1.encoding.char_index, and */
1719 /* a the name to type1.encoding.char_name */
David Turnere49ab252000-05-16 23:44:38 +00001720
David Turner2dfb5ac2000-01-27 14:02:04 +00001721 min_char = +32000;
1722 max_char = -32000;
David Turnere49ab252000-05-16 23:44:38 +00001723
David Turner2dfb5ac2000-01-27 14:02:04 +00001724 charcode = 0;
Tom Kacvinsky95ac6572000-10-15 08:53:27 +00001725 for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
David Turner2dfb5ac2000-01-27 14:02:04 +00001726 {
1727 type1->encoding.char_index[charcode] = 0;
Werner Lembergb1dd3532000-07-31 22:51:00 +00001728 type1->encoding.char_name [charcode] = (char *)".notdef";
David Turnere49ab252000-05-16 23:44:38 +00001729
David Turner2dfb5ac2000-01-27 14:02:04 +00001730 char_name = loader.encoding_table.elements[charcode];
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001731 if ( char_name )
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001732 for ( idx = 0; idx < type1->num_glyphs; idx++ )
David Turner2dfb5ac2000-01-27 14:02:04 +00001733 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001734 glyph_name = (FT_Byte*)type1->glyph_names[idx];
David Turner0dd34342000-02-02 12:20:53 +00001735 if ( strcmp( (const char*)char_name,
1736 (const char*)glyph_name ) == 0 )
David Turner2dfb5ac2000-01-27 14:02:04 +00001737 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001738 type1->encoding.char_index[charcode] = (FT_UShort)idx;
David Turner0dd34342000-02-02 12:20:53 +00001739 type1->encoding.char_name [charcode] = (char*)glyph_name;
David Turnere49ab252000-05-16 23:44:38 +00001740
Werner Lemberg05f0ad02000-10-19 05:12:00 +00001741 /* Change min/max encoded char only if glyph name is */
1742 /* not /.notdef */
1743 if ( strcmp( (const char*)".notdef",
1744 (const char*)glyph_name ) != 0 )
1745 {
1746 if (charcode < min_char) min_char = charcode;
1747 if (charcode > max_char) max_char = charcode;
1748 }
David Turner2dfb5ac2000-01-27 14:02:04 +00001749 break;
1750 }
1751 }
1752 }
1753 type1->encoding.code_first = min_char;
1754 type1->encoding.code_last = max_char;
1755 type1->encoding.num_chars = loader.num_chars;
Werner Lemberg556ad082002-01-28 13:34:52 +00001756 }
David Turnere49ab252000-05-16 23:44:38 +00001757
David Turner2dfb5ac2000-01-27 14:02:04 +00001758 Exit:
1759 t1_done_loader( &loader );
1760 return error;
David Turnere49ab252000-05-16 23:44:38 +00001761 }
Werner Lemberg681e8ee2000-07-09 00:48:37 +00001762
1763
1764/* END */