Commit 1a380e02d1668d559a073d75200e3866d37b8e4d

Werner Lemberg 2006-07-14T18:28:08

* freetype2/include/freetype/internal/psaux.h: New macros IS_PS_NEWLINE, IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, IS_PS_XDIGIT, and IS_PS_BASE85 (from freetype2/src/psaux/psconv.h). (T1_FieldLocation): Add T1_FIELD_LOCATION_LOADER, T1_FIELD_LOCATION_FACE, and T1_FIELD_LOCATION_BLEND. (T1_DecoderRec): New fields `buildchar' and `face'. (IS_PS_TOKEN): New macro. * freetype2/include/freetype/internal/t1types.h (T1_FaceRec): New fields `ndv_idx', `cdv_idx', and `len_buildchar'. * freetype2/include/freetype/t1tables.h (PS_BlendRec): New fields `default_design_vector' and `num_default_design_vector'. * freetype2/src/psaux/psconv.h: Move macros IS_PS_NEWLINE, IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, IS_PS_XDIGIT, and IS_PS_BASE85 to freetype2/include/freetype/internal/psaux.h. * freetype2/src/psaux/psobjs.c (ps_parser_to_token_array): Allow `token' argument to be NULL if we want only to count the number of tokens. (ps_tocoordarray): Allow `coords' argument to be NULL if we just want to skip the array. (ps_tofixedarray): Allow `values' argument to be NULL if we just want to skip the array. * freetype2/src/psaux/t1decode.c (t1_decoder_parse_charstrings): Add support for (partially commented out) othersubrs 19-25, 27, and 28. (t1_decoder_init): Initialize new fields `face' and `buildchar'. (t1_decoder_done): Release new field `buildchar'. * freetype2/src/type1/t1load.c (parse_buildchar, parse_private): New functions. (t1_keywords): Register them. (t1_allocate_blend): Updated. (t1_load_keyword): Handle field types T1_FIELD_LOCATION_LOADER, T1_FIELD_LOCATION_FACE and T1_FIELD_LOCATION_BLEND. (parse_dict): Remove `keyword_flags' argument. Use new macro IS_PS_TOKEN. Changed function so that later PostScript definitions override earlier ones. (t1_init_loader): Initialize new field `keywords_encountered'. (T1_Open_Face): Initialize new fields `ndv_idx', `cdv_idx', and `len_buildchar'. Remove `keywords_flags'. * freetype2/src/type1/t1load.h (T1_LoaderRect): New field `keywords_encountered'. (T1_PRIVATE, T1_FONTDIR_AFTER_PRIVATE): New macros. * freetype2/src/type1/t1tokens.h [!T1_CONFIG_OPTION_NO_MM_SUPPORT]: New entries for parsing /NDV, /CDV, and /DesignVector.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
diff --git a/ChangeLog b/ChangeLog
index 3e278f4..07a39f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+2006-07-14  Jens Claudius  <jens.claudius@yahoo.com>
+
+	* freetype2/include/freetype/internal/psaux.h: New macros
+	IS_PS_NEWLINE, IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT,
+	IS_PS_XDIGIT, and IS_PS_BASE85 (from freetype2/src/psaux/psconv.h).
+	(T1_FieldLocation): Add T1_FIELD_LOCATION_LOADER,
+	T1_FIELD_LOCATION_FACE, and T1_FIELD_LOCATION_BLEND.
+	(T1_DecoderRec): New fields `buildchar' and `face'.
+	(IS_PS_TOKEN): New macro.
+
+	* freetype2/include/freetype/internal/t1types.h (T1_FaceRec): New
+	fields `ndv_idx', `cdv_idx', and `len_buildchar'.
+
+	* freetype2/include/freetype/t1tables.h (PS_BlendRec): New fields
+	`default_design_vector' and `num_default_design_vector'.
+
+	* freetype2/src/psaux/psconv.h: Move macros IS_PS_NEWLINE,
+	IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, IS_PS_XDIGIT,
+	and IS_PS_BASE85 to freetype2/include/freetype/internal/psaux.h.
+
+	* freetype2/src/psaux/psobjs.c (ps_parser_to_token_array): Allow
+	`token' argument to be NULL if we want only to count the number of
+	tokens.
+	(ps_tocoordarray): Allow `coords' argument to be NULL if we just
+	want to skip the array.
+	(ps_tofixedarray): Allow `values' argument to be NULL if we just
+	want to skip the array.
+
+	* freetype2/src/psaux/t1decode.c (t1_decoder_parse_charstrings): Add
+	support for (partially commented out) othersubrs 19-25, 27, and 28.
+	(t1_decoder_init): Initialize new fields `face' and `buildchar'.
+	(t1_decoder_done): Release new field `buildchar'.
+
+	* freetype2/src/type1/t1load.c (parse_buildchar, parse_private): New
+	functions.
+	(t1_keywords): Register them.
+	(t1_allocate_blend): Updated.
+	(t1_load_keyword): Handle field types T1_FIELD_LOCATION_LOADER,
+	T1_FIELD_LOCATION_FACE and T1_FIELD_LOCATION_BLEND.
+	(parse_dict): Remove `keyword_flags' argument.
+	Use new macro IS_PS_TOKEN.
+	Changed function so that later PostScript definitions override
+	earlier ones.
+	(t1_init_loader): Initialize new field `keywords_encountered'.
+	(T1_Open_Face): Initialize new fields `ndv_idx', `cdv_idx', and
+	`len_buildchar'.
+	Remove `keywords_flags'.
+
+	* freetype2/src/type1/t1load.h (T1_LoaderRect): New field
+	`keywords_encountered'.
+	(T1_PRIVATE, T1_FONTDIR_AFTER_PRIVATE): New macros.
+
+	* freetype2/src/type1/t1tokens.h [!T1_CONFIG_OPTION_NO_MM_SUPPORT]:
+	New entries for parsing /NDV, /CDV, and /DesignVector.
+
 2006-07-07  Werner Lemberg  <wl@gnu.org>
 
 	Add many checks to protect against malformed PCF files.
diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h
index d2e4910..4afd2b0 100644
--- a/include/freetype/internal/psaux.h
+++ b/include/freetype/internal/psaux.h
@@ -199,6 +199,9 @@ FT_BEGIN_HEADER
     T1_FIELD_LOCATION_FONT_INFO,
     T1_FIELD_LOCATION_PRIVATE,
     T1_FIELD_LOCATION_BBOX,
+    T1_FIELD_LOCATION_LOADER,
+    T1_FIELD_LOCATION_FACE,
+    T1_FIELD_LOCATION_BLEND,
 
     /* do not remove */
     T1_FIELD_LOCATION_MAX
@@ -683,6 +686,10 @@ FT_BEGIN_HEADER
     T1_Decoder_Callback  parse_callback;
     T1_Decoder_FuncsRec  funcs;
 
+    FT_Int*              buildchar;
+
+    T1_Face              face;
+
   } T1_DecoderRec;
 
 
@@ -712,8 +719,10 @@ FT_BEGIN_HEADER
 
   } AFM_Parser_FuncsRec;
 
+
   typedef struct AFM_StreamRec_*  AFM_Stream;
 
+
   /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
@@ -801,6 +810,57 @@ FT_BEGIN_HEADER
   /* backwards-compatible type definition */
   typedef PSAux_ServiceRec   PSAux_Interface;
 
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                 Some convenience functions                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define IS_PS_NEWLINE( ch ) \
+  ( (ch) == '\r' ||         \
+    (ch) == '\n' )
+
+#define IS_PS_SPACE( ch )  \
+  ( (ch) == ' '         || \
+    IS_PS_NEWLINE( ch ) || \
+    (ch) == '\t'        || \
+    (ch) == '\f'        || \
+    (ch) == '\0' )
+
+#define IS_PS_SPECIAL( ch )       \
+  ( (ch) == '/'                || \
+    (ch) == '(' || (ch) == ')' || \
+    (ch) == '<' || (ch) == '>' || \
+    (ch) == '[' || (ch) == ']' || \
+    (ch) == '{' || (ch) == '}' || \
+    (ch) == '%'                )
+
+#define IS_PS_DELIM( ch )  \
+  ( IS_PS_SPACE( ch )   || \
+    IS_PS_SPECIAL( ch ) )
+
+#define IS_PS_DIGIT( ch )        \
+  ( (ch) >= '0' && (ch) <= '9' )
+
+#define IS_PS_XDIGIT( ch )            \
+  ( IS_PS_DIGIT( ch )              || \
+    ( (ch) >= 'A' && (ch) <= 'F' ) || \
+    ( (ch) >= 'a' && (ch) <= 'f' ) )
+
+#define IS_PS_BASE85( ch )       \
+  ( (ch) >= '!' && (ch) <= 'u' )
+
+#define IS_PS_TOKEN( cur, limit, token )                                \
+  ( (char)(cur)[0] == (token)[0]                                     && \
+    ( (cur) + sizeof ( (token) ) == (limit) ||                          \
+      ( (cur) + sizeof( (token) ) < (limit)          &&                 \
+        IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) )             && \
+    ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 )
+
+
 FT_END_HEADER
 
 #endif /* __PSAUX_H__ */
diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h
index 65d9ca9..eca91a7 100644
--- a/include/freetype/internal/t1types.h
+++ b/include/freetype/internal/t1types.h
@@ -208,6 +208,16 @@ FT_BEGIN_HEADER
     /* support for Multiple Masters fonts */
     PS_Blend        blend;
 
+    /* undocumented, optional: indices of subroutines that express      */
+    /* the NormalizeDesignVector and the ConvertDesignVector procedure, */
+    /* respectively, as Type 2 charstrings; -1 if keywords not present  */
+    FT_Int           ndv_idx;
+    FT_Int           cdv_idx;
+
+    /* undocumented, optional: has the same meaning as len_buildchar */
+    /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25    */
+    FT_UInt          len_buildchar;
+
     /* since version 2.1 - interface to PostScript hinter */
     const void*     pshinter;
 
diff --git a/include/freetype/t1tables.h b/include/freetype/t1tables.h
index 1815250..7979ea5 100644
--- a/include/freetype/t1tables.h
+++ b/include/freetype/t1tables.h
@@ -5,7 +5,7 @@
 /*    Basic Type 1/Type 2 tables definitions and interface (specification  */
 /*    only).                                                               */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2006 by                         */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -256,6 +256,15 @@ FT_BEGIN_HEADER
 
     FT_BBox*         bboxes    [T1_MAX_MM_DESIGNS + 1];
 
+    /* since 2.2.2 */
+
+    /* undocumented, optional: the default design instance;   */
+    /* corresponds to default_weight_vector --                */
+    /* num_default_design_vector == 0 means it is not present */
+    /* in the font and associated metrics files               */
+    FT_UInt          default_design_vector[T1_MAX_MM_DESIGNS];
+    FT_UInt          num_default_design_vector;
+
   } PS_BlendRec, *PS_Blend;
 
 
diff --git a/src/psaux/psconv.h b/src/psaux/psconv.h
index 82c3707..e511241 100644
--- a/src/psaux/psconv.h
+++ b/src/psaux/psconv.h
@@ -63,42 +63,6 @@ FT_BEGIN_HEADER
                        FT_UShort*  seed );
 
 
-#define IS_PS_NEWLINE( ch ) \
-  ( ( ch ) == '\r' ||       \
-    ( ch ) == '\n' )
-
-#define IS_PS_SPACE( ch )  \
-  ( ( ch ) == ' '       || \
-    IS_PS_NEWLINE( ch ) || \
-    ( ch ) == '\t'      || \
-    ( ch ) == '\f'      || \
-    ( ch ) == '\0' )
-
-#define IS_PS_SPECIAL( ch ) \
-  ( ( ch ) == '/' ||        \
-    ( ch ) == '(' ||        \
-    ( ch ) == ')' ||        \
-    ( ch ) == '<' ||        \
-    ( ch ) == '>' ||        \
-    ( ch ) == '[' ||        \
-    ( ch ) == ']' ||        \
-    ( ch ) == '{' ||        \
-    ( ch ) == '}' ||        \
-    ( ch ) == '%' )
-
-#define IS_PS_DELIM( ch )  \
-  ( IS_PS_SPACE( ch )   || \
-    IS_PS_SPECIAL( ch ) )
-
-#define IS_PS_DIGIT( ch )  ( ( ch ) >= '0' && ( ch ) <= '9' )
-
-#define IS_PS_XDIGIT( ch )                \
-  ( IS_PS_DIGIT( ( ch ) )              || \
-    ( ( ch ) >= 'A' && ( ch ) <= 'F' ) || \
-    ( ( ch ) >= 'a' && ( ch ) <= 'f' ) )
-
-#define IS_PS_BASE85( ch ) ( ( ch ) >= '!' && ( ch ) <= 'u' )
-
 FT_END_HEADER
 
 #endif /* __PSCONV_H__ */
diff --git a/src/psaux/psobjs.c b/src/psaux/psobjs.c
index 25b0bc6..5f7037f 100644
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -698,6 +698,9 @@
   }
 
 
+  /* NB: `tokens' can be NULL if we only want to count */
+  /* the number of array elements                      */
+
   FT_LOCAL_DEF( void )
   ps_parser_to_token_array( PS_Parser  parser,
                             T1_Token   tokens,
@@ -733,7 +736,7 @@
         if ( !token.type )
           break;
 
-        if ( cur < limit )
+        if ( tokens != NULL && cur < limit )
           *cur = token;
 
         cur++;
@@ -748,6 +751,8 @@
 
 
   /* first character must be a delimiter or a part of a number */
+  /* NB: `coords' can be NULL if we just want to skip the      */
+  /*     array; in this case we ignore `max_coords'            */
 
   static FT_Int
   ps_tocoordarray( FT_Byte*  *acur,
@@ -780,21 +785,26 @@
     /* now, read the coordinates */
     while ( cur < limit )
     {
+      FT_Short dummy;
+
+
       /* skip whitespace in front of data */
       skip_spaces( &cur, limit );
       if ( cur >= limit )
         goto Exit;
 
-      if ( count >= max_coords )
+      if ( coords != NULL && count >= max_coords )
         break;
 
-      if ( c == ender )
+      if ( *cur == ender )
       {
         cur++;
         break;
       }
 
-      coords[count] =
+      /* call PS_Conv_ToFixed() even if coords == NULL */
+      /* to properly parse number at `cur'             */
+      *( coords != NULL ? &coords[count] : &dummy ) =
         (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
       count++;
 
@@ -809,6 +819,8 @@
 
 
   /* first character must be a delimiter or a part of a number */
+  /* NB: `values' can be NULL if we just want to skip the      */
+  /*     array in this case we ignore `max_values'             */
 
   static FT_Int
   ps_tofixedarray( FT_Byte*  *acur,
@@ -842,21 +854,27 @@
     /* now, read the values */
     while ( cur < limit )
     {
+      FT_Fixed dummy;
+
+
       /* skip whitespace in front of data */
       skip_spaces( &cur, limit );
       if ( cur >= limit )
         goto Exit;
 
-      if ( count >= max_values )
+      if ( values != NULL && count >= max_values )
         break;
 
-      if ( c == ender )
+      if ( *cur == ender )
       {
         cur++;
         break;
       }
 
-      values[count] = PS_Conv_ToFixed( &cur, limit, power_ten );
+      /* call PS_Conv_ToFixed() even if coords == NULL */
+      /* to properly parse number at `cur'             */
+      *( values != NULL ? &values[count] : &dummy ) =
+        PS_Conv_ToFixed( &cur, limit, power_ten );
       count++;
 
       if ( !ender )
diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c
index 574527c..bc799e4 100644
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -348,6 +348,14 @@
 
     hinter = (T1_Hints_Funcs)builder->hints_funcs;
 
+    /* a font that reads BuildCharArray without setting */
+    /* its values first is buggy, but ...               */
+    if ( decoder->face->len_buildchar > 0 )
+      memset( &decoder->buildchar[0],
+              0,
+              sizeof( decoder->buildchar[0] ) *
+                decoder->face->len_buildchar );
+
     FT_TRACE4(( "\nStart charstring\n" ));
 
     zone->base           = charstring_base;
@@ -582,12 +590,9 @@
         subr_no = (FT_Int)top[1];
         arg_cnt = (FT_Int)top[0];
 
-        if ( arg_cnt > top - decoder->stack )
-          goto Stack_Underflow;
-
         /***********************************************************/
         /*                                                         */
-        /* remove all operands to callsubr from the stack          */
+        /* remove all operands to callothersubr from the stack     */
         /*                                                         */
         /* for handled othersubrs, where we know the number of     */
         /* arguments, we increase the stack by the value of        */
@@ -596,11 +601,30 @@
         /* for unhandled othersubrs the following pops adjust the  */
         /* stack pointer as necessary                              */
 
+        if ( arg_cnt > top - decoder->stack )
+          goto Stack_Underflow;
+
         top -= arg_cnt;
 
         known_othersubr_result_cnt   = 0;
         unknown_othersubr_result_cnt = 0;
 
+        /* XXX TODO: The checks to `arg_count == <whatever>'       */
+        /* might not be correct; an othersubr expects a certain    */
+        /* number of operands on the PostScript stack (as opposed  */
+        /* to the T1 stack) but it doesn't have to put them there  */
+        /* by itself; previous othersubrs might have left the      */
+        /* operands there if they were not followed by an          */
+        /* appropriate number of pops                              */
+        /*                                                         */
+        /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
+        /* accept a font that contains charstrings like            */
+        /*                                                         */
+        /*     100 200 2 20 callothersubr                          */
+        /*     300 1 20 callothersubr pop                          */
+        /*                                                         */
+        /* Perhaps this is the reason why BuildCharArray exists.   */
+
         switch ( subr_no )
         {
         case 1:                     /* start flex feature */
@@ -726,6 +750,158 @@
             break;
           }
 
+#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
+
+          /* We cannot yet enable these since currently  */
+          /* our T1 stack stores integers which lack the */
+          /* precision to express the values             */
+
+        case 19:
+          /* <idx> 1 19 callothersubr                             */
+          /* => replace elements starting from index cvi( <idx> ) */
+          /*    of BuildCharArray with WeightVector               */
+          {
+            FT_Int    idx;
+            PS_Blend  blend = decoder->blend;
+
+
+            if ( arg_cnt != 1 || blend == NULL )
+              goto Unexpected_OtherSubr;
+
+            idx = top[0];
+
+            if ( idx < 0                                                 ||
+                 idx + blend->num_designs > decoder->face->len_buildchar )
+              goto Unexpected_OtherSubr;
+
+            memcpy( &decoder->buildchar[idx],
+                    blend->weight_vector,
+                    blend->num_designs *
+                      sizeof( blend->weight_vector[ 0 ] ) );
+          }
+          break;
+
+        case 20:
+          /* <arg1> <arg2> 2 20 callothersubr pop   */
+          /* ==> push <arg1> + <arg2> onto T1 stack */
+          if ( arg_cnt != 2 )
+            goto Unexpected_OtherSubr;
+
+          top[0] += top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+        case 21:
+          /* <arg1> <arg2> 2 21 callothersubr pop   */
+          /* ==> push <arg1> - <arg2> onto T1 stack */
+          if ( arg_cnt != 2 )
+            goto Unexpected_OtherSubr;
+
+          top[0] -= top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+        case 22:
+          /* <arg1> <arg2> 2 22 callothersubr pop   */
+          /* ==> push <arg1> * <arg2> onto T1 stack */
+          if ( arg_cnt != 2 )
+            goto Unexpected_OtherSubr;
+
+          top[0] *= top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+        case 23:
+          /* <arg1> <arg2> 2 23 callothersubr pop   */
+          /* ==> push <arg1> / <arg2> onto T1 stack */
+          if ( arg_cnt != 2 || top[1] == 0 )
+            goto Unexpected_OtherSubr;
+
+          top[0] /= top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+#endif /* CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS */
+
+        case 24:
+          /* <val> <idx> 2 24 callothersubr              */
+          /* => set BuildCharArray[cvi( <idx> )] = <val> */
+          {
+            FT_Int    idx;
+            PS_Blend  blend = decoder->blend;
+
+            if ( arg_cnt != 2 || blend == NULL )
+              goto Unexpected_OtherSubr;
+
+            idx = top[1];
+
+            if ( idx < 0 || (FT_UInt) idx >= decoder->face->len_buildchar )
+              goto Unexpected_OtherSubr;
+
+            decoder->buildchar[idx] = top[0];
+          }
+          break;
+
+        case 25:
+          /* <idx> 1 25 callothersubr pop       */
+          /* => push BuildCharArray[cvi( idx )] */
+          /*    onto T1 stack                   */
+          {
+            FT_Int    idx;
+            PS_Blend  blend = decoder->blend;
+
+            if ( arg_cnt != 1 || blend == NULL )
+              goto Unexpected_OtherSubr;
+
+            idx = top[0];
+
+            if ( idx < 0 || (FT_UInt) idx >= decoder->face->len_buildchar )
+              goto Unexpected_OtherSubr;
+
+            top[0] = decoder->buildchar[idx];
+          }
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+#if 0
+        case 26:
+          /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */
+          /*                      leave mark on T1 stack                    */
+          /* <val> <idx>      ==> set BuildCharArray[cvi( <idx> )] = <val>  */
+          XXX who has left his mark on the (PostScript) stack ?;
+          break;
+#endif
+
+        case 27:
+          /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
+          /* ==> push <res1> onto T1 stack if <val1> <= <val2>,  */
+          /*     otherwise push <res2>                          */
+          if ( arg_cnt != 4 )
+            goto Unexpected_OtherSubr;
+
+          if ( top[2] > top[3] )
+            top[0] = top[1];
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
+        case 28:
+          /* 0 28 callothersubr pop                               */
+          /* => push random value from interval [0, 1) onto stack */
+          if ( arg_cnt != 0 )
+            goto Unexpected_OtherSubr;
+
+          top[0] = FT_rand();
+          known_othersubr_result_cnt = 1;
+          break;
+#endif
+
         default:
           FT_ERROR(( "t1_decoder_parse_charstrings: "
                      "unknown othersubr [%d %d], wish me luck!\n",
@@ -805,8 +981,30 @@
           /* add current outline to the glyph slot */
           FT_GlyphLoader_Add( builder->loader );
 
+          FT_TRACE4(( "\n" ));
+
+          /* the compiler should optimize away this empty loop but ... */
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+          if ( decoder->face->len_buildchar > 0 )
+          {
+            FT_UInt  i;
+
+
+            FT_TRACE4(( "BuildCharArray = [ " ));
+
+            for ( i = 0; i < decoder->face->len_buildchar; ++i )
+              FT_TRACE4(( "%d ", decoder->buildchar[ i ] ));
+
+            FT_TRACE4(( "]\n" ));
+          }
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+          FT_TRACE4(( "\n" ));
+
           /* return now! */
-          FT_TRACE4(( "\n\n" ));
           return PSaux_Err_Ok;
 
         case op_hsbw:
@@ -1225,6 +1423,10 @@
                    FT_Render_Mode       hint_mode,
                    T1_Decoder_Callback  parse_callback )
   {
+    FT_Error   error;
+    FT_Memory  memory = face->memory;
+
+
     FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
 
     /* retrieve PSNames interface from list of current modules */
@@ -1243,6 +1445,18 @@
       decoder->psnames = psnames;
     }
 
+    decoder->face = (T1_Face) face;
+
+    if ( decoder->face->len_buildchar > 0 )
+    {
+      if ( FT_NEW_ARRAY( decoder->buildchar, decoder->face->len_buildchar ) )
+      {
+        FT_ERROR(( "t1_decoder_init: " ));
+        FT_ERROR(( "cannot allocate memory for BuildCharArray\n" ));
+        return error;
+      }
+    }
+
     t1_builder_init( &decoder->builder, face, size, slot, hinting );
 
     decoder->num_glyphs     = (FT_UInt)face->num_glyphs;
@@ -1261,7 +1475,12 @@
   FT_LOCAL_DEF( void )
   t1_decoder_done( T1_Decoder  decoder )
   {
+    FT_Memory  memory = decoder->face->root.memory;
+
+
     t1_builder_done( &decoder->builder );
+
+    FT_FREE( decoder->buildchar );
   }
 
 
diff --git a/src/type1/t1load.c b/src/type1/t1load.c
index 38d9055..635e16c 100644
--- a/src/type1/t1load.c
+++ b/src/type1/t1load.c
@@ -107,6 +107,8 @@
       if ( FT_NEW( blend ) )
         goto Exit;
 
+      blend->num_default_design_vector = 0;
+
       face->blend = blend;
     }
 
@@ -877,6 +879,18 @@
   }
 
 
+  /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
+  /* we're only interested in the number of array elements */
+  static void
+  parse_buildchar( T1_Face    face,
+                   T1_Loader  loader )
+  {
+    face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
+
+    return;
+  }
+
+
 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
 
 
@@ -950,6 +964,26 @@
       }
       break;
 
+    case T1_FIELD_LOCATION_LOADER:
+      dummy_object = loader;
+      objects      = &dummy_object;
+      max_objects  = 0;
+      break;
+
+    case T1_FIELD_LOCATION_FACE:
+      dummy_object = face;
+      objects      = &dummy_object;
+      max_objects  = 0;
+      break;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+    case T1_FIELD_LOCATION_BLEND:
+      dummy_object = face->blend;
+      objects      = &dummy_object;
+      max_objects  = 0;
+      break;
+#endif
+
     default:
       dummy_object = &face->type1;
       objects      = &dummy_object;
@@ -969,6 +1003,16 @@
   }
 
 
+  static void
+  parse_private( T1_Face    face,
+                 T1_Loader  loader )
+  {
+    FT_UNUSED( face );
+
+    loader->keywords_encountered |= T1_PRIVATE;
+  }
+
+
   static int
   is_space( FT_Byte  c )
   {
@@ -1681,12 +1725,14 @@
     T1_FIELD_CALLBACK( "Encoding", parse_encoding )
     T1_FIELD_CALLBACK( "Subrs", parse_subrs )
     T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
+    T1_FIELD_CALLBACK( "Private", parse_private )
 
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
     T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
     T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
     T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
     T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
+    T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar )
 #endif
 
     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
@@ -1701,8 +1747,7 @@
   parse_dict( T1_Face    face,
               T1_Loader  loader,
               FT_Byte*   base,
-              FT_Long    size,
-              FT_Byte*   keyword_flags )
+              FT_Long    size )
   {
     T1_Parser  parser = &loader->parser;
     FT_Byte   *limit, *start_binary = NULL;
@@ -1724,31 +1769,23 @@
 
       cur = parser->root.cursor;
 
-      /* cur[5] must be a token delimiter;                 */
-      /* eexec encryption is optional, so look for `eexec' */
-      if ( *cur == 'e' && cur + 5 < limit            &&
-           ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
+      /* look for `eexec' */
+      if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
         break;
 
-      /* cur[9] must be a token delimiter;                 */
       /* look for `closefile' which ends the eexec section */
-      else if ( *cur == 'c' && cur + 9 < limit                &&
-                ft_strncmp( (char*)cur, "closefile", 9 ) == 0 )
+      else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
         break;
 
-#ifdef TO_BE_DONE
       /* in a synthetic font the base font starts after a           */
       /* `FontDictionary' token that is placed after a Private dict */
-
-      /* cur[13] must be a token delimiter */
-      else if ( *cur == 'F' && cur + 13 < limit                    &&
-                ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+      else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
       {
-        if ( loader->private_encountered )
-          loader->fontdir_after_private = 1;
+        if ( loader->keywords_encountered & T1_PRIVATE )
+          loader->keywords_encountered |=
+            T1_FONTDIR_AFTER_PRIVATE;
         parser->root.cursor += 13;
       }
-#endif
 
       /* check whether we have an integer */
       else if ( ft_isdigit( *cur ) )
@@ -1807,8 +1844,7 @@
         if ( len > 0 && len < 22 && parser->root.cursor < limit )
         {
           /* now compare the immediate name to the keyword table */
-          T1_Field  keyword      = (T1_Field)t1_keywords;
-          FT_Byte*  keyword_flag = keyword_flags;
+          T1_Field  keyword = (T1_Field)t1_keywords;
 
 
           for (;;)
@@ -1824,21 +1860,28 @@
                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
                  ft_memcmp( cur, name, len ) == 0                   )
             {
-              /* We found it -- run the parsing callback! */
-              /* We only record the first instance of any */
-              /* field to deal adequately with synthetic  */
-              /* fonts; /Subrs and /CharStrings are       */
-              /* handled specially.                       */
-              if ( keyword_flag[0] == 0                               ||
-                   ft_strcmp( (const char*)name, "Subrs" ) == 0       ||
-                   ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
+              /* We found it -- run the parsing callback!     */
+              /* We record every instance of every field      */
+              /* (until we reach the base font of a           */
+              /* synthetic font) to deal adequately with      */
+              /* multiple master fonts; this is also          */
+              /* necessary because later PostScript           */
+              /* definitions override earlier ones            */
+
+              /* Once we encounter `FontDirectory' after      */
+              /* `/Private', we know that this is a synthetic */
+              /* font; except for `/CharStrings' we are not   */
+              /* interested in anything that follows this     */
+              /* `FontDirectory'                              */
+
+              if ( !( loader->keywords_encountered                &
+                      T1_FONTDIR_AFTER_PRIVATE ) ||
+                   ft_strcmp((const char*)name, "CharStrings") == 0 )
               {
                 parser->root.error = t1_load_keyword( face,
                                                       loader,
                                                       keyword );
-                if ( parser->root.error == T1_Err_Ok )
-                  keyword_flag[0] = 1;
-                else
+                if ( parser->root.error != T1_Err_Ok )
                 {
                   if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore )
                     parser->root.error = T1_Err_Ok;
@@ -1850,7 +1893,6 @@
             }
 
             keyword++;
-            keyword_flag++;
           }
         }
 
@@ -1883,12 +1925,13 @@
     loader->num_chars  = 0;
 
     /* initialize the tables -- simply set their `init' field to 0 */
-    loader->encoding_table.init = 0;
-    loader->charstrings.init    = 0;
-    loader->glyph_names.init    = 0;
-    loader->subrs.init          = 0;
-    loader->swap_table.init     = 0;
-    loader->fontdata            = 0;
+    loader->encoding_table.init  = 0;
+    loader->charstrings.init     = 0;
+    loader->glyph_names.init     = 0;
+    loader->subrs.init           = 0;
+    loader->swap_table.init      = 0;
+    loader->fontdata             = 0;
+    loader->keywords_encountered = 0;
   }
 
 
@@ -1918,7 +1961,6 @@
     T1_Font        type1 = &face->type1;
     PS_Private     priv  = &type1->private_dict;
     FT_Error       error;
-    FT_Byte        keyword_flags[T1_FIELD_COUNT];
 
     PSAux_Service  psaux = (PSAux_Service)face->psaux;
 
@@ -1926,6 +1968,10 @@
     t1_init_loader( &loader, face );
 
     /* default values */
+    face->ndv_idx          = -1;
+    face->cdv_idx          = -1;
+    face->len_buildchar    = 0;
+
     priv->blue_shift       = 7;
     priv->blue_fuzz        = 1;
     priv->lenIV            = 4;
@@ -1940,16 +1986,8 @@
     if ( error )
       goto Exit;
 
-    {
-      FT_UInt  n;
-
-
-      for ( n = 0; n < T1_FIELD_COUNT; n++ )
-        keyword_flags[n] = 0;
-    }
-
-    error = parse_dict( face, &loader, parser->base_dict, parser->base_len,
-                        keyword_flags );
+    error = parse_dict( face, &loader,
+                        parser->base_dict, parser->base_len );
     if ( error )
       goto Exit;
 
@@ -1957,9 +1995,8 @@
     if ( error )
       goto Exit;
 
-    error = parse_dict( face, &loader, parser->private_dict,
-                        parser->private_len,
-                        keyword_flags );
+    error = parse_dict( face, &loader,
+                        parser->private_dict, parser->private_len );
     if ( error )
       goto Exit;
 
@@ -1968,6 +2005,19 @@
 
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
 
+    if ( face->blend                                                     &&
+         face->blend->num_default_design_vector != 0                     &&
+         face->blend->num_default_design_vector != face->blend->num_axis )
+    {
+      /* we don't use it currently so just warn, reset, and ignore */
+      FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
+                 "while there are %u axes.\n",
+                 face->blend->num_default_design_vector,
+                 face->blend->num_axis ));
+
+      face->blend->num_default_design_vector = 0;
+    }
+
     /* the following can happen for MM instances; we then treat the */
     /* font as a normal PS font                                     */
     if ( face->blend                                             &&
diff --git a/src/type1/t1load.h b/src/type1/t1load.h
index 9823f53..717ae61 100644
--- a/src/type1/t1load.h
+++ b/src/type1/t1load.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Type 1 font loader (specification).                                  */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2004 by                                     */
+/*  Copyright 1996-2001, 2002, 2004, 2006 by                               */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -48,9 +48,18 @@ FT_BEGIN_HEADER
     PS_TableRec   subrs;
     FT_Bool       fontdata;
 
+    FT_UInt       keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */
+
   } T1_LoaderRec, *T1_Loader;
 
 
+  /* treatment of some keywords differs depending on whether */
+  /* they preceed or follow certain other keywords           */
+
+#define T1_PRIVATE                ( 1 << 0 )
+#define T1_FONTDIR_AFTER_PRIVATE  ( 1 << 1 )
+
+
   FT_LOCAL( FT_Error )
   T1_Open_Face( T1_Face  face );
 
diff --git a/src/type1/t1tokens.h b/src/type1/t1tokens.h
index a3cc952..bd27361 100644
--- a/src/type1/t1tokens.h
+++ b/src/type1/t1tokens.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Type 1 tokenizer (specification).                                    */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2006 by                         */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -73,6 +73,7 @@
   T1_FIELD_NUM  ( "FontType", font_type )
   T1_FIELD_FIXED( "StrokeWidth", stroke_width )
 
+
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  FT_BBox
 #undef  T1CODE
@@ -81,4 +82,26 @@
   T1_FIELD_BBOX("FontBBox", xMin )
 
 
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  T1_FaceRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FACE
+
+  T1_FIELD_NUM      ( "NDV", ndv_idx )
+  T1_FIELD_NUM      ( "CDV", cdv_idx )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PS_BlendRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_BLEND
+
+  T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, T1_MAX_MM_DESIGNS )
+
+
+#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
 /* END */