]>
Commit | Line | Data |
---|---|---|
cabec872 RR |
1 | /***************************************************************************/ |
2 | /* */ | |
3 | /* t2gload.c */ | |
4 | /* */ | |
5 | /* OpenType Glyph Loader (body). */ | |
6 | /* */ | |
7 | /* Copyright 1996-2000 by */ | |
8 | /* 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 <freetype/internal/ftdebug.h> | |
20 | #include <freetype/internal/ftcalc.h> | |
21 | #include <freetype/internal/ftstream.h> | |
22 | #include <freetype/internal/sfnt.h> | |
23 | #include <freetype/ftoutln.h> | |
24 | #include <freetype/tttags.h> | |
25 | ||
26 | ||
27 | #ifdef FT_FLAT_COMPILE | |
28 | ||
29 | #include "t2load.h" | |
30 | #include "t2gload.h" | |
31 | ||
32 | #else | |
33 | ||
34 | #include <cff/t2load.h> | |
35 | #include <cff/t2gload.h> | |
36 | ||
37 | #endif | |
38 | ||
39 | ||
40 | #include <freetype/internal/t2errors.h> | |
41 | ||
42 | ||
43 | /*************************************************************************/ | |
44 | /* */ | |
45 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
46 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
47 | /* messages during execution. */ | |
48 | /* */ | |
49 | #undef FT_COMPONENT | |
50 | #define FT_COMPONENT trace_t2gload | |
51 | ||
52 | ||
53 | typedef enum T2_Operator_ | |
54 | { | |
55 | t2_op_unknown = 0, | |
56 | ||
57 | t2_op_rmoveto, | |
58 | t2_op_hmoveto, | |
59 | t2_op_vmoveto, | |
60 | ||
61 | t2_op_rlineto, | |
62 | t2_op_hlineto, | |
63 | t2_op_vlineto, | |
64 | ||
65 | t2_op_rrcurveto, | |
66 | t2_op_hhcurveto, | |
67 | t2_op_hvcurveto, | |
68 | t2_op_rcurveline, | |
69 | t2_op_rlinecurve, | |
70 | t2_op_vhcurveto, | |
71 | t2_op_vvcurveto, | |
72 | ||
73 | t2_op_flex, | |
74 | t2_op_hflex, | |
75 | t2_op_hflex1, | |
76 | t2_op_flex1, | |
77 | ||
78 | t2_op_endchar, | |
79 | ||
80 | t2_op_hstem, | |
81 | t2_op_vstem, | |
82 | t2_op_hstemhm, | |
83 | t2_op_vstemhm, | |
84 | ||
85 | t2_op_hintmask, | |
86 | t2_op_cntrmask, | |
87 | ||
88 | t2_op_abs, | |
89 | t2_op_add, | |
90 | t2_op_sub, | |
91 | t2_op_div, | |
92 | t2_op_neg, | |
93 | t2_op_random, | |
94 | t2_op_mul, | |
95 | t2_op_sqrt, | |
96 | ||
97 | t2_op_blend, | |
98 | ||
99 | t2_op_drop, | |
100 | t2_op_exch, | |
101 | t2_op_index, | |
102 | t2_op_roll, | |
103 | t2_op_dup, | |
104 | ||
105 | t2_op_put, | |
106 | t2_op_get, | |
107 | t2_op_store, | |
108 | t2_op_load, | |
109 | ||
110 | t2_op_and, | |
111 | t2_op_or, | |
112 | t2_op_not, | |
113 | t2_op_eq, | |
114 | t2_op_ifelse, | |
115 | ||
116 | t2_op_callsubr, | |
117 | t2_op_callgsubr, | |
118 | t2_op_return, | |
119 | ||
120 | /* do not remove */ | |
121 | t2_op_max | |
122 | ||
123 | } T2_Operator; | |
124 | ||
125 | ||
126 | #define T2_COUNT_CHECK_WIDTH 0x80 | |
127 | #define T2_COUNT_EXACT 0x40 | |
128 | #define T2_COUNT_CLEAR_STACK 0x20 | |
129 | ||
130 | ||
131 | static const FT_Byte t2_argument_counts[] = | |
132 | { | |
133 | 0, /* unknown */ | |
134 | ||
135 | 2 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, /* rmoveto */ | |
136 | 1 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, | |
137 | 1 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, | |
138 | ||
139 | 0 | T2_COUNT_CLEAR_STACK, /* rlineto */ | |
140 | 0 | T2_COUNT_CLEAR_STACK, | |
141 | 0 | T2_COUNT_CLEAR_STACK, | |
142 | ||
143 | 0 | T2_COUNT_CLEAR_STACK, /* rrcurveto */ | |
144 | 0 | T2_COUNT_CLEAR_STACK, | |
145 | 0 | T2_COUNT_CLEAR_STACK, | |
146 | 0 | T2_COUNT_CLEAR_STACK, | |
147 | 0 | T2_COUNT_CLEAR_STACK, | |
148 | 0 | T2_COUNT_CLEAR_STACK, | |
149 | 0 | T2_COUNT_CLEAR_STACK, | |
150 | ||
151 | 13, /* flex */ | |
152 | 7, | |
153 | 9, | |
154 | 11, | |
155 | ||
156 | 0, /* endchar */ | |
157 | ||
158 | 2 | T2_COUNT_CHECK_WIDTH, /* hstem */ | |
159 | 2 | T2_COUNT_CHECK_WIDTH, | |
160 | 2 | T2_COUNT_CHECK_WIDTH, | |
161 | 2 | T2_COUNT_CHECK_WIDTH, | |
162 | ||
163 | 0, /* hintmask */ | |
164 | 0, /* cntrmask */ | |
165 | ||
166 | 1, /* abs */ | |
167 | 2, | |
168 | 2, | |
169 | 2, | |
170 | 1, | |
171 | 0, | |
172 | 2, | |
173 | 1, | |
174 | ||
175 | 1, /* blend */ | |
176 | ||
177 | 1, /* drop */ | |
178 | 2, | |
179 | 1, | |
180 | 2, | |
181 | 1, | |
182 | ||
183 | 2, /* put */ | |
184 | 1, | |
185 | 4, | |
186 | 3, | |
187 | ||
188 | 2, /* and */ | |
189 | 2, | |
190 | 1, | |
191 | 2, | |
192 | 4, | |
193 | ||
194 | 1, /* callsubr */ | |
195 | 1, | |
196 | 0 | |
197 | }; | |
198 | ||
199 | ||
200 | /*************************************************************************/ | |
201 | /*************************************************************************/ | |
202 | /*************************************************************************/ | |
203 | /********** *********/ | |
204 | /********** *********/ | |
205 | /********** GENERIC CHARSTRING PARSING *********/ | |
206 | /********** *********/ | |
207 | /********** *********/ | |
208 | /*************************************************************************/ | |
209 | /*************************************************************************/ | |
210 | /*************************************************************************/ | |
211 | ||
212 | ||
213 | /*************************************************************************/ | |
214 | /* */ | |
215 | /* <Function> */ | |
216 | /* T2_Init_Builder */ | |
217 | /* */ | |
218 | /* <Description> */ | |
219 | /* Initializes a given glyph builder. */ | |
220 | /* */ | |
221 | /* <InOut> */ | |
222 | /* builder :: A pointer to the glyph builder to initialize. */ | |
223 | /* */ | |
224 | /* <Input> */ | |
225 | /* face :: The current face object. */ | |
226 | /* */ | |
227 | /* size :: The current size object. */ | |
228 | /* */ | |
229 | /* glyph :: The current glyph object. */ | |
230 | /* */ | |
231 | static | |
232 | void T2_Init_Builder( T2_Builder* builder, | |
233 | TT_Face face, | |
234 | T2_Size size, | |
235 | T2_GlyphSlot glyph ) | |
236 | { | |
237 | builder->path_begun = 0; | |
238 | builder->load_points = 1; | |
239 | ||
240 | builder->face = face; | |
241 | builder->glyph = glyph; | |
242 | builder->memory = face->root.memory; | |
243 | ||
244 | if ( glyph ) | |
245 | { | |
246 | FT_GlyphLoader* loader = glyph->root.loader; | |
247 | ||
248 | ||
249 | builder->loader = loader; | |
250 | builder->base = &loader->base.outline; | |
251 | builder->current = &loader->current.outline; | |
252 | FT_GlyphLoader_Rewind( loader ); | |
253 | } | |
254 | ||
255 | if ( size ) | |
256 | { | |
257 | builder->scale_x = size->metrics.x_scale; | |
258 | builder->scale_y = size->metrics.y_scale; | |
259 | } | |
260 | ||
261 | builder->pos_x = 0; | |
262 | builder->pos_y = 0; | |
263 | ||
264 | builder->left_bearing.x = 0; | |
265 | builder->left_bearing.y = 0; | |
266 | builder->advance.x = 0; | |
267 | builder->advance.y = 0; | |
268 | } | |
269 | ||
270 | ||
271 | /*************************************************************************/ | |
272 | /* */ | |
273 | /* <Function> */ | |
274 | /* T2_Done_Builder */ | |
275 | /* */ | |
276 | /* <Description> */ | |
277 | /* Finalizes a given glyph builder. Its contents can still be used */ | |
278 | /* after the call, but the function saves important information */ | |
279 | /* within the corresponding glyph slot. */ | |
280 | /* */ | |
281 | /* <Input> */ | |
282 | /* builder :: A pointer to the glyph builder to finalize. */ | |
283 | /* */ | |
284 | static | |
285 | void T2_Done_Builder( T2_Builder* builder ) | |
286 | { | |
287 | T2_GlyphSlot glyph = builder->glyph; | |
288 | ||
289 | ||
290 | if ( glyph ) | |
291 | glyph->root.outline = *builder->base; | |
292 | } | |
293 | ||
294 | ||
295 | /*************************************************************************/ | |
296 | /* */ | |
297 | /* <Function> */ | |
298 | /* t2_compute_bias */ | |
299 | /* */ | |
300 | /* <Description> */ | |
301 | /* Computes the bias value in dependence of the number of glyph */ | |
302 | /* subroutines. */ | |
303 | /* */ | |
304 | /* <Input> */ | |
305 | /* num_subrs :: The number of glyph subroutines. */ | |
306 | /* */ | |
307 | /* <Return> */ | |
308 | /* The bias value. */ | |
309 | static | |
310 | FT_Int t2_compute_bias( FT_UInt num_subrs ) | |
311 | { | |
312 | FT_Int result; | |
313 | ||
314 | ||
315 | if ( num_subrs < 1240 ) | |
316 | result = 107; | |
317 | else if ( num_subrs < 33900 ) | |
318 | result = 1131; | |
319 | else | |
320 | result = 32768; | |
321 | ||
322 | return result; | |
323 | } | |
324 | ||
325 | ||
326 | /*************************************************************************/ | |
327 | /* */ | |
328 | /* <Function> */ | |
329 | /* T2_Init_Decoder */ | |
330 | /* */ | |
331 | /* <Description> */ | |
332 | /* Initializes a given glyph decoder. */ | |
333 | /* */ | |
334 | /* <InOut> */ | |
335 | /* decoder :: A pointer to the glyph builder to initialize. */ | |
336 | /* */ | |
337 | /* <Input> */ | |
338 | /* face :: The current face object. */ | |
339 | /* */ | |
340 | /* size :: The current size object. */ | |
341 | /* */ | |
342 | /* slot :: The current glyph object. */ | |
343 | /* */ | |
344 | LOCAL_FUNC | |
345 | void T2_Init_Decoder( T2_Decoder* decoder, | |
346 | TT_Face face, | |
347 | T2_Size size, | |
348 | T2_GlyphSlot slot ) | |
349 | { | |
350 | CFF_Font* cff = (CFF_Font*)face->extra.data; | |
351 | ||
352 | ||
353 | /* clear everything */ | |
354 | MEM_Set( decoder, 0, sizeof ( *decoder ) ); | |
355 | ||
356 | /* initialize builder */ | |
357 | T2_Init_Builder( &decoder->builder, face, size, slot ); | |
358 | ||
359 | /* initialize Type2 decoder */ | |
360 | decoder->num_globals = cff->num_global_subrs; | |
361 | decoder->globals = cff->global_subrs; | |
362 | decoder->globals_bias = t2_compute_bias( decoder->num_globals ); | |
363 | } | |
364 | ||
365 | ||
366 | /* this function is used to select the locals subrs array */ | |
367 | LOCAL_DEF | |
368 | void T2_Prepare_Decoder( T2_Decoder* decoder, | |
369 | FT_UInt glyph_index ) | |
370 | { | |
371 | CFF_Font* cff = (CFF_Font*)decoder->builder.face->extra.data; | |
372 | CFF_SubFont* sub = &cff->top_font; | |
373 | ||
374 | ||
375 | /* manage CID fonts */ | |
376 | if ( cff->num_subfonts >= 1 ) | |
377 | { | |
378 | FT_Byte fd_index = CFF_Get_FD( &cff->fd_select, glyph_index ); | |
379 | ||
380 | ||
381 | sub = cff->subfonts[fd_index]; | |
382 | } | |
383 | ||
384 | decoder->num_locals = sub->num_local_subrs; | |
385 | decoder->locals = sub->local_subrs; | |
386 | decoder->locals_bias = t2_compute_bias( decoder->num_locals ); | |
387 | ||
388 | decoder->glyph_width = sub->private_dict.default_width; | |
389 | decoder->nominal_width = sub->private_dict.nominal_width; | |
390 | } | |
391 | ||
392 | ||
393 | /* check that there is enough room for `count' more points */ | |
394 | static | |
395 | FT_Error check_points( T2_Builder* builder, | |
396 | FT_Int count ) | |
397 | { | |
398 | return FT_GlyphLoader_Check_Points( builder->loader, count, 0 ); | |
399 | } | |
400 | ||
401 | ||
402 | /* add a new point, do not check space */ | |
403 | static | |
404 | void add_point( T2_Builder* builder, | |
405 | FT_Pos x, | |
406 | FT_Pos y, | |
407 | FT_Byte flag ) | |
408 | { | |
409 | FT_Outline* outline = builder->current; | |
410 | ||
411 | ||
412 | if ( builder->load_points ) | |
413 | { | |
414 | FT_Vector* point = outline->points + outline->n_points; | |
415 | FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; | |
416 | ||
417 | ||
418 | point->x = x >> 16; | |
419 | point->y = y >> 16; | |
420 | *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; | |
421 | ||
422 | builder->last = *point; | |
423 | } | |
424 | outline->n_points++; | |
425 | } | |
426 | ||
427 | ||
428 | /* check space for a new on-curve point, then add it */ | |
429 | static | |
430 | FT_Error add_point1( T2_Builder* builder, | |
431 | FT_Pos x, | |
432 | FT_Pos y ) | |
433 | { | |
434 | FT_Error error; | |
435 | ||
436 | ||
437 | error = check_points( builder, 1 ); | |
438 | if ( !error ) | |
439 | add_point( builder, x, y, 1 ); | |
440 | ||
441 | return error; | |
442 | } | |
443 | ||
444 | ||
445 | /* check room for a new contour, then add it */ | |
446 | static | |
447 | FT_Error add_contour( T2_Builder* builder ) | |
448 | { | |
449 | FT_Outline* outline = builder->current; | |
450 | FT_Error error; | |
451 | ||
452 | ||
453 | if ( !builder->load_points ) | |
454 | { | |
455 | outline->n_contours++; | |
456 | return T2_Err_Ok; | |
457 | } | |
458 | ||
459 | error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 ); | |
460 | if ( !error ) | |
461 | { | |
462 | if ( outline->n_contours > 0 ) | |
463 | outline->contours[outline->n_contours - 1] = outline->n_points - 1; | |
464 | ||
465 | outline->n_contours++; | |
466 | } | |
467 | ||
468 | return error; | |
469 | } | |
470 | ||
471 | ||
472 | /* if a path was begun, add its first on-curve point */ | |
473 | static | |
474 | FT_Error start_point( T2_Builder* builder, | |
475 | FT_Pos x, | |
476 | FT_Pos y ) | |
477 | { | |
478 | FT_Error error = 0; | |
479 | ||
480 | ||
481 | /* test whether we are building a new contour */ | |
482 | if ( !builder->path_begun ) | |
483 | { | |
484 | builder->path_begun = 1; | |
485 | error = add_contour( builder ); | |
486 | if ( !error ) | |
487 | error = add_point1( builder, x, y ); | |
488 | } | |
489 | return error; | |
490 | } | |
491 | ||
492 | ||
493 | /* close the current contour */ | |
494 | static | |
495 | void close_contour( T2_Builder* builder ) | |
496 | { | |
497 | FT_Outline* outline = builder->current; | |
498 | ||
499 | /* XXXX: We must not include the last point in the path if it */ | |
500 | /* is located on the first point. */ | |
501 | if ( outline->n_points > 1 ) | |
502 | { | |
503 | FT_Int first = 0; | |
504 | FT_Vector* p1 = outline->points + first; | |
505 | FT_Vector* p2 = outline->points + outline->n_points - 1; | |
506 | ||
507 | if ( outline->n_contours > 1 ) | |
508 | { | |
509 | first = outline->contours[outline->n_contours - 2] + 1; | |
510 | p1 = outline->points + first; | |
511 | } | |
512 | ||
513 | if ( p1->x == p2->x && p1->y == p2->y ) | |
514 | outline->n_points--; | |
515 | } | |
516 | ||
517 | if ( outline->n_contours > 0 ) | |
518 | outline->contours[outline->n_contours - 1] = outline->n_points - 1; | |
519 | } | |
520 | ||
521 | ||
522 | #define USE_ARGS( n ) do \ | |
523 | { \ | |
524 | top -= n; \ | |
525 | if ( top < decoder->stack ) \ | |
526 | goto Stack_Underflow; \ | |
527 | } while ( 0 ) | |
528 | ||
529 | ||
530 | /*************************************************************************/ | |
531 | /* */ | |
532 | /* <Function> */ | |
533 | /* T2_Parse_CharStrings */ | |
534 | /* */ | |
535 | /* <Description> */ | |
536 | /* Parses a given Type 2 charstrings program. */ | |
537 | /* */ | |
538 | /* <InOut> */ | |
539 | /* decoder :: The current Type 1 decoder. */ | |
540 | /* */ | |
541 | /* <Input> */ | |
542 | /* charstring_base :: The base of the charstring stream. */ | |
543 | /* */ | |
544 | /* charstring_len :: The length in bytes of the charstring stream. */ | |
545 | /* */ | |
546 | /* <Return> */ | |
547 | /* FreeType error code. 0 means success. */ | |
548 | /* */ | |
549 | LOCAL_FUNC | |
550 | FT_Error T2_Parse_CharStrings( T2_Decoder* decoder, | |
551 | FT_Byte* charstring_base, | |
552 | FT_Int charstring_len ) | |
553 | { | |
554 | FT_Error error; | |
555 | T2_Decoder_Zone* zone; | |
556 | FT_Byte* ip; | |
557 | FT_Byte* limit; | |
558 | T2_Builder* builder = &decoder->builder; | |
559 | FT_Outline* outline; | |
560 | FT_Pos x, y; | |
561 | FT_Fixed seed; | |
562 | FT_Fixed* stack; | |
563 | ||
564 | ||
565 | /* set default width */ | |
566 | decoder->num_hints = 0; | |
567 | decoder->read_width = 1; | |
568 | ||
569 | /* compute random seed from stack address of parameter */ | |
570 | seed = (FT_Fixed)(char*)&seed ^ | |
571 | (FT_Fixed)(char*)&decoder ^ | |
572 | (FT_Fixed)(char*)&charstring_base; | |
573 | seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF; | |
574 | if ( seed == 0 ) | |
575 | seed = 0x7384; | |
576 | ||
577 | /* initialize the decoder */ | |
578 | decoder->top = decoder->stack; | |
579 | decoder->zone = decoder->zones; | |
580 | zone = decoder->zones; | |
581 | stack = decoder->top; | |
582 | ||
583 | builder->path_begun = 0; | |
584 | ||
585 | zone->base = charstring_base; | |
586 | limit = zone->limit = charstring_base + charstring_len; | |
587 | ip = zone->cursor = zone->base; | |
588 | ||
589 | error = T2_Err_Ok; | |
590 | outline = builder->current; | |
591 | ||
592 | x = builder->pos_x; | |
593 | y = builder->pos_y; | |
594 | ||
595 | /* now, execute loop */ | |
596 | while ( ip < limit ) | |
597 | { | |
598 | T2_Operator op; | |
599 | FT_Byte v; | |
600 | FT_Byte count; | |
601 | ||
602 | ||
603 | /********************************************************************/ | |
604 | /* */ | |
605 | /* Decode operator or operand */ | |
606 | /* */ | |
607 | v = *ip++; | |
608 | if ( v >= 32 || v == 28 ) | |
609 | { | |
610 | FT_Int shift = 16; | |
611 | FT_Int32 val; | |
612 | ||
613 | ||
614 | /* this is an operand, push it on the stack */ | |
615 | if ( v == 28 ) | |
616 | { | |
617 | if ( ip + 1 >= limit ) | |
618 | goto Syntax_Error; | |
619 | val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] ); | |
620 | ip += 2; | |
621 | } | |
622 | else if ( v < 247 ) | |
623 | val = (FT_Long)v - 139; | |
624 | else if ( v < 251 ) | |
625 | { | |
626 | if ( ip >= limit ) | |
627 | goto Syntax_Error; | |
628 | val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108; | |
629 | } | |
630 | else if ( v < 255 ) | |
631 | { | |
632 | if ( ip >= limit ) | |
633 | goto Syntax_Error; | |
634 | val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108; | |
635 | } | |
636 | else | |
637 | { | |
638 | if ( ip + 3 >= limit ) | |
639 | goto Syntax_Error; | |
640 | val = ( (FT_Int32)ip[0] << 24 ) | | |
641 | ( (FT_Int32)ip[1] << 16 ) | | |
642 | ( (FT_Int32)ip[2] << 8 ) | | |
643 | ip[3]; | |
644 | ip += 4; | |
645 | shift = 0; | |
646 | } | |
647 | if ( decoder->top - stack >= T2_MAX_OPERANDS ) | |
648 | goto Stack_Overflow; | |
649 | ||
650 | val <<= shift; | |
651 | *decoder->top++ = val; | |
652 | ||
653 | #ifdef FT_DEBUG_LEVEL_TRACE | |
654 | if ( !( val & 0xFFFF ) ) | |
655 | FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) )); | |
656 | else | |
657 | FT_TRACE4(( " %.2f", val/65536.0 )); | |
658 | #endif | |
659 | ||
660 | } | |
661 | else | |
662 | { | |
663 | FT_Fixed* args = decoder->top; | |
664 | FT_Int num_args = args - decoder->stack; | |
665 | FT_Int req_args; | |
666 | ||
667 | ||
668 | /* find operator */ | |
669 | op = t2_op_unknown; | |
670 | ||
671 | switch ( v ) | |
672 | { | |
673 | case 1: | |
674 | op = t2_op_hstem; | |
675 | break; | |
676 | case 3: | |
677 | op = t2_op_vstem; | |
678 | break; | |
679 | case 4: | |
680 | op = t2_op_vmoveto; | |
681 | break; | |
682 | case 5: | |
683 | op = t2_op_rlineto; | |
684 | break; | |
685 | case 6: | |
686 | op = t2_op_hlineto; | |
687 | break; | |
688 | case 7: | |
689 | op = t2_op_vlineto; | |
690 | break; | |
691 | case 8: | |
692 | op = t2_op_rrcurveto; | |
693 | break; | |
694 | case 10: | |
695 | op = t2_op_callsubr; | |
696 | break; | |
697 | case 11: | |
698 | op = t2_op_return; | |
699 | break; | |
700 | case 12: | |
701 | { | |
702 | if ( ip >= limit ) | |
703 | goto Syntax_Error; | |
704 | v = *ip++; | |
705 | ||
706 | switch ( v ) | |
707 | { | |
708 | case 3: | |
709 | op = t2_op_and; | |
710 | break; | |
711 | case 4: | |
712 | op = t2_op_or; | |
713 | break; | |
714 | case 5: | |
715 | op = t2_op_not; | |
716 | break; | |
717 | case 8: | |
718 | op = t2_op_store; | |
719 | break; | |
720 | case 9: | |
721 | op = t2_op_abs; | |
722 | break; | |
723 | case 10: | |
724 | op = t2_op_add; | |
725 | break; | |
726 | case 11: | |
727 | op = t2_op_sub; | |
728 | break; | |
729 | case 12: | |
730 | op = t2_op_div; | |
731 | break; | |
732 | case 13: | |
733 | op = t2_op_load; | |
734 | break; | |
735 | case 14: | |
736 | op = t2_op_neg; | |
737 | break; | |
738 | case 15: | |
739 | op = t2_op_eq; | |
740 | break; | |
741 | case 18: | |
742 | op = t2_op_drop; | |
743 | break; | |
744 | case 20: | |
745 | op = t2_op_put; | |
746 | break; | |
747 | case 21: | |
748 | op = t2_op_get; | |
749 | break; | |
750 | case 22: | |
751 | op = t2_op_ifelse; | |
752 | break; | |
753 | case 23: | |
754 | op = t2_op_random; | |
755 | break; | |
756 | case 24: | |
757 | op = t2_op_mul; | |
758 | break; | |
759 | case 26: | |
760 | op = t2_op_sqrt; | |
761 | break; | |
762 | case 27: | |
763 | op = t2_op_dup; | |
764 | break; | |
765 | case 28: | |
766 | op = t2_op_exch; | |
767 | break; | |
768 | case 29: | |
769 | op = t2_op_index; | |
770 | break; | |
771 | case 30: | |
772 | op = t2_op_roll; | |
773 | break; | |
774 | case 34: | |
775 | op = t2_op_hflex; | |
776 | break; | |
777 | case 35: | |
778 | op = t2_op_flex; | |
779 | break; | |
780 | case 36: | |
781 | op = t2_op_hflex1; | |
782 | break; | |
783 | case 37: | |
784 | op = t2_op_flex1; | |
785 | break; | |
786 | default: | |
787 | /* decrement ip for syntax error message */ | |
788 | ip--; | |
789 | } | |
790 | } | |
791 | break; | |
792 | case 14: | |
793 | op = t2_op_endchar; | |
794 | break; | |
795 | case 16: | |
796 | op = t2_op_blend; | |
797 | break; | |
798 | case 18: | |
799 | op = t2_op_hstemhm; | |
800 | break; | |
801 | case 19: | |
802 | op = t2_op_hintmask; | |
803 | break; | |
804 | case 20: | |
805 | op = t2_op_cntrmask; | |
806 | break; | |
807 | case 21: | |
808 | op = t2_op_rmoveto; | |
809 | break; | |
810 | case 22: | |
811 | op = t2_op_hmoveto; | |
812 | break; | |
813 | case 23: | |
814 | op = t2_op_vstemhm; | |
815 | break; | |
816 | case 24: | |
817 | op = t2_op_rcurveline; | |
818 | break; | |
819 | case 25: | |
820 | op = t2_op_rlinecurve; | |
821 | break; | |
822 | case 26: | |
823 | op = t2_op_vvcurveto; | |
824 | break; | |
825 | case 27: | |
826 | op = t2_op_hhcurveto; | |
827 | break; | |
828 | case 29: | |
829 | op = t2_op_callgsubr; | |
830 | break; | |
831 | case 30: | |
832 | op = t2_op_vhcurveto; | |
833 | break; | |
834 | case 31: | |
835 | op = t2_op_hvcurveto; | |
836 | break; | |
837 | default: | |
838 | ; | |
839 | } | |
840 | if ( op == t2_op_unknown ) | |
841 | goto Syntax_Error; | |
842 | ||
843 | /* check arguments */ | |
844 | req_args = count = t2_argument_counts[op]; | |
845 | if ( req_args & T2_COUNT_CHECK_WIDTH ) | |
846 | { | |
847 | args = stack; | |
848 | if ( num_args & 1 && decoder->read_width ) | |
849 | { | |
850 | decoder->glyph_width = decoder->nominal_width + | |
851 | ( stack[0] >> 16 ); | |
852 | num_args--; | |
853 | args++; | |
854 | } | |
855 | decoder->read_width = 0; | |
856 | req_args = 0; | |
857 | } | |
858 | ||
859 | req_args &= 15; | |
860 | if ( num_args < req_args ) | |
861 | goto Stack_Underflow; | |
862 | args -= req_args; | |
863 | num_args -= req_args; | |
864 | ||
865 | switch ( op ) | |
866 | { | |
867 | case t2_op_hstem: | |
868 | case t2_op_vstem: | |
869 | case t2_op_hstemhm: | |
870 | case t2_op_vstemhm: | |
871 | /* if the number of arguments is not even, the first one */ | |
872 | /* is simply the glyph width, encoded as the difference */ | |
873 | /* to nominalWidthX */ | |
874 | FT_TRACE4(( op == t2_op_hstem ? " hstem" : | |
875 | op == t2_op_vstem ? " vstem" : | |
876 | op == t2_op_hstemhm ? " hstemhm" : | |
877 | " vstemhm" )); | |
878 | decoder->num_hints += num_args / 2; | |
879 | args = stack; | |
880 | break; | |
881 | ||
882 | case t2_op_hintmask: | |
883 | case t2_op_cntrmask: | |
884 | FT_TRACE4(( op == t2_op_hintmask ? " hintmask" | |
885 | : " cntrmask" )); | |
886 | ||
887 | decoder->num_hints += num_args / 2; | |
888 | ip += ( decoder->num_hints + 7 ) >> 3; | |
889 | if ( ip >= limit ) | |
890 | goto Syntax_Error; | |
891 | args = stack; | |
892 | break; | |
893 | ||
894 | case t2_op_rmoveto: | |
895 | FT_TRACE4(( " rmoveto" )); | |
896 | ||
897 | close_contour( builder ); | |
898 | builder->path_begun = 0; | |
899 | x += args[0]; | |
900 | y += args[1]; | |
901 | args = stack; | |
902 | break; | |
903 | ||
904 | case t2_op_vmoveto: | |
905 | FT_TRACE4(( " vmoveto" )); | |
906 | ||
907 | close_contour( builder ); | |
908 | builder->path_begun = 0; | |
909 | y += args[0]; | |
910 | args = stack; | |
911 | break; | |
912 | ||
913 | case t2_op_hmoveto: | |
914 | FT_TRACE4(( " hmoveto" )); | |
915 | ||
916 | close_contour( builder ); | |
917 | builder->path_begun = 0; | |
918 | x += args[0]; | |
919 | args = stack; | |
920 | break; | |
921 | ||
922 | case t2_op_rlineto: | |
923 | FT_TRACE4(( " rlineto" )); | |
924 | ||
925 | if ( start_point ( builder, x, y ) || | |
926 | check_points( builder, num_args / 2 ) ) | |
927 | goto Memory_Error; | |
928 | ||
929 | if ( num_args < 2 || num_args & 1 ) | |
930 | goto Stack_Underflow; | |
931 | ||
932 | args = stack; | |
933 | while ( args < decoder->top ) | |
934 | { | |
935 | x += args[0]; | |
936 | y += args[1]; | |
937 | add_point( builder, x, y, 1 ); | |
938 | args += 2; | |
939 | } | |
940 | args = stack; | |
941 | break; | |
942 | ||
943 | case t2_op_hlineto: | |
944 | case t2_op_vlineto: | |
945 | { | |
946 | FT_Int phase = ( op == t2_op_hlineto ); | |
947 | ||
948 | ||
949 | FT_TRACE4(( op == t2_op_hlineto ? " hlineto" | |
950 | : " vlineto" )); | |
951 | ||
952 | if ( start_point ( builder, x, y ) || | |
953 | check_points( builder, num_args ) ) | |
954 | goto Memory_Error; | |
955 | ||
956 | args = stack; | |
957 | while (args < decoder->top ) | |
958 | { | |
959 | if ( phase ) | |
960 | x += args[0]; | |
961 | else | |
962 | y += args[0]; | |
963 | ||
964 | if ( add_point1( builder, x, y ) ) | |
965 | goto Memory_Error; | |
966 | ||
967 | args++; | |
968 | phase ^= 1; | |
969 | } | |
970 | args = stack; | |
971 | } | |
972 | break; | |
973 | ||
974 | case t2_op_rrcurveto: | |
975 | FT_TRACE4(( " rrcurveto" )); | |
976 | ||
977 | /* check number of arguments; must be a multiple of 6 */ | |
978 | if ( num_args % 6 != 0 ) | |
979 | goto Stack_Underflow; | |
980 | ||
981 | if ( start_point ( builder, x, y ) || | |
982 | check_points( builder, num_args / 2 ) ) | |
983 | goto Memory_Error; | |
984 | ||
985 | args = stack; | |
986 | while ( args < decoder->top ) | |
987 | { | |
988 | x += args[0]; | |
989 | y += args[1]; | |
990 | add_point( builder, x, y, 0 ); | |
991 | x += args[2]; | |
992 | y += args[3]; | |
993 | add_point( builder, x, y, 0 ); | |
994 | x += args[4]; | |
995 | y += args[5]; | |
996 | add_point( builder, x, y, 1 ); | |
997 | args += 6; | |
998 | } | |
999 | args = stack; | |
1000 | break; | |
1001 | ||
1002 | case t2_op_vvcurveto: | |
1003 | FT_TRACE4(( " vvcurveto" )); | |
1004 | ||
1005 | if ( start_point ( builder, x, y ) ) | |
1006 | goto Memory_Error; | |
1007 | ||
1008 | args = stack; | |
1009 | if ( num_args & 1 ) | |
1010 | { | |
1011 | x += args[0]; | |
1012 | args++; | |
1013 | num_args--; | |
1014 | } | |
1015 | ||
1016 | if ( num_args % 4 != 0 ) | |
1017 | goto Stack_Underflow; | |
1018 | ||
1019 | if ( check_points( builder, 3 * ( num_args / 4 ) ) ) | |
1020 | goto Memory_Error; | |
1021 | ||
1022 | while ( args < decoder->top ) | |
1023 | { | |
1024 | y += args[0]; | |
1025 | add_point( builder, x, y, 0 ); | |
1026 | x += args[1]; | |
1027 | y += args[2]; | |
1028 | add_point( builder, x, y, 0 ); | |
1029 | y += args[3]; | |
1030 | add_point( builder, x, y, 1 ); | |
1031 | args += 4; | |
1032 | } | |
1033 | args = stack; | |
1034 | break; | |
1035 | ||
1036 | case t2_op_hhcurveto: | |
1037 | FT_TRACE4(( " hhcurveto" )); | |
1038 | ||
1039 | if ( start_point ( builder, x, y ) ) | |
1040 | goto Memory_Error; | |
1041 | ||
1042 | args = stack; | |
1043 | if ( num_args & 1 ) | |
1044 | { | |
1045 | y += args[0]; | |
1046 | args++; | |
1047 | num_args--; | |
1048 | } | |
1049 | ||
1050 | if ( num_args % 4 != 0 ) | |
1051 | goto Stack_Underflow; | |
1052 | ||
1053 | if ( check_points( builder, 3 * ( num_args / 4 ) ) ) | |
1054 | goto Memory_Error; | |
1055 | ||
1056 | while ( args < decoder->top ) | |
1057 | { | |
1058 | x += args[0]; | |
1059 | add_point( builder, x, y, 0 ); | |
1060 | x += args[1]; | |
1061 | y += args[2]; | |
1062 | add_point( builder, x, y, 0 ); | |
1063 | x += args[3]; | |
1064 | add_point( builder, x, y, 1 ); | |
1065 | args += 4; | |
1066 | } | |
1067 | args = stack; | |
1068 | break; | |
1069 | ||
1070 | case t2_op_vhcurveto: | |
1071 | case t2_op_hvcurveto: | |
1072 | { | |
1073 | FT_Int phase; | |
1074 | ||
1075 | ||
1076 | FT_TRACE4(( op == t2_op_vhcurveto ? " vhcurveto" | |
1077 | : " hvcurveto" )); | |
1078 | ||
1079 | if ( start_point ( builder, x, y ) ) | |
1080 | goto Memory_Error; | |
1081 | ||
1082 | args = stack; | |
1083 | if (num_args < 4 || ( num_args % 4 ) > 1 ) | |
1084 | goto Stack_Underflow; | |
1085 | ||
1086 | if ( check_points( builder, ( num_args / 4 ) * 3 ) ) | |
1087 | goto Stack_Underflow; | |
1088 | ||
1089 | phase = ( op == t2_op_hvcurveto ); | |
1090 | ||
1091 | while ( num_args >= 4 ) | |
1092 | { | |
1093 | num_args -= 4; | |
1094 | if ( phase ) | |
1095 | { | |
1096 | x += args[0]; | |
1097 | add_point( builder, x, y, 0 ); | |
1098 | x += args[1]; | |
1099 | y += args[2]; | |
1100 | add_point( builder, x, y, 0 ); | |
1101 | y += args[3]; | |
1102 | if ( num_args == 1 ) | |
1103 | x += args[4]; | |
1104 | add_point( builder, x, y, 1 ); | |
1105 | } | |
1106 | else | |
1107 | { | |
1108 | y += args[0]; | |
1109 | add_point( builder, x, y, 0 ); | |
1110 | x += args[1]; | |
1111 | y += args[2]; | |
1112 | add_point( builder, x, y, 0 ); | |
1113 | x += args[3]; | |
1114 | if ( num_args == 1 ) | |
1115 | y += args[4]; | |
1116 | add_point( builder, x, y, 1 ); | |
1117 | } | |
1118 | args += 4; | |
1119 | phase ^= 1; | |
1120 | } | |
1121 | args = stack; | |
1122 | } | |
1123 | break; | |
1124 | ||
1125 | case t2_op_rlinecurve: | |
1126 | { | |
1127 | FT_Int num_lines = ( num_args - 6 ) / 2; | |
1128 | ||
1129 | ||
1130 | FT_TRACE4(( " rlinecurve" )); | |
1131 | ||
1132 | if ( num_args < 8 || ( num_args - 6 ) & 1 ) | |
1133 | goto Stack_Underflow; | |
1134 | ||
1135 | if ( start_point( builder, x, y ) || | |
1136 | check_points( builder, num_lines + 3 ) ) | |
1137 | goto Memory_Error; | |
1138 | ||
1139 | args = stack; | |
1140 | ||
1141 | /* first, add the line segments */ | |
1142 | while ( num_lines > 0 ) | |
1143 | { | |
1144 | x += args[0]; | |
1145 | y += args[1]; | |
1146 | add_point( builder, x, y, 1 ); | |
1147 | args += 2; | |
1148 | num_lines--; | |
1149 | } | |
1150 | ||
1151 | /* then the curve */ | |
1152 | x += args[0]; | |
1153 | y += args[1]; | |
1154 | add_point( builder, x, y, 0 ); | |
1155 | x += args[2]; | |
1156 | y += args[3]; | |
1157 | add_point( builder, x, y, 0 ); | |
1158 | x += args[4]; | |
1159 | y += args[5]; | |
1160 | add_point( builder, x, y, 1 ); | |
1161 | args = stack; | |
1162 | } | |
1163 | break; | |
1164 | ||
1165 | case t2_op_rcurveline: | |
1166 | { | |
1167 | FT_Int num_curves = ( num_args - 2 ) / 6; | |
1168 | ||
1169 | ||
1170 | FT_TRACE4(( " rcurveline" )); | |
1171 | ||
1172 | if ( num_args < 8 || ( num_args - 2 ) % 6 ) | |
1173 | goto Stack_Underflow; | |
1174 | ||
1175 | if ( start_point ( builder, x, y ) || | |
1176 | check_points( builder, num_curves*3 + 2 ) ) | |
1177 | goto Memory_Error; | |
1178 | ||
1179 | args = stack; | |
1180 | ||
1181 | /* first, add the curves */ | |
1182 | while ( num_curves > 0 ) | |
1183 | { | |
1184 | x += args[0]; | |
1185 | y += args[1]; | |
1186 | add_point( builder, x, y, 0 ); | |
1187 | x += args[2]; | |
1188 | y += args[3]; | |
1189 | add_point( builder, x, y, 0 ); | |
1190 | x += args[4]; | |
1191 | y += args[5]; | |
1192 | add_point( builder, x, y, 1 ); | |
1193 | args += 6; | |
1194 | num_curves--; | |
1195 | } | |
1196 | ||
1197 | /* then the final line */ | |
1198 | x += args[0]; | |
1199 | y += args[1]; | |
1200 | add_point( builder, x, y, 1 ); | |
1201 | args = stack; | |
1202 | } | |
1203 | break; | |
1204 | ||
1205 | case t2_op_hflex1: | |
1206 | { | |
1207 | FT_Pos start_y; | |
1208 | ||
1209 | ||
1210 | FT_TRACE4(( " hflex1" )); | |
1211 | ||
1212 | args = stack; | |
1213 | ||
1214 | /* adding five more points; 4 control points, 1 on-curve point */ | |
1215 | /* make sure we have enough space for the start point if it */ | |
1216 | /* needs to be added.. */ | |
1217 | if ( start_point( builder, x, y ) || | |
1218 | check_points( builder, 6 ) ) | |
1219 | goto Memory_Error; | |
1220 | ||
1221 | /* Record the starting point's y postion for later use */ | |
1222 | start_y = y; | |
1223 | ||
1224 | /* first control point */ | |
1225 | x += args[0]; | |
1226 | y += args[1]; | |
1227 | add_point( builder, x, y, 0 ); | |
1228 | ||
1229 | /* second control point */ | |
1230 | x += args[2]; | |
1231 | y += args[3]; | |
1232 | add_point( builder, x, y, 0 ); | |
1233 | ||
1234 | /* join point; on curve, with y-value the same as the last */ | |
1235 | /* control point's y-value */ | |
1236 | x += args[4]; | |
1237 | add_point( builder, x, y, 1 ); | |
1238 | ||
1239 | /* third control point, with y-value the same as the join */ | |
1240 | /* point's y-value */ | |
1241 | x += args[5]; | |
1242 | add_point( builder, x, y, 0 ); | |
1243 | ||
1244 | /* fourth control point */ | |
1245 | x += args[6]; | |
1246 | y += args[7]; | |
1247 | add_point( builder, x, y, 0 ); | |
1248 | ||
1249 | /* ending point, with y-value the same as the start */ | |
1250 | x += args[8]; | |
1251 | y = start_y; | |
1252 | add_point( builder, x, y, 1 ); | |
1253 | ||
1254 | args = stack; | |
1255 | break; | |
1256 | } | |
1257 | ||
1258 | case t2_op_hflex: | |
1259 | { | |
1260 | FT_Pos start_y; | |
1261 | ||
1262 | ||
1263 | FT_TRACE4(( " hflex" )); | |
1264 | ||
1265 | args = stack; | |
1266 | ||
1267 | /* adding six more points; 4 control points, 2 on-curve points */ | |
1268 | if ( start_point( builder, x, y ) || | |
1269 | check_points ( builder, 6 ) ) | |
1270 | goto Memory_Error; | |
1271 | ||
1272 | /* record the starting point's y-position for later use */ | |
1273 | start_y = y; | |
1274 | ||
1275 | /* first control point */ | |
1276 | x += args[0]; | |
1277 | add_point( builder, x, y, 0 ); | |
1278 | ||
1279 | /* second control point */ | |
1280 | x += args[1]; | |
1281 | y += args[2]; | |
1282 | add_point( builder, x, y, 0 ); | |
1283 | ||
1284 | /* join point; on curve, with y-value the same as the last */ | |
1285 | /* control point's y-value */ | |
1286 | x += args[3]; | |
1287 | add_point( builder, x, y, 1 ); | |
1288 | ||
1289 | /* third control point, with y-value the same as the join */ | |
1290 | /* point's y-value */ | |
1291 | x += args[4]; | |
1292 | add_point( builder, x, y, 0 ); | |
1293 | ||
1294 | /* fourth control point */ | |
1295 | x += args[5]; | |
1296 | y = start_y; | |
1297 | add_point( builder, x, y, 0 ); | |
1298 | ||
1299 | /* ending point, with y-value the same as the start point's */ | |
1300 | /* y-value -- we don't add this point, though */ | |
1301 | x += args[6]; | |
1302 | add_point( builder, x, y, 1 ); | |
1303 | ||
1304 | args = stack; | |
1305 | break; | |
1306 | } | |
1307 | ||
1308 | case t2_op_flex1: | |
1309 | { | |
1310 | FT_Pos start_x, start_y; /* record start x, y values for alter */ | |
1311 | /* use */ | |
1312 | FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */ | |
1313 | /* algorithm below */ | |
1314 | FT_Int horizontal, count; | |
1315 | ||
1316 | ||
1317 | FT_TRACE4(( " flex1" )); | |
1318 | ||
1319 | /* adding six more points; 4 control points, 2 on-curve points */ | |
1320 | if ( start_point( builder, x, y ) || | |
1321 | check_points( builder, 6 ) ) | |
1322 | goto Memory_Error; | |
1323 | ||
1324 | /* record the starting point's x, y postion for later use */ | |
1325 | start_x = x; | |
1326 | start_y = y; | |
1327 | ||
1328 | /* XXX: figure out whether this is supposed to be a horizontal */ | |
1329 | /* or vertical flex; the Type 2 specification is vague... */ | |
1330 | ||
1331 | args = stack; | |
1332 | ||
1333 | /* grab up to the last argument */ | |
1334 | for ( count = 5; count > 0; count-- ) | |
1335 | { | |
1336 | dx += args[0]; | |
1337 | dy += args[1]; | |
1338 | args += 2; | |
1339 | } | |
1340 | ||
1341 | /* rewind */ | |
1342 | args = stack; | |
1343 | ||
1344 | if ( dx < 0 ) dx = -dx; | |
1345 | if ( dy < 0 ) dy = -dy; | |
1346 | ||
1347 | /* strange test, but here it is... */ | |
1348 | horizontal = ( dx > dy ); | |
1349 | ||
1350 | for ( count = 5; count > 0; count-- ) | |
1351 | { | |
1352 | x += args[0]; | |
1353 | y += args[1]; | |
1354 | add_point( builder, x, y, (FT_Bool)( count == 3 ) ); | |
1355 | args += 2; | |
1356 | } | |
1357 | ||
1358 | /* is last operand an x- or y-delta? */ | |
1359 | if ( horizontal ) | |
1360 | { | |
1361 | x += args[0]; | |
1362 | y = start_y; | |
1363 | } | |
1364 | else | |
1365 | { | |
1366 | x = start_x; | |
1367 | y += args[0]; | |
1368 | } | |
1369 | ||
1370 | add_point( builder, x, y, 1 ); | |
1371 | ||
1372 | args = stack; | |
1373 | break; | |
1374 | } | |
1375 | ||
1376 | case t2_op_flex: | |
1377 | { | |
1378 | FT_UInt count; | |
1379 | ||
1380 | ||
1381 | FT_TRACE4(( " flex" )); | |
1382 | ||
1383 | if ( start_point( builder, x, y ) || | |
1384 | check_points( builder, 6 ) ) | |
1385 | goto Memory_Error; | |
1386 | ||
1387 | args = stack; | |
1388 | for ( count = 6; count > 0; count-- ) | |
1389 | { | |
1390 | x += args[0]; | |
1391 | y += args[1]; | |
1392 | add_point( builder, x, y, | |
1393 | (FT_Bool)( count == 3 || count == 0 ) ); | |
1394 | args += 2; | |
1395 | } | |
1396 | ||
1397 | args = stack; | |
1398 | } | |
1399 | break; | |
1400 | ||
1401 | case t2_op_endchar: | |
1402 | FT_TRACE4(( " endchar" )); | |
1403 | ||
1404 | close_contour( builder ); | |
1405 | ||
1406 | /* add current outline to the glyph slot */ | |
1407 | FT_GlyphLoader_Add( builder->loader ); | |
1408 | ||
1409 | /* return now! */ | |
1410 | FT_TRACE4(( "\n\n" )); | |
1411 | return T2_Err_Ok; | |
1412 | ||
1413 | case t2_op_abs: | |
1414 | FT_TRACE4(( " abs" )); | |
1415 | ||
1416 | if ( args[0] < 0 ) | |
1417 | args[0] = -args[0]; | |
1418 | args++; | |
1419 | break; | |
1420 | ||
1421 | case t2_op_add: | |
1422 | FT_TRACE4(( " add" )); | |
1423 | ||
1424 | args[0] += args[1]; | |
1425 | args++; | |
1426 | break; | |
1427 | ||
1428 | case t2_op_sub: | |
1429 | FT_TRACE4(( " sub" )); | |
1430 | ||
1431 | args[0] -= args[1]; | |
1432 | args++; | |
1433 | break; | |
1434 | ||
1435 | case t2_op_div: | |
1436 | FT_TRACE4(( " div" )); | |
1437 | ||
1438 | args[0] = FT_DivFix( args[0], args[1] ); | |
1439 | args++; | |
1440 | break; | |
1441 | ||
1442 | case t2_op_neg: | |
1443 | FT_TRACE4(( " neg" )); | |
1444 | ||
1445 | args[0] = -args[0]; | |
1446 | args++; | |
1447 | break; | |
1448 | ||
1449 | case t2_op_random: | |
1450 | { | |
1451 | FT_Fixed rand; | |
1452 | ||
1453 | ||
1454 | FT_TRACE4(( " rand" )); | |
1455 | ||
1456 | rand = seed; | |
1457 | if ( rand >= 0x8000 ) | |
1458 | rand++; | |
1459 | ||
1460 | args[0] = rand; | |
1461 | seed = FT_MulFix( seed, 0x10000L - seed ); | |
1462 | if ( seed == 0 ) | |
1463 | seed += 0x2873; | |
1464 | args++; | |
1465 | } | |
1466 | break; | |
1467 | ||
1468 | case t2_op_mul: | |
1469 | FT_TRACE4(( " mul" )); | |
1470 | ||
1471 | args[0] = FT_MulFix( args[0], args[1] ); | |
1472 | args++; | |
1473 | break; | |
1474 | ||
1475 | case t2_op_sqrt: | |
1476 | FT_TRACE4(( " sqrt" )); | |
1477 | ||
1478 | if ( args[0] > 0 ) | |
1479 | { | |
1480 | FT_Int count = 9; | |
1481 | FT_Fixed root = args[0]; | |
1482 | FT_Fixed new_root; | |
1483 | ||
1484 | ||
1485 | for (;;) | |
1486 | { | |
1487 | new_root = ( root + FT_DivFix(args[0],root) + 1 ) >> 1; | |
1488 | if ( new_root == root || count <= 0 ) | |
1489 | break; | |
1490 | root = new_root; | |
1491 | } | |
1492 | args[0] = new_root; | |
1493 | } | |
1494 | else | |
1495 | args[0] = 0; | |
1496 | args++; | |
1497 | break; | |
1498 | ||
1499 | case t2_op_drop: | |
1500 | /* nothing */ | |
1501 | FT_TRACE4(( " drop" )); | |
1502 | ||
1503 | break; | |
1504 | ||
1505 | case t2_op_exch: | |
1506 | { | |
1507 | FT_Fixed tmp; | |
1508 | ||
1509 | ||
1510 | FT_TRACE4(( " exch" )); | |
1511 | ||
1512 | tmp = args[0]; | |
1513 | args[0] = args[1]; | |
1514 | args[1] = tmp; | |
1515 | args += 2; | |
1516 | } | |
1517 | break; | |
1518 | ||
1519 | case t2_op_index: | |
1520 | { | |
1521 | FT_Int index = args[0] >> 16; | |
1522 | ||
1523 | ||
1524 | FT_TRACE4(( " index" )); | |
1525 | ||
1526 | if ( index < 0 ) | |
1527 | index = 0; | |
1528 | else if ( index > num_args - 2 ) | |
1529 | index = num_args - 2; | |
1530 | args[0] = args[-( index + 1 )]; | |
1531 | args++; | |
1532 | } | |
1533 | break; | |
1534 | ||
1535 | case t2_op_roll: | |
1536 | { | |
1537 | FT_Int count = (FT_Int)( args[0] >> 16 ); | |
1538 | FT_Int index = (FT_Int)( args[1] >> 16 ); | |
1539 | ||
1540 | ||
1541 | FT_TRACE4(( " roll" )); | |
1542 | ||
1543 | if ( count <= 0 ) | |
1544 | count = 1; | |
1545 | ||
1546 | args -= count; | |
1547 | if ( args < stack ) | |
1548 | goto Stack_Underflow; | |
1549 | ||
1550 | if ( index >= 0 ) | |
1551 | { | |
1552 | while ( index > 0 ) | |
1553 | { | |
1554 | FT_Fixed tmp = args[count - 1]; | |
1555 | FT_Int i; | |
1556 | ||
1557 | ||
1558 | for ( i = count - 2; i >= 0; i-- ) | |
1559 | args[i + 1] = args[i]; | |
1560 | args[0] = tmp; | |
1561 | index--; | |
1562 | } | |
1563 | } | |
1564 | else | |
1565 | { | |
1566 | while ( index < 0 ) | |
1567 | { | |
1568 | FT_Fixed tmp = args[0]; | |
1569 | FT_Int i; | |
1570 | ||
1571 | ||
1572 | for ( i = 0; i < count - 1; i++ ) | |
1573 | args[i] = args[i + 1]; | |
1574 | args[count - 1] = tmp; | |
1575 | index++; | |
1576 | } | |
1577 | } | |
1578 | args += count; | |
1579 | } | |
1580 | break; | |
1581 | ||
1582 | case t2_op_dup: | |
1583 | FT_TRACE4(( " dup" )); | |
1584 | ||
1585 | args[1] = args[0]; | |
1586 | args++; | |
1587 | break; | |
1588 | ||
1589 | case t2_op_put: | |
1590 | { | |
1591 | FT_Fixed val = args[0]; | |
1592 | FT_Int index = (FT_Int)( args[1] >> 16 ); | |
1593 | ||
1594 | ||
1595 | FT_TRACE4(( " put" )); | |
1596 | ||
1597 | if ( index >= 0 && index < decoder->len_buildchar ) | |
1598 | decoder->buildchar[index] = val; | |
1599 | } | |
1600 | break; | |
1601 | ||
1602 | case t2_op_get: | |
1603 | { | |
1604 | FT_Int index = (FT_Int)( args[0] >> 16 ); | |
1605 | FT_Fixed val = 0; | |
1606 | ||
1607 | ||
1608 | FT_TRACE4(( " get" )); | |
1609 | ||
1610 | if ( index >= 0 && index < decoder->len_buildchar ) | |
1611 | val = decoder->buildchar[index]; | |
1612 | ||
1613 | args[0] = val; | |
1614 | args++; | |
1615 | } | |
1616 | break; | |
1617 | ||
1618 | case t2_op_store: | |
1619 | FT_TRACE4(( " store ")); | |
1620 | ||
1621 | goto Unimplemented; | |
1622 | ||
1623 | case t2_op_load: | |
1624 | FT_TRACE4(( " load" )); | |
1625 | ||
1626 | goto Unimplemented; | |
1627 | ||
1628 | case t2_op_and: | |
1629 | { | |
1630 | FT_Fixed cond = args[0] && args[1]; | |
1631 | ||
1632 | ||
1633 | FT_TRACE4(( " and" )); | |
1634 | ||
1635 | args[0] = cond ? 0x10000L : 0; | |
1636 | args++; | |
1637 | } | |
1638 | break; | |
1639 | ||
1640 | case t2_op_or: | |
1641 | { | |
1642 | FT_Fixed cond = args[0] || args[1]; | |
1643 | ||
1644 | ||
1645 | FT_TRACE4(( " or" )); | |
1646 | ||
1647 | args[0] = cond ? 0x10000L : 0; | |
1648 | args++; | |
1649 | } | |
1650 | break; | |
1651 | ||
1652 | case t2_op_eq: | |
1653 | { | |
1654 | FT_Fixed cond = !args[0]; | |
1655 | ||
1656 | ||
1657 | FT_TRACE4(( " eq" )); | |
1658 | ||
1659 | args[0] = cond ? 0x10000L : 0; | |
1660 | args++; | |
1661 | } | |
1662 | break; | |
1663 | ||
1664 | case t2_op_ifelse: | |
1665 | { | |
1666 | FT_Fixed cond = (args[2] <= args[3]); | |
1667 | ||
1668 | ||
1669 | FT_TRACE4(( " ifelse" )); | |
1670 | ||
1671 | if ( !cond ) | |
1672 | args[0] = args[1]; | |
1673 | args++; | |
1674 | } | |
1675 | break; | |
1676 | ||
1677 | case t2_op_callsubr: | |
1678 | { | |
1679 | FT_UInt index = (FT_UInt)( ( args[0] >> 16 ) + | |
1680 | decoder->locals_bias ); | |
1681 | ||
1682 | ||
1683 | FT_TRACE4(( " callsubr(%d)", index )); | |
1684 | ||
1685 | if ( index >= decoder->num_locals ) | |
1686 | { | |
1687 | FT_ERROR(( "T2_Parse_CharStrings:" )); | |
1688 | FT_ERROR(( " invalid local subr index\n" )); | |
1689 | goto Syntax_Error; | |
1690 | } | |
1691 | ||
1692 | if ( zone - decoder->zones >= T2_MAX_SUBRS_CALLS ) | |
1693 | { | |
1694 | FT_ERROR(( "T2_Parse_CharStrings: too many nested subrs\n" )); | |
1695 | goto Syntax_Error; | |
1696 | } | |
1697 | ||
1698 | zone->cursor = ip; /* save current instruction pointer */ | |
1699 | ||
1700 | zone++; | |
1701 | zone->base = decoder->locals[index]; | |
1702 | zone->limit = decoder->locals[index+1]; | |
1703 | zone->cursor = zone->base; | |
1704 | ||
1705 | if ( !zone->base ) | |
1706 | { | |
1707 | FT_ERROR(( "T2_Parse_CharStrings: invoking empty subrs!\n" )); | |
1708 | goto Syntax_Error; | |
1709 | } | |
1710 | ||
1711 | decoder->zone = zone; | |
1712 | ip = zone->base; | |
1713 | limit = zone->limit; | |
1714 | } | |
1715 | break; | |
1716 | ||
1717 | case t2_op_callgsubr: | |
1718 | { | |
1719 | FT_UInt index = (FT_UInt)( ( args[0] >> 16 ) + | |
1720 | decoder->globals_bias ); | |
1721 | ||
1722 | ||
1723 | FT_TRACE4(( " callgsubr(%d)", index )); | |
1724 | ||
1725 | if ( index >= decoder->num_globals ) | |
1726 | { | |
1727 | FT_ERROR(( "T2_Parse_CharStrings:" )); | |
1728 | FT_ERROR(( " invalid global subr index\n" )); | |
1729 | goto Syntax_Error; | |
1730 | } | |
1731 | ||
1732 | if ( zone - decoder->zones >= T2_MAX_SUBRS_CALLS ) | |
1733 | { | |
1734 | FT_ERROR(( "T2_Parse_CharStrings: too many nested subrs\n" )); | |
1735 | goto Syntax_Error; | |
1736 | } | |
1737 | ||
1738 | zone->cursor = ip; /* save current instruction pointer */ | |
1739 | ||
1740 | zone++; | |
1741 | zone->base = decoder->globals[index]; | |
1742 | zone->limit = decoder->globals[index+1]; | |
1743 | zone->cursor = zone->base; | |
1744 | ||
1745 | if ( !zone->base ) | |
1746 | { | |
1747 | FT_ERROR(( "T2_Parse_CharStrings: invoking empty subrs!\n" )); | |
1748 | goto Syntax_Error; | |
1749 | } | |
1750 | ||
1751 | decoder->zone = zone; | |
1752 | ip = zone->base; | |
1753 | limit = zone->limit; | |
1754 | } | |
1755 | break; | |
1756 | ||
1757 | case t2_op_return: | |
1758 | FT_TRACE4(( " return" )); | |
1759 | ||
1760 | if ( decoder->zone <= decoder->zones ) | |
1761 | { | |
1762 | FT_ERROR(( "T2_Parse_CharStrings: unexpected return\n" )); | |
1763 | goto Syntax_Error; | |
1764 | } | |
1765 | ||
1766 | decoder->zone--; | |
1767 | zone = decoder->zone; | |
1768 | ip = zone->cursor; | |
1769 | limit = zone->limit; | |
1770 | break; | |
1771 | ||
1772 | default: | |
1773 | Unimplemented: | |
1774 | FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); | |
1775 | ||
1776 | if ( ip[-1] == 12 ) | |
1777 | FT_ERROR(( " %d", ip[0] )); | |
1778 | FT_ERROR(( "\n" )); | |
1779 | ||
1780 | return T2_Err_Unimplemented_Feature; | |
1781 | } | |
1782 | ||
1783 | decoder->top = args; | |
1784 | ||
1785 | } /* general operator processing */ | |
1786 | ||
1787 | } /* while ip < limit */ | |
1788 | ||
1789 | FT_TRACE4(( "..end..\n\n" )); | |
1790 | ||
1791 | return error; | |
1792 | ||
1793 | Syntax_Error: | |
1794 | FT_TRACE4(( "T2_Parse_CharStrings: syntax error!" )); | |
1795 | return T2_Err_Invalid_File_Format; | |
1796 | ||
1797 | Stack_Underflow: | |
1798 | FT_TRACE4(( "T2_Parse_CharStrings: stack underflow!" )); | |
1799 | return T2_Err_Too_Few_Arguments; | |
1800 | ||
1801 | Stack_Overflow: | |
1802 | FT_TRACE4(( "T2_Parse_CharStrings: stack overflow!" )); | |
1803 | return T2_Err_Stack_Overflow; | |
1804 | ||
1805 | Memory_Error: | |
1806 | return builder->error; | |
1807 | } | |
1808 | ||
1809 | ||
1810 | /*************************************************************************/ | |
1811 | /*************************************************************************/ | |
1812 | /*************************************************************************/ | |
1813 | /********** *********/ | |
1814 | /********** *********/ | |
1815 | /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ | |
1816 | /********** *********/ | |
1817 | /********** The following code is in charge of computing *********/ | |
1818 | /********** the maximum advance width of the font. It *********/ | |
1819 | /********** quickly processes each glyph charstring to *********/ | |
1820 | /********** extract the value from either a `sbw' or `seac' *********/ | |
1821 | /********** operator. *********/ | |
1822 | /********** *********/ | |
1823 | /*************************************************************************/ | |
1824 | /*************************************************************************/ | |
1825 | /*************************************************************************/ | |
1826 | ||
1827 | ||
1828 | #if 0 /* unused until we support pure CFF fonts */ | |
1829 | ||
1830 | ||
1831 | LOCAL_FUNC | |
1832 | FT_Error T2_Compute_Max_Advance( TT_Face face, | |
1833 | FT_Int* max_advance ) | |
1834 | { | |
1835 | FT_Error error = 0; | |
1836 | T2_Decoder decoder; | |
1837 | FT_Int glyph_index; | |
1838 | CFF_Font* cff = (CFF_Font*)face->other; | |
1839 | ||
1840 | ||
1841 | *max_advance = 0; | |
1842 | ||
1843 | /* Initialize load decoder */ | |
1844 | T2_Init_Decoder( &decoder, face, 0, 0 ); | |
1845 | ||
1846 | decoder.builder.metrics_only = 1; | |
1847 | decoder.builder.load_points = 0; | |
1848 | ||
1849 | /* For each glyph, parse the glyph charstring and extract */ | |
1850 | /* the advance width. */ | |
1851 | for ( glyph_index = 0; glyph_index < face->root.num_glyphs; | |
1852 | glyph_index++ ) | |
1853 | { | |
1854 | FT_Byte* charstring; | |
1855 | FT_ULong charstring_len; | |
1856 | ||
1857 | ||
1858 | /* now get load the unscaled outline */ | |
1859 | error = T2_Access_Element( &cff->charstrings_index, glyph_index, | |
1860 | &charstring, &charstring_len ); | |
1861 | if ( !error ) | |
1862 | { | |
1863 | T2_Prepare_Decoder( &decoder, glyph_index ); | |
1864 | error = T2_Parse_CharStrings( &decoder, charstring, charstring_len ); | |
1865 | ||
1866 | T2_Forget_Element( &cff->charstrings_index, &charstring ); | |
1867 | } | |
1868 | ||
1869 | /* ignore the error if one has occurred -- skip to next glyph */ | |
1870 | error = 0; | |
1871 | } | |
1872 | ||
1873 | *max_advance = decoder.builder.advance.x; | |
1874 | ||
1875 | return T2_Err_Ok; | |
1876 | } | |
1877 | ||
1878 | ||
1879 | #endif /* 0 */ | |
1880 | ||
1881 | ||
1882 | /*************************************************************************/ | |
1883 | /*************************************************************************/ | |
1884 | /*************************************************************************/ | |
1885 | /********** *********/ | |
1886 | /********** *********/ | |
1887 | /********** UNHINTED GLYPH LOADER *********/ | |
1888 | /********** *********/ | |
1889 | /********** The following code is in charge of loading a *********/ | |
1890 | /********** single outline. It completely ignores hinting *********/ | |
1891 | /********** and is used when FT_LOAD_NO_HINTING is set. *********/ | |
1892 | /********** *********/ | |
1893 | /*************************************************************************/ | |
1894 | /*************************************************************************/ | |
1895 | /*************************************************************************/ | |
1896 | ||
1897 | ||
1898 | LOCAL_FUNC | |
1899 | FT_Error T2_Load_Glyph( T2_GlyphSlot glyph, | |
1900 | T2_Size size, | |
1901 | FT_Int glyph_index, | |
1902 | FT_Int load_flags ) | |
1903 | { | |
1904 | FT_Error error; | |
1905 | T2_Decoder decoder; | |
1906 | TT_Face face = (TT_Face)glyph->root.face; | |
1907 | FT_Bool hinting; | |
1908 | CFF_Font* cff = (CFF_Font*)face->extra.data; | |
1909 | ||
1910 | ||
1911 | if ( load_flags & FT_LOAD_NO_RECURSE ) | |
1912 | load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; | |
1913 | ||
1914 | glyph->x_scale = 0x10000L; | |
1915 | glyph->y_scale = 0x10000L; | |
1916 | if ( size ) | |
1917 | { | |
1918 | glyph->x_scale = size->metrics.x_scale; | |
1919 | glyph->y_scale = size->metrics.y_scale; | |
1920 | } | |
1921 | ||
1922 | glyph->root.outline.n_points = 0; | |
1923 | glyph->root.outline.n_contours = 0; | |
1924 | ||
1925 | hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && | |
1926 | ( load_flags & FT_LOAD_NO_HINTING ) == 0; | |
1927 | ||
1928 | glyph->root.format = ft_glyph_format_outline; /* by default */ | |
1929 | ||
1930 | { | |
1931 | FT_Byte* charstring; | |
1932 | FT_ULong charstring_len; | |
1933 | ||
1934 | ||
1935 | T2_Init_Decoder( &decoder, face, size, glyph ); | |
1936 | ||
1937 | decoder.builder.no_recurse = | |
1938 | (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); | |
1939 | ||
1940 | /* now load the unscaled outline */ | |
1941 | error = T2_Access_Element( &cff->charstrings_index, glyph_index, | |
1942 | &charstring, &charstring_len ); | |
1943 | if ( !error ) | |
1944 | { | |
1945 | T2_Prepare_Decoder( &decoder, glyph_index ); | |
1946 | error = T2_Parse_CharStrings( &decoder, charstring, charstring_len ); | |
1947 | ||
1948 | T2_Forget_Element( &cff->charstrings_index, &charstring ); | |
1949 | } | |
1950 | ||
1951 | /* save new glyph tables */ | |
1952 | T2_Done_Builder( &decoder.builder ); | |
1953 | } | |
1954 | ||
1955 | /* Now, set the metrics -- this is rather simple, as */ | |
1956 | /* the left side bearing is the xMin, and the top side */ | |
1957 | /* bearing the yMax. */ | |
1958 | if ( !error ) | |
1959 | { | |
1960 | /* for composite glyphs, return only left side bearing and */ | |
1961 | /* advance width */ | |
1962 | if ( glyph->root.format == ft_glyph_format_composite ) | |
1963 | { | |
1964 | glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; | |
1965 | glyph->root.metrics.horiAdvance = decoder.glyph_width; | |
1966 | } | |
1967 | else | |
1968 | { | |
1969 | FT_BBox cbox; | |
1970 | FT_Glyph_Metrics* metrics = &glyph->root.metrics; | |
1971 | ||
1972 | ||
1973 | /* copy the _unscaled_ advance width */ | |
1974 | metrics->horiAdvance = decoder.glyph_width; | |
1975 | ||
1976 | /* make up vertical metrics */ | |
1977 | metrics->vertBearingX = 0; | |
1978 | metrics->vertBearingY = 0; | |
1979 | metrics->vertAdvance = 0; | |
1980 | ||
1981 | glyph->root.format = ft_glyph_format_outline; | |
1982 | ||
1983 | glyph->root.outline.flags = 0; | |
1984 | if ( size && size->metrics.y_ppem < 24 ) | |
1985 | glyph->root.outline.flags |= ft_outline_high_precision; | |
1986 | ||
1987 | glyph->root.outline.flags |= ft_outline_reverse_fill; | |
1988 | ||
1989 | if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
1990 | { | |
1991 | /* scale the outline and the metrics */ | |
1992 | FT_Int n; | |
1993 | FT_Outline* cur = &glyph->root.outline; | |
1994 | FT_Vector* vec = cur->points; | |
1995 | FT_Fixed x_scale = glyph->x_scale; | |
1996 | FT_Fixed y_scale = glyph->y_scale; | |
1997 | ||
1998 | ||
1999 | /* First of all, scale the points */ | |
2000 | for ( n = cur->n_points; n > 0; n--, vec++ ) | |
2001 | { | |
2002 | vec->x = FT_MulFix( vec->x, x_scale ); | |
2003 | vec->y = FT_MulFix( vec->y, y_scale ); | |
2004 | } | |
2005 | ||
2006 | FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); | |
2007 | ||
2008 | /* Then scale the metrics */ | |
2009 | metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); | |
2010 | metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); | |
2011 | ||
2012 | metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); | |
2013 | metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); | |
2014 | } | |
2015 | ||
2016 | #if 0 | |
2017 | /* apply the font matrix */ | |
2018 | FT_Outline_Transform( &glyph->root.outline, cff->font_matrix ); | |
2019 | #endif | |
2020 | ||
2021 | /* compute the other metrics */ | |
2022 | FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); | |
2023 | ||
2024 | /* grid fit the bounding box if necessary */ | |
2025 | if ( hinting ) | |
2026 | { | |
2027 | cbox.xMin &= -64; | |
2028 | cbox.yMin &= -64; | |
2029 | cbox.xMax = ( cbox.xMax + 63 ) & -64; | |
2030 | cbox.yMax = ( cbox.yMax + 63 ) & -64; | |
2031 | } | |
2032 | ||
2033 | metrics->width = cbox.xMax - cbox.xMin; | |
2034 | metrics->height = cbox.yMax - cbox.yMin; | |
2035 | ||
2036 | metrics->horiBearingX = cbox.xMin; | |
2037 | metrics->horiBearingY = cbox.yMax; | |
2038 | } | |
2039 | } | |
2040 | ||
2041 | return error; | |
2042 | } | |
2043 | ||
2044 | ||
2045 | /* END */ |