blob: f8d611030737933d7db266ad0d77284e156a2b1e [file] [log] [blame]
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001/***************************************************************************/
2/* */
3/* cffgload.c */
4/* */
5/* OpenType Glyph Loader (body). */
6/* */
Werner Lemberg5972e9a2004-02-01 00:49:56 +00007/* Copyright 1996-2001, 2002, 2003, 2004 by */
Tom Kacvinskycd92b112001-01-03 00:15:00 +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#include <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_CALC_H
22#include FT_INTERNAL_STREAM_H
23#include FT_INTERNAL_SFNT_H
24#include FT_OUTLINE_H
25#include FT_TRUETYPE_TAGS_H
David Turner2b30c172001-12-12 16:07:29 +000026#include FT_INTERNAL_POSTSCRIPT_HINTS_H
Tom Kacvinskycd92b112001-01-03 00:15:00 +000027
David Turnerc8087482001-12-20 13:14:18 +000028#include "cffobjs.h"
David Turner8d3a4012001-03-20 11:14:24 +000029#include "cffload.h"
30#include "cffgload.h"
Tom Kacvinskycd92b112001-01-03 00:15:00 +000031
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000032#include "cfferrs.h"
Tom Kacvinskycd92b112001-01-03 00:15:00 +000033
34
35 /*************************************************************************/
36 /* */
37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
39 /* messages during execution. */
40 /* */
41#undef FT_COMPONENT
42#define FT_COMPONENT trace_cffgload
43
44
45 typedef enum CFF_Operator_
46 {
47 cff_op_unknown = 0,
48
49 cff_op_rmoveto,
50 cff_op_hmoveto,
51 cff_op_vmoveto,
52
53 cff_op_rlineto,
54 cff_op_hlineto,
55 cff_op_vlineto,
56
57 cff_op_rrcurveto,
58 cff_op_hhcurveto,
59 cff_op_hvcurveto,
60 cff_op_rcurveline,
61 cff_op_rlinecurve,
62 cff_op_vhcurveto,
63 cff_op_vvcurveto,
64
65 cff_op_flex,
66 cff_op_hflex,
67 cff_op_hflex1,
68 cff_op_flex1,
69
70 cff_op_endchar,
71
72 cff_op_hstem,
73 cff_op_vstem,
74 cff_op_hstemhm,
75 cff_op_vstemhm,
76
77 cff_op_hintmask,
78 cff_op_cntrmask,
David Turner8d3a4012001-03-20 11:14:24 +000079 cff_op_dotsection, /* deprecated, acts as no-op */
Tom Kacvinskycd92b112001-01-03 00:15:00 +000080
81 cff_op_abs,
82 cff_op_add,
83 cff_op_sub,
84 cff_op_div,
85 cff_op_neg,
86 cff_op_random,
87 cff_op_mul,
88 cff_op_sqrt,
89
90 cff_op_blend,
91
92 cff_op_drop,
93 cff_op_exch,
94 cff_op_index,
95 cff_op_roll,
96 cff_op_dup,
97
98 cff_op_put,
99 cff_op_get,
100 cff_op_store,
101 cff_op_load,
102
103 cff_op_and,
104 cff_op_or,
105 cff_op_not,
106 cff_op_eq,
107 cff_op_ifelse,
108
109 cff_op_callsubr,
110 cff_op_callgsubr,
111 cff_op_return,
112
113 /* do not remove */
114 cff_op_max
115
116 } CFF_Operator;
117
118
119#define CFF_COUNT_CHECK_WIDTH 0x80
120#define CFF_COUNT_EXACT 0x40
121#define CFF_COUNT_CLEAR_STACK 0x20
122
123
124 static const FT_Byte cff_argument_counts[] =
125 {
126 0, /* unknown */
127
128 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */
129 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
130 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
131
132 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */
133 0 | CFF_COUNT_CLEAR_STACK,
134 0 | CFF_COUNT_CLEAR_STACK,
135
136 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */
137 0 | CFF_COUNT_CLEAR_STACK,
138 0 | CFF_COUNT_CLEAR_STACK,
139 0 | CFF_COUNT_CLEAR_STACK,
140 0 | CFF_COUNT_CLEAR_STACK,
141 0 | CFF_COUNT_CLEAR_STACK,
142 0 | CFF_COUNT_CLEAR_STACK,
143
144 13, /* flex */
145 7,
146 9,
147 11,
148
149 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */
150
151 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */
152 2 | CFF_COUNT_CHECK_WIDTH,
153 2 | CFF_COUNT_CHECK_WIDTH,
154 2 | CFF_COUNT_CHECK_WIDTH,
155
David Turnerc8087482001-12-20 13:14:18 +0000156 0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */
157 0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000158 0, /* dotsection */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000159
160 1, /* abs */
161 2,
162 2,
163 2,
164 1,
165 0,
166 2,
167 1,
168
169 1, /* blend */
170
171 1, /* drop */
172 2,
173 1,
174 2,
175 1,
176
177 2, /* put */
178 1,
179 4,
180 3,
181
182 2, /* and */
183 2,
184 1,
185 2,
186 4,
187
188 1, /* callsubr */
189 1,
190 0
191 };
192
193
194 /*************************************************************************/
195 /*************************************************************************/
196 /*************************************************************************/
197 /********** *********/
198 /********** *********/
199 /********** GENERIC CHARSTRING PARSING *********/
200 /********** *********/
201 /********** *********/
202 /*************************************************************************/
203 /*************************************************************************/
204 /*************************************************************************/
205
206
207 /*************************************************************************/
208 /* */
209 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000210 /* cff_builder_init */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000211 /* */
212 /* <Description> */
213 /* Initializes a given glyph builder. */
214 /* */
215 /* <InOut> */
216 /* builder :: A pointer to the glyph builder to initialize. */
217 /* */
218 /* <Input> */
219 /* face :: The current face object. */
220 /* */
221 /* size :: The current size object. */
222 /* */
223 /* glyph :: The current glyph object. */
224 /* */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000225 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000226 cff_builder_init( CFF_Builder* builder,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000227 TT_Face face,
228 CFF_Size size,
David Turnerc8087482001-12-20 13:14:18 +0000229 CFF_GlyphSlot glyph,
230 FT_Bool hinting )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000231 {
232 builder->path_begun = 0;
233 builder->load_points = 1;
234
235 builder->face = face;
236 builder->glyph = glyph;
237 builder->memory = face->root.memory;
238
239 if ( glyph )
240 {
David Turner4d570242002-02-24 02:59:24 +0000241 FT_GlyphLoader loader = glyph->root.internal->loader;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000242
243
244 builder->loader = loader;
245 builder->base = &loader->base.outline;
246 builder->current = &loader->current.outline;
247 FT_GlyphLoader_Rewind( loader );
David Turnerc8087482001-12-20 13:14:18 +0000248
249 builder->hints_globals = 0;
250 builder->hints_funcs = 0;
David Turner4d570242002-02-24 02:59:24 +0000251
David Turnerc8087482001-12-20 13:14:18 +0000252 if ( hinting && size )
253 {
254 builder->hints_globals = size->internal;
255 builder->hints_funcs = glyph->root.internal->glyph_hints;
256 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000257 }
258
259 if ( size )
260 {
261 builder->scale_x = size->metrics.x_scale;
262 builder->scale_y = size->metrics.y_scale;
263 }
264
265 builder->pos_x = 0;
266 builder->pos_y = 0;
267
268 builder->left_bearing.x = 0;
269 builder->left_bearing.y = 0;
270 builder->advance.x = 0;
271 builder->advance.y = 0;
272 }
273
274
275 /*************************************************************************/
276 /* */
277 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000278 /* cff_builder_done */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000279 /* */
280 /* <Description> */
281 /* Finalizes a given glyph builder. Its contents can still be used */
282 /* after the call, but the function saves important information */
283 /* within the corresponding glyph slot. */
284 /* */
285 /* <Input> */
286 /* builder :: A pointer to the glyph builder to finalize. */
287 /* */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000288 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000289 cff_builder_done( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000290 {
291 CFF_GlyphSlot glyph = builder->glyph;
292
293
294 if ( glyph )
295 glyph->root.outline = *builder->base;
296 }
297
298
299 /*************************************************************************/
300 /* */
301 /* <Function> */
Werner Lembergd573c7e2001-01-03 07:14:12 +0000302 /* cff_compute_bias */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000303 /* */
304 /* <Description> */
305 /* Computes the bias value in dependence of the number of glyph */
306 /* subroutines. */
307 /* */
308 /* <Input> */
309 /* num_subrs :: The number of glyph subroutines. */
310 /* */
311 /* <Return> */
312 /* The bias value. */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000313 static FT_Int
314 cff_compute_bias( FT_UInt num_subrs )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000315 {
316 FT_Int result;
317
318
319 if ( num_subrs < 1240 )
320 result = 107;
Werner Lembergcf24d512001-06-18 14:23:45 +0000321 else if ( num_subrs < 33900U )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000322 result = 1131;
323 else
Werner Lembergcf24d512001-06-18 14:23:45 +0000324 result = 32768U;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000325
326 return result;
327 }
328
329
330 /*************************************************************************/
331 /* */
332 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000333 /* cff_decoder_init */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000334 /* */
335 /* <Description> */
336 /* Initializes a given glyph decoder. */
337 /* */
338 /* <InOut> */
339 /* decoder :: A pointer to the glyph builder to initialize. */
340 /* */
341 /* <Input> */
342 /* face :: The current face object. */
343 /* */
344 /* size :: The current size object. */
345 /* */
346 /* slot :: The current glyph object. */
347 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000348 FT_LOCAL_DEF( void )
David Turnerd1245c02002-08-27 22:34:20 +0000349 cff_decoder_init( CFF_Decoder* decoder,
350 TT_Face face,
351 CFF_Size size,
352 CFF_GlyphSlot slot,
353 FT_Bool hinting,
354 FT_Render_Mode hint_mode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000355 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000356 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000357
358
359 /* clear everything */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000360 FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000361
362 /* initialize builder */
David Turnerb9b2cac2002-07-10 16:52:06 +0000363 cff_builder_init( &decoder->builder, face, size, slot, hinting );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000364
365 /* initialize Type2 decoder */
366 decoder->num_globals = cff->num_global_subrs;
367 decoder->globals = cff->global_subrs;
368 decoder->globals_bias = cff_compute_bias( decoder->num_globals );
David Turner87c0d302003-12-24 01:10:46 +0000369
David Turnerd1245c02002-08-27 22:34:20 +0000370 decoder->hint_mode = hint_mode;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000371 }
372
373
374 /* this function is used to select the locals subrs array */
David Turnerbc82f1b2002-03-01 02:26:22 +0000375 FT_LOCAL_DEF( void )
David Turnerb9b2cac2002-07-10 16:52:06 +0000376 cff_decoder_prepare( CFF_Decoder* decoder,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000377 FT_UInt glyph_index )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000378 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000379 CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data;
380 CFF_SubFont sub = &cff->top_font;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000381
382
383 /* manage CID fonts */
384 if ( cff->num_subfonts >= 1 )
385 {
David Turnerb9b2cac2002-07-10 16:52:06 +0000386 FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000387
388
389 sub = cff->subfonts[fd_index];
390 }
391
392 decoder->num_locals = sub->num_local_subrs;
393 decoder->locals = sub->local_subrs;
394 decoder->locals_bias = cff_compute_bias( decoder->num_locals );
395
396 decoder->glyph_width = sub->private_dict.default_width;
397 decoder->nominal_width = sub->private_dict.nominal_width;
398 }
399
400
Werner Lembergb36d4a52003-12-12 15:38:39 +0000401 /* check that there is enough space for `count' more points */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000402 static FT_Error
403 check_points( CFF_Builder* builder,
404 FT_Int count )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000405 {
David Turnereba5ad42002-03-14 12:56:35 +0000406 return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000407 }
408
409
410 /* add a new point, do not check space */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000411 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000412 cff_builder_add_point( CFF_Builder* builder,
413 FT_Pos x,
414 FT_Pos y,
415 FT_Byte flag )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000416 {
417 FT_Outline* outline = builder->current;
418
419
420 if ( builder->load_points )
421 {
422 FT_Vector* point = outline->points + outline->n_points;
423 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
424
425
426 point->x = x >> 16;
427 point->y = y >> 16;
David Turnerb08fe2d2002-08-27 20:20:29 +0000428 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000429
430 builder->last = *point;
431 }
Werner Lemberg48c984b2002-03-30 16:41:09 +0000432
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000433 outline->n_points++;
434 }
435
436
437 /* check space for a new on-curve point, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000438 static FT_Error
Werner Lemberg7f74a522002-07-26 09:09:10 +0000439 cff_builder_add_point1( CFF_Builder* builder,
David Turnerb9b2cac2002-07-10 16:52:06 +0000440 FT_Pos x,
441 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000442 {
443 FT_Error error;
444
445
446 error = check_points( builder, 1 );
447 if ( !error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000448 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000449
450 return error;
451 }
452
453
Werner Lembergb36d4a52003-12-12 15:38:39 +0000454 /* check space for a new contour, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000455 static FT_Error
David Turnerb9b2cac2002-07-10 16:52:06 +0000456 cff_builder_add_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000457 {
458 FT_Outline* outline = builder->current;
459 FT_Error error;
460
461
462 if ( !builder->load_points )
463 {
464 outline->n_contours++;
465 return CFF_Err_Ok;
466 }
467
David Turnereba5ad42002-03-14 12:56:35 +0000468 error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000469 if ( !error )
470 {
471 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000472 outline->contours[outline->n_contours - 1] =
473 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000474
475 outline->n_contours++;
476 }
477
478 return error;
479 }
480
481
482 /* if a path was begun, add its first on-curve point */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000483 static FT_Error
David Turnerb9b2cac2002-07-10 16:52:06 +0000484 cff_builder_start_point( CFF_Builder* builder,
485 FT_Pos x,
486 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000487 {
488 FT_Error error = 0;
489
490
491 /* test whether we are building a new contour */
492 if ( !builder->path_begun )
493 {
494 builder->path_begun = 1;
David Turnerb9b2cac2002-07-10 16:52:06 +0000495 error = cff_builder_add_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000496 if ( !error )
Werner Lemberg7f74a522002-07-26 09:09:10 +0000497 error = cff_builder_add_point1( builder, x, y );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000498 }
Werner Lemberg48c984b2002-03-30 16:41:09 +0000499
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000500 return error;
501 }
502
503
504 /* close the current contour */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000505 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000506 cff_builder_close_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000507 {
508 FT_Outline* outline = builder->current;
509
Werner Lemberg48c984b2002-03-30 16:41:09 +0000510
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000511 /* XXXX: We must not include the last point in the path if it */
512 /* is located on the first point. */
513 if ( outline->n_points > 1 )
514 {
515 FT_Int first = 0;
516 FT_Vector* p1 = outline->points + first;
517 FT_Vector* p2 = outline->points + outline->n_points - 1;
518 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
519
520
521 if ( outline->n_contours > 1 )
522 {
523 first = outline->contours[outline->n_contours - 2] + 1;
524 p1 = outline->points + first;
525 }
526
Werner Lemberg48c984b2002-03-30 16:41:09 +0000527 /* `delete' last point only if it coincides with the first */
528 /* point and if it is not a control point (which can happen). */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000529 if ( p1->x == p2->x && p1->y == p2->y )
David Turnerb08fe2d2002-08-27 20:20:29 +0000530 if ( *control == FT_CURVE_TAG_ON )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000531 outline->n_points--;
532 }
533
534 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000535 outline->contours[outline->n_contours - 1] =
536 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000537 }
538
539
Werner Lemberg93616ec2001-06-27 19:46:12 +0000540 static FT_Int
David Turnerab4fc4d2002-03-14 08:57:10 +0000541 cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
Werner Lemberg48c984b2002-03-30 16:41:09 +0000542 FT_Int charcode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000543 {
544 FT_UInt n;
545 FT_UShort glyph_sid;
546
547
Werner Lemberg328abf32003-12-24 13:37:58 +0000548 /* CID-keyed fonts don't have glyph names */
549 if ( !cff->charset.sids )
550 return -1;
551
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000552 /* check range of standard char code */
553 if ( charcode < 0 || charcode > 255 )
554 return -1;
555
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000556 /* Get code to SID mapping from `cff_standard_encoding'. */
David Turnerb9b2cac2002-07-10 16:52:06 +0000557 glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000558
559 for ( n = 0; n < cff->num_glyphs; n++ )
560 {
561 if ( cff->charset.sids[n] == glyph_sid )
562 return n;
563 }
564
565 return -1;
566 }
567
568
Werner Lemberg93616ec2001-06-27 19:46:12 +0000569 static FT_Error
Graham Asher3fd12f12002-08-15 12:10:48 +0000570 cff_get_glyph_data( TT_Face face,
571 FT_UInt glyph_index,
572 FT_Byte** pointer,
573 FT_ULong* length )
574 {
575#ifdef FT_CONFIG_OPTION_INCREMENTAL
576 /* For incremental fonts get the character data using the */
577 /* callback function. */
578 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000579 {
580 FT_Data data;
581 FT_Error error =
582 face->root.internal->incremental_interface->funcs->get_glyph_data(
583 face->root.internal->incremental_interface->object,
584 glyph_index, &data );
585
586
Graham Asher3fd12f12002-08-15 12:10:48 +0000587 *pointer = (FT_Byte*)data.pointer;
Graham Asher9eefed12002-08-23 10:08:38 +0000588 *length = data.length;
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000589
Graham Asher3fd12f12002-08-15 12:10:48 +0000590 return error;
591 }
592 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000593#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Graham Asher3fd12f12002-08-15 12:10:48 +0000594
595 {
Graham Asher9eefed12002-08-23 10:08:38 +0000596 CFF_Font cff = (CFF_Font)(face->extra.data);
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000597
598
Graham Asher3fd12f12002-08-15 12:10:48 +0000599 return cff_index_access_element( &cff->charstrings_index, glyph_index,
600 pointer, length );
601 }
602 }
603
604
605 static void
606 cff_free_glyph_data( TT_Face face,
607 FT_Byte** pointer,
608 FT_ULong length )
609 {
Graham Asher824daa52002-08-15 12:58:21 +0000610#ifndef FT_CONFIG_OPTION_INCREMENTAL
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000611 FT_UNUSED( length );
Graham Asher824daa52002-08-15 12:58:21 +0000612#endif
613
Graham Asher3fd12f12002-08-15 12:10:48 +0000614#ifdef FT_CONFIG_OPTION_INCREMENTAL
615 /* For incremental fonts get the character data using the */
616 /* callback function. */
617 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000618 {
Graham Asher9eefed12002-08-23 10:08:38 +0000619 FT_Data data;
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000620
621
622 data.pointer = *pointer;
623 data.length = length;
624
Graham Asher3fd12f12002-08-15 12:10:48 +0000625 face->root.internal->incremental_interface->funcs->free_glyph_data(
626 face->root.internal->incremental_interface->object,&data );
627 }
628 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000629#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Graham Asher3fd12f12002-08-15 12:10:48 +0000630
631 {
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000632 CFF_Font cff = (CFF_Font)(face->extra.data);
633
634
Graham Asher3fd12f12002-08-15 12:10:48 +0000635 cff_index_forget_element( &cff->charstrings_index, pointer );
636 }
637 }
638
639
640 static FT_Error
Werner Lemberg93616ec2001-06-27 19:46:12 +0000641 cff_operator_seac( CFF_Decoder* decoder,
642 FT_Pos adx,
643 FT_Pos ady,
644 FT_Int bchar,
645 FT_Int achar )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000646 {
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000647 FT_Error error;
648 CFF_Builder* builder = &decoder->builder;
649 FT_Int bchar_index, achar_index;
650 TT_Face face = decoder->builder.face;
651 FT_Vector left_bearing, advance;
652 FT_Byte* charstring;
653 FT_ULong charstring_len;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000654
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000655
Graham Asher9eefed12002-08-23 10:08:38 +0000656#ifdef FT_CONFIG_OPTION_INCREMENTAL
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000657 /* Incremental fonts don't necessarily have valid charsets. */
658 /* They use the character code, not the glyph index, in this case. */
Graham Asher9eefed12002-08-23 10:08:38 +0000659 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000660 {
Graham Asher9eefed12002-08-23 10:08:38 +0000661 bchar_index = bchar;
662 achar_index = achar;
663 }
664 else
665#endif /* FT_CONFIG_OPTION_INCREMENTAL */
666 {
667 CFF_Font cff = (CFF_Font)(face->extra.data);
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000668
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000669
Graham Asher9eefed12002-08-23 10:08:38 +0000670 bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
671 achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000672 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000673
674 if ( bchar_index < 0 || achar_index < 0 )
675 {
676 FT_ERROR(( "cff_operator_seac:" ));
677 FT_ERROR(( " invalid seac character code arguments\n" ));
678 return CFF_Err_Syntax_Error;
679 }
680
681 /* If we are trying to load a composite glyph, do not load the */
682 /* accent character and return the array of subglyphs. */
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000683 if ( builder->no_recurse )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000684 {
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000685 FT_GlyphSlot glyph = (FT_GlyphSlot)builder->glyph;
Werner Lemberg48c984b2002-03-30 16:41:09 +0000686 FT_GlyphLoader loader = glyph->internal->loader;
David Turnereba5ad42002-03-14 12:56:35 +0000687 FT_SubGlyph subg;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000688
689
690 /* reallocate subglyph array if necessary */
David Turnereba5ad42002-03-14 12:56:35 +0000691 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000692 if ( error )
693 goto Exit;
694
695 subg = loader->current.subglyphs;
696
697 /* subglyph 0 = base character */
698 subg->index = bchar_index;
699 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
700 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
701 subg->arg1 = 0;
702 subg->arg2 = 0;
703 subg++;
704
705 /* subglyph 1 = accent character */
706 subg->index = achar_index;
707 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000708 subg->arg1 = (FT_Int)( adx >> 16 );
709 subg->arg2 = (FT_Int)( ady >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000710
711 /* set up remaining glyph fields */
712 glyph->num_subglyphs = 2;
713 glyph->subglyphs = loader->base.subglyphs;
David Turnerb08fe2d2002-08-27 20:20:29 +0000714 glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000715
716 loader->current.num_subglyphs = 2;
717 }
718
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000719 FT_GlyphLoader_Prepare( builder->loader );
720
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000721 /* First load `bchar' in builder */
Graham Asher3fd12f12002-08-15 12:10:48 +0000722 error = cff_get_glyph_data( face, bchar_index,
723 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000724 if ( !error )
725 {
Graham Asher9eefed12002-08-23 10:08:38 +0000726 error = cff_decoder_parse_charstrings( decoder, charstring,
727 charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000728
729 if ( error )
730 goto Exit;
731
Graham Asher3fd12f12002-08-15 12:10:48 +0000732 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000733 }
734
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000735 /* Save the left bearing and width of the base character */
736 /* as they will be erased by the next load. */
737
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000738 left_bearing = builder->left_bearing;
739 advance = builder->advance;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000740
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000741 builder->left_bearing.x = 0;
742 builder->left_bearing.y = 0;
743
744 builder->pos_x = adx;
745 builder->pos_y = ady;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000746
747 /* Now load `achar' on top of the base outline. */
Graham Asher3fd12f12002-08-15 12:10:48 +0000748 error = cff_get_glyph_data( face, achar_index,
749 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000750 if ( !error )
751 {
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000752 error = cff_decoder_parse_charstrings( decoder, charstring,
753 charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000754
755 if ( error )
756 goto Exit;
757
Graham Asher3fd12f12002-08-15 12:10:48 +0000758 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000759 }
760
761 /* Restore the left side bearing and advance width */
762 /* of the base character. */
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000763 builder->left_bearing = left_bearing;
764 builder->advance = advance;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000765
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000766 builder->pos_x = 0;
767 builder->pos_y = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000768
769 Exit:
770 return error;
771 }
772
773
774 /*************************************************************************/
775 /* */
776 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000777 /* cff_decoder_parse_charstrings */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000778 /* */
779 /* <Description> */
780 /* Parses a given Type 2 charstrings program. */
781 /* */
782 /* <InOut> */
783 /* decoder :: The current Type 1 decoder. */
784 /* */
785 /* <Input> */
786 /* charstring_base :: The base of the charstring stream. */
787 /* */
788 /* charstring_len :: The length in bytes of the charstring stream. */
789 /* */
790 /* <Return> */
791 /* FreeType error code. 0 means success. */
792 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000793 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000794 cff_decoder_parse_charstrings( CFF_Decoder* decoder,
Werner Lemberg7f74a522002-07-26 09:09:10 +0000795 FT_Byte* charstring_base,
Werner Lemberg68e9f922002-09-27 11:09:23 +0000796 FT_ULong charstring_len )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000797 {
Werner Lembergd573c7e2001-01-03 07:14:12 +0000798 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000799 CFF_Decoder_Zone* zone;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000800 FT_Byte* ip;
801 FT_Byte* limit;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000802 CFF_Builder* builder = &decoder->builder;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000803 FT_Pos x, y;
804 FT_Fixed seed;
805 FT_Fixed* stack;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000806
David Turner2b30c172001-12-12 16:07:29 +0000807 T2_Hints_Funcs hinter;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000808
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000809
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000810 /* set default width */
811 decoder->num_hints = 0;
812 decoder->read_width = 1;
813
814 /* compute random seed from stack address of parameter */
815 seed = (FT_Fixed)(char*)&seed ^
816 (FT_Fixed)(char*)&decoder ^
817 (FT_Fixed)(char*)&charstring_base;
Werner Lemberg43ba0842003-06-23 19:26:53 +0000818 seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000819 if ( seed == 0 )
820 seed = 0x7384;
821
822 /* initialize the decoder */
823 decoder->top = decoder->stack;
824 decoder->zone = decoder->zones;
825 zone = decoder->zones;
826 stack = decoder->top;
827
David Turner2b30c172001-12-12 16:07:29 +0000828 hinter = (T2_Hints_Funcs) builder->hints_funcs;
829
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000830 builder->path_begun = 0;
831
832 zone->base = charstring_base;
833 limit = zone->limit = charstring_base + charstring_len;
834 ip = zone->cursor = zone->base;
835
Werner Lembergcf24d512001-06-18 14:23:45 +0000836 error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000837
838 x = builder->pos_x;
839 y = builder->pos_y;
840
David Turner2b30c172001-12-12 16:07:29 +0000841 /* begin hints recording session, if any */
842 if ( hinter )
843 hinter->open( hinter->hints );
844
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000845 /* now, execute loop */
846 while ( ip < limit )
847 {
848 CFF_Operator op;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000849 FT_Byte v;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000850
851
852 /********************************************************************/
853 /* */
854 /* Decode operator or operand */
855 /* */
856 v = *ip++;
857 if ( v >= 32 || v == 28 )
858 {
859 FT_Int shift = 16;
860 FT_Int32 val;
861
862
863 /* this is an operand, push it on the stack */
864 if ( v == 28 )
865 {
866 if ( ip + 1 >= limit )
867 goto Syntax_Error;
868 val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
869 ip += 2;
870 }
871 else if ( v < 247 )
872 val = (FT_Long)v - 139;
873 else if ( v < 251 )
874 {
875 if ( ip >= limit )
876 goto Syntax_Error;
877 val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
878 }
879 else if ( v < 255 )
880 {
881 if ( ip >= limit )
882 goto Syntax_Error;
883 val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
884 }
885 else
886 {
887 if ( ip + 3 >= limit )
888 goto Syntax_Error;
889 val = ( (FT_Int32)ip[0] << 24 ) |
890 ( (FT_Int32)ip[1] << 16 ) |
891 ( (FT_Int32)ip[2] << 8 ) |
892 ip[3];
893 ip += 4;
894 shift = 0;
895 }
896 if ( decoder->top - stack >= CFF_MAX_OPERANDS )
897 goto Stack_Overflow;
898
899 val <<= shift;
900 *decoder->top++ = val;
901
902#ifdef FT_DEBUG_LEVEL_TRACE
Werner Lemberg43ba0842003-06-23 19:26:53 +0000903 if ( !( val & 0xFFFFL ) )
Werner Lemberg84c60bb2004-01-01 08:21:30 +0000904 FT_TRACE4(( " %ld", (FT_Int32)( val >> 16 ) ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000905 else
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000906 FT_TRACE4(( " %.2f", val / 65536.0 ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000907#endif
908
909 }
910 else
911 {
912 FT_Fixed* args = decoder->top;
Werner Lemberg68e9f922002-09-27 11:09:23 +0000913 FT_Int num_args = (FT_Int)( args - decoder->stack );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000914 FT_Int req_args;
915
916
917 /* find operator */
918 op = cff_op_unknown;
919
920 switch ( v )
921 {
922 case 1:
923 op = cff_op_hstem;
924 break;
925 case 3:
926 op = cff_op_vstem;
927 break;
928 case 4:
929 op = cff_op_vmoveto;
930 break;
931 case 5:
932 op = cff_op_rlineto;
933 break;
934 case 6:
935 op = cff_op_hlineto;
936 break;
937 case 7:
938 op = cff_op_vlineto;
939 break;
940 case 8:
941 op = cff_op_rrcurveto;
942 break;
943 case 10:
944 op = cff_op_callsubr;
945 break;
946 case 11:
947 op = cff_op_return;
948 break;
949 case 12:
950 {
951 if ( ip >= limit )
952 goto Syntax_Error;
953 v = *ip++;
954
955 switch ( v )
956 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000957 case 0:
958 op = cff_op_dotsection;
959 break;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000960 case 3:
961 op = cff_op_and;
962 break;
963 case 4:
964 op = cff_op_or;
965 break;
966 case 5:
967 op = cff_op_not;
968 break;
969 case 8:
970 op = cff_op_store;
971 break;
972 case 9:
973 op = cff_op_abs;
974 break;
975 case 10:
976 op = cff_op_add;
977 break;
978 case 11:
979 op = cff_op_sub;
980 break;
981 case 12:
982 op = cff_op_div;
983 break;
984 case 13:
985 op = cff_op_load;
986 break;
987 case 14:
988 op = cff_op_neg;
989 break;
990 case 15:
991 op = cff_op_eq;
992 break;
993 case 18:
994 op = cff_op_drop;
995 break;
996 case 20:
997 op = cff_op_put;
998 break;
999 case 21:
1000 op = cff_op_get;
1001 break;
1002 case 22:
1003 op = cff_op_ifelse;
1004 break;
1005 case 23:
1006 op = cff_op_random;
1007 break;
1008 case 24:
1009 op = cff_op_mul;
1010 break;
1011 case 26:
1012 op = cff_op_sqrt;
1013 break;
1014 case 27:
1015 op = cff_op_dup;
1016 break;
1017 case 28:
1018 op = cff_op_exch;
1019 break;
1020 case 29:
1021 op = cff_op_index;
1022 break;
1023 case 30:
1024 op = cff_op_roll;
1025 break;
1026 case 34:
1027 op = cff_op_hflex;
1028 break;
1029 case 35:
1030 op = cff_op_flex;
1031 break;
1032 case 36:
1033 op = cff_op_hflex1;
1034 break;
1035 case 37:
1036 op = cff_op_flex1;
1037 break;
1038 default:
1039 /* decrement ip for syntax error message */
1040 ip--;
1041 }
1042 }
1043 break;
1044 case 14:
1045 op = cff_op_endchar;
1046 break;
1047 case 16:
1048 op = cff_op_blend;
1049 break;
1050 case 18:
1051 op = cff_op_hstemhm;
1052 break;
1053 case 19:
1054 op = cff_op_hintmask;
1055 break;
1056 case 20:
1057 op = cff_op_cntrmask;
1058 break;
1059 case 21:
1060 op = cff_op_rmoveto;
1061 break;
1062 case 22:
1063 op = cff_op_hmoveto;
1064 break;
1065 case 23:
1066 op = cff_op_vstemhm;
1067 break;
1068 case 24:
1069 op = cff_op_rcurveline;
1070 break;
1071 case 25:
1072 op = cff_op_rlinecurve;
1073 break;
1074 case 26:
1075 op = cff_op_vvcurveto;
1076 break;
1077 case 27:
1078 op = cff_op_hhcurveto;
1079 break;
1080 case 29:
1081 op = cff_op_callgsubr;
1082 break;
1083 case 30:
1084 op = cff_op_vhcurveto;
1085 break;
1086 case 31:
1087 op = cff_op_hvcurveto;
1088 break;
1089 default:
1090 ;
1091 }
1092 if ( op == cff_op_unknown )
1093 goto Syntax_Error;
1094
1095 /* check arguments */
1096 req_args = cff_argument_counts[op];
1097 if ( req_args & CFF_COUNT_CHECK_WIDTH )
1098 {
1099 args = stack;
1100
1101 if ( num_args > 0 && decoder->read_width )
1102 {
1103 /* If `nominal_width' is non-zero, the number is really a */
1104 /* difference against `nominal_width'. Else, the number here */
1105 /* is truly a width, not a difference against `nominal_width'. */
1106 /* If the font does not set `nominal_width', then */
1107 /* `nominal_width' defaults to zero, and so we can set */
1108 /* `glyph_width' to `nominal_width' plus number on the stack */
1109 /* -- for either case. */
1110
Werner Lemberg916838c2004-02-10 16:02:20 +00001111 FT_Int set_width_ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001112
1113
1114 switch ( op )
1115 {
1116 case cff_op_hmoveto:
1117 case cff_op_vmoveto:
1118 set_width_ok = num_args & 2;
1119 break;
1120
1121 case cff_op_hstem:
1122 case cff_op_vstem:
1123 case cff_op_hstemhm:
1124 case cff_op_vstemhm:
1125 case cff_op_rmoveto:
Werner Lemberg916838c2004-02-10 16:02:20 +00001126 case cff_op_hintmask:
1127 case cff_op_cntrmask:
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001128 set_width_ok = num_args & 1;
1129 break;
1130
1131 case cff_op_endchar:
1132 /* If there is a width specified for endchar, we either have */
1133 /* 1 argument or 5 arguments. We like to argue. */
1134 set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
1135 break;
1136
1137 default:
1138 set_width_ok = 0;
1139 break;
1140 }
1141
1142 if ( set_width_ok )
1143 {
1144 decoder->glyph_width = decoder->nominal_width +
1145 ( stack[0] >> 16 );
1146
1147 /* Consumed an argument. */
1148 num_args--;
1149 args++;
1150 }
1151 }
1152
1153 decoder->read_width = 0;
1154 req_args = 0;
1155 }
1156
1157 req_args &= 15;
1158 if ( num_args < req_args )
1159 goto Stack_Underflow;
1160 args -= req_args;
1161 num_args -= req_args;
1162
1163 switch ( op )
1164 {
1165 case cff_op_hstem:
1166 case cff_op_vstem:
1167 case cff_op_hstemhm:
1168 case cff_op_vstemhm:
David Turner2b30c172001-12-12 16:07:29 +00001169 /* the number of arguments is always even here */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001170 FT_TRACE4(( op == cff_op_hstem ? " hstem" :
David Turner2b30c172001-12-12 16:07:29 +00001171 ( op == cff_op_vstem ? " vstem" :
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001172 ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
David Turnerbce29862001-12-14 14:52:58 +00001173
David Turner2b30c172001-12-12 16:07:29 +00001174 if ( hinter )
1175 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001176 ( op == cff_op_hstem || op == cff_op_hstemhm ),
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001177 num_args / 2,
David Turner2b30c172001-12-12 16:07:29 +00001178 args );
David Turnerbce29862001-12-14 14:52:58 +00001179
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001180 decoder->num_hints += num_args / 2;
1181 args = stack;
1182 break;
David Turnerbce29862001-12-14 14:52:58 +00001183
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001184 case cff_op_hintmask:
1185 case cff_op_cntrmask:
David Turner2b30c172001-12-12 16:07:29 +00001186 FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
David Turner4d570242002-02-24 02:59:24 +00001187
Werner Lembergaf594e62001-12-22 14:38:40 +00001188 /* implement vstem when needed -- */
David Turnerb5c7de52001-12-21 21:21:13 +00001189 /* the specification doesn't say it, but this also works */
Werner Lembergaf594e62001-12-22 14:38:40 +00001190 /* with the 'cntrmask' operator */
David Turnerb5c7de52001-12-21 21:21:13 +00001191 /* */
David Turnerc8087482001-12-20 13:14:18 +00001192 if ( num_args > 0 )
1193 {
1194 if ( hinter )
1195 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001196 0,
David Turnerc8087482001-12-20 13:14:18 +00001197 num_args / 2,
1198 args );
David Turner4d570242002-02-24 02:59:24 +00001199
David Turnerc8087482001-12-20 13:14:18 +00001200 decoder->num_hints += num_args / 2;
1201 }
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001202
David Turner2b30c172001-12-12 16:07:29 +00001203 if ( hinter )
1204 {
1205 if ( op == cff_op_hintmask )
1206 hinter->hintmask( hinter->hints,
1207 builder->current->n_points,
David Turnerc8087482001-12-20 13:14:18 +00001208 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001209 ip );
1210 else
1211 hinter->counter( hinter->hints,
David Turnerc8087482001-12-20 13:14:18 +00001212 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001213 ip );
1214 }
David Turnerbce29862001-12-14 14:52:58 +00001215
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001216#ifdef FT_DEBUG_LEVEL_TRACE
1217 {
1218 FT_UInt maskbyte;
1219
Werner Lemberg48c984b2002-03-30 16:41:09 +00001220
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001221 FT_TRACE4(( " " ));
1222
Werner Lemberg521a2d72001-03-20 22:58:56 +00001223 for ( maskbyte = 0;
David Turner6d4fbec2001-04-20 08:50:36 +00001224 maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
Werner Lemberg521a2d72001-03-20 22:58:56 +00001225 maskbyte++, ip++ )
Werner Lemberg6fd95122003-12-31 07:51:30 +00001226 FT_TRACE4(( "0x%02X", *ip ));
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001227 }
1228#else
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001229 ip += ( decoder->num_hints + 7 ) >> 3;
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001230#endif
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001231 if ( ip >= limit )
1232 goto Syntax_Error;
1233 args = stack;
1234 break;
1235
1236 case cff_op_rmoveto:
1237 FT_TRACE4(( " rmoveto" ));
1238
David Turnerb9b2cac2002-07-10 16:52:06 +00001239 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001240 builder->path_begun = 0;
1241 x += args[0];
1242 y += args[1];
1243 args = stack;
1244 break;
1245
1246 case cff_op_vmoveto:
1247 FT_TRACE4(( " vmoveto" ));
1248
David Turnerb9b2cac2002-07-10 16:52:06 +00001249 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001250 builder->path_begun = 0;
1251 y += args[0];
1252 args = stack;
1253 break;
1254
1255 case cff_op_hmoveto:
1256 FT_TRACE4(( " hmoveto" ));
1257
David Turnerb9b2cac2002-07-10 16:52:06 +00001258 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001259 builder->path_begun = 0;
1260 x += args[0];
1261 args = stack;
1262 break;
1263
1264 case cff_op_rlineto:
1265 FT_TRACE4(( " rlineto" ));
1266
Werner Lemberg7f74a522002-07-26 09:09:10 +00001267 if ( cff_builder_start_point ( builder, x, y ) ||
1268 check_points( builder, num_args / 2 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001269 goto Memory_Error;
1270
1271 if ( num_args < 2 || num_args & 1 )
1272 goto Stack_Underflow;
1273
1274 args = stack;
1275 while ( args < decoder->top )
1276 {
1277 x += args[0];
1278 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001279 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001280 args += 2;
1281 }
1282 args = stack;
1283 break;
1284
1285 case cff_op_hlineto:
1286 case cff_op_vlineto:
1287 {
1288 FT_Int phase = ( op == cff_op_hlineto );
1289
1290
1291 FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001292 : " vlineto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001293
David Turnerb9b2cac2002-07-10 16:52:06 +00001294 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001295 check_points( builder, num_args ) )
1296 goto Memory_Error;
1297
1298 args = stack;
1299 while (args < decoder->top )
1300 {
1301 if ( phase )
1302 x += args[0];
1303 else
1304 y += args[0];
1305
Werner Lemberg7f74a522002-07-26 09:09:10 +00001306 if ( cff_builder_add_point1( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001307 goto Memory_Error;
1308
1309 args++;
1310 phase ^= 1;
1311 }
1312 args = stack;
1313 }
1314 break;
1315
1316 case cff_op_rrcurveto:
1317 FT_TRACE4(( " rrcurveto" ));
1318
1319 /* check number of arguments; must be a multiple of 6 */
1320 if ( num_args % 6 != 0 )
1321 goto Stack_Underflow;
1322
Werner Lemberg7f74a522002-07-26 09:09:10 +00001323 if ( cff_builder_start_point ( builder, x, y ) ||
1324 check_points( builder, num_args / 2 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001325 goto Memory_Error;
1326
1327 args = stack;
1328 while ( args < decoder->top )
1329 {
1330 x += args[0];
1331 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001332 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001333 x += args[2];
1334 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001335 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001336 x += args[4];
1337 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001338 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001339 args += 6;
1340 }
1341 args = stack;
1342 break;
1343
1344 case cff_op_vvcurveto:
1345 FT_TRACE4(( " vvcurveto" ));
1346
David Turnerb9b2cac2002-07-10 16:52:06 +00001347 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001348 goto Memory_Error;
1349
1350 args = stack;
1351 if ( num_args & 1 )
1352 {
1353 x += args[0];
1354 args++;
1355 num_args--;
1356 }
1357
1358 if ( num_args % 4 != 0 )
1359 goto Stack_Underflow;
1360
1361 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1362 goto Memory_Error;
1363
1364 while ( args < decoder->top )
1365 {
1366 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001367 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001368 x += args[1];
1369 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001370 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001371 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001372 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001373 args += 4;
1374 }
1375 args = stack;
1376 break;
1377
1378 case cff_op_hhcurveto:
1379 FT_TRACE4(( " hhcurveto" ));
1380
David Turnerb9b2cac2002-07-10 16:52:06 +00001381 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001382 goto Memory_Error;
1383
1384 args = stack;
1385 if ( num_args & 1 )
1386 {
1387 y += args[0];
1388 args++;
1389 num_args--;
1390 }
1391
1392 if ( num_args % 4 != 0 )
1393 goto Stack_Underflow;
1394
1395 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1396 goto Memory_Error;
1397
1398 while ( args < decoder->top )
1399 {
1400 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001401 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001402 x += args[1];
1403 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001404 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001405 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001406 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001407 args += 4;
1408 }
1409 args = stack;
1410 break;
1411
1412 case cff_op_vhcurveto:
1413 case cff_op_hvcurveto:
1414 {
1415 FT_Int phase;
1416
1417
1418 FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001419 : " hvcurveto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001420
David Turnerb9b2cac2002-07-10 16:52:06 +00001421 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001422 goto Memory_Error;
1423
1424 args = stack;
1425 if (num_args < 4 || ( num_args % 4 ) > 1 )
1426 goto Stack_Underflow;
1427
1428 if ( check_points( builder, ( num_args / 4 ) * 3 ) )
1429 goto Stack_Underflow;
1430
1431 phase = ( op == cff_op_hvcurveto );
1432
1433 while ( num_args >= 4 )
1434 {
1435 num_args -= 4;
1436 if ( phase )
1437 {
1438 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001439 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001440 x += args[1];
1441 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001442 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001443 y += args[3];
1444 if ( num_args == 1 )
1445 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001446 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001447 }
1448 else
1449 {
1450 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001451 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001452 x += args[1];
1453 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001454 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001455 x += args[3];
1456 if ( num_args == 1 )
1457 y += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001458 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001459 }
1460 args += 4;
1461 phase ^= 1;
1462 }
1463 args = stack;
1464 }
1465 break;
1466
1467 case cff_op_rlinecurve:
1468 {
1469 FT_Int num_lines = ( num_args - 6 ) / 2;
1470
1471
1472 FT_TRACE4(( " rlinecurve" ));
1473
1474 if ( num_args < 8 || ( num_args - 6 ) & 1 )
1475 goto Stack_Underflow;
1476
Werner Lemberg7f74a522002-07-26 09:09:10 +00001477 if ( cff_builder_start_point( builder, x, y ) ||
1478 check_points( builder, num_lines + 3 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001479 goto Memory_Error;
1480
1481 args = stack;
1482
1483 /* first, add the line segments */
1484 while ( num_lines > 0 )
1485 {
1486 x += args[0];
1487 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001488 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001489 args += 2;
1490 num_lines--;
1491 }
1492
1493 /* then the curve */
1494 x += args[0];
1495 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001496 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001497 x += args[2];
1498 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001499 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001500 x += args[4];
1501 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001502 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001503 args = stack;
1504 }
1505 break;
1506
1507 case cff_op_rcurveline:
1508 {
1509 FT_Int num_curves = ( num_args - 2 ) / 6;
1510
1511
1512 FT_TRACE4(( " rcurveline" ));
1513
1514 if ( num_args < 8 || ( num_args - 2 ) % 6 )
1515 goto Stack_Underflow;
1516
Werner Lemberg7f74a522002-07-26 09:09:10 +00001517 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001518 check_points( builder, num_curves*3 + 2 ) )
1519 goto Memory_Error;
1520
1521 args = stack;
1522
1523 /* first, add the curves */
1524 while ( num_curves > 0 )
1525 {
1526 x += args[0];
1527 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001528 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001529 x += args[2];
1530 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001531 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001532 x += args[4];
1533 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001534 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001535 args += 6;
1536 num_curves--;
1537 }
1538
1539 /* then the final line */
1540 x += args[0];
1541 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001542 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001543 args = stack;
1544 }
1545 break;
1546
1547 case cff_op_hflex1:
1548 {
1549 FT_Pos start_y;
1550
1551
1552 FT_TRACE4(( " hflex1" ));
1553
1554 args = stack;
1555
1556 /* adding five more points; 4 control points, 1 on-curve point */
1557 /* make sure we have enough space for the start point if it */
1558 /* needs to be added.. */
David Turnerb9b2cac2002-07-10 16:52:06 +00001559 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001560 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001561 goto Memory_Error;
1562
1563 /* Record the starting point's y postion for later use */
1564 start_y = y;
1565
1566 /* first control point */
1567 x += args[0];
1568 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001569 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001570
1571 /* second control point */
1572 x += args[2];
1573 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001574 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001575
1576 /* join point; on curve, with y-value the same as the last */
1577 /* control point's y-value */
1578 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001579 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001580
1581 /* third control point, with y-value the same as the join */
1582 /* point's y-value */
1583 x += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001584 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001585
1586 /* fourth control point */
1587 x += args[6];
1588 y += args[7];
David Turnerb9b2cac2002-07-10 16:52:06 +00001589 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001590
1591 /* ending point, with y-value the same as the start */
1592 x += args[8];
1593 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001594 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001595
1596 args = stack;
1597 break;
1598 }
1599
1600 case cff_op_hflex:
1601 {
1602 FT_Pos start_y;
1603
1604
1605 FT_TRACE4(( " hflex" ));
1606
1607 args = stack;
1608
1609 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001610 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001611 check_points ( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001612 goto Memory_Error;
1613
1614 /* record the starting point's y-position for later use */
1615 start_y = y;
1616
1617 /* first control point */
1618 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001619 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001620
1621 /* second control point */
1622 x += args[1];
1623 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001624 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001625
1626 /* join point; on curve, with y-value the same as the last */
1627 /* control point's y-value */
1628 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001629 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001630
1631 /* third control point, with y-value the same as the join */
1632 /* point's y-value */
1633 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001634 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001635
1636 /* fourth control point */
1637 x += args[5];
1638 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001639 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001640
1641 /* ending point, with y-value the same as the start point's */
1642 /* y-value -- we don't add this point, though */
1643 x += args[6];
David Turnerb9b2cac2002-07-10 16:52:06 +00001644 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001645
1646 args = stack;
1647 break;
1648 }
1649
1650 case cff_op_flex1:
1651 {
Werner Lemberg84c60bb2004-01-01 08:21:30 +00001652 FT_Pos start_x, start_y; /* record start x, y values for */
1653 /* alter use */
1654 FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */
1655 /* algorithm below */
1656 FT_Int horizontal, count;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001657
1658
1659 FT_TRACE4(( " flex1" ));
1660
1661 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001662 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001663 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001664 goto Memory_Error;
1665
1666 /* record the starting point's x, y postion for later use */
1667 start_x = x;
1668 start_y = y;
1669
1670 /* XXX: figure out whether this is supposed to be a horizontal */
1671 /* or vertical flex; the Type 2 specification is vague... */
1672
1673 args = stack;
1674
1675 /* grab up to the last argument */
1676 for ( count = 5; count > 0; count-- )
1677 {
Werner Lemberg84c60bb2004-01-01 08:21:30 +00001678 dx += args[0];
1679 dy += args[1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001680 args += 2;
1681 }
1682
1683 /* rewind */
1684 args = stack;
1685
1686 if ( dx < 0 ) dx = -dx;
1687 if ( dy < 0 ) dy = -dy;
1688
1689 /* strange test, but here it is... */
1690 horizontal = ( dx > dy );
1691
1692 for ( count = 5; count > 0; count-- )
1693 {
1694 x += args[0];
1695 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001696 cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001697 args += 2;
1698 }
1699
1700 /* is last operand an x- or y-delta? */
1701 if ( horizontal )
1702 {
1703 x += args[0];
1704 y = start_y;
1705 }
1706 else
1707 {
1708 x = start_x;
1709 y += args[0];
1710 }
1711
David Turnerb9b2cac2002-07-10 16:52:06 +00001712 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001713
1714 args = stack;
1715 break;
1716 }
1717
1718 case cff_op_flex:
1719 {
1720 FT_UInt count;
1721
1722
1723 FT_TRACE4(( " flex" ));
1724
David Turnerb9b2cac2002-07-10 16:52:06 +00001725 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001726 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001727 goto Memory_Error;
1728
1729 args = stack;
1730 for ( count = 6; count > 0; count-- )
1731 {
1732 x += args[0];
1733 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001734 cff_builder_add_point( builder, x, y,
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001735 (FT_Bool)( count == 4 || count == 1 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001736 args += 2;
1737 }
1738
1739 args = stack;
1740 }
1741 break;
1742
1743 case cff_op_endchar:
1744 FT_TRACE4(( " endchar" ));
1745
1746 /* We are going to emulate the seac operator. */
1747 if ( num_args == 4 )
1748 {
Werner Lemberg916838c2004-02-10 16:02:20 +00001749 /* Save glyph width so that the subglyphs don't overwrite it. */
1750 FT_Pos glyph_width = decoder->glyph_width;
1751
1752
Werner Lembergd573c7e2001-01-03 07:14:12 +00001753 error = cff_operator_seac( decoder,
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001754 args[0],
1755 args[1],
Werner Lemberg68e9f922002-09-27 11:09:23 +00001756 (FT_Int)( args[2] >> 16 ),
1757 (FT_Int)( args[3] >> 16 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001758 args += 4;
Werner Lemberg916838c2004-02-10 16:02:20 +00001759
1760 decoder->glyph_width = glyph_width;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001761 }
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001762 else
David Turner2b30c172001-12-12 16:07:29 +00001763 {
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001764 if ( !error )
1765 error = CFF_Err_Ok;
David Turnerbce29862001-12-14 14:52:58 +00001766
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001767 cff_builder_close_contour( builder );
1768
1769 /* close hints recording session */
1770 if ( hinter )
1771 {
1772 if (hinter->close( hinter->hints, builder->current->n_points ) )
1773 goto Syntax_Error;
1774
1775 /* apply hints to the loaded glyph outline now */
1776 hinter->apply( hinter->hints,
1777 builder->current,
1778 (PSH_Globals)builder->hints_globals,
1779 decoder->hint_mode );
1780 }
1781
1782 /* add current outline to the glyph slot */
1783 FT_GlyphLoader_Add( builder->loader );
David Turner2b30c172001-12-12 16:07:29 +00001784 }
1785
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001786 /* return now! */
1787 FT_TRACE4(( "\n\n" ));
1788 return error;
1789
1790 case cff_op_abs:
1791 FT_TRACE4(( " abs" ));
1792
1793 if ( args[0] < 0 )
1794 args[0] = -args[0];
1795 args++;
1796 break;
1797
1798 case cff_op_add:
1799 FT_TRACE4(( " add" ));
1800
1801 args[0] += args[1];
1802 args++;
1803 break;
1804
1805 case cff_op_sub:
1806 FT_TRACE4(( " sub" ));
1807
1808 args[0] -= args[1];
1809 args++;
1810 break;
1811
1812 case cff_op_div:
1813 FT_TRACE4(( " div" ));
1814
1815 args[0] = FT_DivFix( args[0], args[1] );
1816 args++;
1817 break;
1818
1819 case cff_op_neg:
1820 FT_TRACE4(( " neg" ));
1821
1822 args[0] = -args[0];
1823 args++;
1824 break;
1825
1826 case cff_op_random:
1827 {
Werner Lemberg94ffae52002-04-14 00:54:32 +00001828 FT_Fixed Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001829
1830
1831 FT_TRACE4(( " rand" ));
1832
Werner Lemberg94ffae52002-04-14 00:54:32 +00001833 Rand = seed;
Werner Lemberg43ba0842003-06-23 19:26:53 +00001834 if ( Rand >= 0x8000L )
Werner Lemberg94ffae52002-04-14 00:54:32 +00001835 Rand++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001836
Werner Lemberg94ffae52002-04-14 00:54:32 +00001837 args[0] = Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001838 seed = FT_MulFix( seed, 0x10000L - seed );
1839 if ( seed == 0 )
1840 seed += 0x2873;
1841 args++;
1842 }
1843 break;
1844
1845 case cff_op_mul:
1846 FT_TRACE4(( " mul" ));
1847
1848 args[0] = FT_MulFix( args[0], args[1] );
1849 args++;
1850 break;
1851
1852 case cff_op_sqrt:
1853 FT_TRACE4(( " sqrt" ));
1854
1855 if ( args[0] > 0 )
1856 {
1857 FT_Int count = 9;
1858 FT_Fixed root = args[0];
1859 FT_Fixed new_root;
1860
1861
1862 for (;;)
1863 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001864 new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001865 if ( new_root == root || count <= 0 )
1866 break;
1867 root = new_root;
1868 }
1869 args[0] = new_root;
1870 }
1871 else
1872 args[0] = 0;
1873 args++;
1874 break;
1875
1876 case cff_op_drop:
1877 /* nothing */
1878 FT_TRACE4(( " drop" ));
1879
1880 break;
1881
1882 case cff_op_exch:
1883 {
1884 FT_Fixed tmp;
1885
1886
1887 FT_TRACE4(( " exch" ));
1888
1889 tmp = args[0];
1890 args[0] = args[1];
1891 args[1] = tmp;
1892 args += 2;
1893 }
1894 break;
1895
1896 case cff_op_index:
1897 {
Werner Lemberg68e9f922002-09-27 11:09:23 +00001898 FT_Int idx = (FT_Int)( args[0] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001899
1900
1901 FT_TRACE4(( " index" ));
1902
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001903 if ( idx < 0 )
1904 idx = 0;
1905 else if ( idx > num_args - 2 )
1906 idx = num_args - 2;
1907 args[0] = args[-( idx + 1 )];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001908 args++;
1909 }
1910 break;
1911
1912 case cff_op_roll:
1913 {
1914 FT_Int count = (FT_Int)( args[0] >> 16 );
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001915 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001916
1917
1918 FT_TRACE4(( " roll" ));
1919
1920 if ( count <= 0 )
1921 count = 1;
1922
1923 args -= count;
1924 if ( args < stack )
1925 goto Stack_Underflow;
1926
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001927 if ( idx >= 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001928 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001929 while ( idx > 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001930 {
1931 FT_Fixed tmp = args[count - 1];
1932 FT_Int i;
1933
1934
1935 for ( i = count - 2; i >= 0; i-- )
1936 args[i + 1] = args[i];
1937 args[0] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001938 idx--;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001939 }
1940 }
1941 else
1942 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001943 while ( idx < 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001944 {
1945 FT_Fixed tmp = args[0];
1946 FT_Int i;
1947
1948
1949 for ( i = 0; i < count - 1; i++ )
1950 args[i] = args[i + 1];
1951 args[count - 1] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001952 idx++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001953 }
1954 }
1955 args += count;
1956 }
1957 break;
1958
1959 case cff_op_dup:
1960 FT_TRACE4(( " dup" ));
1961
1962 args[1] = args[0];
1963 args++;
1964 break;
1965
1966 case cff_op_put:
1967 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001968 FT_Fixed val = args[0];
1969 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001970
1971
1972 FT_TRACE4(( " put" ));
1973
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001974 if ( idx >= 0 && idx < decoder->len_buildchar )
1975 decoder->buildchar[idx] = val;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001976 }
1977 break;
1978
1979 case cff_op_get:
1980 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001981 FT_Int idx = (FT_Int)( args[0] >> 16 );
1982 FT_Fixed val = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001983
1984
1985 FT_TRACE4(( " get" ));
1986
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001987 if ( idx >= 0 && idx < decoder->len_buildchar )
1988 val = decoder->buildchar[idx];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001989
1990 args[0] = val;
1991 args++;
1992 }
1993 break;
1994
1995 case cff_op_store:
1996 FT_TRACE4(( " store "));
1997
1998 goto Unimplemented;
1999
2000 case cff_op_load:
2001 FT_TRACE4(( " load" ));
2002
2003 goto Unimplemented;
2004
David Turner8d3a4012001-03-20 11:14:24 +00002005 case cff_op_dotsection:
Werner Lemberg521a2d72001-03-20 22:58:56 +00002006 /* this operator is deprecated and ignored by the parser */
2007 FT_TRACE4(( " dotsection" ));
David Turner8d3a4012001-03-20 11:14:24 +00002008 break;
2009
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002010 case cff_op_and:
2011 {
2012 FT_Fixed cond = args[0] && args[1];
2013
2014
2015 FT_TRACE4(( " and" ));
2016
2017 args[0] = cond ? 0x10000L : 0;
2018 args++;
2019 }
2020 break;
2021
2022 case cff_op_or:
2023 {
2024 FT_Fixed cond = args[0] || args[1];
2025
2026
2027 FT_TRACE4(( " or" ));
2028
2029 args[0] = cond ? 0x10000L : 0;
2030 args++;
2031 }
2032 break;
2033
2034 case cff_op_eq:
2035 {
2036 FT_Fixed cond = !args[0];
2037
2038
2039 FT_TRACE4(( " eq" ));
2040
2041 args[0] = cond ? 0x10000L : 0;
2042 args++;
2043 }
2044 break;
2045
2046 case cff_op_ifelse:
2047 {
2048 FT_Fixed cond = (args[2] <= args[3]);
2049
2050
2051 FT_TRACE4(( " ifelse" ));
2052
2053 if ( !cond )
2054 args[0] = args[1];
2055 args++;
2056 }
2057 break;
2058
2059 case cff_op_callsubr:
2060 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002061 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2062 decoder->locals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002063
2064
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002065 FT_TRACE4(( " callsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002066
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002067 if ( idx >= decoder->num_locals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002068 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002069 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002070 FT_ERROR(( " invalid local subr index\n" ));
2071 goto Syntax_Error;
2072 }
2073
2074 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2075 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002076 FT_ERROR(( "cff_decoder_parse_charstrings:"
2077 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002078 goto Syntax_Error;
2079 }
2080
2081 zone->cursor = ip; /* save current instruction pointer */
2082
2083 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002084 zone->base = decoder->locals[idx];
2085 zone->limit = decoder->locals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002086 zone->cursor = zone->base;
2087
2088 if ( !zone->base )
2089 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002090 FT_ERROR(( "cff_decoder_parse_charstrings:"
2091 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002092 goto Syntax_Error;
2093 }
2094
2095 decoder->zone = zone;
2096 ip = zone->base;
2097 limit = zone->limit;
2098 }
2099 break;
2100
2101 case cff_op_callgsubr:
2102 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002103 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2104 decoder->globals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002105
2106
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002107 FT_TRACE4(( " callgsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002108
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002109 if ( idx >= decoder->num_globals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002110 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002111 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002112 FT_ERROR(( " invalid global subr index\n" ));
2113 goto Syntax_Error;
2114 }
2115
2116 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2117 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002118 FT_ERROR(( "cff_decoder_parse_charstrings:"
2119 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002120 goto Syntax_Error;
2121 }
2122
2123 zone->cursor = ip; /* save current instruction pointer */
2124
2125 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002126 zone->base = decoder->globals[idx];
2127 zone->limit = decoder->globals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002128 zone->cursor = zone->base;
2129
2130 if ( !zone->base )
2131 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002132 FT_ERROR(( "cff_decoder_parse_charstrings:"
2133 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002134 goto Syntax_Error;
2135 }
2136
2137 decoder->zone = zone;
2138 ip = zone->base;
2139 limit = zone->limit;
2140 }
2141 break;
2142
2143 case cff_op_return:
2144 FT_TRACE4(( " return" ));
2145
2146 if ( decoder->zone <= decoder->zones )
2147 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002148 FT_ERROR(( "cff_decoder_parse_charstrings:"
2149 " unexpected return\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002150 goto Syntax_Error;
2151 }
2152
2153 decoder->zone--;
2154 zone = decoder->zone;
2155 ip = zone->cursor;
2156 limit = zone->limit;
2157 break;
2158
2159 default:
2160 Unimplemented:
2161 FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
2162
2163 if ( ip[-1] == 12 )
2164 FT_ERROR(( " %d", ip[0] ));
2165 FT_ERROR(( "\n" ));
2166
2167 return CFF_Err_Unimplemented_Feature;
2168 }
2169
2170 decoder->top = args;
2171
2172 } /* general operator processing */
2173
2174 } /* while ip < limit */
2175
2176 FT_TRACE4(( "..end..\n\n" ));
2177
2178 return error;
2179
2180 Syntax_Error:
David Turnerb9b2cac2002-07-10 16:52:06 +00002181 FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002182 return CFF_Err_Invalid_File_Format;
2183
2184 Stack_Underflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002185 FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002186 return CFF_Err_Too_Few_Arguments;
2187
2188 Stack_Overflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002189 FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002190 return CFF_Err_Stack_Overflow;
2191
2192 Memory_Error:
2193 return builder->error;
2194 }
2195
2196
2197 /*************************************************************************/
2198 /*************************************************************************/
2199 /*************************************************************************/
2200 /********** *********/
2201 /********** *********/
2202 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
2203 /********** *********/
2204 /********** The following code is in charge of computing *********/
2205 /********** the maximum advance width of the font. It *********/
2206 /********** quickly processes each glyph charstring to *********/
2207 /********** extract the value from either a `sbw' or `seac' *********/
2208 /********** operator. *********/
2209 /********** *********/
2210 /*************************************************************************/
2211 /*************************************************************************/
2212 /*************************************************************************/
2213
2214
2215#if 0 /* unused until we support pure CFF fonts */
2216
2217
David Turnerbc82f1b2002-03-01 02:26:22 +00002218 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002219 cff_compute_max_advance( TT_Face face,
Werner Lemberg93616ec2001-06-27 19:46:12 +00002220 FT_Int* max_advance )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002221 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002222 FT_Error error = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002223 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002224 FT_Int glyph_index;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002225 CFF_Font cff = (CFF_Font)face->other;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002226
2227
2228 *max_advance = 0;
2229
2230 /* Initialize load decoder */
David Turnerd1245c02002-08-27 22:34:20 +00002231 cff_decoder_init( &decoder, face, 0, 0, 0, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002232
2233 decoder.builder.metrics_only = 1;
2234 decoder.builder.load_points = 0;
2235
2236 /* For each glyph, parse the glyph charstring and extract */
2237 /* the advance width. */
2238 for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
2239 glyph_index++ )
2240 {
2241 FT_Byte* charstring;
2242 FT_ULong charstring_len;
2243
2244
2245 /* now get load the unscaled outline */
Graham Asher3fd12f12002-08-15 12:10:48 +00002246 error = cff_get_glyph_data( face, glyph_index,
2247 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002248 if ( !error )
2249 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002250 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002251 error = cff_decoder_parse_charstrings( &decoder,
2252 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002253
Graham Asher3fd12f12002-08-15 12:10:48 +00002254 cff_free_glyph_data( face, &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002255 }
2256
2257 /* ignore the error if one has occurred -- skip to next glyph */
2258 error = 0;
2259 }
2260
2261 *max_advance = decoder.builder.advance.x;
2262
2263 return CFF_Err_Ok;
2264 }
2265
2266
2267#endif /* 0 */
2268
2269
2270 /*************************************************************************/
2271 /*************************************************************************/
2272 /*************************************************************************/
2273 /********** *********/
2274 /********** *********/
2275 /********** UNHINTED GLYPH LOADER *********/
2276 /********** *********/
2277 /********** The following code is in charge of loading a *********/
2278 /********** single outline. It completely ignores hinting *********/
2279 /********** and is used when FT_LOAD_NO_HINTING is set. *********/
2280 /********** *********/
2281 /*************************************************************************/
2282 /*************************************************************************/
2283 /*************************************************************************/
2284
2285
David Turnerbc82f1b2002-03-01 02:26:22 +00002286 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002287 cff_slot_load( CFF_GlyphSlot glyph,
2288 CFF_Size size,
2289 FT_Int glyph_index,
David Turnerd1245c02002-08-27 22:34:20 +00002290 FT_Int32 load_flags )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002291 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002292 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002293 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002294 TT_Face face = (TT_Face)glyph->root.face;
2295 FT_Bool hinting;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002296 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002297
Werner Lembergd573c7e2001-01-03 07:14:12 +00002298 FT_Matrix font_matrix;
2299 FT_Vector font_offset;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002300
2301
2302 if ( load_flags & FT_LOAD_NO_RECURSE )
2303 load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2304
2305 glyph->x_scale = 0x10000L;
2306 glyph->y_scale = 0x10000L;
2307 if ( size )
2308 {
2309 glyph->x_scale = size->metrics.x_scale;
2310 glyph->y_scale = size->metrics.y_scale;
2311 }
2312
2313 glyph->root.outline.n_points = 0;
2314 glyph->root.outline.n_contours = 0;
2315
David Turner8edbcab2001-06-19 08:28:24 +00002316 hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
2317 ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002318
David Turnerb08fe2d2002-08-27 20:20:29 +00002319 glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002320
2321 {
2322 FT_Byte* charstring;
2323 FT_ULong charstring_len;
2324
2325
Werner Lembergb36d4a52003-12-12 15:38:39 +00002326 /* in a CID-keyed font, consider `glyph_index' as a CID and map */
Werner Lemberga9cd8562003-12-18 08:18:37 +00002327 /* it immediately to the real glyph_index -- if it isn't a */
2328 /* subsetted font, glyph_indices and CIDs are identical, though */
2329 if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
2330 cff->charset.cids )
Werner Lembergb36d4a52003-12-12 15:38:39 +00002331 glyph_index = cff->charset.cids[glyph_index];
2332
David Turnerd1245c02002-08-27 22:34:20 +00002333 cff_decoder_init( &decoder, face, size, glyph, hinting,
Werner Lembergc846eac2004-02-19 21:39:58 +00002334 FT_LOAD_TARGET_MODE( load_flags ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002335
2336 decoder.builder.no_recurse =
2337 (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
2338
2339 /* now load the unscaled outline */
Graham Asher3fd12f12002-08-15 12:10:48 +00002340 error = cff_get_glyph_data( face, glyph_index,
2341 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002342 if ( !error )
2343 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002344 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002345 error = cff_decoder_parse_charstrings( &decoder,
2346 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002347
Graham Asher3fd12f12002-08-15 12:10:48 +00002348 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002349
Graham Asher3fd12f12002-08-15 12:10:48 +00002350
2351#ifdef FT_CONFIG_OPTION_INCREMENTAL
Werner Lemberg6b5c6692002-09-05 15:10:54 +00002352 /* Control data and length may not be available for incremental */
Graham Asher3fd12f12002-08-15 12:10:48 +00002353 /* fonts. */
2354 if ( face->root.internal->incremental_interface )
2355 {
2356 glyph->root.control_data = 0;
2357 glyph->root.control_len = 0;
2358 }
2359 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +00002360#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2361
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002362 /* We set control_data and control_len if charstrings is loaded. */
Werner Lemberg7f74a522002-07-26 09:09:10 +00002363 /* See how charstring loads at cff_index_access_element() in */
2364 /* cffload.c. */
Graham Asher3fd12f12002-08-15 12:10:48 +00002365 {
Werner Lemberg6b5c6692002-09-05 15:10:54 +00002366 CFF_IndexRec csindex = cff->charstrings_index;
2367
2368
2369 glyph->root.control_data =
2370 csindex.bytes + csindex.offsets[glyph_index] - 1;
2371 glyph->root.control_len =
2372 charstring_len;
Graham Asher3fd12f12002-08-15 12:10:48 +00002373 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002374 }
2375
2376 /* save new glyph tables */
David Turnerb9b2cac2002-07-10 16:52:06 +00002377 cff_builder_done( &decoder.builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002378 }
2379
Werner Lemberg9b067fa2003-12-11 17:55:58 +00002380#ifdef FT_CONFIG_OPTION_INCREMENTAL
Graham Asher46960df2003-02-13 17:49:27 +00002381
2382 /* Incremental fonts can optionally override the metrics. */
Werner Lemberg2acb9632003-04-23 06:47:12 +00002383 if ( !error &&
2384 face->root.internal->incremental_interface &&
Graham Asher46960df2003-02-13 17:49:27 +00002385 face->root.internal->incremental_interface->funcs->get_glyph_metrics )
2386 {
2387 FT_Incremental_MetricsRec metrics;
2388
Werner Lemberg2acb9632003-04-23 06:47:12 +00002389
Graham Asher46960df2003-02-13 17:49:27 +00002390 metrics.bearing_x = decoder.builder.left_bearing.x;
Werner Lemberg428c2e42003-04-25 05:35:04 +00002391 metrics.bearing_y = decoder.builder.left_bearing.y;
2392 metrics.advance = decoder.builder.advance.x;
Graham Asher46960df2003-02-13 17:49:27 +00002393 error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
2394 face->root.internal->incremental_interface->object,
2395 glyph_index, FALSE, &metrics );
2396 decoder.builder.left_bearing.x = metrics.bearing_x;
2397 decoder.builder.left_bearing.y = metrics.bearing_y;
2398 decoder.builder.advance.x = metrics.advance;
2399 decoder.builder.advance.y = 0;
2400 }
2401
2402#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2403
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002404 font_matrix = cff->top_font.font_dict.font_matrix;
2405 font_offset = cff->top_font.font_dict.font_offset;
2406
2407 /* Now, set the metrics -- this is rather simple, as */
2408 /* the left side bearing is the xMin, and the top side */
2409 /* bearing the yMax. */
2410 if ( !error )
2411 {
2412 /* For composite glyphs, return only left side bearing and */
2413 /* advance width. */
2414 if ( load_flags & FT_LOAD_NO_RECURSE )
2415 {
2416 FT_Slot_Internal internal = glyph->root.internal;
Werner Lemberg415235d2001-06-28 17:49:10 +00002417
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002418
2419 glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
2420 glyph->root.metrics.horiAdvance = decoder.glyph_width;
2421 internal->glyph_matrix = font_matrix;
2422 internal->glyph_delta = font_offset;
2423 internal->glyph_transformed = 1;
2424 }
2425 else
2426 {
2427 FT_BBox cbox;
2428 FT_Glyph_Metrics* metrics = &glyph->root.metrics;
Werner Lemberge8ff7692003-08-06 04:40:48 +00002429 FT_Vector advance;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002430
2431
2432 /* copy the _unscaled_ advance width */
2433 metrics->horiAdvance = decoder.glyph_width;
2434 glyph->root.linearHoriAdvance = decoder.glyph_width;
2435 glyph->root.internal->glyph_transformed = 0;
2436
2437 /* make up vertical metrics */
2438 metrics->vertBearingX = 0;
2439 metrics->vertBearingY = 0;
2440 metrics->vertAdvance = 0;
2441
2442 glyph->root.linearVertAdvance = 0;
2443
David Turnerb08fe2d2002-08-27 20:20:29 +00002444 glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002445
2446 glyph->root.outline.flags = 0;
2447 if ( size && size->metrics.y_ppem < 24 )
David Turnerb08fe2d2002-08-27 20:20:29 +00002448 glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002449
David Turnerb08fe2d2002-08-27 20:20:29 +00002450 glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002451
2452 /* apply the font matrix */
2453 FT_Outline_Transform( &glyph->root.outline, &font_matrix );
2454
2455 FT_Outline_Translate( &glyph->root.outline,
2456 font_offset.x,
2457 font_offset.y );
2458
Werner Lemberge8ff7692003-08-06 04:40:48 +00002459 advance.x = metrics->horiAdvance;
Werner Lemberge52c4ba2003-08-06 17:27:14 +00002460 advance.y = 0;
2461 FT_Vector_Transform( &advance, &font_matrix );
2462 metrics->horiAdvance = advance.x + font_offset.x;
2463 advance.x = 0;
Werner Lemberge8ff7692003-08-06 04:40:48 +00002464 advance.y = metrics->vertAdvance;
2465 FT_Vector_Transform( &advance, &font_matrix );
Werner Lemberge52c4ba2003-08-06 17:27:14 +00002466 metrics->vertAdvance = advance.y + font_offset.y;
Werner Lemberge8ff7692003-08-06 04:40:48 +00002467
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002468 if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
2469 {
2470 /* scale the outline and the metrics */
2471 FT_Int n;
2472 FT_Outline* cur = &glyph->root.outline;
2473 FT_Vector* vec = cur->points;
2474 FT_Fixed x_scale = glyph->x_scale;
2475 FT_Fixed y_scale = glyph->y_scale;
2476
2477
2478 /* First of all, scale the points */
David Turnerc8087482001-12-20 13:14:18 +00002479 if ( !hinting )
2480 for ( n = cur->n_points; n > 0; n--, vec++ )
2481 {
2482 vec->x = FT_MulFix( vec->x, x_scale );
2483 vec->y = FT_MulFix( vec->y, y_scale );
2484 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002485
2486 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2487
2488 /* Then scale the metrics */
2489 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
2490 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
2491
2492 metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
2493 metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
David Turnerbce29862001-12-14 14:52:58 +00002494
2495 if ( hinting )
2496 {
David Turner87c0d302003-12-24 01:10:46 +00002497 metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance );
2498 metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance );
David Turnerbce29862001-12-14 14:52:58 +00002499
David Turner87c0d302003-12-24 01:10:46 +00002500 metrics->vertBearingX = FT_PIX_ROUND( metrics->vertBearingX );
2501 metrics->vertBearingY = FT_PIX_ROUND( metrics->vertBearingY );
David Turnerbce29862001-12-14 14:52:58 +00002502 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002503 }
2504
2505 /* compute the other metrics */
2506 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2507
2508 /* grid fit the bounding box if necessary */
2509 if ( hinting )
2510 {
2511 cbox.xMin &= -64;
2512 cbox.yMin &= -64;
2513 cbox.xMax = ( cbox.xMax + 63 ) & -64;
2514 cbox.yMax = ( cbox.yMax + 63 ) & -64;
2515 }
2516
2517 metrics->width = cbox.xMax - cbox.xMin;
2518 metrics->height = cbox.yMax - cbox.yMin;
2519
2520 metrics->horiBearingX = cbox.xMin;
2521 metrics->horiBearingY = cbox.yMax;
2522 }
2523 }
2524
2525 return error;
2526 }
2527
2528
2529/* END */