]> git.saurik.com Git - wxWidgets.git/blame - src/freetype/type1z/z1gload.c
fixed bug in determining the best listbox size
[wxWidgets.git] / src / freetype / type1z / z1gload.c
CommitLineData
cabec872
RR
1/***************************************************************************/
2/* */
3/* z1gload.c */
4/* */
5/* Experimental Type 1 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#ifdef FT_FLAT_COMPILE
20
21#include "z1gload.h"
22
23#else
24
25#include <type1z/z1gload.h>
26
27#endif
28
29
30#include <freetype/internal/ftdebug.h>
31#include <freetype/internal/ftstream.h>
32#include <freetype/ftoutln.h>
33
34#include <string.h> /* for strcmp() */
35
36
37 /*************************************************************************/
38 /* */
39 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
40 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
41 /* messages during execution. */
42 /* */
43#undef FT_COMPONENT
44#define FT_COMPONENT trace_z1gload
45
46
47 typedef enum Z1_Operator_
48 {
49 op_none = 0,
50 op_endchar,
51 op_hsbw,
52 op_seac,
53 op_sbw,
54 op_closepath,
55 op_hlineto,
56 op_hmoveto,
57 op_hvcurveto,
58 op_rlineto,
59 op_rmoveto,
60 op_rrcurveto,
61 op_vhcurveto,
62 op_vlineto,
63 op_vmoveto,
64 op_dotsection,
65 op_hstem,
66 op_hstem3,
67 op_vstem,
68 op_vstem3,
69 op_div,
70 op_callothersubr,
71 op_callsubr,
72 op_pop,
73 op_return,
74 op_setcurrentpoint,
75
76 op_max /* never remove this one */
77
78 } Z1_Operator;
79
80 static
81 const FT_Int t1_args_count[op_max] =
82 {
83 0, /* none */
84 0, /* endchar */
85 2, /* hsbw */
86 5, /* seac */
87 4, /* sbw */
88 0, /* closepath */
89 1, /* hlineto */
90 1, /* hmoveto */
91 4, /* hvcurveto */
92 2, /* rlineto */
93 2, /* rmoveto */
94 6, /* rrcurveto */
95 4, /* vhcurveto */
96 1, /* vlineto */
97 1, /* vmoveto */
98 0, /* dotsection */
99 2, /* hstem */
100 6, /* hstem3 */
101 2, /* vstem */
102 6, /* vstem3 */
103 2, /* div */
104 -1, /* callothersubr */
105 1, /* callsubr */
106 0, /* pop */
107 0, /* return */
108 2 /* setcurrentpoint */
109 };
110
111
112 /*************************************************************************/
113 /*************************************************************************/
114 /*************************************************************************/
115 /********** *********/
116 /********** *********/
117 /********** GENERIC CHARSTRING PARSING *********/
118 /********** *********/
119 /********** *********/
120 /*************************************************************************/
121 /*************************************************************************/
122 /*************************************************************************/
123
124
125 /*************************************************************************/
126 /* */
127 /* <Function> */
128 /* Z1_Init_Builder */
129 /* */
130 /* <Description> */
131 /* Initializes a given glyph builder. */
132 /* */
133 /* <InOut> */
134 /* builder :: A pointer to the glyph builder to initialize. */
135 /* */
136 /* <Input> */
137 /* face :: The current face object. */
138 /* */
139 /* size :: The current size object. */
140 /* */
141 /* glyph :: The current glyph object. */
142 /* */
143 LOCAL_FUNC
144 void Z1_Init_Builder( Z1_Builder* builder,
145 T1_Face face,
146 Z1_Size size,
147 Z1_GlyphSlot glyph )
148 {
149 builder->path_begun = 0;
150 builder->load_points = 1;
151
152 builder->face = face;
153 builder->glyph = glyph;
154 builder->memory = face->root.memory;
155
156 if ( glyph )
157 {
158 FT_GlyphLoader* loader = glyph->root.loader;
159
160
161 builder->loader = loader;
162 builder->current = &loader->current.outline;
163 builder->base = &loader->base.outline;
164
165 FT_GlyphLoader_Rewind( loader );
166 }
167
168 if ( size )
169 {
170 builder->scale_x = size->root.metrics.x_scale;
171 builder->scale_y = size->root.metrics.y_scale;
172 }
173
174 builder->pos_x = 0;
175 builder->pos_y = 0;
176
177 builder->left_bearing.x = 0;
178 builder->left_bearing.y = 0;
179 builder->advance.x = 0;
180 builder->advance.y = 0;
181 }
182
183
184 /*************************************************************************/
185 /* */
186 /* <Function> */
187 /* Z1_Done_Builder */
188 /* */
189 /* <Description> */
190 /* Finalizes a given glyph builder. Its contents can still be used */
191 /* after the call, but the function saves important information */
192 /* within the corresponding glyph slot. */
193 /* */
194 /* <Input> */
195 /* builder :: A pointer to the glyph builder to finalize. */
196 /* */
197 LOCAL_FUNC
198 void Z1_Done_Builder( Z1_Builder* builder )
199 {
200 Z1_GlyphSlot glyph = builder->glyph;
201
202
203 if ( glyph )
204 glyph->root.outline = *builder->base;
205 }
206
207
208 /*************************************************************************/
209 /* */
210 /* <Function> */
211 /* Z1_Init_Decoder */
212 /* */
213 /* <Description> */
214 /* Initializes a given glyph decoder. */
215 /* */
216 /* <InOut> */
217 /* decoder :: A pointer to the glyph builder to initialize. */
218 /* */
219 LOCAL_FUNC
220 void Z1_Init_Decoder( Z1_Decoder* decoder )
221 {
222 decoder->top = 0;
223 decoder->zone = 0;
224 decoder->flex_state = 0;
225 decoder->num_flex_vectors = 0;
226 decoder->blend = 0;
227
228 /* Clear loader */
229 MEM_Set( &decoder->builder, 0, sizeof ( decoder->builder ) );
230 }
231
232
233 /* check that there is enough space for `count' more points */
234 static
235 FT_Error check_points( Z1_Builder* builder,
236 FT_Int count )
237 {
238 return FT_GlyphLoader_Check_Points( builder->loader, count, 0 );
239 }
240
241
242 /* add a new point; do not check space */
243 static
244 void add_point( Z1_Builder* builder,
245 FT_Pos x,
246 FT_Pos y,
247 FT_Byte flag )
248 {
249 FT_Outline* outline = builder->current;
250
251
252 if ( builder->load_points )
253 {
254 FT_Vector* point = outline->points + outline->n_points;
255 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
256
257
258 point->x = x;
259 point->y = y;
260 *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic;
261
262 builder->last = *point;
263 }
264
265 outline->n_points++;
266 }
267
268
269 /* check space for a new on-curve point, then add it */
270 static
271 FT_Error add_point1( Z1_Builder* builder,
272 FT_Pos x,
273 FT_Pos y )
274 {
275 FT_Error error;
276
277
278 error = check_points( builder, 1 );
279 if ( !error )
280 add_point( builder, x, y, 1 );
281
282 return error;
283 }
284
285
286 /* check space for a new contour, then add it */
287 static
288 FT_Error add_contour( Z1_Builder* builder )
289 {
290 FT_Outline* outline = builder->current;
291 FT_Error error;
292
293
294 if ( !builder->load_points )
295 {
296 outline->n_contours++;
297 return FT_Err_Ok;
298 }
299
300 /* reallocate contours array if necessary */
301 error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 );
302 if ( !error )
303 {
304 if ( outline->n_contours > 0 )
305 outline->contours[outline->n_contours - 1] = outline->n_points - 1;
306
307 outline->n_contours++;
308 }
309
310 return error;
311 }
312
313
314 /* if a path was begun, add its first on-curve point */
315 static
316 FT_Error start_point( Z1_Builder* builder,
317 FT_Pos x,
318 FT_Pos y )
319 {
320 /* test whether we are building a new contour */
321 if ( !builder->path_begun )
322 {
323 FT_Error error;
324
325
326 builder->path_begun = 1;
327 error = add_contour( builder );
328 if ( error )
329 return error;
330 }
331 return add_point1( builder, x, y );
332 }
333
334
335 /* close the current contour */
336 static
337 void close_contour( Z1_Builder* builder )
338 {
339 FT_Outline* outline = builder->current;
340
341
342 /* XXX: we must not include the last point in the path if it */
343 /* is located on the first point */
344 if ( outline->n_points > 1 )
345 {
346 FT_Int first = 0;
347 FT_Vector* p1 = outline->points + first;
348 FT_Vector* p2 = outline->points + outline->n_points-1;
349
350
351 if ( outline->n_contours > 1 )
352 {
353 first = outline->contours[outline->n_contours - 2] + 1;
354 p1 = outline->points + first;
355 }
356
357 if ( p1->x == p2->x && p1->y == p2->y )
358 outline->n_points--;
359 }
360
361 if ( outline->n_contours > 0 )
362 outline->contours[outline->n_contours - 1] = outline->n_points - 1;
363 }
364
365
366 /*************************************************************************/
367 /* */
368 /* <Function> */
369 /* lookup_glyph_by_stdcharcode */
370 /* */
371 /* <Description> */
372 /* Looks up a given glyph by its StandardEncoding charcode. Used */
373 /* to implement the SEAC Type 1 operator. */
374 /* */
375 /* <Input> */
376 /* face :: The current face object. */
377 /* */
378 /* charcode :: The character code to look for. */
379 /* */
380 /* <Return> */
381 /* A glyph index in the font face. Returns -1 if the corresponding */
382 /* glyph wasn't found. */
383 /* */
384 static
385 FT_Int lookup_glyph_by_stdcharcode( T1_Face face,
386 FT_Int charcode )
387 {
388 FT_Int n;
389 const FT_String* glyph_name;
390 PSNames_Interface* psnames = (PSNames_Interface*)face->psnames;
391
392
393 /* check range of standard char code */
394 if ( charcode < 0 || charcode > 255 )
395 return -1;
396
397 glyph_name = psnames->adobe_std_strings(
398 psnames->adobe_std_encoding[charcode]);
399
400 for ( n = 0; n < face->type1.num_glyphs; n++ )
401 {
402 FT_String* name = (FT_String*)face->type1.glyph_names[n];
403
404
405 if ( name && strcmp( name,glyph_name ) == 0 )
406 return n;
407 }
408
409 return -1;
410 }
411
412
413 /*************************************************************************/
414 /* */
415 /* <Function> */
416 /* t1operator_seac */
417 /* */
418 /* <Description> */
419 /* Implements the `seac' Type 1 operator for a Type 1 decoder. */
420 /* */
421 /* <Input> */
422 /* decoder :: The current CID decoder. */
423 /* */
424 /* asb :: The accent's side bearing. */
425 /* */
426 /* adx :: The horizontal offset of the accent. */
427 /* */
428 /* ady :: The vertical offset of the accent. */
429 /* */
430 /* bchar :: The base character's StandardEncoding charcode. */
431 /* */
432 /* achar :: The accent character's StandardEncoding charcode. */
433 /* */
434 /* <Return> */
435 /* FreeType error code. 0 means success. */
436 /* */
437 static
438 FT_Error t1operator_seac( Z1_Decoder* decoder,
439 FT_Pos asb,
440 FT_Pos adx,
441 FT_Pos ady,
442 FT_Int bchar,
443 FT_Int achar )
444 {
445 FT_Error error;
446 FT_Int bchar_index, achar_index, n_base_points;
447 FT_Outline* base = decoder->builder.base;
448 FT_Vector left_bearing, advance;
449 T1_Face face = decoder->builder.face;
450 T1_Font* type1 = &face->type1;
451
452
453 bchar_index = lookup_glyph_by_stdcharcode( face, bchar );
454 achar_index = lookup_glyph_by_stdcharcode( face, achar );
455
456 if ( bchar_index < 0 || achar_index < 0 )
457 {
458 FT_ERROR(( "t1operator_seac:" ));
459 FT_ERROR(( " invalid seac character code arguments\n" ));
460 return T1_Err_Syntax_Error;
461 }
462
463 /* if we are trying to load a composite glyph, do not load the */
464 /* accent character and return the array of subglyphs. */
465 if ( decoder->builder.no_recurse )
466 {
467 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
468 FT_GlyphLoader* loader = glyph->loader;
469 FT_SubGlyph* subg;
470
471
472 /* reallocate subglyph array if necessary */
473 error = FT_GlyphLoader_Check_Subglyphs( loader, 2 );
474 if ( error )
475 goto Exit;
476
477 subg = loader->current.subglyphs;
478
479 /* subglyph 0 = base character */
480 subg->index = bchar_index;
481 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
482 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
483 subg->arg1 = 0;
484 subg->arg2 = 0;
485 subg++;
486
487 /* subglyph 1 = accent character */
488 subg->index = achar_index;
489 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
490 subg->arg1 = adx - asb;
491 subg->arg2 = ady;
492
493 /* set up remaining glyph fields */
494 glyph->num_subglyphs = 2;
495 glyph->subglyphs = loader->base.subglyphs;
496 glyph->format = ft_glyph_format_composite;
497
498 loader->current.num_subglyphs = 2;
499 }
500
501 /* First load `bchar' in builder */
502 /* now load the unscaled outline */
503
504 FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */
505
506 error = Z1_Parse_CharStrings( decoder,
507 type1->charstrings [bchar_index],
508 type1->charstrings_len[bchar_index],
509 type1->num_subrs,
510 type1->subrs,
511 type1->subrs_len );
512 if ( error )
513 goto Exit;
514
515 n_base_points = base->n_points;
516
517 /* save the left bearing and width of the base character */
518 /* as they will be erased by the next load. */
519
520 left_bearing = decoder->builder.left_bearing;
521 advance = decoder->builder.advance;
522
523 decoder->builder.left_bearing.x = 0;
524 decoder->builder.left_bearing.y = 0;
525
526 /* Now load `achar' on top of */
527 /* the base outline */
528 error = Z1_Parse_CharStrings( decoder,
529 type1->charstrings [achar_index],
530 type1->charstrings_len[achar_index],
531 type1->num_subrs,
532 type1->subrs,
533 type1->subrs_len );
534 if ( error )
535 return error;
536
537 /* restore the left side bearing and */
538 /* advance width of the base character */
539
540 decoder->builder.left_bearing = left_bearing;
541 decoder->builder.advance = advance;
542
543 /* Finally, move the accent */
544 if ( decoder->builder.load_points )
545 {
546 FT_Outline dummy;
547
548
549 dummy.n_points = base->n_points - n_base_points;
550 dummy.points = base->points + n_base_points;
551 FT_Outline_Translate( &dummy, adx - asb, ady );
552 }
553
554 Exit:
555 return error;
556 }
557
558
559#define USE_ARGS( n ) do \
560 { \
561 top -= n; \
562 if ( top < decoder->stack ) \
563 goto Stack_Underflow; \
564 } while ( 0 )
565
566
567 /*************************************************************************/
568 /* */
569 /* <Function> */
570 /* Z1_Parse_CharStrings */
571 /* */
572 /* <Description> */
573 /* Parses a given Type 1 charstrings program. */
574 /* */
575 /* <Input> */
576 /* decoder :: The current Type 1 decoder. */
577 /* */
578 /* charstring_base :: The base address of the charstring stream. */
579 /* */
580 /* charstring_len :: The length in bytes of the charstring stream. */
581 /* */
582 /* num_subrs :: The number of sub-routines. */
583 /* */
584 /* subrs_base :: An array of sub-routines addresses. */
585 /* */
586 /* subrs_len :: An array of sub-routines lengths. */
587 /* */
588 /* <Return> */
589 /* Free error code. 0 means success. */
590 /* */
591 LOCAL_FUNC
592 FT_Error Z1_Parse_CharStrings( Z1_Decoder* decoder,
593 FT_Byte* charstring_base,
594 FT_Int charstring_len,
595 FT_Int num_subrs,
596 FT_Byte** subrs_base,
597 FT_Int* subrs_len )
598 {
599 FT_Error error;
600 Z1_Decoder_Zone* zone;
601 FT_Byte* ip;
602 FT_Byte* limit;
603 Z1_Builder* builder = &decoder->builder;
604 FT_Outline* outline;
605 FT_Pos x, y;
606
607
608 /* First of all, initialize the decoder */
609 decoder->top = decoder->stack;
610 decoder->zone = decoder->zones;
611 zone = decoder->zones;
612
613 builder->path_begun = 0;
614
615 zone->base = charstring_base;
616 limit = zone->limit = charstring_base + charstring_len;
617 ip = zone->cursor = zone->base;
618
619 error = T1_Err_Ok;
620 outline = builder->current;
621
622 x = builder->pos_x;
623 y = builder->pos_y;
624
625 /* now, execute loop */
626 while ( ip < limit )
627 {
628 FT_Int* top = decoder->top;
629 Z1_Operator op = op_none;
630 FT_Long value = 0;
631
632
633 /*********************************************************************/
634 /* */
635 /* Decode operator or operand */
636 /* */
637 /* */
638
639 /* first of all, decompress operator or value */
640 switch ( *ip++ )
641 {
642 case 1:
643 op = op_hstem;
644 break;
645
646 case 3:
647 op = op_vstem;
648 break;
649 case 4:
650 op = op_vmoveto;
651 break;
652 case 5:
653 op = op_rlineto;
654 break;
655 case 6:
656 op = op_hlineto;
657 break;
658 case 7:
659 op = op_vlineto;
660 break;
661 case 8:
662 op = op_rrcurveto;
663 break;
664 case 9:
665 op = op_closepath;
666 break;
667 case 10:
668 op = op_callsubr;
669 break;
670 case 11:
671 op = op_return;
672 break;
673
674 case 13:
675 op = op_hsbw;
676 break;
677 case 14:
678 op = op_endchar;
679 break;
680
681 case 21:
682 op = op_rmoveto;
683 break;
684 case 22:
685 op = op_hmoveto;
686 break;
687
688 case 30:
689 op = op_vhcurveto;
690 break;
691 case 31:
692 op = op_hvcurveto;
693 break;
694
695 case 12:
696 if ( ip > limit )
697 {
698 FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+EOF)\n" ));
699 goto Syntax_Error;
700 }
701
702 switch ( *ip++ )
703 {
704 case 0:
705 op = op_dotsection;
706 break;
707 case 1:
708 op = op_vstem3;
709 break;
710 case 2:
711 op = op_hstem3;
712 break;
713 case 6:
714 op = op_seac;
715 break;
716 case 7:
717 op = op_sbw;
718 break;
719 case 12:
720 op = op_div;
721 break;
722 case 16:
723 op = op_callothersubr;
724 break;
725 case 17:
726 op = op_pop;
727 break;
728 case 33:
729 op = op_setcurrentpoint;
730 break;
731
732 default:
733 FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n",
734 ip[-1] ));
735 goto Syntax_Error;
736 }
737 break;
738
739 case 255: /* four bytes integer */
740 if ( ip + 4 > limit )
741 {
742 FT_ERROR(( "Z1_Parse_CharStrings: unexpected EOF in integer\n" ));
743 goto Syntax_Error;
744 }
745
746 value = ( (FT_Long)ip[0] << 24 ) |
747 ( (FT_Long)ip[1] << 16 ) |
748 ( (FT_Long)ip[2] << 8 ) |
749 ip[3];
750 ip += 4;
751 break;
752
753 default:
754 if ( ip[-1] >= 32 )
755 {
756 if ( ip[-1] < 247 )
757 value = (FT_Long)ip[-1] - 139;
758 else
759 {
760 if ( ++ip > limit )
761 {
762 FT_ERROR(( "Z1_Parse_CharStrings:" ));
763 FT_ERROR(( " unexpected EOF in integer\n" ));
764 goto Syntax_Error;
765 }
766
767 if ( ip[-2] < 251 )
768 value = ( (FT_Long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108;
769 else
770 value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 );
771 }
772 }
773 else
774 {
775 FT_ERROR(( "Z1_Parse_CharStrings: invalid byte (%d)\n",
776 ip[-1] ));
777 goto Syntax_Error;
778 }
779 }
780
781 /*********************************************************************/
782 /* */
783 /* Push value on stack, or process operator */
784 /* */
785 /* */
786 if ( op == op_none )
787 {
788 if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
789 {
790 FT_ERROR(( "Z1_Parse_CharStrings: stack overflow!\n" ));
791 goto Syntax_Error;
792 }
793
794 FT_TRACE4(( " %ld", value ));
795
796 *top++ = value;
797 decoder->top = top;
798 }
799 else if ( op == op_callothersubr ) /* callothersubr */
800 {
801 FT_TRACE4(( " callothersubr" ));
802
803 if ( top - decoder->stack < 2 )
804 goto Stack_Underflow;
805
806 top -= 2;
807 switch ( top[1] )
808 {
809 case 1: /* start flex feature */
810 if ( top[0] != 0 )
811 goto Unexpected_OtherSubr;
812
813 decoder->flex_state = 1;
814 decoder->num_flex_vectors = 0;
815 if ( start_point( builder, x, y ) ||
816 check_points( builder, 6 ) )
817 goto Memory_Error;
818 break;
819
820 case 2: /* add flex vectors */
821 {
822 FT_Int index;
823
824 if ( top[0] != 0 )
825 goto Unexpected_OtherSubr;
826
827 /* note that we should not add a point for index 0; */
828 /* this will move our current position to the flex */
829 /* point without adding any point to the outline */
830 index = decoder->num_flex_vectors++;
831 if ( index > 0 && index < 7 )
832 add_point( builder,
833 x,
834 y,
835 (FT_Byte)( index == 3 || index == 6 ) );
836 }
837 break;
838
839 case 0: /* end flex feature */
840 if ( top[0] != 3 )
841 goto Unexpected_OtherSubr;
842
843 if ( decoder->flex_state == 0 ||
844 decoder->num_flex_vectors != 7 )
845 {
846 FT_ERROR(( "Z1_Parse_CharStrings: unexpected flex end\n" ));
847 goto Syntax_Error;
848 }
849
850 /* now consume the remaining `pop pop setcurpoint' */
851 if ( ip + 6 > limit ||
852 ip[0] != 12 || ip[1] != 17 || /* pop */
853 ip[2] != 12 || ip[3] != 17 || /* pop */
854 ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */
855 {
856 FT_ERROR(( "Z1_Parse_CharStrings: invalid flex charstring\n" ));
857 goto Syntax_Error;
858 }
859
860 ip += 6;
861 decoder->flex_state = 0;
862 break;
863
864 case 3: /* change hints */
865 if ( top[0] != 1 )
866 goto Unexpected_OtherSubr;
867
868 /* eat the following `pop' */
869 if ( ip + 2 > limit )
870 {
871 FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n",
872 ip[-1] ));
873 goto Syntax_Error;
874 }
875
876 if ( ip[0] != 12 || ip[1] != 17 )
877 {
878 FT_ERROR(( "Z1_Parse_CharStrings:" ));
879 FT_ERROR(( " `pop' expected, found (%d %d)\n",
880 ip[0], ip[1] ));
881 goto Syntax_Error;
882 }
883 ip += 2;
884 break;
885
886 case 12:
887 case 13:
888 /* counter control hints, clear stack */
889 top = decoder->stack;
890 break;
891
892 case 14:
893 case 15:
894 case 16:
895 case 17:
896 case 18: /* multiple masters */
897 {
898 T1_Blend* blend = decoder->blend;
899 FT_UInt num_points, nn, mm;
900 FT_Int* delta;
901 FT_Int* values;
902
903
904 if ( !blend )
905 {
906 FT_ERROR(( "Z1_Parse_CharStrings:" ));
907 FT_ERROR(( " unexpected multiple masters operator!\n" ));
908 goto Syntax_Error;
909 }
910
911 num_points = top[1] - 13 + ( top[1] == 18 );
912 if ( top[0] != (FT_Int)( num_points * blend->num_designs ) )
913 {
914 FT_ERROR(( "Z1_Parse_CharStrings:" ));
915 FT_ERROR(( " incorrect number of mm arguments\n" ));
916 goto Syntax_Error;
917 }
918
919 top -= blend->num_designs*num_points;
920 if ( top < decoder->stack )
921 goto Stack_Underflow;
922
923 /* we want to compute: */
924 /* */
925 /* a0*w0 + a1*w1 + ... + ak*wk */
926 /* */
927 /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */
928 /* however, given that w0 + w1 + ... + wk == 1, we can */
929 /* rewrite it easily as: */
930 /* */
931 /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */
932 /* */
933 /* where k == num_designs-1 */
934 /* */
935 /* I guess that's why it's written in this `compact' */
936 /* form. */
937 /* */
938 delta = top + num_points;
939 values = top;
940 for ( nn = 0; nn < num_points; nn++ )
941 {
942 FT_Int x = values[0];
943
944
945 for ( mm = 1; mm < blend->num_designs; mm++ )
946 x += FT_MulFix( *delta++, blend->weight_vector[mm] );
947
948 *values++ = x;
949 }
950 /* note that `top' will be incremented later by calls to `pop' */
951 break;
952 }
953
954 default:
955 Unexpected_OtherSubr:
956 FT_ERROR(( "Z1_Parse_CharStrings: invalid othersubr [%d %d]!\n",
957 top[0], top[1] ));
958 goto Syntax_Error;
959 }
960 decoder->top = top;
961 }
962 else /* general operator */
963 {
964 FT_Int num_args = t1_args_count[op];
965
966
967 if ( top - decoder->stack < num_args )
968 goto Stack_Underflow;
969
970 top -= num_args;
971
972 switch ( op )
973 {
974 case op_endchar:
975 FT_TRACE4(( " endchar" ));
976
977 close_contour( builder );
978
979 /* add current outline to the glyph slot */
980 FT_GlyphLoader_Add( builder->loader );
981
982 /* return now! */
983 FT_TRACE4(( "\n\n" ));
984 return T1_Err_Ok;
985
986 case op_hsbw:
987 FT_TRACE4(( " hsbw" ));
988
989 builder->left_bearing.x += top[0];
990 builder->advance.x = top[1];
991 builder->advance.y = 0;
992
993 builder->last.x = x = top[0];
994 builder->last.y = y = 0;
995
996 /* the `metrics_only' indicates that we only want to compute */
997 /* the glyph's metrics (lsb + advance width), not load the */
998 /* rest of it; so exit immediately */
999 if ( builder->metrics_only )
1000 return T1_Err_Ok;
1001
1002 break;
1003
1004 case op_seac:
1005 /* return immediately after the processing */
1006 return t1operator_seac( decoder, top[0], top[1],
1007 top[2], top[3], top[4] );
1008
1009 case op_sbw:
1010 FT_TRACE4(( " sbw" ));
1011
1012 builder->left_bearing.x += top[0];
1013 builder->left_bearing.y += top[1];
1014 builder->advance.x = top[2];
1015 builder->advance.y = top[3];
1016
1017 builder->last.x = x = top[0];
1018 builder->last.y = y = top[1];
1019
1020 /* the `metrics_only' indicates that we only want to compute */
1021 /* the glyph's metrics (lsb + advance width), not load the */
1022 /* rest of it; so exit immediately */
1023 if ( builder->metrics_only )
1024 return T1_Err_Ok;
1025
1026 break;
1027
1028 case op_closepath:
1029 FT_TRACE4(( " closepath" ));
1030
1031 close_contour( builder );
1032 builder->path_begun = 0;
1033 break;
1034
1035 case op_hlineto:
1036 FT_TRACE4(( " hlineto" ));
1037
1038 if ( start_point( builder, x, y ) )
1039 goto Memory_Error;
1040
1041 x += top[0];
1042 goto Add_Line;
1043
1044 case op_hmoveto:
1045 FT_TRACE4(( " hmoveto" ));
1046
1047 x += top[0];
1048 break;
1049
1050 case op_hvcurveto:
1051 FT_TRACE4(( " hvcurveto" ));
1052
1053 if ( start_point( builder, x, y ) ||
1054 check_points( builder, 3 ) )
1055 goto Memory_Error;
1056
1057 x += top[0];
1058 add_point( builder, x, y, 0 );
1059 x += top[1];
1060 y += top[2];
1061 add_point( builder, x, y, 0 );
1062 y += top[3];
1063 add_point( builder, x, y, 1 );
1064 break;
1065
1066 case op_rlineto:
1067 FT_TRACE4(( " rlineto" ));
1068
1069 if ( start_point( builder, x, y ) )
1070 goto Memory_Error;
1071
1072 x += top[0];
1073 y += top[1];
1074
1075 Add_Line:
1076 if ( add_point1( builder, x, y ) )
1077 goto Memory_Error;
1078 break;
1079
1080 case op_rmoveto:
1081 FT_TRACE4(( " rmoveto" ));
1082
1083 x += top[0];
1084 y += top[1];
1085 break;
1086
1087 case op_rrcurveto:
1088 FT_TRACE4(( " rcurveto" ));
1089
1090 if ( start_point( builder, x, y ) ||
1091 check_points( builder, 3 ) )
1092 goto Memory_Error;
1093
1094 x += top[0];
1095 y += top[1];
1096 add_point( builder, x, y, 0 );
1097
1098 x += top[2];
1099 y += top[3];
1100 add_point( builder, x, y, 0 );
1101
1102 x += top[4];
1103 y += top[5];
1104 add_point( builder, x, y, 1 );
1105 break;
1106
1107 case op_vhcurveto:
1108 FT_TRACE4(( " vhcurveto" ));
1109
1110 if ( start_point( builder, x, y ) ||
1111 check_points( builder, 3 ) )
1112 goto Memory_Error;
1113
1114 y += top[0];
1115 add_point( builder, x, y, 0 );
1116 x += top[1];
1117 y += top[2];
1118 add_point( builder, x, y, 0 );
1119 x += top[3];
1120 add_point( builder, x, y, 1 );
1121 break;
1122
1123 case op_vlineto:
1124 FT_TRACE4(( " vlineto" ));
1125
1126 if ( start_point( builder, x, y ) )
1127 goto Memory_Error;
1128
1129 y += top[0];
1130 goto Add_Line;
1131
1132 case op_vmoveto:
1133 FT_TRACE4(( " vmoveto" ));
1134
1135 y += top[0];
1136 break;
1137
1138 case op_div:
1139 FT_TRACE4(( " div" ));
1140
1141 if ( top[1] )
1142 {
1143 *top = top[0] / top[1];
1144 ++top;
1145 }
1146 else
1147 {
1148 FT_ERROR(( "Z1_Parse_CharStrings: division by 0\n" ));
1149 goto Syntax_Error;
1150 }
1151 break;
1152
1153 case op_callsubr:
1154 {
1155 FT_Int index;
1156
1157
1158 FT_TRACE4(( " callsubr" ));
1159
1160 index = top[0];
1161 if ( index < 0 || index >= num_subrs )
1162 {
1163 FT_ERROR(( "Z1_Parse_CharStrings: invalid subrs index\n" ));
1164 goto Syntax_Error;
1165 }
1166
1167 if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
1168 {
1169 FT_ERROR(( "Z1_Parse_CharStrings: too many nested subrs\n" ));
1170 goto Syntax_Error;
1171 }
1172
1173 zone->cursor = ip; /* save current instruction pointer */
1174
1175 zone++;
1176 zone->base = subrs_base[index];
1177 zone->limit = zone->base + subrs_len[index];
1178 zone->cursor = zone->base;
1179
1180 if ( !zone->base )
1181 {
1182 FT_ERROR(( "Z1_Parse_CharStrings: invoking empty subrs!\n" ));
1183 goto Syntax_Error;
1184 }
1185
1186 decoder->zone = zone;
1187 ip = zone->base;
1188 limit = zone->limit;
1189 break;
1190 }
1191
1192 case op_pop:
1193 FT_TRACE4(( " pop" ));
1194
1195 /* theorically, the arguments are already on the stack */
1196 top++;
1197 break;
1198
1199 case op_return:
1200 FT_TRACE4(( " return" ));
1201
1202 if ( zone <= decoder->zones )
1203 {
1204 FT_ERROR(( "Z1_Parse_CharStrings: unexpected return\n" ));
1205 goto Syntax_Error;
1206 }
1207
1208 zone--;
1209 ip = zone->cursor;
1210 limit = zone->limit;
1211 decoder->zone = zone;
1212 break;
1213
1214 case op_dotsection:
1215 FT_TRACE4(( " dotsection" ));
1216
1217 break;
1218
1219 case op_hstem:
1220 FT_TRACE4(( " hstem" ));
1221
1222 break;
1223
1224 case op_hstem3:
1225 FT_TRACE4(( " hstem3" ));
1226
1227 break;
1228
1229 case op_vstem:
1230 FT_TRACE4(( " vstem" ));
1231
1232 break;
1233
1234 case op_vstem3:
1235 FT_TRACE4(( " vstem3" ));
1236
1237 break;
1238
1239 case op_setcurrentpoint:
1240 FT_TRACE4(( " setcurrentpoint" ));
1241
1242 FT_ERROR(( "Z1_Parse_CharStrings:" ));
1243 FT_ERROR(( " unexpected `setcurrentpoint'\n" ));
1244 goto Syntax_Error;
1245
1246 default:
1247 FT_ERROR(( "Z1_Parse_CharStrings: unhandled opcode %d\n", op ));
1248 goto Syntax_Error;
1249 }
1250
1251 decoder->top = top;
1252
1253 } /* general operator processing */
1254
1255 } /* while ip < limit */
1256
1257 FT_TRACE4(( "..end..\n\n" ));
1258 return error;
1259
1260 Syntax_Error:
1261 return T1_Err_Syntax_Error;
1262
1263 Stack_Underflow:
1264 return T1_Err_Stack_Underflow;
1265
1266 Memory_Error:
1267 return builder->error;
1268 }
1269
1270
1271 /*************************************************************************/
1272 /*************************************************************************/
1273 /*************************************************************************/
1274 /********** *********/
1275 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
1276 /********** *********/
1277 /********** The following code is in charge of computing *********/
1278 /********** the maximum advance width of the font. It *********/
1279 /********** quickly processes each glyph charstring to *********/
1280 /********** extract the value from either a `sbw' or `seac' *********/
1281 /********** operator. *********/
1282 /********** *********/
1283 /*************************************************************************/
1284 /*************************************************************************/
1285 /*************************************************************************/
1286
1287
1288 LOCAL_FUNC
1289 FT_Error Z1_Compute_Max_Advance( T1_Face face,
1290 FT_Int* max_advance )
1291 {
1292 FT_Error error;
1293 Z1_Decoder decoder;
1294 FT_Int glyph_index;
1295 T1_Font* type1 = &face->type1;
1296
1297
1298 *max_advance = 0;
1299
1300 /* Initialize load decoder */
1301 Z1_Init_Decoder( &decoder );
1302 Z1_Init_Builder( &decoder.builder, face, 0, 0 );
1303
1304 decoder.blend = face->blend;
1305 decoder.builder.metrics_only = 1;
1306 decoder.builder.load_points = 0;
1307
1308 /* for each glyph, parse the glyph charstring and extract */
1309 /* the advance width */
1310 for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
1311 {
1312 /* now get load the unscaled outline */
1313 error = Z1_Parse_CharStrings( &decoder,
1314 type1->charstrings [glyph_index],
1315 type1->charstrings_len[glyph_index],
1316 type1->num_subrs,
1317 type1->subrs,
1318 type1->subrs_len );
1319 /* ignore the error if one occured - skip to next glyph */
1320 }
1321
1322 *max_advance = decoder.builder.advance.x;
1323 return T1_Err_Ok;
1324 }
1325
1326
1327 /*************************************************************************/
1328 /*************************************************************************/
1329 /*************************************************************************/
1330 /********** *********/
1331 /********** UNHINTED GLYPH LOADER *********/
1332 /********** *********/
1333 /********** The following code is in charge of loading a *********/
1334 /********** single outline. It completely ignores hinting *********/
1335 /********** and is used when FT_LOAD_NO_HINTING is set. *********/
1336 /********** *********/
1337 /********** The Type 1 hinter is located in `t1hint.c' *********/
1338 /********** *********/
1339 /*************************************************************************/
1340 /*************************************************************************/
1341 /*************************************************************************/
1342
1343
1344 LOCAL_FUNC
1345 FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph,
1346 Z1_Size size,
1347 FT_Int glyph_index,
1348 FT_Int load_flags )
1349 {
1350 FT_Error error;
1351 Z1_Decoder decoder;
1352 T1_Face face = (T1_Face)glyph->root.face;
1353 FT_Bool hinting;
1354 T1_Font* type1 = &face->type1;
1355
1356
1357 if ( load_flags & FT_LOAD_NO_RECURSE )
1358 load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
1359
1360 glyph->x_scale = size->root.metrics.x_scale;
1361 glyph->y_scale = size->root.metrics.y_scale;
1362
1363 glyph->root.outline.n_points = 0;
1364 glyph->root.outline.n_contours = 0;
1365
1366 hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
1367 ( load_flags & FT_LOAD_NO_HINTING ) == 0;
1368
1369 glyph->root.format = ft_glyph_format_outline;
1370
1371 Z1_Init_Decoder( &decoder );
1372 Z1_Init_Builder( &decoder.builder, face, size, glyph );
1373
1374 decoder.blend = ((T1_Face)glyph->root.face)->blend;
1375 decoder.builder.no_recurse = ( load_flags & FT_LOAD_NO_RECURSE ) != 0;
1376
1377 /* now load the unscaled outline */
1378 error = Z1_Parse_CharStrings( &decoder,
1379 type1->charstrings [glyph_index],
1380 type1->charstrings_len[glyph_index],
1381 type1->num_subrs,
1382 type1->subrs,
1383 type1->subrs_len );
1384
1385 /* save new glyph tables */
1386 Z1_Done_Builder( &decoder.builder );
1387
1388 /* now, set the metrics -- this is rather simple, as */
1389 /* the left side bearing is the xMin, and the top side */
1390 /* bearing the yMax */
1391 if ( !error )
1392 {
1393 glyph->root.outline.flags &= ft_outline_owner;
1394 glyph->root.outline.flags |= ft_outline_reverse_fill;
1395
1396 /* for composite glyphs, return only left side bearing and */
1397 /* advance width */
1398 if ( load_flags & FT_LOAD_NO_RECURSE )
1399 {
1400 glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
1401 glyph->root.metrics.horiAdvance = decoder.builder.advance.x;
1402 }
1403 else
1404 {
1405 FT_BBox cbox;
1406 FT_Glyph_Metrics* metrics = &glyph->root.metrics;
1407
1408
1409 /* copy the _unscaled_ advance width */
1410 metrics->horiAdvance = decoder.builder.advance.x;
1411
1412 /* make up vertical metrics */
1413 metrics->vertBearingX = 0;
1414 metrics->vertBearingY = 0;
1415 metrics->vertAdvance = 0;
1416
1417 glyph->root.format = ft_glyph_format_outline;
1418
1419 if ( size && size->root.metrics.y_ppem < 24 )
1420 glyph->root.outline.flags |= ft_outline_high_precision;
1421
1422#if 0
1423 glyph->root.outline.second_pass = TRUE;
1424 glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24;
1425 glyph->root.outline.dropout_mode = 2;
1426#endif /* 0 */
1427
1428 if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
1429 {
1430 /* scale the outline and the metrics */
1431 FT_Int n;
1432 FT_Outline* cur = decoder.builder.base;
1433 FT_Vector* vec = cur->points;
1434 FT_Fixed x_scale = glyph->x_scale;
1435 FT_Fixed y_scale = glyph->y_scale;
1436
1437
1438 /* First of all, scale the points */
1439 for ( n = cur->n_points; n > 0; n--, vec++ )
1440 {
1441 vec->x = FT_MulFix( vec->x, x_scale );
1442 vec->y = FT_MulFix( vec->y, y_scale );
1443 }
1444
1445 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
1446
1447 /* Then scale the metrics */
1448 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
1449 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
1450
1451 metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
1452 metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
1453 }
1454
1455 /* apply the font matrix */
1456 FT_Outline_Transform( &glyph->root.outline,
1457 &face->type1.font_matrix );
1458
1459 /* compute the other metrics */
1460 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
1461
1462 /* grid fit the bounding box if necessary */
1463 if ( hinting )
1464 {
1465 cbox.xMin &= -64;
1466 cbox.yMin &= -64;
1467 cbox.xMax = ( cbox.xMax+63 ) & -64;
1468 cbox.yMax = ( cbox.yMax+63 ) & -64;
1469 }
1470
1471 metrics->width = cbox.xMax - cbox.xMin;
1472 metrics->height = cbox.yMax - cbox.yMin;
1473
1474 metrics->horiBearingX = cbox.xMin;
1475 metrics->horiBearingY = cbox.yMax;
1476 }
1477 }
1478 return error;
1479 }
1480
1481
1482/* END */