Initialize Tizen 2.3
[framework/graphics/freetype.git] / src / otvalid / otvgpos.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  otvgpos.c                                                              */
4 /*                                                                         */
5 /*    OpenType GPOS table validation (body).                               */
6 /*                                                                         */
7 /*  Copyright 2002, 2004, 2005, 2006, 2007, 2008 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 "otvalid.h"
20 #include "otvcommn.h"
21 #include "otvgpos.h"
22
23
24   /*************************************************************************/
25   /*                                                                       */
26   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
27   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
28   /* messages during execution.                                            */
29   /*                                                                       */
30 #undef  FT_COMPONENT
31 #define FT_COMPONENT  trace_otvgpos
32
33
34   static void
35   otv_Anchor_validate( FT_Bytes       table,
36                        OTV_Validator  valid );
37
38   static void
39   otv_MarkArray_validate( FT_Bytes       table,
40                           OTV_Validator  valid );
41
42
43   /*************************************************************************/
44   /*************************************************************************/
45   /*****                                                               *****/
46   /*****                      UTILITY FUNCTIONS                        *****/
47   /*****                                                               *****/
48   /*************************************************************************/
49   /*************************************************************************/
50
51 #define BaseArrayFunc       otv_x_sxy
52 #define LigatureAttachFunc  otv_x_sxy
53 #define Mark2ArrayFunc      otv_x_sxy
54
55   /* uses valid->extra1 (counter)                             */
56   /* uses valid->extra2 (boolean to handle NULL anchor field) */
57
58   static void
59   otv_x_sxy( FT_Bytes       table,
60              OTV_Validator  valid )
61   {
62     FT_Bytes  p = table;
63     FT_UInt   Count, count1, table_size;
64
65
66     OTV_ENTER;
67
68     OTV_LIMIT_CHECK( 2 );
69
70     Count = FT_NEXT_USHORT( p );
71
72     OTV_TRACE(( " (Count = %d)\n", Count ));
73
74     OTV_LIMIT_CHECK( Count * valid->extra1 * 2 );
75
76     table_size = Count * valid->extra1 * 2 + 2;
77
78     for ( ; Count > 0; Count-- )
79       for ( count1 = valid->extra1; count1 > 0; count1-- )
80       {
81         OTV_OPTIONAL_TABLE( anchor_offset );
82
83
84         OTV_OPTIONAL_OFFSET( anchor_offset );
85
86         if ( valid->extra2 )
87         {
88           OTV_SIZE_CHECK( anchor_offset );
89           if ( anchor_offset )
90             otv_Anchor_validate( table + anchor_offset, valid );
91         }
92         else
93           otv_Anchor_validate( table + anchor_offset, valid );
94       }
95
96     OTV_EXIT;
97   }
98
99
100 #define MarkBasePosFormat1Func  otv_u_O_O_u_O_O
101 #define MarkLigPosFormat1Func   otv_u_O_O_u_O_O
102 #define MarkMarkPosFormat1Func  otv_u_O_O_u_O_O
103
104   /* sets valid->extra1 (class count) */
105
106   static void
107   otv_u_O_O_u_O_O( FT_Bytes       table,
108                    OTV_Validator  valid )
109   {
110     FT_Bytes           p = table;
111     FT_UInt            Coverage1, Coverage2, ClassCount;
112     FT_UInt            Array1, Array2;
113     OTV_Validate_Func  func;
114
115
116     OTV_ENTER;
117
118     p += 2;     /* skip PosFormat */
119
120     OTV_LIMIT_CHECK( 10 );
121     Coverage1  = FT_NEXT_USHORT( p );
122     Coverage2  = FT_NEXT_USHORT( p );
123     ClassCount = FT_NEXT_USHORT( p );
124     Array1     = FT_NEXT_USHORT( p );
125     Array2     = FT_NEXT_USHORT( p );
126
127     otv_Coverage_validate( table + Coverage1, valid, -1 );
128     otv_Coverage_validate( table + Coverage2, valid, -1 );
129
130     otv_MarkArray_validate( table + Array1, valid );
131
132     valid->nesting_level++;
133     func          = valid->func[valid->nesting_level];
134     valid->extra1 = ClassCount;
135
136     func( table + Array2, valid );
137
138     valid->nesting_level--;
139
140     OTV_EXIT;
141   }
142
143
144   /*************************************************************************/
145   /*************************************************************************/
146   /*****                                                               *****/
147   /*****                        VALUE RECORDS                          *****/
148   /*****                                                               *****/
149   /*************************************************************************/
150   /*************************************************************************/
151
152   static FT_UInt
153   otv_value_length( FT_UInt  format )
154   {
155     FT_UInt  count;
156
157
158     count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
159     count = ( ( count  & 0xCC ) >> 2 ) + ( count  & 0x33 );
160     count = ( ( count  & 0xF0 ) >> 4 ) + ( count  & 0x0F );
161
162     return count * 2;
163   }
164
165
166   /* uses valid->extra3 (pointer to base table) */
167
168   static void
169   otv_ValueRecord_validate( FT_Bytes       table,
170                             FT_UInt        format,
171                             OTV_Validator  valid )
172   {
173     FT_Bytes  p = table;
174     FT_UInt   count;
175
176 #ifdef FT_DEBUG_LEVEL_TRACE
177     FT_Int    loop;
178     FT_ULong  res = 0;
179
180
181     OTV_NAME_ENTER( "ValueRecord" );
182
183     /* display `format' in dual representation */
184     for ( loop = 7; loop >= 0; loop-- )
185     {
186       res <<= 4;
187       res  += ( format >> loop ) & 1;
188     }
189
190     OTV_TRACE(( " (format 0b%08lx)\n", res ));
191 #endif
192
193     if ( format >= 0x100 )
194       FT_INVALID_FORMAT;
195
196     for ( count = 4; count > 0; count-- )
197     {
198       if ( format & 1 )
199       {
200         /* XPlacement, YPlacement, XAdvance, YAdvance */
201         OTV_LIMIT_CHECK( 2 );
202         p += 2;
203       }
204
205       format >>= 1;
206     }
207
208     for ( count = 4; count > 0; count-- )
209     {
210       if ( format & 1 )
211       {
212         FT_PtrDist  table_size;
213
214         OTV_OPTIONAL_TABLE( device );
215
216
217         /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
218         OTV_LIMIT_CHECK( 2 );
219         OTV_OPTIONAL_OFFSET( device );
220
221         /* XXX: this value is usually too small, especially if the current */
222         /* ValueRecord is part of an array -- getting the correct table    */
223         /* size is probably not worth the trouble                          */
224
225         table_size = p - valid->extra3;
226
227         OTV_SIZE_CHECK( device );
228         if ( device )
229           otv_Device_validate( valid->extra3 + device, valid );
230       }
231       format >>= 1;
232     }
233
234     OTV_EXIT;
235   }
236
237
238   /*************************************************************************/
239   /*************************************************************************/
240   /*****                                                               *****/
241   /*****                           ANCHORS                             *****/
242   /*****                                                               *****/
243   /*************************************************************************/
244   /*************************************************************************/
245
246   static void
247   otv_Anchor_validate( FT_Bytes       table,
248                        OTV_Validator  valid )
249   {
250     FT_Bytes  p = table;
251     FT_UInt   AnchorFormat;
252
253
254     OTV_NAME_ENTER( "Anchor");
255
256     OTV_LIMIT_CHECK( 6 );
257     AnchorFormat = FT_NEXT_USHORT( p );
258
259     OTV_TRACE(( " (format %d)\n", AnchorFormat ));
260
261     p += 4;     /* skip XCoordinate and YCoordinate */
262
263     switch ( AnchorFormat )
264     {
265     case 1:
266       break;
267
268     case 2:
269       OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
270       break;
271
272     case 3:
273       {
274         FT_UInt   table_size;
275
276         OTV_OPTIONAL_TABLE( XDeviceTable );
277         OTV_OPTIONAL_TABLE( YDeviceTable );
278
279
280         OTV_LIMIT_CHECK( 4 );
281         OTV_OPTIONAL_OFFSET( XDeviceTable );
282         OTV_OPTIONAL_OFFSET( YDeviceTable );
283
284         table_size = 6 + 4;
285
286         OTV_SIZE_CHECK( XDeviceTable );
287         if ( XDeviceTable )
288           otv_Device_validate( table + XDeviceTable, valid );
289
290         OTV_SIZE_CHECK( YDeviceTable );
291         if ( YDeviceTable )
292           otv_Device_validate( table + YDeviceTable, valid );
293       }
294       break;
295
296     default:
297       FT_INVALID_FORMAT;
298     }
299
300     OTV_EXIT;
301   }
302
303
304   /*************************************************************************/
305   /*************************************************************************/
306   /*****                                                               *****/
307   /*****                         MARK ARRAYS                           *****/
308   /*****                                                               *****/
309   /*************************************************************************/
310   /*************************************************************************/
311
312   static void
313   otv_MarkArray_validate( FT_Bytes       table,
314                           OTV_Validator  valid )
315   {
316     FT_Bytes  p = table;
317     FT_UInt   MarkCount;
318
319
320     OTV_NAME_ENTER( "MarkArray" );
321
322     OTV_LIMIT_CHECK( 2 );
323     MarkCount = FT_NEXT_USHORT( p );
324
325     OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
326
327     OTV_LIMIT_CHECK( MarkCount * 4 );
328
329     /* MarkRecord */
330     for ( ; MarkCount > 0; MarkCount-- )
331     {
332       p += 2;   /* skip Class */
333       /* MarkAnchor */
334       otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid );
335     }
336
337     OTV_EXIT;
338   }
339
340
341   /*************************************************************************/
342   /*************************************************************************/
343   /*****                                                               *****/
344   /*****                     GPOS LOOKUP TYPE 1                        *****/
345   /*****                                                               *****/
346   /*************************************************************************/
347   /*************************************************************************/
348
349   /* sets valid->extra3 (pointer to base table) */
350
351   static void
352   otv_SinglePos_validate( FT_Bytes       table,
353                           OTV_Validator  valid )
354   {
355     FT_Bytes  p = table;
356     FT_UInt   PosFormat;
357
358
359     OTV_NAME_ENTER( "SinglePos" );
360
361     OTV_LIMIT_CHECK( 2 );
362     PosFormat = FT_NEXT_USHORT( p );
363
364     OTV_TRACE(( " (format %d)\n", PosFormat ));
365
366     valid->extra3 = table;
367
368     switch ( PosFormat )
369     {
370     case 1:     /* SinglePosFormat1 */
371       {
372         FT_UInt  Coverage, ValueFormat;
373
374
375         OTV_LIMIT_CHECK( 4 );
376         Coverage    = FT_NEXT_USHORT( p );
377         ValueFormat = FT_NEXT_USHORT( p );
378
379         otv_Coverage_validate( table + Coverage, valid, -1 );
380         otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */
381       }
382       break;
383
384     case 2:     /* SinglePosFormat2 */
385       {
386         FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
387
388
389         OTV_LIMIT_CHECK( 6 );
390         Coverage    = FT_NEXT_USHORT( p );
391         ValueFormat = FT_NEXT_USHORT( p );
392         ValueCount  = FT_NEXT_USHORT( p );
393
394         OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
395
396         len_value = otv_value_length( ValueFormat );
397
398         otv_Coverage_validate( table + Coverage, valid, ValueCount );
399
400         OTV_LIMIT_CHECK( ValueCount * len_value );
401
402         /* Value */
403         for ( ; ValueCount > 0; ValueCount-- )
404         {
405           otv_ValueRecord_validate( p, ValueFormat, valid );
406           p += len_value;
407         }
408       }
409       break;
410
411     default:
412       FT_INVALID_FORMAT;
413     }
414
415     OTV_EXIT;
416   }
417
418
419   /*************************************************************************/
420   /*************************************************************************/
421   /*****                                                               *****/
422   /*****                     GPOS LOOKUP TYPE 2                        *****/
423   /*****                                                               *****/
424   /*************************************************************************/
425   /*************************************************************************/
426
427   static void
428   otv_PairSet_validate( FT_Bytes       table,
429                         FT_UInt        format1,
430                         FT_UInt        format2,
431                         OTV_Validator  valid )
432   {
433     FT_Bytes  p = table;
434     FT_UInt   value_len1, value_len2, PairValueCount;
435
436
437     OTV_NAME_ENTER( "PairSet" );
438
439     OTV_LIMIT_CHECK( 2 );
440     PairValueCount = FT_NEXT_USHORT( p );
441
442     OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
443
444     value_len1 = otv_value_length( format1 );
445     value_len2 = otv_value_length( format2 );
446
447     OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
448
449     /* PairValueRecord */
450     for ( ; PairValueCount > 0; PairValueCount-- )
451     {
452       p += 2;       /* skip SecondGlyph */
453
454       if ( format1 )
455         otv_ValueRecord_validate( p, format1, valid ); /* Value1 */
456       p += value_len1;
457
458       if ( format2 )
459         otv_ValueRecord_validate( p, format2, valid ); /* Value2 */
460       p += value_len2;
461     }
462
463     OTV_EXIT;
464   }
465
466
467   /* sets valid->extra3 (pointer to base table) */
468
469   static void
470   otv_PairPos_validate( FT_Bytes       table,
471                         OTV_Validator  valid )
472   {
473     FT_Bytes  p = table;
474     FT_UInt   PosFormat;
475
476
477     OTV_NAME_ENTER( "PairPos" );
478
479     OTV_LIMIT_CHECK( 2 );
480     PosFormat = FT_NEXT_USHORT( p );
481
482     OTV_TRACE(( " (format %d)\n", PosFormat ));
483
484     valid->extra3 = table;
485
486     switch ( PosFormat )
487     {
488     case 1:     /* PairPosFormat1 */
489       {
490         FT_UInt  Coverage, ValueFormat1, ValueFormat2, PairSetCount;
491
492
493         OTV_LIMIT_CHECK( 8 );
494         Coverage     = FT_NEXT_USHORT( p );
495         ValueFormat1 = FT_NEXT_USHORT( p );
496         ValueFormat2 = FT_NEXT_USHORT( p );
497         PairSetCount = FT_NEXT_USHORT( p );
498
499         OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount ));
500
501         otv_Coverage_validate( table + Coverage, valid, -1 );
502
503         OTV_LIMIT_CHECK( PairSetCount * 2 );
504
505         /* PairSetOffset */
506         for ( ; PairSetCount > 0; PairSetCount-- )
507           otv_PairSet_validate( table + FT_NEXT_USHORT( p ),
508                                 ValueFormat1, ValueFormat2, valid );
509       }
510       break;
511
512     case 2:     /* PairPosFormat2 */
513       {
514         FT_UInt  Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2;
515         FT_UInt  ClassCount1, ClassCount2, len_value1, len_value2, count;
516
517
518         OTV_LIMIT_CHECK( 14 );
519         Coverage     = FT_NEXT_USHORT( p );
520         ValueFormat1 = FT_NEXT_USHORT( p );
521         ValueFormat2 = FT_NEXT_USHORT( p );
522         ClassDef1    = FT_NEXT_USHORT( p );
523         ClassDef2    = FT_NEXT_USHORT( p );
524         ClassCount1  = FT_NEXT_USHORT( p );
525         ClassCount2  = FT_NEXT_USHORT( p );
526
527         OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 ));
528         OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 ));
529
530         len_value1 = otv_value_length( ValueFormat1 );
531         len_value2 = otv_value_length( ValueFormat2 );
532
533         otv_Coverage_validate( table + Coverage, valid, -1 );
534         otv_ClassDef_validate( table + ClassDef1, valid );
535         otv_ClassDef_validate( table + ClassDef2, valid );
536
537         OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
538                      ( len_value1 + len_value2 ) );
539
540         /* Class1Record */
541         for ( ; ClassCount1 > 0; ClassCount1-- )
542         {
543           /* Class2Record */
544           for ( count = ClassCount2; count > 0; count-- )
545           {
546             if ( ValueFormat1 )
547               /* Value1 */
548               otv_ValueRecord_validate( p, ValueFormat1, valid );
549             p += len_value1;
550
551             if ( ValueFormat2 )
552               /* Value2 */
553               otv_ValueRecord_validate( p, ValueFormat2, valid );
554             p += len_value2;
555           }
556         }
557       }
558       break;
559
560     default:
561       FT_INVALID_FORMAT;
562     }
563
564     OTV_EXIT;
565   }
566
567
568   /*************************************************************************/
569   /*************************************************************************/
570   /*****                                                               *****/
571   /*****                     GPOS LOOKUP TYPE 3                        *****/
572   /*****                                                               *****/
573   /*************************************************************************/
574   /*************************************************************************/
575
576   static void
577   otv_CursivePos_validate( FT_Bytes       table,
578                            OTV_Validator  valid )
579   {
580     FT_Bytes  p = table;
581     FT_UInt   PosFormat;
582
583
584     OTV_NAME_ENTER( "CursivePos" );
585
586     OTV_LIMIT_CHECK( 2 );
587     PosFormat = FT_NEXT_USHORT( p );
588
589     OTV_TRACE(( " (format %d)\n", PosFormat ));
590
591     switch ( PosFormat )
592     {
593     case 1:     /* CursivePosFormat1 */
594       {
595         FT_UInt   table_size;
596         FT_UInt   Coverage, EntryExitCount;
597
598         OTV_OPTIONAL_TABLE( EntryAnchor );
599         OTV_OPTIONAL_TABLE( ExitAnchor  );
600
601
602         OTV_LIMIT_CHECK( 4 );
603         Coverage       = FT_NEXT_USHORT( p );
604         EntryExitCount = FT_NEXT_USHORT( p );
605
606         OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
607
608         otv_Coverage_validate( table + Coverage, valid, EntryExitCount );
609
610         OTV_LIMIT_CHECK( EntryExitCount * 4 );
611
612         table_size = EntryExitCount * 4 + 4;
613
614         /* EntryExitRecord */
615         for ( ; EntryExitCount > 0; EntryExitCount-- )
616         {
617           OTV_OPTIONAL_OFFSET( EntryAnchor );
618           OTV_OPTIONAL_OFFSET( ExitAnchor  );
619
620           OTV_SIZE_CHECK( EntryAnchor );
621           if ( EntryAnchor )
622             otv_Anchor_validate( table + EntryAnchor, valid );
623
624           OTV_SIZE_CHECK( ExitAnchor );
625           if ( ExitAnchor )
626             otv_Anchor_validate( table + ExitAnchor, valid );
627         }
628       }
629       break;
630
631     default:
632       FT_INVALID_FORMAT;
633     }
634
635     OTV_EXIT;
636   }
637
638
639   /*************************************************************************/
640   /*************************************************************************/
641   /*****                                                               *****/
642   /*****                     GPOS LOOKUP TYPE 4                        *****/
643   /*****                                                               *****/
644   /*************************************************************************/
645   /*************************************************************************/
646
647   /* UNDOCUMENTED (in OpenType 1.5):              */
648   /* BaseRecord tables can contain NULL pointers. */
649
650   /* sets valid->extra2 (1) */
651
652   static void
653   otv_MarkBasePos_validate( FT_Bytes       table,
654                             OTV_Validator  valid )
655   {
656     FT_Bytes  p = table;
657     FT_UInt   PosFormat;
658
659
660     OTV_NAME_ENTER( "MarkBasePos" );
661
662     OTV_LIMIT_CHECK( 2 );
663     PosFormat = FT_NEXT_USHORT( p );
664
665     OTV_TRACE(( " (format %d)\n", PosFormat ));
666
667     switch ( PosFormat )
668     {
669     case 1:
670       valid->extra2 = 1;
671       OTV_NEST2( MarkBasePosFormat1, BaseArray );
672       OTV_RUN( table, valid );
673       break;
674
675     default:
676       FT_INVALID_FORMAT;
677     }
678
679     OTV_EXIT;
680   }
681
682
683   /*************************************************************************/
684   /*************************************************************************/
685   /*****                                                               *****/
686   /*****                     GPOS LOOKUP TYPE 5                        *****/
687   /*****                                                               *****/
688   /*************************************************************************/
689   /*************************************************************************/
690
691   /* sets valid->extra2 (1) */
692
693   static void
694   otv_MarkLigPos_validate( FT_Bytes       table,
695                            OTV_Validator  valid )
696   {
697     FT_Bytes  p = table;
698     FT_UInt   PosFormat;
699
700
701     OTV_NAME_ENTER( "MarkLigPos" );
702
703     OTV_LIMIT_CHECK( 2 );
704     PosFormat = FT_NEXT_USHORT( p );
705
706     OTV_TRACE(( " (format %d)\n", PosFormat ));
707
708     switch ( PosFormat )
709     {
710     case 1:
711       valid->extra2 = 1;
712       OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
713       OTV_RUN( table, valid );
714       break;
715
716     default:
717       FT_INVALID_FORMAT;
718     }
719
720     OTV_EXIT;
721   }
722
723
724   /*************************************************************************/
725   /*************************************************************************/
726   /*****                                                               *****/
727   /*****                     GPOS LOOKUP TYPE 6                        *****/
728   /*****                                                               *****/
729   /*************************************************************************/
730   /*************************************************************************/
731
732   /* sets valid->extra2 (0) */
733
734   static void
735   otv_MarkMarkPos_validate( FT_Bytes       table,
736                             OTV_Validator  valid )
737   {
738     FT_Bytes  p = table;
739     FT_UInt   PosFormat;
740
741
742     OTV_NAME_ENTER( "MarkMarkPos" );
743
744     OTV_LIMIT_CHECK( 2 );
745     PosFormat = FT_NEXT_USHORT( p );
746
747     OTV_TRACE(( " (format %d)\n", PosFormat ));
748
749     switch ( PosFormat )
750     {
751     case 1:
752       valid->extra2 = 0;
753       OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
754       OTV_RUN( table, valid );
755       break;
756
757     default:
758       FT_INVALID_FORMAT;
759     }
760
761     OTV_EXIT;
762   }
763
764
765   /*************************************************************************/
766   /*************************************************************************/
767   /*****                                                               *****/
768   /*****                     GPOS LOOKUP TYPE 7                        *****/
769   /*****                                                               *****/
770   /*************************************************************************/
771   /*************************************************************************/
772
773   /* sets valid->extra1 (lookup count) */
774
775   static void
776   otv_ContextPos_validate( FT_Bytes       table,
777                            OTV_Validator  valid )
778   {
779     FT_Bytes  p = table;
780     FT_UInt   PosFormat;
781
782
783     OTV_NAME_ENTER( "ContextPos" );
784
785     OTV_LIMIT_CHECK( 2 );
786     PosFormat = FT_NEXT_USHORT( p );
787
788     OTV_TRACE(( " (format %d)\n", PosFormat ));
789
790     switch ( PosFormat )
791     {
792     case 1:
793       /* no need to check glyph indices/classes used as input for these */
794       /* context rules since even invalid glyph indices/classes return  */
795       /* meaningful results                                             */
796
797       valid->extra1 = valid->lookup_count;
798       OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
799       OTV_RUN( table, valid );
800       break;
801
802     case 2:
803       /* no need to check glyph indices/classes used as input for these */
804       /* context rules since even invalid glyph indices/classes return  */
805       /* meaningful results                                             */
806
807       OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
808       OTV_RUN( table, valid );
809       break;
810
811     case 3:
812       OTV_NEST1( ContextPosFormat3 );
813       OTV_RUN( table, valid );
814       break;
815
816     default:
817       FT_INVALID_FORMAT;
818     }
819
820     OTV_EXIT;
821   }
822
823
824   /*************************************************************************/
825   /*************************************************************************/
826   /*****                                                               *****/
827   /*****                     GPOS LOOKUP TYPE 8                        *****/
828   /*****                                                               *****/
829   /*************************************************************************/
830   /*************************************************************************/
831
832   /* sets valid->extra1 (lookup count) */
833
834   static void
835   otv_ChainContextPos_validate( FT_Bytes       table,
836                                 OTV_Validator  valid )
837   {
838     FT_Bytes  p = table;
839     FT_UInt   PosFormat;
840
841
842     OTV_NAME_ENTER( "ChainContextPos" );
843
844     OTV_LIMIT_CHECK( 2 );
845     PosFormat = FT_NEXT_USHORT( p );
846
847     OTV_TRACE(( " (format %d)\n", PosFormat ));
848
849     switch ( PosFormat )
850     {
851     case 1:
852       /* no need to check glyph indices/classes used as input for these */
853       /* context rules since even invalid glyph indices/classes return  */
854       /* meaningful results                                             */
855
856       valid->extra1 = valid->lookup_count;
857       OTV_NEST3( ChainContextPosFormat1,
858                  ChainPosRuleSet, ChainPosRule );
859       OTV_RUN( table, valid );
860       break;
861
862     case 2:
863       /* no need to check glyph indices/classes used as input for these */
864       /* context rules since even invalid glyph indices/classes return  */
865       /* meaningful results                                             */
866
867       OTV_NEST3( ChainContextPosFormat2,
868                  ChainPosClassSet, ChainPosClassRule );
869       OTV_RUN( table, valid );
870       break;
871
872     case 3:
873       OTV_NEST1( ChainContextPosFormat3 );
874       OTV_RUN( table, valid );
875       break;
876
877     default:
878       FT_INVALID_FORMAT;
879     }
880
881     OTV_EXIT;
882   }
883
884
885   /*************************************************************************/
886   /*************************************************************************/
887   /*****                                                               *****/
888   /*****                     GPOS LOOKUP TYPE 9                        *****/
889   /*****                                                               *****/
890   /*************************************************************************/
891   /*************************************************************************/
892
893   /* uses valid->type_funcs */
894
895   static void
896   otv_ExtensionPos_validate( FT_Bytes       table,
897                              OTV_Validator  valid )
898   {
899     FT_Bytes  p = table;
900     FT_UInt   PosFormat;
901
902
903     OTV_NAME_ENTER( "ExtensionPos" );
904
905     OTV_LIMIT_CHECK( 2 );
906     PosFormat = FT_NEXT_USHORT( p );
907
908     OTV_TRACE(( " (format %d)\n", PosFormat ));
909
910     switch ( PosFormat )
911     {
912     case 1:     /* ExtensionPosFormat1 */
913       {
914         FT_UInt            ExtensionLookupType;
915         FT_ULong           ExtensionOffset;
916         OTV_Validate_Func  validate;
917
918
919         OTV_LIMIT_CHECK( 6 );
920         ExtensionLookupType = FT_NEXT_USHORT( p );
921         ExtensionOffset     = FT_NEXT_ULONG( p );
922
923         if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
924           FT_INVALID_DATA;
925
926         validate = valid->type_funcs[ExtensionLookupType - 1];
927         validate( table + ExtensionOffset, valid );
928       }
929       break;
930
931     default:
932       FT_INVALID_FORMAT;
933     }
934
935     OTV_EXIT;
936   }
937
938
939   static const OTV_Validate_Func  otv_gpos_validate_funcs[9] =
940   {
941     otv_SinglePos_validate,
942     otv_PairPos_validate,
943     otv_CursivePos_validate,
944     otv_MarkBasePos_validate,
945     otv_MarkLigPos_validate,
946     otv_MarkMarkPos_validate,
947     otv_ContextPos_validate,
948     otv_ChainContextPos_validate,
949     otv_ExtensionPos_validate
950   };
951
952
953   /* sets valid->type_count */
954   /* sets valid->type_funcs */
955
956   FT_LOCAL_DEF( void )
957   otv_GPOS_subtable_validate( FT_Bytes       table,
958                               OTV_Validator  valid )
959   {
960     valid->type_count = 9;
961     valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
962
963     otv_Lookup_validate( table, valid );
964   }
965
966
967   /*************************************************************************/
968   /*************************************************************************/
969   /*****                                                               *****/
970   /*****                          GPOS TABLE                           *****/
971   /*****                                                               *****/
972   /*************************************************************************/
973   /*************************************************************************/
974
975   /* sets valid->glyph_count */
976
977   FT_LOCAL_DEF( void )
978   otv_GPOS_validate( FT_Bytes      table,
979                      FT_UInt       glyph_count,
980                      FT_Validator  ftvalid )
981   {
982     OTV_ValidatorRec  validrec;
983     OTV_Validator     valid = &validrec;
984     FT_Bytes          p     = table;
985     FT_UInt           ScriptList, FeatureList, LookupList;
986
987
988     valid->root = ftvalid;
989
990     FT_TRACE3(( "validating GPOS table\n" ));
991     OTV_INIT;
992
993     OTV_LIMIT_CHECK( 10 );
994
995     if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
996       FT_INVALID_FORMAT;
997
998     ScriptList  = FT_NEXT_USHORT( p );
999     FeatureList = FT_NEXT_USHORT( p );
1000     LookupList  = FT_NEXT_USHORT( p );
1001
1002     valid->type_count  = 9;
1003     valid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
1004     valid->glyph_count = glyph_count;
1005
1006     otv_LookupList_validate( table + LookupList,
1007                              valid );
1008     otv_FeatureList_validate( table + FeatureList, table + LookupList,
1009                               valid );
1010     otv_ScriptList_validate( table + ScriptList, table + FeatureList,
1011                              valid );
1012
1013     FT_TRACE4(( "\n" ));
1014   }
1015
1016
1017 /* END */