blob: f7f0c9a81e66b0455b74f714fc790c84a713e5e3 [file] [log] [blame]
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001/***************************************************************************/
2/* */
3/* cffgload.c */
4/* */
5/* OpenType Glyph Loader (body). */
6/* */
Werner Lembergf1c2b912006-01-13 14:53:28 +00007/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 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 {
Werner Lembergbfb712f2004-03-03 08:21:12 +0000254 builder->hints_globals = size->root.internal;
David Turnerc8087482001-12-20 13:14:18 +0000255 builder->hints_funcs = glyph->root.internal->glyph_hints;
256 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000257 }
258
259 if ( size )
260 {
Werner Lembergbfb712f2004-03-03 08:21:12 +0000261 builder->scale_x = size->root.metrics.x_scale;
262 builder->scale_y = size->root.metrics.y_scale;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000263 }
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 Turner9fbd2ab2005-10-28 16:14:14 +0000406 return FT_GLYPHLOADER_CHECK_POINTS( 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 Turner9fbd2ab2005-10-28 16:14:14 +0000468 error = FT_GLYPHLOADER_CHECK_POINTS( 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 {
Werner Lembergbfb712f2004-03-03 08:21:12 +0000488 FT_Error error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000489
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
Werner Lembergda245ee2005-08-18 07:40:32 +0000511 if ( !outline )
512 return;
513
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000514 /* XXXX: We must not include the last point in the path if it */
515 /* is located on the first point. */
516 if ( outline->n_points > 1 )
517 {
518 FT_Int first = 0;
519 FT_Vector* p1 = outline->points + first;
520 FT_Vector* p2 = outline->points + outline->n_points - 1;
521 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
522
523
524 if ( outline->n_contours > 1 )
525 {
526 first = outline->contours[outline->n_contours - 2] + 1;
527 p1 = outline->points + first;
528 }
529
Werner Lemberg48c984b2002-03-30 16:41:09 +0000530 /* `delete' last point only if it coincides with the first */
531 /* point and if it is not a control point (which can happen). */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000532 if ( p1->x == p2->x && p1->y == p2->y )
David Turnerb08fe2d2002-08-27 20:20:29 +0000533 if ( *control == FT_CURVE_TAG_ON )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000534 outline->n_points--;
535 }
536
537 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000538 outline->contours[outline->n_contours - 1] =
539 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000540 }
541
542
Werner Lemberg93616ec2001-06-27 19:46:12 +0000543 static FT_Int
David Turnerab4fc4d2002-03-14 08:57:10 +0000544 cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
Werner Lemberg48c984b2002-03-30 16:41:09 +0000545 FT_Int charcode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000546 {
547 FT_UInt n;
548 FT_UShort glyph_sid;
549
550
Werner Lemberg328abf32003-12-24 13:37:58 +0000551 /* CID-keyed fonts don't have glyph names */
552 if ( !cff->charset.sids )
553 return -1;
554
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000555 /* check range of standard char code */
556 if ( charcode < 0 || charcode > 255 )
557 return -1;
558
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000559 /* Get code to SID mapping from `cff_standard_encoding'. */
David Turnerb9b2cac2002-07-10 16:52:06 +0000560 glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000561
562 for ( n = 0; n < cff->num_glyphs; n++ )
563 {
564 if ( cff->charset.sids[n] == glyph_sid )
565 return n;
566 }
567
568 return -1;
569 }
570
571
Werner Lemberg93616ec2001-06-27 19:46:12 +0000572 static FT_Error
Graham Asher3fd12f12002-08-15 12:10:48 +0000573 cff_get_glyph_data( TT_Face face,
574 FT_UInt glyph_index,
575 FT_Byte** pointer,
576 FT_ULong* length )
577 {
578#ifdef FT_CONFIG_OPTION_INCREMENTAL
579 /* For incremental fonts get the character data using the */
580 /* callback function. */
581 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000582 {
583 FT_Data data;
584 FT_Error error =
585 face->root.internal->incremental_interface->funcs->get_glyph_data(
586 face->root.internal->incremental_interface->object,
587 glyph_index, &data );
588
589
Graham Asher3fd12f12002-08-15 12:10:48 +0000590 *pointer = (FT_Byte*)data.pointer;
Graham Asher9eefed12002-08-23 10:08:38 +0000591 *length = data.length;
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000592
Graham Asher3fd12f12002-08-15 12:10:48 +0000593 return error;
594 }
595 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000596#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Graham Asher3fd12f12002-08-15 12:10:48 +0000597
598 {
Graham Asher9eefed12002-08-23 10:08:38 +0000599 CFF_Font cff = (CFF_Font)(face->extra.data);
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000600
601
Graham Asher3fd12f12002-08-15 12:10:48 +0000602 return cff_index_access_element( &cff->charstrings_index, glyph_index,
603 pointer, length );
604 }
605 }
606
607
608 static void
609 cff_free_glyph_data( TT_Face face,
610 FT_Byte** pointer,
611 FT_ULong length )
612 {
Graham Asher824daa52002-08-15 12:58:21 +0000613#ifndef FT_CONFIG_OPTION_INCREMENTAL
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000614 FT_UNUSED( length );
Graham Asher824daa52002-08-15 12:58:21 +0000615#endif
616
Graham Asher3fd12f12002-08-15 12:10:48 +0000617#ifdef FT_CONFIG_OPTION_INCREMENTAL
618 /* For incremental fonts get the character data using the */
619 /* callback function. */
620 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000621 {
Graham Asher9eefed12002-08-23 10:08:38 +0000622 FT_Data data;
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000623
624
625 data.pointer = *pointer;
626 data.length = length;
627
Graham Asher3fd12f12002-08-15 12:10:48 +0000628 face->root.internal->incremental_interface->funcs->free_glyph_data(
629 face->root.internal->incremental_interface->object,&data );
630 }
631 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000632#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Graham Asher3fd12f12002-08-15 12:10:48 +0000633
634 {
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000635 CFF_Font cff = (CFF_Font)(face->extra.data);
636
637
Graham Asher3fd12f12002-08-15 12:10:48 +0000638 cff_index_forget_element( &cff->charstrings_index, pointer );
639 }
640 }
641
642
643 static FT_Error
Werner Lemberg93616ec2001-06-27 19:46:12 +0000644 cff_operator_seac( CFF_Decoder* decoder,
645 FT_Pos adx,
646 FT_Pos ady,
647 FT_Int bchar,
648 FT_Int achar )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000649 {
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000650 FT_Error error;
651 CFF_Builder* builder = &decoder->builder;
652 FT_Int bchar_index, achar_index;
653 TT_Face face = decoder->builder.face;
654 FT_Vector left_bearing, advance;
655 FT_Byte* charstring;
656 FT_ULong charstring_len;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000657
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000658
Graham Asher9eefed12002-08-23 10:08:38 +0000659#ifdef FT_CONFIG_OPTION_INCREMENTAL
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000660 /* Incremental fonts don't necessarily have valid charsets. */
661 /* They use the character code, not the glyph index, in this case. */
Graham Asher9eefed12002-08-23 10:08:38 +0000662 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000663 {
Graham Asher9eefed12002-08-23 10:08:38 +0000664 bchar_index = bchar;
665 achar_index = achar;
666 }
667 else
668#endif /* FT_CONFIG_OPTION_INCREMENTAL */
669 {
670 CFF_Font cff = (CFF_Font)(face->extra.data);
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000671
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000672
Graham Asher9eefed12002-08-23 10:08:38 +0000673 bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
674 achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000675 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000676
677 if ( bchar_index < 0 || achar_index < 0 )
678 {
679 FT_ERROR(( "cff_operator_seac:" ));
680 FT_ERROR(( " invalid seac character code arguments\n" ));
681 return CFF_Err_Syntax_Error;
682 }
683
684 /* If we are trying to load a composite glyph, do not load the */
685 /* accent character and return the array of subglyphs. */
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000686 if ( builder->no_recurse )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000687 {
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000688 FT_GlyphSlot glyph = (FT_GlyphSlot)builder->glyph;
Werner Lemberg48c984b2002-03-30 16:41:09 +0000689 FT_GlyphLoader loader = glyph->internal->loader;
David Turnereba5ad42002-03-14 12:56:35 +0000690 FT_SubGlyph subg;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000691
692
693 /* reallocate subglyph array if necessary */
David Turnereba5ad42002-03-14 12:56:35 +0000694 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000695 if ( error )
696 goto Exit;
697
698 subg = loader->current.subglyphs;
699
700 /* subglyph 0 = base character */
701 subg->index = bchar_index;
702 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
703 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
704 subg->arg1 = 0;
705 subg->arg2 = 0;
706 subg++;
707
708 /* subglyph 1 = accent character */
709 subg->index = achar_index;
710 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000711 subg->arg1 = (FT_Int)( adx >> 16 );
712 subg->arg2 = (FT_Int)( ady >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000713
714 /* set up remaining glyph fields */
715 glyph->num_subglyphs = 2;
716 glyph->subglyphs = loader->base.subglyphs;
David Turnerb08fe2d2002-08-27 20:20:29 +0000717 glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000718
719 loader->current.num_subglyphs = 2;
720 }
721
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000722 FT_GlyphLoader_Prepare( builder->loader );
723
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000724 /* First load `bchar' in builder */
Graham Asher3fd12f12002-08-15 12:10:48 +0000725 error = cff_get_glyph_data( face, bchar_index,
726 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000727 if ( !error )
728 {
Graham Asher9eefed12002-08-23 10:08:38 +0000729 error = cff_decoder_parse_charstrings( decoder, charstring,
730 charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000731
732 if ( error )
733 goto Exit;
734
Graham Asher3fd12f12002-08-15 12:10:48 +0000735 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000736 }
737
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000738 /* Save the left bearing and width of the base character */
739 /* as they will be erased by the next load. */
740
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000741 left_bearing = builder->left_bearing;
742 advance = builder->advance;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000743
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000744 builder->left_bearing.x = 0;
745 builder->left_bearing.y = 0;
746
747 builder->pos_x = adx;
748 builder->pos_y = ady;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000749
750 /* Now load `achar' on top of the base outline. */
Graham Asher3fd12f12002-08-15 12:10:48 +0000751 error = cff_get_glyph_data( face, achar_index,
752 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000753 if ( !error )
754 {
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000755 error = cff_decoder_parse_charstrings( decoder, charstring,
756 charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000757
758 if ( error )
759 goto Exit;
760
Graham Asher3fd12f12002-08-15 12:10:48 +0000761 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000762 }
763
764 /* Restore the left side bearing and advance width */
765 /* of the base character. */
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000766 builder->left_bearing = left_bearing;
767 builder->advance = advance;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000768
Werner Lemberg5972e9a2004-02-01 00:49:56 +0000769 builder->pos_x = 0;
770 builder->pos_y = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000771
772 Exit:
773 return error;
774 }
775
776
777 /*************************************************************************/
778 /* */
779 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000780 /* cff_decoder_parse_charstrings */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000781 /* */
782 /* <Description> */
783 /* Parses a given Type 2 charstrings program. */
784 /* */
785 /* <InOut> */
786 /* decoder :: The current Type 1 decoder. */
787 /* */
788 /* <Input> */
789 /* charstring_base :: The base of the charstring stream. */
790 /* */
791 /* charstring_len :: The length in bytes of the charstring stream. */
792 /* */
793 /* <Return> */
794 /* FreeType error code. 0 means success. */
795 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000796 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000797 cff_decoder_parse_charstrings( CFF_Decoder* decoder,
Werner Lemberg7f74a522002-07-26 09:09:10 +0000798 FT_Byte* charstring_base,
Werner Lemberg68e9f922002-09-27 11:09:23 +0000799 FT_ULong charstring_len )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000800 {
Werner Lembergd573c7e2001-01-03 07:14:12 +0000801 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000802 CFF_Decoder_Zone* zone;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000803 FT_Byte* ip;
804 FT_Byte* limit;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000805 CFF_Builder* builder = &decoder->builder;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000806 FT_Pos x, y;
807 FT_Fixed seed;
808 FT_Fixed* stack;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000809
David Turner2b30c172001-12-12 16:07:29 +0000810 T2_Hints_Funcs hinter;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000811
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000812
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000813 /* set default width */
814 decoder->num_hints = 0;
815 decoder->read_width = 1;
816
817 /* compute random seed from stack address of parameter */
818 seed = (FT_Fixed)(char*)&seed ^
819 (FT_Fixed)(char*)&decoder ^
820 (FT_Fixed)(char*)&charstring_base;
Werner Lemberg43ba0842003-06-23 19:26:53 +0000821 seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000822 if ( seed == 0 )
823 seed = 0x7384;
824
825 /* initialize the decoder */
826 decoder->top = decoder->stack;
827 decoder->zone = decoder->zones;
828 zone = decoder->zones;
829 stack = decoder->top;
830
Werner Lembergf2586272004-05-13 21:59:17 +0000831 hinter = (T2_Hints_Funcs)builder->hints_funcs;
David Turner2b30c172001-12-12 16:07:29 +0000832
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000833 builder->path_begun = 0;
834
835 zone->base = charstring_base;
836 limit = zone->limit = charstring_base + charstring_len;
837 ip = zone->cursor = zone->base;
838
Werner Lembergcf24d512001-06-18 14:23:45 +0000839 error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000840
841 x = builder->pos_x;
842 y = builder->pos_y;
843
David Turner2b30c172001-12-12 16:07:29 +0000844 /* begin hints recording session, if any */
845 if ( hinter )
846 hinter->open( hinter->hints );
847
Werner Lembergf2586272004-05-13 21:59:17 +0000848 /* now execute loop */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000849 while ( ip < limit )
850 {
851 CFF_Operator op;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000852 FT_Byte v;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000853
854
855 /********************************************************************/
856 /* */
857 /* Decode operator or operand */
858 /* */
859 v = *ip++;
860 if ( v >= 32 || v == 28 )
861 {
862 FT_Int shift = 16;
863 FT_Int32 val;
864
865
866 /* this is an operand, push it on the stack */
867 if ( v == 28 )
868 {
869 if ( ip + 1 >= limit )
870 goto Syntax_Error;
871 val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
872 ip += 2;
873 }
874 else if ( v < 247 )
875 val = (FT_Long)v - 139;
876 else if ( v < 251 )
877 {
878 if ( ip >= limit )
879 goto Syntax_Error;
880 val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
881 }
882 else if ( v < 255 )
883 {
884 if ( ip >= limit )
885 goto Syntax_Error;
886 val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
887 }
888 else
889 {
890 if ( ip + 3 >= limit )
891 goto Syntax_Error;
892 val = ( (FT_Int32)ip[0] << 24 ) |
893 ( (FT_Int32)ip[1] << 16 ) |
894 ( (FT_Int32)ip[2] << 8 ) |
895 ip[3];
896 ip += 4;
897 shift = 0;
898 }
899 if ( decoder->top - stack >= CFF_MAX_OPERANDS )
900 goto Stack_Overflow;
901
902 val <<= shift;
903 *decoder->top++ = val;
904
905#ifdef FT_DEBUG_LEVEL_TRACE
Werner Lemberg43ba0842003-06-23 19:26:53 +0000906 if ( !( val & 0xFFFFL ) )
Werner Lemberg84c60bb2004-01-01 08:21:30 +0000907 FT_TRACE4(( " %ld", (FT_Int32)( val >> 16 ) ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000908 else
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000909 FT_TRACE4(( " %.2f", val / 65536.0 ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000910#endif
911
912 }
913 else
914 {
915 FT_Fixed* args = decoder->top;
Werner Lemberg68e9f922002-09-27 11:09:23 +0000916 FT_Int num_args = (FT_Int)( args - decoder->stack );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000917 FT_Int req_args;
918
919
920 /* find operator */
921 op = cff_op_unknown;
922
923 switch ( v )
924 {
925 case 1:
926 op = cff_op_hstem;
927 break;
928 case 3:
929 op = cff_op_vstem;
930 break;
931 case 4:
932 op = cff_op_vmoveto;
933 break;
934 case 5:
935 op = cff_op_rlineto;
936 break;
937 case 6:
938 op = cff_op_hlineto;
939 break;
940 case 7:
941 op = cff_op_vlineto;
942 break;
943 case 8:
944 op = cff_op_rrcurveto;
945 break;
946 case 10:
947 op = cff_op_callsubr;
948 break;
949 case 11:
950 op = cff_op_return;
951 break;
952 case 12:
953 {
954 if ( ip >= limit )
955 goto Syntax_Error;
956 v = *ip++;
957
958 switch ( v )
959 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000960 case 0:
961 op = cff_op_dotsection;
962 break;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000963 case 3:
964 op = cff_op_and;
965 break;
966 case 4:
967 op = cff_op_or;
968 break;
969 case 5:
970 op = cff_op_not;
971 break;
972 case 8:
973 op = cff_op_store;
974 break;
975 case 9:
976 op = cff_op_abs;
977 break;
978 case 10:
979 op = cff_op_add;
980 break;
981 case 11:
982 op = cff_op_sub;
983 break;
984 case 12:
985 op = cff_op_div;
986 break;
987 case 13:
988 op = cff_op_load;
989 break;
990 case 14:
991 op = cff_op_neg;
992 break;
993 case 15:
994 op = cff_op_eq;
995 break;
996 case 18:
997 op = cff_op_drop;
998 break;
999 case 20:
1000 op = cff_op_put;
1001 break;
1002 case 21:
1003 op = cff_op_get;
1004 break;
1005 case 22:
1006 op = cff_op_ifelse;
1007 break;
1008 case 23:
1009 op = cff_op_random;
1010 break;
1011 case 24:
1012 op = cff_op_mul;
1013 break;
1014 case 26:
1015 op = cff_op_sqrt;
1016 break;
1017 case 27:
1018 op = cff_op_dup;
1019 break;
1020 case 28:
1021 op = cff_op_exch;
1022 break;
1023 case 29:
1024 op = cff_op_index;
1025 break;
1026 case 30:
1027 op = cff_op_roll;
1028 break;
1029 case 34:
1030 op = cff_op_hflex;
1031 break;
1032 case 35:
1033 op = cff_op_flex;
1034 break;
1035 case 36:
1036 op = cff_op_hflex1;
1037 break;
1038 case 37:
1039 op = cff_op_flex1;
1040 break;
1041 default:
1042 /* decrement ip for syntax error message */
1043 ip--;
1044 }
1045 }
1046 break;
1047 case 14:
1048 op = cff_op_endchar;
1049 break;
1050 case 16:
1051 op = cff_op_blend;
1052 break;
1053 case 18:
1054 op = cff_op_hstemhm;
1055 break;
1056 case 19:
1057 op = cff_op_hintmask;
1058 break;
1059 case 20:
1060 op = cff_op_cntrmask;
1061 break;
1062 case 21:
1063 op = cff_op_rmoveto;
1064 break;
1065 case 22:
1066 op = cff_op_hmoveto;
1067 break;
1068 case 23:
1069 op = cff_op_vstemhm;
1070 break;
1071 case 24:
1072 op = cff_op_rcurveline;
1073 break;
1074 case 25:
1075 op = cff_op_rlinecurve;
1076 break;
1077 case 26:
1078 op = cff_op_vvcurveto;
1079 break;
1080 case 27:
1081 op = cff_op_hhcurveto;
1082 break;
1083 case 29:
1084 op = cff_op_callgsubr;
1085 break;
1086 case 30:
1087 op = cff_op_vhcurveto;
1088 break;
1089 case 31:
1090 op = cff_op_hvcurveto;
1091 break;
1092 default:
1093 ;
1094 }
1095 if ( op == cff_op_unknown )
1096 goto Syntax_Error;
1097
1098 /* check arguments */
1099 req_args = cff_argument_counts[op];
1100 if ( req_args & CFF_COUNT_CHECK_WIDTH )
1101 {
1102 args = stack;
1103
1104 if ( num_args > 0 && decoder->read_width )
1105 {
1106 /* If `nominal_width' is non-zero, the number is really a */
1107 /* difference against `nominal_width'. Else, the number here */
1108 /* is truly a width, not a difference against `nominal_width'. */
1109 /* If the font does not set `nominal_width', then */
1110 /* `nominal_width' defaults to zero, and so we can set */
1111 /* `glyph_width' to `nominal_width' plus number on the stack */
1112 /* -- for either case. */
1113
Werner Lemberg916838c2004-02-10 16:02:20 +00001114 FT_Int set_width_ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001115
1116
1117 switch ( op )
1118 {
1119 case cff_op_hmoveto:
1120 case cff_op_vmoveto:
1121 set_width_ok = num_args & 2;
1122 break;
1123
1124 case cff_op_hstem:
1125 case cff_op_vstem:
1126 case cff_op_hstemhm:
1127 case cff_op_vstemhm:
1128 case cff_op_rmoveto:
Werner Lemberg916838c2004-02-10 16:02:20 +00001129 case cff_op_hintmask:
1130 case cff_op_cntrmask:
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001131 set_width_ok = num_args & 1;
1132 break;
1133
1134 case cff_op_endchar:
1135 /* If there is a width specified for endchar, we either have */
1136 /* 1 argument or 5 arguments. We like to argue. */
1137 set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
1138 break;
1139
1140 default:
1141 set_width_ok = 0;
1142 break;
1143 }
1144
1145 if ( set_width_ok )
1146 {
1147 decoder->glyph_width = decoder->nominal_width +
1148 ( stack[0] >> 16 );
1149
1150 /* Consumed an argument. */
1151 num_args--;
1152 args++;
1153 }
1154 }
1155
1156 decoder->read_width = 0;
1157 req_args = 0;
1158 }
1159
1160 req_args &= 15;
1161 if ( num_args < req_args )
1162 goto Stack_Underflow;
1163 args -= req_args;
1164 num_args -= req_args;
1165
1166 switch ( op )
1167 {
1168 case cff_op_hstem:
1169 case cff_op_vstem:
1170 case cff_op_hstemhm:
1171 case cff_op_vstemhm:
David Turner2b30c172001-12-12 16:07:29 +00001172 /* the number of arguments is always even here */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001173 FT_TRACE4(( op == cff_op_hstem ? " hstem" :
David Turner2b30c172001-12-12 16:07:29 +00001174 ( op == cff_op_vstem ? " vstem" :
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001175 ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
David Turnerbce29862001-12-14 14:52:58 +00001176
David Turner2b30c172001-12-12 16:07:29 +00001177 if ( hinter )
1178 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001179 ( op == cff_op_hstem || op == cff_op_hstemhm ),
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001180 num_args / 2,
David Turner2b30c172001-12-12 16:07:29 +00001181 args );
David Turnerbce29862001-12-14 14:52:58 +00001182
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001183 decoder->num_hints += num_args / 2;
1184 args = stack;
1185 break;
David Turnerbce29862001-12-14 14:52:58 +00001186
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001187 case cff_op_hintmask:
1188 case cff_op_cntrmask:
David Turner2b30c172001-12-12 16:07:29 +00001189 FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
David Turner4d570242002-02-24 02:59:24 +00001190
Werner Lembergaf594e62001-12-22 14:38:40 +00001191 /* implement vstem when needed -- */
David Turnerb5c7de52001-12-21 21:21:13 +00001192 /* the specification doesn't say it, but this also works */
Werner Lembergaf594e62001-12-22 14:38:40 +00001193 /* with the 'cntrmask' operator */
David Turnerb5c7de52001-12-21 21:21:13 +00001194 /* */
David Turnerc8087482001-12-20 13:14:18 +00001195 if ( num_args > 0 )
1196 {
1197 if ( hinter )
1198 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001199 0,
David Turnerc8087482001-12-20 13:14:18 +00001200 num_args / 2,
1201 args );
David Turner4d570242002-02-24 02:59:24 +00001202
David Turnerc8087482001-12-20 13:14:18 +00001203 decoder->num_hints += num_args / 2;
1204 }
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001205
David Turner2b30c172001-12-12 16:07:29 +00001206 if ( hinter )
1207 {
1208 if ( op == cff_op_hintmask )
1209 hinter->hintmask( hinter->hints,
1210 builder->current->n_points,
David Turnerc8087482001-12-20 13:14:18 +00001211 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001212 ip );
1213 else
1214 hinter->counter( hinter->hints,
David Turnerc8087482001-12-20 13:14:18 +00001215 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001216 ip );
1217 }
David Turnerbce29862001-12-14 14:52:58 +00001218
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001219#ifdef FT_DEBUG_LEVEL_TRACE
1220 {
1221 FT_UInt maskbyte;
1222
Werner Lemberg48c984b2002-03-30 16:41:09 +00001223
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001224 FT_TRACE4(( " " ));
1225
Werner Lemberg521a2d72001-03-20 22:58:56 +00001226 for ( maskbyte = 0;
David Turner6d4fbec2001-04-20 08:50:36 +00001227 maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
Werner Lemberg521a2d72001-03-20 22:58:56 +00001228 maskbyte++, ip++ )
Werner Lemberg6fd95122003-12-31 07:51:30 +00001229 FT_TRACE4(( "0x%02X", *ip ));
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001230 }
1231#else
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001232 ip += ( decoder->num_hints + 7 ) >> 3;
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001233#endif
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001234 if ( ip >= limit )
1235 goto Syntax_Error;
1236 args = stack;
1237 break;
1238
1239 case cff_op_rmoveto:
1240 FT_TRACE4(( " rmoveto" ));
1241
David Turnerb9b2cac2002-07-10 16:52:06 +00001242 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001243 builder->path_begun = 0;
1244 x += args[0];
1245 y += args[1];
1246 args = stack;
1247 break;
1248
1249 case cff_op_vmoveto:
1250 FT_TRACE4(( " vmoveto" ));
1251
David Turnerb9b2cac2002-07-10 16:52:06 +00001252 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001253 builder->path_begun = 0;
1254 y += args[0];
1255 args = stack;
1256 break;
1257
1258 case cff_op_hmoveto:
1259 FT_TRACE4(( " hmoveto" ));
1260
David Turnerb9b2cac2002-07-10 16:52:06 +00001261 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001262 builder->path_begun = 0;
1263 x += args[0];
1264 args = stack;
1265 break;
1266
1267 case cff_op_rlineto:
1268 FT_TRACE4(( " rlineto" ));
1269
Werner Lemberg7f74a522002-07-26 09:09:10 +00001270 if ( cff_builder_start_point ( builder, x, y ) ||
1271 check_points( builder, num_args / 2 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001272 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001273
1274 if ( num_args < 2 || num_args & 1 )
1275 goto Stack_Underflow;
1276
1277 args = stack;
1278 while ( args < decoder->top )
1279 {
1280 x += args[0];
1281 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001282 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001283 args += 2;
1284 }
1285 args = stack;
1286 break;
1287
1288 case cff_op_hlineto:
1289 case cff_op_vlineto:
1290 {
1291 FT_Int phase = ( op == cff_op_hlineto );
1292
1293
1294 FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001295 : " vlineto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001296
Werner Lembergf2586272004-05-13 21:59:17 +00001297 if ( cff_builder_start_point ( builder, x, y ) ||
1298 check_points( builder, num_args ) )
1299 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001300
1301 args = stack;
Werner Lembergcfc0cf22005-11-17 08:12:00 +00001302 while ( args < decoder->top )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001303 {
1304 if ( phase )
1305 x += args[0];
1306 else
1307 y += args[0];
1308
Werner Lemberg7f74a522002-07-26 09:09:10 +00001309 if ( cff_builder_add_point1( builder, x, y ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001310 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001311
1312 args++;
1313 phase ^= 1;
1314 }
1315 args = stack;
1316 }
1317 break;
1318
1319 case cff_op_rrcurveto:
1320 FT_TRACE4(( " rrcurveto" ));
1321
1322 /* check number of arguments; must be a multiple of 6 */
1323 if ( num_args % 6 != 0 )
1324 goto Stack_Underflow;
1325
Werner Lemberg7f74a522002-07-26 09:09:10 +00001326 if ( cff_builder_start_point ( builder, x, y ) ||
1327 check_points( builder, num_args / 2 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001328 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001329
1330 args = stack;
1331 while ( args < decoder->top )
1332 {
1333 x += args[0];
1334 y += args[1];
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[2];
1337 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001338 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001339 x += args[4];
1340 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001341 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001342 args += 6;
1343 }
1344 args = stack;
1345 break;
1346
1347 case cff_op_vvcurveto:
1348 FT_TRACE4(( " vvcurveto" ));
1349
Werner Lembergefd4e872004-05-13 12:59:59 +00001350 if ( cff_builder_start_point( builder, x, y ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001351 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001352
1353 args = stack;
1354 if ( num_args & 1 )
1355 {
1356 x += args[0];
1357 args++;
1358 num_args--;
1359 }
1360
1361 if ( num_args % 4 != 0 )
1362 goto Stack_Underflow;
1363
1364 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001365 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001366
1367 while ( args < decoder->top )
1368 {
1369 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001370 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001371 x += args[1];
1372 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001373 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001374 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001375 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001376 args += 4;
1377 }
1378 args = stack;
1379 break;
1380
1381 case cff_op_hhcurveto:
1382 FT_TRACE4(( " hhcurveto" ));
1383
Werner Lembergefd4e872004-05-13 12:59:59 +00001384 if ( cff_builder_start_point( builder, x, y ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001385 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001386
1387 args = stack;
1388 if ( num_args & 1 )
1389 {
1390 y += args[0];
1391 args++;
1392 num_args--;
1393 }
1394
1395 if ( num_args % 4 != 0 )
1396 goto Stack_Underflow;
1397
1398 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001399 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001400
1401 while ( args < decoder->top )
1402 {
1403 x += args[0];
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[1];
1406 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001407 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001408 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001409 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001410 args += 4;
1411 }
1412 args = stack;
1413 break;
1414
1415 case cff_op_vhcurveto:
1416 case cff_op_hvcurveto:
1417 {
1418 FT_Int phase;
1419
1420
1421 FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001422 : " hvcurveto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001423
Werner Lembergefd4e872004-05-13 12:59:59 +00001424 if ( cff_builder_start_point( builder, x, y ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001425 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001426
1427 args = stack;
Werner Lembergcfc0cf22005-11-17 08:12:00 +00001428 if ( num_args < 4 || ( num_args % 4 ) > 1 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001429 goto Stack_Underflow;
1430
1431 if ( check_points( builder, ( num_args / 4 ) * 3 ) )
1432 goto Stack_Underflow;
1433
1434 phase = ( op == cff_op_hvcurveto );
1435
1436 while ( num_args >= 4 )
1437 {
1438 num_args -= 4;
1439 if ( phase )
1440 {
1441 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001442 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001443 x += args[1];
1444 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001445 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001446 y += args[3];
1447 if ( num_args == 1 )
1448 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001449 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001450 }
1451 else
1452 {
1453 y += args[0];
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[1];
1456 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001457 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001458 x += args[3];
1459 if ( num_args == 1 )
1460 y += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001461 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001462 }
1463 args += 4;
1464 phase ^= 1;
1465 }
1466 args = stack;
1467 }
1468 break;
1469
1470 case cff_op_rlinecurve:
1471 {
1472 FT_Int num_lines = ( num_args - 6 ) / 2;
1473
1474
1475 FT_TRACE4(( " rlinecurve" ));
1476
1477 if ( num_args < 8 || ( num_args - 6 ) & 1 )
1478 goto Stack_Underflow;
1479
Werner Lemberg7f74a522002-07-26 09:09:10 +00001480 if ( cff_builder_start_point( builder, x, y ) ||
1481 check_points( builder, num_lines + 3 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001482 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001483
1484 args = stack;
1485
1486 /* first, add the line segments */
1487 while ( num_lines > 0 )
1488 {
1489 x += args[0];
1490 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001491 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001492 args += 2;
1493 num_lines--;
1494 }
1495
1496 /* then the curve */
1497 x += args[0];
1498 y += args[1];
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[2];
1501 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001502 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001503 x += args[4];
1504 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001505 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001506 args = stack;
1507 }
1508 break;
1509
1510 case cff_op_rcurveline:
1511 {
1512 FT_Int num_curves = ( num_args - 2 ) / 6;
1513
1514
1515 FT_TRACE4(( " rcurveline" ));
1516
1517 if ( num_args < 8 || ( num_args - 2 ) % 6 )
1518 goto Stack_Underflow;
1519
Werner Lemberg7f74a522002-07-26 09:09:10 +00001520 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001521 check_points( builder, num_curves*3 + 2 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001522 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001523
1524 args = stack;
1525
1526 /* first, add the curves */
1527 while ( num_curves > 0 )
1528 {
1529 x += args[0];
1530 y += args[1];
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[2];
1533 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001534 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001535 x += args[4];
1536 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001537 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001538 args += 6;
1539 num_curves--;
1540 }
1541
1542 /* then the final line */
1543 x += args[0];
1544 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001545 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001546 args = stack;
1547 }
1548 break;
1549
1550 case cff_op_hflex1:
1551 {
1552 FT_Pos start_y;
1553
1554
1555 FT_TRACE4(( " hflex1" ));
1556
1557 args = stack;
1558
1559 /* adding five more points; 4 control points, 1 on-curve point */
1560 /* make sure we have enough space for the start point if it */
Werner Lembergf2586272004-05-13 21:59:17 +00001561 /* needs to be added */
David Turnerb9b2cac2002-07-10 16:52:06 +00001562 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001563 check_points( builder, 6 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001564 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001565
1566 /* Record the starting point's y postion for later use */
1567 start_y = y;
1568
1569 /* first control point */
1570 x += args[0];
1571 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001572 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001573
1574 /* second control point */
1575 x += args[2];
1576 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001577 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001578
1579 /* join point; on curve, with y-value the same as the last */
1580 /* control point's y-value */
1581 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001582 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001583
1584 /* third control point, with y-value the same as the join */
1585 /* point's y-value */
1586 x += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001587 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001588
1589 /* fourth control point */
1590 x += args[6];
1591 y += args[7];
David Turnerb9b2cac2002-07-10 16:52:06 +00001592 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001593
1594 /* ending point, with y-value the same as the start */
1595 x += args[8];
1596 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001597 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001598
1599 args = stack;
1600 break;
1601 }
1602
1603 case cff_op_hflex:
1604 {
1605 FT_Pos start_y;
1606
1607
1608 FT_TRACE4(( " hflex" ));
1609
1610 args = stack;
1611
1612 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001613 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lembergefd4e872004-05-13 12:59:59 +00001614 check_points( builder, 6 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001615 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001616
1617 /* record the starting point's y-position for later use */
1618 start_y = y;
1619
1620 /* first control point */
1621 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001622 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001623
1624 /* second control point */
1625 x += args[1];
1626 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001627 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001628
1629 /* join point; on curve, with y-value the same as the last */
1630 /* control point's y-value */
1631 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001632 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001633
1634 /* third control point, with y-value the same as the join */
1635 /* point's y-value */
1636 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001637 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001638
1639 /* fourth control point */
1640 x += args[5];
1641 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001642 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001643
1644 /* ending point, with y-value the same as the start point's */
1645 /* y-value -- we don't add this point, though */
1646 x += args[6];
David Turnerb9b2cac2002-07-10 16:52:06 +00001647 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001648
1649 args = stack;
1650 break;
1651 }
1652
1653 case cff_op_flex1:
1654 {
Werner Lemberg84c60bb2004-01-01 08:21:30 +00001655 FT_Pos start_x, start_y; /* record start x, y values for */
1656 /* alter use */
1657 FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */
1658 /* algorithm below */
1659 FT_Int horizontal, count;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001660
1661
1662 FT_TRACE4(( " flex1" ));
1663
1664 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001665 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001666 check_points( builder, 6 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001667 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001668
1669 /* record the starting point's x, y postion for later use */
1670 start_x = x;
1671 start_y = y;
1672
1673 /* XXX: figure out whether this is supposed to be a horizontal */
1674 /* or vertical flex; the Type 2 specification is vague... */
1675
1676 args = stack;
1677
1678 /* grab up to the last argument */
1679 for ( count = 5; count > 0; count-- )
1680 {
Werner Lemberg84c60bb2004-01-01 08:21:30 +00001681 dx += args[0];
1682 dy += args[1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001683 args += 2;
1684 }
1685
1686 /* rewind */
1687 args = stack;
1688
1689 if ( dx < 0 ) dx = -dx;
1690 if ( dy < 0 ) dy = -dy;
1691
1692 /* strange test, but here it is... */
1693 horizontal = ( dx > dy );
1694
1695 for ( count = 5; count > 0; count-- )
1696 {
1697 x += args[0];
1698 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001699 cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001700 args += 2;
1701 }
1702
1703 /* is last operand an x- or y-delta? */
1704 if ( horizontal )
1705 {
1706 x += args[0];
1707 y = start_y;
1708 }
1709 else
1710 {
1711 x = start_x;
1712 y += args[0];
1713 }
1714
David Turnerb9b2cac2002-07-10 16:52:06 +00001715 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001716
1717 args = stack;
1718 break;
1719 }
1720
1721 case cff_op_flex:
1722 {
1723 FT_UInt count;
1724
1725
1726 FT_TRACE4(( " flex" ));
1727
David Turnerb9b2cac2002-07-10 16:52:06 +00001728 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001729 check_points( builder, 6 ) )
Werner Lembergf2586272004-05-13 21:59:17 +00001730 goto Fail;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001731
1732 args = stack;
1733 for ( count = 6; count > 0; count-- )
1734 {
1735 x += args[0];
1736 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001737 cff_builder_add_point( builder, x, y,
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001738 (FT_Bool)( count == 4 || count == 1 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001739 args += 2;
1740 }
1741
1742 args = stack;
1743 }
1744 break;
1745
1746 case cff_op_endchar:
1747 FT_TRACE4(( " endchar" ));
1748
1749 /* We are going to emulate the seac operator. */
1750 if ( num_args == 4 )
1751 {
Werner Lemberg916838c2004-02-10 16:02:20 +00001752 /* Save glyph width so that the subglyphs don't overwrite it. */
1753 FT_Pos glyph_width = decoder->glyph_width;
1754
1755
Werner Lembergd573c7e2001-01-03 07:14:12 +00001756 error = cff_operator_seac( decoder,
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001757 args[0],
1758 args[1],
Werner Lemberg68e9f922002-09-27 11:09:23 +00001759 (FT_Int)( args[2] >> 16 ),
1760 (FT_Int)( args[3] >> 16 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001761 args += 4;
Werner Lemberg916838c2004-02-10 16:02:20 +00001762
1763 decoder->glyph_width = glyph_width;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001764 }
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001765 else
David Turner2b30c172001-12-12 16:07:29 +00001766 {
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001767 if ( !error )
1768 error = CFF_Err_Ok;
David Turnerbce29862001-12-14 14:52:58 +00001769
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001770 cff_builder_close_contour( builder );
1771
1772 /* close hints recording session */
1773 if ( hinter )
1774 {
Werner Lembergcfc0cf22005-11-17 08:12:00 +00001775 if ( hinter->close( hinter->hints,
1776 builder->current->n_points ) )
Werner Lemberg5972e9a2004-02-01 00:49:56 +00001777 goto Syntax_Error;
1778
1779 /* apply hints to the loaded glyph outline now */
1780 hinter->apply( hinter->hints,
1781 builder->current,
1782 (PSH_Globals)builder->hints_globals,
1783 decoder->hint_mode );
1784 }
1785
1786 /* add current outline to the glyph slot */
1787 FT_GlyphLoader_Add( builder->loader );
David Turner2b30c172001-12-12 16:07:29 +00001788 }
1789
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001790 /* return now! */
1791 FT_TRACE4(( "\n\n" ));
1792 return error;
1793
1794 case cff_op_abs:
1795 FT_TRACE4(( " abs" ));
1796
1797 if ( args[0] < 0 )
1798 args[0] = -args[0];
1799 args++;
1800 break;
1801
1802 case cff_op_add:
1803 FT_TRACE4(( " add" ));
1804
1805 args[0] += args[1];
1806 args++;
1807 break;
1808
1809 case cff_op_sub:
1810 FT_TRACE4(( " sub" ));
1811
1812 args[0] -= args[1];
1813 args++;
1814 break;
1815
1816 case cff_op_div:
1817 FT_TRACE4(( " div" ));
1818
1819 args[0] = FT_DivFix( args[0], args[1] );
1820 args++;
1821 break;
1822
1823 case cff_op_neg:
1824 FT_TRACE4(( " neg" ));
1825
1826 args[0] = -args[0];
1827 args++;
1828 break;
1829
1830 case cff_op_random:
1831 {
Werner Lemberg94ffae52002-04-14 00:54:32 +00001832 FT_Fixed Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001833
1834
1835 FT_TRACE4(( " rand" ));
1836
Werner Lemberg94ffae52002-04-14 00:54:32 +00001837 Rand = seed;
Werner Lemberg43ba0842003-06-23 19:26:53 +00001838 if ( Rand >= 0x8000L )
Werner Lemberg94ffae52002-04-14 00:54:32 +00001839 Rand++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001840
Werner Lemberg94ffae52002-04-14 00:54:32 +00001841 args[0] = Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001842 seed = FT_MulFix( seed, 0x10000L - seed );
1843 if ( seed == 0 )
1844 seed += 0x2873;
1845 args++;
1846 }
1847 break;
1848
1849 case cff_op_mul:
1850 FT_TRACE4(( " mul" ));
1851
1852 args[0] = FT_MulFix( args[0], args[1] );
1853 args++;
1854 break;
1855
1856 case cff_op_sqrt:
1857 FT_TRACE4(( " sqrt" ));
1858
1859 if ( args[0] > 0 )
1860 {
1861 FT_Int count = 9;
1862 FT_Fixed root = args[0];
1863 FT_Fixed new_root;
1864
1865
1866 for (;;)
1867 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001868 new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001869 if ( new_root == root || count <= 0 )
1870 break;
1871 root = new_root;
1872 }
1873 args[0] = new_root;
1874 }
1875 else
1876 args[0] = 0;
1877 args++;
1878 break;
1879
1880 case cff_op_drop:
1881 /* nothing */
1882 FT_TRACE4(( " drop" ));
1883
1884 break;
1885
1886 case cff_op_exch:
1887 {
1888 FT_Fixed tmp;
1889
1890
1891 FT_TRACE4(( " exch" ));
1892
1893 tmp = args[0];
1894 args[0] = args[1];
1895 args[1] = tmp;
1896 args += 2;
1897 }
1898 break;
1899
1900 case cff_op_index:
1901 {
Werner Lemberg68e9f922002-09-27 11:09:23 +00001902 FT_Int idx = (FT_Int)( args[0] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001903
1904
1905 FT_TRACE4(( " index" ));
1906
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001907 if ( idx < 0 )
1908 idx = 0;
1909 else if ( idx > num_args - 2 )
1910 idx = num_args - 2;
1911 args[0] = args[-( idx + 1 )];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001912 args++;
1913 }
1914 break;
1915
1916 case cff_op_roll:
1917 {
1918 FT_Int count = (FT_Int)( args[0] >> 16 );
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001919 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001920
1921
1922 FT_TRACE4(( " roll" ));
1923
1924 if ( count <= 0 )
1925 count = 1;
1926
1927 args -= count;
1928 if ( args < stack )
1929 goto Stack_Underflow;
1930
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001931 if ( idx >= 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001932 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001933 while ( idx > 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001934 {
1935 FT_Fixed tmp = args[count - 1];
1936 FT_Int i;
1937
1938
1939 for ( i = count - 2; i >= 0; i-- )
1940 args[i + 1] = args[i];
1941 args[0] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001942 idx--;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001943 }
1944 }
1945 else
1946 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001947 while ( idx < 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001948 {
1949 FT_Fixed tmp = args[0];
1950 FT_Int i;
1951
1952
1953 for ( i = 0; i < count - 1; i++ )
1954 args[i] = args[i + 1];
1955 args[count - 1] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001956 idx++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001957 }
1958 }
1959 args += count;
1960 }
1961 break;
1962
1963 case cff_op_dup:
1964 FT_TRACE4(( " dup" ));
1965
1966 args[1] = args[0];
1967 args++;
1968 break;
1969
1970 case cff_op_put:
1971 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001972 FT_Fixed val = args[0];
1973 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001974
1975
1976 FT_TRACE4(( " put" ));
1977
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001978 if ( idx >= 0 && idx < decoder->len_buildchar )
1979 decoder->buildchar[idx] = val;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001980 }
1981 break;
1982
1983 case cff_op_get:
1984 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001985 FT_Int idx = (FT_Int)( args[0] >> 16 );
1986 FT_Fixed val = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001987
1988
1989 FT_TRACE4(( " get" ));
1990
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001991 if ( idx >= 0 && idx < decoder->len_buildchar )
1992 val = decoder->buildchar[idx];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001993
1994 args[0] = val;
1995 args++;
1996 }
1997 break;
1998
1999 case cff_op_store:
2000 FT_TRACE4(( " store "));
2001
2002 goto Unimplemented;
2003
2004 case cff_op_load:
2005 FT_TRACE4(( " load" ));
2006
2007 goto Unimplemented;
2008
David Turner8d3a4012001-03-20 11:14:24 +00002009 case cff_op_dotsection:
Werner Lemberg521a2d72001-03-20 22:58:56 +00002010 /* this operator is deprecated and ignored by the parser */
2011 FT_TRACE4(( " dotsection" ));
David Turner8d3a4012001-03-20 11:14:24 +00002012 break;
2013
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002014 case cff_op_and:
2015 {
2016 FT_Fixed cond = args[0] && args[1];
2017
2018
2019 FT_TRACE4(( " and" ));
2020
2021 args[0] = cond ? 0x10000L : 0;
2022 args++;
2023 }
2024 break;
2025
2026 case cff_op_or:
2027 {
2028 FT_Fixed cond = args[0] || args[1];
2029
2030
2031 FT_TRACE4(( " or" ));
2032
2033 args[0] = cond ? 0x10000L : 0;
2034 args++;
2035 }
2036 break;
2037
2038 case cff_op_eq:
2039 {
2040 FT_Fixed cond = !args[0];
2041
2042
2043 FT_TRACE4(( " eq" ));
2044
2045 args[0] = cond ? 0x10000L : 0;
2046 args++;
2047 }
2048 break;
2049
2050 case cff_op_ifelse:
2051 {
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002052 FT_Fixed cond = ( args[2] <= args[3] );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002053
2054
2055 FT_TRACE4(( " ifelse" ));
2056
2057 if ( !cond )
2058 args[0] = args[1];
2059 args++;
2060 }
2061 break;
2062
2063 case cff_op_callsubr:
2064 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002065 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2066 decoder->locals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002067
2068
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002069 FT_TRACE4(( " callsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002070
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002071 if ( idx >= decoder->num_locals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002072 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002073 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002074 FT_ERROR(( " invalid local subr index\n" ));
2075 goto Syntax_Error;
2076 }
2077
2078 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2079 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002080 FT_ERROR(( "cff_decoder_parse_charstrings:"
2081 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002082 goto Syntax_Error;
2083 }
2084
2085 zone->cursor = ip; /* save current instruction pointer */
2086
2087 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002088 zone->base = decoder->locals[idx];
2089 zone->limit = decoder->locals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002090 zone->cursor = zone->base;
2091
2092 if ( !zone->base )
2093 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002094 FT_ERROR(( "cff_decoder_parse_charstrings:"
2095 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002096 goto Syntax_Error;
2097 }
2098
2099 decoder->zone = zone;
2100 ip = zone->base;
2101 limit = zone->limit;
2102 }
2103 break;
2104
2105 case cff_op_callgsubr:
2106 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002107 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2108 decoder->globals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002109
2110
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002111 FT_TRACE4(( " callgsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002112
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002113 if ( idx >= decoder->num_globals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002114 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002115 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002116 FT_ERROR(( " invalid global subr index\n" ));
2117 goto Syntax_Error;
2118 }
2119
2120 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2121 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002122 FT_ERROR(( "cff_decoder_parse_charstrings:"
2123 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002124 goto Syntax_Error;
2125 }
2126
2127 zone->cursor = ip; /* save current instruction pointer */
2128
2129 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002130 zone->base = decoder->globals[idx];
2131 zone->limit = decoder->globals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002132 zone->cursor = zone->base;
2133
2134 if ( !zone->base )
2135 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002136 FT_ERROR(( "cff_decoder_parse_charstrings:"
2137 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002138 goto Syntax_Error;
2139 }
2140
2141 decoder->zone = zone;
2142 ip = zone->base;
2143 limit = zone->limit;
2144 }
2145 break;
2146
2147 case cff_op_return:
2148 FT_TRACE4(( " return" ));
2149
2150 if ( decoder->zone <= decoder->zones )
2151 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002152 FT_ERROR(( "cff_decoder_parse_charstrings:"
2153 " unexpected return\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002154 goto Syntax_Error;
2155 }
2156
2157 decoder->zone--;
2158 zone = decoder->zone;
2159 ip = zone->cursor;
2160 limit = zone->limit;
2161 break;
2162
2163 default:
2164 Unimplemented:
2165 FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
2166
2167 if ( ip[-1] == 12 )
2168 FT_ERROR(( " %d", ip[0] ));
2169 FT_ERROR(( "\n" ));
2170
2171 return CFF_Err_Unimplemented_Feature;
2172 }
2173
2174 decoder->top = args;
2175
2176 } /* general operator processing */
2177
2178 } /* while ip < limit */
2179
2180 FT_TRACE4(( "..end..\n\n" ));
2181
Werner Lembergf2586272004-05-13 21:59:17 +00002182 Fail:
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002183 return error;
2184
2185 Syntax_Error:
David Turnerb9b2cac2002-07-10 16:52:06 +00002186 FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002187 return CFF_Err_Invalid_File_Format;
2188
2189 Stack_Underflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002190 FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002191 return CFF_Err_Too_Few_Arguments;
2192
2193 Stack_Overflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002194 FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002195 return CFF_Err_Stack_Overflow;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002196 }
2197
2198
2199 /*************************************************************************/
2200 /*************************************************************************/
2201 /*************************************************************************/
2202 /********** *********/
2203 /********** *********/
2204 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
2205 /********** *********/
2206 /********** The following code is in charge of computing *********/
2207 /********** the maximum advance width of the font. It *********/
2208 /********** quickly processes each glyph charstring to *********/
2209 /********** extract the value from either a `sbw' or `seac' *********/
2210 /********** operator. *********/
2211 /********** *********/
2212 /*************************************************************************/
2213 /*************************************************************************/
2214 /*************************************************************************/
2215
2216
2217#if 0 /* unused until we support pure CFF fonts */
2218
2219
David Turnerbc82f1b2002-03-01 02:26:22 +00002220 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002221 cff_compute_max_advance( TT_Face face,
Werner Lemberg93616ec2001-06-27 19:46:12 +00002222 FT_Int* max_advance )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002223 {
Werner Lembergbfb712f2004-03-03 08:21:12 +00002224 FT_Error error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002225 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002226 FT_Int glyph_index;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002227 CFF_Font cff = (CFF_Font)face->other;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002228
2229
2230 *max_advance = 0;
2231
2232 /* Initialize load decoder */
David Turnerd1245c02002-08-27 22:34:20 +00002233 cff_decoder_init( &decoder, face, 0, 0, 0, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002234
2235 decoder.builder.metrics_only = 1;
2236 decoder.builder.load_points = 0;
2237
2238 /* For each glyph, parse the glyph charstring and extract */
2239 /* the advance width. */
2240 for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
2241 glyph_index++ )
2242 {
2243 FT_Byte* charstring;
2244 FT_ULong charstring_len;
2245
2246
2247 /* now get load the unscaled outline */
Graham Asher3fd12f12002-08-15 12:10:48 +00002248 error = cff_get_glyph_data( face, glyph_index,
2249 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002250 if ( !error )
2251 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002252 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002253 error = cff_decoder_parse_charstrings( &decoder,
2254 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002255
Graham Asher3fd12f12002-08-15 12:10:48 +00002256 cff_free_glyph_data( face, &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002257 }
2258
2259 /* ignore the error if one has occurred -- skip to next glyph */
Werner Lembergbfb712f2004-03-03 08:21:12 +00002260 error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002261 }
2262
2263 *max_advance = decoder.builder.advance.x;
2264
2265 return CFF_Err_Ok;
2266 }
2267
2268
2269#endif /* 0 */
2270
2271
David Turnerbc82f1b2002-03-01 02:26:22 +00002272 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002273 cff_slot_load( CFF_GlyphSlot glyph,
2274 CFF_Size size,
2275 FT_Int glyph_index,
David Turnerd1245c02002-08-27 22:34:20 +00002276 FT_Int32 load_flags )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002277 {
Werner Lembergbfb712f2004-03-03 08:21:12 +00002278 FT_Error error;
2279 CFF_Decoder decoder;
2280 TT_Face face = (TT_Face)glyph->root.face;
Werner Lembergbfb712f2004-03-03 08:21:12 +00002281 FT_Bool hinting;
2282 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002283
Werner Lembergbfb712f2004-03-03 08:21:12 +00002284 FT_Matrix font_matrix;
2285 FT_Vector font_offset;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002286
2287
2288 if ( load_flags & FT_LOAD_NO_RECURSE )
2289 load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2290
2291 glyph->x_scale = 0x10000L;
2292 glyph->y_scale = 0x10000L;
2293 if ( size )
2294 {
Werner Lembergbfb712f2004-03-03 08:21:12 +00002295 glyph->x_scale = size->root.metrics.x_scale;
2296 glyph->y_scale = size->root.metrics.y_scale;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002297 }
2298
Werner Lembergbfb712f2004-03-03 08:21:12 +00002299#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
2300
2301 /* try to load embedded bitmap if any */
2302 /* */
2303 /* XXX: The convention should be emphasized in */
2304 /* the documents because it can be confusing. */
Werner Lembergba80d612004-04-16 09:56:30 +00002305 if ( size )
Werner Lembergbfb712f2004-03-03 08:21:12 +00002306 {
Werner Lembergba80d612004-04-16 09:56:30 +00002307 CFF_Face cff_face = (CFF_Face)size->root.face;
2308 SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt;
2309 FT_Stream stream = cff_face->root.stream;
Werner Lembergbfb712f2004-03-03 08:21:12 +00002310
2311
Werner Lembergf1c2b912006-01-13 14:53:28 +00002312 if ( size->strike_index != 0xFFFFFFFFUL &&
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +00002313 sfnt->load_eblc &&
Werner Lembergba80d612004-04-16 09:56:30 +00002314 ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
Werner Lembergbfb712f2004-03-03 08:21:12 +00002315 {
Werner Lembergba80d612004-04-16 09:56:30 +00002316 TT_SBit_MetricsRec metrics;
Werner Lembergbfb712f2004-03-03 08:21:12 +00002317
Werner Lembergbfb712f2004-03-03 08:21:12 +00002318
Werner Lembergba80d612004-04-16 09:56:30 +00002319 error = sfnt->load_sbit_image( face,
Wu, Chia-I (吳佳一)fa7d6ab2006-01-13 12:21:31 +00002320 size->strike_index,
Werner Lembergba80d612004-04-16 09:56:30 +00002321 (FT_UInt)glyph_index,
2322 (FT_Int)load_flags,
2323 stream,
2324 &glyph->root.bitmap,
2325 &metrics );
Werner Lembergbfb712f2004-03-03 08:21:12 +00002326
Werner Lembergba80d612004-04-16 09:56:30 +00002327 if ( !error )
Werner Lembergbfb712f2004-03-03 08:21:12 +00002328 {
Werner Lembergba80d612004-04-16 09:56:30 +00002329 glyph->root.outline.n_points = 0;
2330 glyph->root.outline.n_contours = 0;
2331
2332 glyph->root.metrics.width = (FT_Pos)metrics.width << 6;
2333 glyph->root.metrics.height = (FT_Pos)metrics.height << 6;
2334
2335 glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
2336 glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
2337 glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6;
2338
2339 glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
2340 glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
2341 glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6;
2342
2343 glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
2344
2345 if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
2346 {
2347 glyph->root.bitmap_left = metrics.vertBearingX;
2348 glyph->root.bitmap_top = metrics.vertBearingY;
2349 }
2350 else
2351 {
2352 glyph->root.bitmap_left = metrics.horiBearingX;
2353 glyph->root.bitmap_top = metrics.horiBearingY;
2354 }
2355 return error;
Werner Lembergbfb712f2004-03-03 08:21:12 +00002356 }
Werner Lembergbfb712f2004-03-03 08:21:12 +00002357 }
Werner Lembergba80d612004-04-16 09:56:30 +00002358 }
Werner Lembergbfb712f2004-03-03 08:21:12 +00002359
2360#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
2361
2362 /* return immediately if we only want the embedded bitmaps */
2363 if ( load_flags & FT_LOAD_SBITS_ONLY )
2364 return CFF_Err_Invalid_Argument;
2365
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002366 glyph->root.outline.n_points = 0;
2367 glyph->root.outline.n_contours = 0;
2368
David Turner8edbcab2001-06-19 08:28:24 +00002369 hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
2370 ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002371
David Turnerb08fe2d2002-08-27 20:20:29 +00002372 glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002373
2374 {
2375 FT_Byte* charstring;
2376 FT_ULong charstring_len;
2377
2378
Werner Lembergb36d4a52003-12-12 15:38:39 +00002379 /* in a CID-keyed font, consider `glyph_index' as a CID and map */
Werner Lemberga9cd8562003-12-18 08:18:37 +00002380 /* it immediately to the real glyph_index -- if it isn't a */
2381 /* subsetted font, glyph_indices and CIDs are identical, though */
2382 if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
2383 cff->charset.cids )
Werner Lembergb36d4a52003-12-12 15:38:39 +00002384 glyph_index = cff->charset.cids[glyph_index];
2385
David Turnerd1245c02002-08-27 22:34:20 +00002386 cff_decoder_init( &decoder, face, size, glyph, hinting,
Werner Lembergc846eac2004-02-19 21:39:58 +00002387 FT_LOAD_TARGET_MODE( load_flags ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002388
2389 decoder.builder.no_recurse =
2390 (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
2391
2392 /* now load the unscaled outline */
Graham Asher3fd12f12002-08-15 12:10:48 +00002393 error = cff_get_glyph_data( face, glyph_index,
2394 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002395 if ( !error )
2396 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002397 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002398 error = cff_decoder_parse_charstrings( &decoder,
2399 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002400
Graham Asher3fd12f12002-08-15 12:10:48 +00002401 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002402
Graham Asher3fd12f12002-08-15 12:10:48 +00002403
2404#ifdef FT_CONFIG_OPTION_INCREMENTAL
Werner Lemberg6b5c6692002-09-05 15:10:54 +00002405 /* Control data and length may not be available for incremental */
Graham Asher3fd12f12002-08-15 12:10:48 +00002406 /* fonts. */
2407 if ( face->root.internal->incremental_interface )
2408 {
2409 glyph->root.control_data = 0;
2410 glyph->root.control_len = 0;
2411 }
2412 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +00002413#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2414
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002415 /* We set control_data and control_len if charstrings is loaded. */
Werner Lemberg7f74a522002-07-26 09:09:10 +00002416 /* See how charstring loads at cff_index_access_element() in */
2417 /* cffload.c. */
Graham Asher3fd12f12002-08-15 12:10:48 +00002418 {
Werner Lemberg6b5c6692002-09-05 15:10:54 +00002419 CFF_IndexRec csindex = cff->charstrings_index;
2420
2421
2422 glyph->root.control_data =
2423 csindex.bytes + csindex.offsets[glyph_index] - 1;
2424 glyph->root.control_len =
2425 charstring_len;
Graham Asher3fd12f12002-08-15 12:10:48 +00002426 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002427 }
2428
2429 /* save new glyph tables */
David Turnerb9b2cac2002-07-10 16:52:06 +00002430 cff_builder_done( &decoder.builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002431 }
2432
Werner Lemberg9b067fa2003-12-11 17:55:58 +00002433#ifdef FT_CONFIG_OPTION_INCREMENTAL
Graham Asher46960df2003-02-13 17:49:27 +00002434
2435 /* Incremental fonts can optionally override the metrics. */
Werner Lemberg2acb9632003-04-23 06:47:12 +00002436 if ( !error &&
2437 face->root.internal->incremental_interface &&
Graham Asher46960df2003-02-13 17:49:27 +00002438 face->root.internal->incremental_interface->funcs->get_glyph_metrics )
2439 {
2440 FT_Incremental_MetricsRec metrics;
2441
Werner Lemberg2acb9632003-04-23 06:47:12 +00002442
Graham Asher46960df2003-02-13 17:49:27 +00002443 metrics.bearing_x = decoder.builder.left_bearing.x;
Werner Lemberg428c2e42003-04-25 05:35:04 +00002444 metrics.bearing_y = decoder.builder.left_bearing.y;
2445 metrics.advance = decoder.builder.advance.x;
Graham Asher46960df2003-02-13 17:49:27 +00002446 error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
2447 face->root.internal->incremental_interface->object,
2448 glyph_index, FALSE, &metrics );
2449 decoder.builder.left_bearing.x = metrics.bearing_x;
2450 decoder.builder.left_bearing.y = metrics.bearing_y;
2451 decoder.builder.advance.x = metrics.advance;
2452 decoder.builder.advance.y = 0;
2453 }
2454
2455#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2456
Werner Lembergb01676b2005-04-18 07:13:07 +00002457 if ( cff->num_subfonts >= 1 )
2458 {
2459 FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
2460
2461
2462 font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix;
2463 font_offset = cff->subfonts[fd_index]->font_dict.font_offset;
2464 }
2465 else
2466 {
2467 font_matrix = cff->top_font.font_dict.font_matrix;
2468 font_offset = cff->top_font.font_dict.font_offset;
2469 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002470
2471 /* Now, set the metrics -- this is rather simple, as */
2472 /* the left side bearing is the xMin, and the top side */
2473 /* bearing the yMax. */
2474 if ( !error )
2475 {
2476 /* For composite glyphs, return only left side bearing and */
2477 /* advance width. */
2478 if ( load_flags & FT_LOAD_NO_RECURSE )
2479 {
2480 FT_Slot_Internal internal = glyph->root.internal;
Werner Lemberg415235d2001-06-28 17:49:10 +00002481
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002482
2483 glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
2484 glyph->root.metrics.horiAdvance = decoder.glyph_width;
2485 internal->glyph_matrix = font_matrix;
2486 internal->glyph_delta = font_offset;
2487 internal->glyph_transformed = 1;
2488 }
2489 else
2490 {
2491 FT_BBox cbox;
2492 FT_Glyph_Metrics* metrics = &glyph->root.metrics;
Werner Lemberge8ff7692003-08-06 04:40:48 +00002493 FT_Vector advance;
Wu, Chia-I (吳佳一)212aee02006-01-15 06:24:53 +00002494 FT_Bool has_vertical_info;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002495
2496
2497 /* copy the _unscaled_ advance width */
2498 metrics->horiAdvance = decoder.glyph_width;
2499 glyph->root.linearHoriAdvance = decoder.glyph_width;
2500 glyph->root.internal->glyph_transformed = 0;
2501
David Turner6a681fa2006-01-27 12:11:22 +00002502 has_vertical_info = FT_BOOL( face->vertical_info &&
2503 face->vertical.number_Of_VMetrics > 0 &&
2504 face->vertical.long_metrics != 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002505
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002506 /* get the vertical metrics from the vtmx table if we have one */
Wu, Chia-I (吳佳一)212aee02006-01-15 06:24:53 +00002507 if ( has_vertical_info )
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002508 {
2509 FT_Short vertBearingY = 0;
2510 FT_UShort vertAdvance = 0;
2511
2512
Wu, Chia-I (吳佳一)f5aa47b2006-02-14 06:40:10 +00002513 ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
2514 glyph_index,
2515 &vertBearingY,
2516 &vertAdvance );
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002517 metrics->vertBearingY = vertBearingY;
2518 metrics->vertAdvance = vertAdvance;
2519 }
Wu, Chia-I (吳佳一)212aee02006-01-15 06:24:53 +00002520 else
2521 {
2522 /* make up vertical ones */
2523 if ( face->os2.version != 0xFFFFU )
2524 metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender -
2525 face->os2.sTypoDescender );
2526 else
2527 metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender -
2528 face->horizontal.Descender );
2529 }
2530
2531 glyph->root.linearVertAdvance = metrics->vertAdvance;
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002532
David Turnerb08fe2d2002-08-27 20:20:29 +00002533 glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002534
2535 glyph->root.outline.flags = 0;
Werner Lembergbfb712f2004-03-03 08:21:12 +00002536 if ( size && size->root.metrics.y_ppem < 24 )
David Turnerb08fe2d2002-08-27 20:20:29 +00002537 glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002538
David Turnerb08fe2d2002-08-27 20:20:29 +00002539 glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002540
2541 /* apply the font matrix */
2542 FT_Outline_Transform( &glyph->root.outline, &font_matrix );
2543
2544 FT_Outline_Translate( &glyph->root.outline,
2545 font_offset.x,
2546 font_offset.y );
2547
Werner Lemberge8ff7692003-08-06 04:40:48 +00002548 advance.x = metrics->horiAdvance;
Werner Lemberge52c4ba2003-08-06 17:27:14 +00002549 advance.y = 0;
2550 FT_Vector_Transform( &advance, &font_matrix );
2551 metrics->horiAdvance = advance.x + font_offset.x;
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002552
Werner Lemberge52c4ba2003-08-06 17:27:14 +00002553 advance.x = 0;
Werner Lemberge8ff7692003-08-06 04:40:48 +00002554 advance.y = metrics->vertAdvance;
2555 FT_Vector_Transform( &advance, &font_matrix );
Werner Lemberge52c4ba2003-08-06 17:27:14 +00002556 metrics->vertAdvance = advance.y + font_offset.y;
Werner Lemberge8ff7692003-08-06 04:40:48 +00002557
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002558 if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
2559 {
2560 /* scale the outline and the metrics */
2561 FT_Int n;
2562 FT_Outline* cur = &glyph->root.outline;
2563 FT_Vector* vec = cur->points;
2564 FT_Fixed x_scale = glyph->x_scale;
2565 FT_Fixed y_scale = glyph->y_scale;
2566
2567
2568 /* First of all, scale the points */
Werner Lemberg6c990452005-11-18 21:10:59 +00002569 if ( !hinting || !decoder.builder.hints_funcs )
David Turnerc8087482001-12-20 13:14:18 +00002570 for ( n = cur->n_points; n > 0; n--, vec++ )
2571 {
2572 vec->x = FT_MulFix( vec->x, x_scale );
2573 vec->y = FT_MulFix( vec->y, y_scale );
2574 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002575
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002576 /* Then scale the metrics */
Werner Lembergcfc0cf22005-11-17 08:12:00 +00002577 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
2578 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002579 }
2580
2581 /* compute the other metrics */
2582 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2583
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002584 metrics->width = cbox.xMax - cbox.xMin;
2585 metrics->height = cbox.yMax - cbox.yMin;
2586
2587 metrics->horiBearingX = cbox.xMin;
2588 metrics->horiBearingY = cbox.yMax;
Wu, Chia-I (吳佳一)212aee02006-01-15 06:24:53 +00002589
2590 if ( has_vertical_info )
2591 metrics->vertBearingX = -metrics->width / 2;
2592 else
Wu, Chia-I (吳佳一)ea1e8d32006-01-15 15:01:45 +00002593 ft_synthesize_vertical_metrics( metrics,
2594 metrics->vertAdvance );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002595 }
2596 }
2597
2598 return error;
2599 }
2600
2601
2602/* END */