1 /***************************************************************************/
5 /* OpenType GPOS table validation (body). */
7 /* Copyright 2002, 2004, 2005, 2006, 2007, 2008 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
24 /*************************************************************************/
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. */
31 #define FT_COMPONENT trace_otvgpos
35 otv_Anchor_validate( FT_Bytes table
,
36 OTV_Validator valid
);
39 otv_MarkArray_validate( FT_Bytes table
,
40 OTV_Validator valid
);
43 /*************************************************************************/
44 /*************************************************************************/
46 /***** UTILITY FUNCTIONS *****/
48 /*************************************************************************/
49 /*************************************************************************/
51 #define BaseArrayFunc otv_x_sxy
52 #define LigatureAttachFunc otv_x_sxy
53 #define Mark2ArrayFunc otv_x_sxy
55 /* uses valid->extra1 (counter) */
56 /* uses valid->extra2 (boolean to handle NULL anchor field) */
59 otv_x_sxy( FT_Bytes table
,
63 FT_UInt Count
, count1
, table_size
;
70 Count
= FT_NEXT_USHORT( p
);
72 OTV_TRACE(( " (Count = %d)\n", Count
));
74 OTV_LIMIT_CHECK( Count
* valid
->extra1
* 2 );
76 table_size
= Count
* valid
->extra1
* 2 + 2;
78 for ( ; Count
> 0; Count
-- )
79 for ( count1
= valid
->extra1
; count1
> 0; count1
-- )
81 OTV_OPTIONAL_TABLE( anchor_offset
);
84 OTV_OPTIONAL_OFFSET( anchor_offset
);
88 OTV_SIZE_CHECK( anchor_offset
);
90 otv_Anchor_validate( table
+ anchor_offset
, valid
);
93 otv_Anchor_validate( table
+ anchor_offset
, valid
);
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
104 /* sets valid->extra1 (class count) */
107 otv_u_O_O_u_O_O( FT_Bytes table
,
108 OTV_Validator valid
)
111 FT_UInt Coverage1
, Coverage2
, ClassCount
;
112 FT_UInt Array1
, Array2
;
113 OTV_Validate_Func func
;
118 p
+= 2; /* skip PosFormat */
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
);
127 otv_Coverage_validate( table
+ Coverage1
, valid
, -1 );
128 otv_Coverage_validate( table
+ Coverage2
, valid
, -1 );
130 otv_MarkArray_validate( table
+ Array1
, valid
);
132 valid
->nesting_level
++;
133 func
= valid
->func
[valid
->nesting_level
];
134 valid
->extra1
= ClassCount
;
136 func( table
+ Array2
, valid
);
138 valid
->nesting_level
--;
144 /*************************************************************************/
145 /*************************************************************************/
147 /***** VALUE RECORDS *****/
149 /*************************************************************************/
150 /*************************************************************************/
153 otv_value_length( FT_UInt format
)
158 count
= ( ( format
& 0xAA ) >> 1 ) + ( format
& 0x55 );
159 count
= ( ( count
& 0xCC ) >> 2 ) + ( count
& 0x33 );
160 count
= ( ( count
& 0xF0 ) >> 4 ) + ( count
& 0x0F );
166 /* uses valid->extra3 (pointer to base table) */
169 otv_ValueRecord_validate( FT_Bytes table
,
171 OTV_Validator valid
)
176 #ifdef FT_DEBUG_LEVEL_TRACE
181 OTV_NAME_ENTER( "ValueRecord" );
183 /* display `format' in dual representation */
184 for ( loop
= 7; loop
>= 0; loop
-- )
187 res
+= ( format
>> loop
) & 1;
190 OTV_TRACE(( " (format 0b%08lx)\n", res
));
193 if ( format
>= 0x100 )
196 for ( count
= 4; count
> 0; count
-- )
200 /* XPlacement, YPlacement, XAdvance, YAdvance */
201 OTV_LIMIT_CHECK( 2 );
208 for ( count
= 4; count
> 0; count
-- )
212 FT_PtrDist table_size
;
214 OTV_OPTIONAL_TABLE( device
);
217 /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
218 OTV_LIMIT_CHECK( 2 );
219 OTV_OPTIONAL_OFFSET( device
);
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 */
225 table_size
= p
- valid
->extra3
;
227 OTV_SIZE_CHECK( device
);
229 otv_Device_validate( valid
->extra3
+ device
, valid
);
238 /*************************************************************************/
239 /*************************************************************************/
241 /***** ANCHORS *****/
243 /*************************************************************************/
244 /*************************************************************************/
247 otv_Anchor_validate( FT_Bytes table
,
248 OTV_Validator valid
)
251 FT_UInt AnchorFormat
;
254 OTV_NAME_ENTER( "Anchor");
256 OTV_LIMIT_CHECK( 6 );
257 AnchorFormat
= FT_NEXT_USHORT( p
);
259 OTV_TRACE(( " (format %d)\n", AnchorFormat
));
261 p
+= 4; /* skip XCoordinate and YCoordinate */
263 switch ( AnchorFormat
)
269 OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */
276 OTV_OPTIONAL_TABLE( XDeviceTable
);
277 OTV_OPTIONAL_TABLE( YDeviceTable
);
280 OTV_LIMIT_CHECK( 4 );
281 OTV_OPTIONAL_OFFSET( XDeviceTable
);
282 OTV_OPTIONAL_OFFSET( YDeviceTable
);
286 OTV_SIZE_CHECK( XDeviceTable
);
288 otv_Device_validate( table
+ XDeviceTable
, valid
);
290 OTV_SIZE_CHECK( YDeviceTable
);
292 otv_Device_validate( table
+ YDeviceTable
, valid
);
304 /*************************************************************************/
305 /*************************************************************************/
307 /***** MARK ARRAYS *****/
309 /*************************************************************************/
310 /*************************************************************************/
313 otv_MarkArray_validate( FT_Bytes table
,
314 OTV_Validator valid
)
320 OTV_NAME_ENTER( "MarkArray" );
322 OTV_LIMIT_CHECK( 2 );
323 MarkCount
= FT_NEXT_USHORT( p
);
325 OTV_TRACE(( " (MarkCount = %d)\n", MarkCount
));
327 OTV_LIMIT_CHECK( MarkCount
* 4 );
330 for ( ; MarkCount
> 0; MarkCount
-- )
332 p
+= 2; /* skip Class */
334 otv_Anchor_validate( table
+ FT_NEXT_USHORT( p
), valid
);
341 /*************************************************************************/
342 /*************************************************************************/
344 /***** GPOS LOOKUP TYPE 1 *****/
346 /*************************************************************************/
347 /*************************************************************************/
349 /* sets valid->extra3 (pointer to base table) */
352 otv_SinglePos_validate( FT_Bytes table
,
353 OTV_Validator valid
)
359 OTV_NAME_ENTER( "SinglePos" );
361 OTV_LIMIT_CHECK( 2 );
362 PosFormat
= FT_NEXT_USHORT( p
);
364 OTV_TRACE(( " (format %d)\n", PosFormat
));
366 valid
->extra3
= table
;
370 case 1: /* SinglePosFormat1 */
372 FT_UInt Coverage
, ValueFormat
;
375 OTV_LIMIT_CHECK( 4 );
376 Coverage
= FT_NEXT_USHORT( p
);
377 ValueFormat
= FT_NEXT_USHORT( p
);
379 otv_Coverage_validate( table
+ Coverage
, valid
, -1 );
380 otv_ValueRecord_validate( p
, ValueFormat
, valid
); /* Value */
384 case 2: /* SinglePosFormat2 */
386 FT_UInt Coverage
, ValueFormat
, ValueCount
, len_value
;
389 OTV_LIMIT_CHECK( 6 );
390 Coverage
= FT_NEXT_USHORT( p
);
391 ValueFormat
= FT_NEXT_USHORT( p
);
392 ValueCount
= FT_NEXT_USHORT( p
);
394 OTV_TRACE(( " (ValueCount = %d)\n", ValueCount
));
396 len_value
= otv_value_length( ValueFormat
);
398 otv_Coverage_validate( table
+ Coverage
, valid
, ValueCount
);
400 OTV_LIMIT_CHECK( ValueCount
* len_value
);
403 for ( ; ValueCount
> 0; ValueCount
-- )
405 otv_ValueRecord_validate( p
, ValueFormat
, valid
);
419 /*************************************************************************/
420 /*************************************************************************/
422 /***** GPOS LOOKUP TYPE 2 *****/
424 /*************************************************************************/
425 /*************************************************************************/
428 otv_PairSet_validate( FT_Bytes table
,
431 OTV_Validator valid
)
434 FT_UInt value_len1
, value_len2
, PairValueCount
;
437 OTV_NAME_ENTER( "PairSet" );
439 OTV_LIMIT_CHECK( 2 );
440 PairValueCount
= FT_NEXT_USHORT( p
);
442 OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount
));
444 value_len1
= otv_value_length( format1
);
445 value_len2
= otv_value_length( format2
);
447 OTV_LIMIT_CHECK( PairValueCount
* ( value_len1
+ value_len2
+ 2 ) );
449 /* PairValueRecord */
450 for ( ; PairValueCount
> 0; PairValueCount
-- )
452 p
+= 2; /* skip SecondGlyph */
455 otv_ValueRecord_validate( p
, format1
, valid
); /* Value1 */
459 otv_ValueRecord_validate( p
, format2
, valid
); /* Value2 */
467 /* sets valid->extra3 (pointer to base table) */
470 otv_PairPos_validate( FT_Bytes table
,
471 OTV_Validator valid
)
477 OTV_NAME_ENTER( "PairPos" );
479 OTV_LIMIT_CHECK( 2 );
480 PosFormat
= FT_NEXT_USHORT( p
);
482 OTV_TRACE(( " (format %d)\n", PosFormat
));
484 valid
->extra3
= table
;
488 case 1: /* PairPosFormat1 */
490 FT_UInt Coverage
, ValueFormat1
, ValueFormat2
, PairSetCount
;
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
);
499 OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount
));
501 otv_Coverage_validate( table
+ Coverage
, valid
, -1 );
503 OTV_LIMIT_CHECK( PairSetCount
* 2 );
506 for ( ; PairSetCount
> 0; PairSetCount
-- )
507 otv_PairSet_validate( table
+ FT_NEXT_USHORT( p
),
508 ValueFormat1
, ValueFormat2
, valid
);
512 case 2: /* PairPosFormat2 */
514 FT_UInt Coverage
, ValueFormat1
, ValueFormat2
, ClassDef1
, ClassDef2
;
515 FT_UInt ClassCount1
, ClassCount2
, len_value1
, len_value2
, count
;
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
);
527 OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1
));
528 OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2
));
530 len_value1
= otv_value_length( ValueFormat1
);
531 len_value2
= otv_value_length( ValueFormat2
);
533 otv_Coverage_validate( table
+ Coverage
, valid
, -1 );
534 otv_ClassDef_validate( table
+ ClassDef1
, valid
);
535 otv_ClassDef_validate( table
+ ClassDef2
, valid
);
537 OTV_LIMIT_CHECK( ClassCount1
* ClassCount2
*
538 ( len_value1
+ len_value2
) );
541 for ( ; ClassCount1
> 0; ClassCount1
-- )
544 for ( count
= ClassCount2
; count
> 0; count
-- )
548 otv_ValueRecord_validate( p
, ValueFormat1
, valid
);
553 otv_ValueRecord_validate( p
, ValueFormat2
, valid
);
568 /*************************************************************************/
569 /*************************************************************************/
571 /***** GPOS LOOKUP TYPE 3 *****/
573 /*************************************************************************/
574 /*************************************************************************/
577 otv_CursivePos_validate( FT_Bytes table
,
578 OTV_Validator valid
)
584 OTV_NAME_ENTER( "CursivePos" );
586 OTV_LIMIT_CHECK( 2 );
587 PosFormat
= FT_NEXT_USHORT( p
);
589 OTV_TRACE(( " (format %d)\n", PosFormat
));
593 case 1: /* CursivePosFormat1 */
596 FT_UInt Coverage
, EntryExitCount
;
598 OTV_OPTIONAL_TABLE( EntryAnchor
);
599 OTV_OPTIONAL_TABLE( ExitAnchor
);
602 OTV_LIMIT_CHECK( 4 );
603 Coverage
= FT_NEXT_USHORT( p
);
604 EntryExitCount
= FT_NEXT_USHORT( p
);
606 OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount
));
608 otv_Coverage_validate( table
+ Coverage
, valid
, EntryExitCount
);
610 OTV_LIMIT_CHECK( EntryExitCount
* 4 );
612 table_size
= EntryExitCount
* 4 + 4;
614 /* EntryExitRecord */
615 for ( ; EntryExitCount
> 0; EntryExitCount
-- )
617 OTV_OPTIONAL_OFFSET( EntryAnchor
);
618 OTV_OPTIONAL_OFFSET( ExitAnchor
);
620 OTV_SIZE_CHECK( EntryAnchor
);
622 otv_Anchor_validate( table
+ EntryAnchor
, valid
);
624 OTV_SIZE_CHECK( ExitAnchor
);
626 otv_Anchor_validate( table
+ ExitAnchor
, valid
);
639 /*************************************************************************/
640 /*************************************************************************/
642 /***** GPOS LOOKUP TYPE 4 *****/
644 /*************************************************************************/
645 /*************************************************************************/
647 /* UNDOCUMENTED (in OpenType 1.5): */
648 /* BaseRecord tables can contain NULL pointers. */
650 /* sets valid->extra2 (1) */
653 otv_MarkBasePos_validate( FT_Bytes table
,
654 OTV_Validator valid
)
660 OTV_NAME_ENTER( "MarkBasePos" );
662 OTV_LIMIT_CHECK( 2 );
663 PosFormat
= FT_NEXT_USHORT( p
);
665 OTV_TRACE(( " (format %d)\n", PosFormat
));
671 OTV_NEST2( MarkBasePosFormat1
, BaseArray
);
672 OTV_RUN( table
, valid
);
683 /*************************************************************************/
684 /*************************************************************************/
686 /***** GPOS LOOKUP TYPE 5 *****/
688 /*************************************************************************/
689 /*************************************************************************/
691 /* sets valid->extra2 (1) */
694 otv_MarkLigPos_validate( FT_Bytes table
,
695 OTV_Validator valid
)
701 OTV_NAME_ENTER( "MarkLigPos" );
703 OTV_LIMIT_CHECK( 2 );
704 PosFormat
= FT_NEXT_USHORT( p
);
706 OTV_TRACE(( " (format %d)\n", PosFormat
));
712 OTV_NEST3( MarkLigPosFormat1
, LigatureArray
, LigatureAttach
);
713 OTV_RUN( table
, valid
);
724 /*************************************************************************/
725 /*************************************************************************/
727 /***** GPOS LOOKUP TYPE 6 *****/
729 /*************************************************************************/
730 /*************************************************************************/
732 /* sets valid->extra2 (0) */
735 otv_MarkMarkPos_validate( FT_Bytes table
,
736 OTV_Validator valid
)
742 OTV_NAME_ENTER( "MarkMarkPos" );
744 OTV_LIMIT_CHECK( 2 );
745 PosFormat
= FT_NEXT_USHORT( p
);
747 OTV_TRACE(( " (format %d)\n", PosFormat
));
753 OTV_NEST2( MarkMarkPosFormat1
, Mark2Array
);
754 OTV_RUN( table
, valid
);
765 /*************************************************************************/
766 /*************************************************************************/
768 /***** GPOS LOOKUP TYPE 7 *****/
770 /*************************************************************************/
771 /*************************************************************************/
773 /* sets valid->extra1 (lookup count) */
776 otv_ContextPos_validate( FT_Bytes table
,
777 OTV_Validator valid
)
783 OTV_NAME_ENTER( "ContextPos" );
785 OTV_LIMIT_CHECK( 2 );
786 PosFormat
= FT_NEXT_USHORT( p
);
788 OTV_TRACE(( " (format %d)\n", PosFormat
));
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 */
797 valid
->extra1
= valid
->lookup_count
;
798 OTV_NEST3( ContextPosFormat1
, PosRuleSet
, PosRule
);
799 OTV_RUN( table
, valid
);
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 */
807 OTV_NEST3( ContextPosFormat2
, PosClassSet
, PosClassRule
);
808 OTV_RUN( table
, valid
);
812 OTV_NEST1( ContextPosFormat3
);
813 OTV_RUN( table
, valid
);
824 /*************************************************************************/
825 /*************************************************************************/
827 /***** GPOS LOOKUP TYPE 8 *****/
829 /*************************************************************************/
830 /*************************************************************************/
832 /* sets valid->extra1 (lookup count) */
835 otv_ChainContextPos_validate( FT_Bytes table
,
836 OTV_Validator valid
)
842 OTV_NAME_ENTER( "ChainContextPos" );
844 OTV_LIMIT_CHECK( 2 );
845 PosFormat
= FT_NEXT_USHORT( p
);
847 OTV_TRACE(( " (format %d)\n", PosFormat
));
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 */
856 valid
->extra1
= valid
->lookup_count
;
857 OTV_NEST3( ChainContextPosFormat1
,
858 ChainPosRuleSet
, ChainPosRule
);
859 OTV_RUN( table
, valid
);
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 */
867 OTV_NEST3( ChainContextPosFormat2
,
868 ChainPosClassSet
, ChainPosClassRule
);
869 OTV_RUN( table
, valid
);
873 OTV_NEST1( ChainContextPosFormat3
);
874 OTV_RUN( table
, valid
);
885 /*************************************************************************/
886 /*************************************************************************/
888 /***** GPOS LOOKUP TYPE 9 *****/
890 /*************************************************************************/
891 /*************************************************************************/
893 /* uses valid->type_funcs */
896 otv_ExtensionPos_validate( FT_Bytes table
,
897 OTV_Validator valid
)
903 OTV_NAME_ENTER( "ExtensionPos" );
905 OTV_LIMIT_CHECK( 2 );
906 PosFormat
= FT_NEXT_USHORT( p
);
908 OTV_TRACE(( " (format %d)\n", PosFormat
));
912 case 1: /* ExtensionPosFormat1 */
914 FT_UInt ExtensionLookupType
;
915 FT_ULong ExtensionOffset
;
916 OTV_Validate_Func validate
;
919 OTV_LIMIT_CHECK( 6 );
920 ExtensionLookupType
= FT_NEXT_USHORT( p
);
921 ExtensionOffset
= FT_NEXT_ULONG( p
);
923 if ( ExtensionLookupType
== 0 || ExtensionLookupType
>= 9 )
926 validate
= valid
->type_funcs
[ExtensionLookupType
- 1];
927 validate( table
+ ExtensionOffset
, valid
);
939 static const OTV_Validate_Func otv_gpos_validate_funcs
[9] =
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
953 /* sets valid->type_count */
954 /* sets valid->type_funcs */
957 otv_GPOS_subtable_validate( FT_Bytes table
,
958 OTV_Validator valid
)
960 valid
->type_count
= 9;
961 valid
->type_funcs
= (OTV_Validate_Func
*)otv_gpos_validate_funcs
;
963 otv_Lookup_validate( table
, valid
);
967 /*************************************************************************/
968 /*************************************************************************/
970 /***** GPOS TABLE *****/
972 /*************************************************************************/
973 /*************************************************************************/
975 /* sets valid->glyph_count */
978 otv_GPOS_validate( FT_Bytes table
,
980 FT_Validator ftvalid
)
982 OTV_ValidatorRec validrec
;
983 OTV_Validator valid
= &validrec
;
985 FT_UInt ScriptList
, FeatureList
, LookupList
;
988 valid
->root
= ftvalid
;
990 FT_TRACE3(( "validating GPOS table\n" ));
993 OTV_LIMIT_CHECK( 10 );
995 if ( FT_NEXT_ULONG( p
) != 0x10000UL
) /* Version */
998 ScriptList
= FT_NEXT_USHORT( p
);
999 FeatureList
= FT_NEXT_USHORT( p
);
1000 LookupList
= FT_NEXT_USHORT( p
);
1002 valid
->type_count
= 9;
1003 valid
->type_funcs
= (OTV_Validate_Func
*)otv_gpos_validate_funcs
;
1004 valid
->glyph_count
= glyph_count
;
1006 otv_LookupList_validate( table
+ LookupList
,
1008 otv_FeatureList_validate( table
+ FeatureList
, table
+ LookupList
,
1010 otv_ScriptList_validate( table
+ ScriptList
, table
+ FeatureList
,
1013 FT_TRACE4(( "\n" ));