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" ));