]> git.saurik.com Git - wxWidgets.git/blame - src/freetype/cff/t2gload.c
added common regex
[wxWidgets.git] / src / freetype / cff / t2gload.c
CommitLineData
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 */