1 /****************************************************************************
5 * OpenType GSUB table validation (body).
7 * Copyright (C) 2004-2023 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.
23 /**************************************************************************
25 * The macro FT_COMPONENT is used in trace mode. It is an implicit
26 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
27 * messages during execution.
30 #define FT_COMPONENT otvgsub
33 /*************************************************************************/
34 /*************************************************************************/
36 /***** GSUB LOOKUP TYPE 1 *****/
38 /*************************************************************************/
39 /*************************************************************************/
41 /* uses otvalid->glyph_count */
44 otv_SingleSubst_validate( FT_Bytes table,
45 OTV_Validator otvalid )
51 OTV_NAME_ENTER( "SingleSubst" );
54 SubstFormat = FT_NEXT_USHORT( p );
56 OTV_TRACE(( " (format %d)\n", SubstFormat ));
58 switch ( SubstFormat )
60 case 1: /* SingleSubstFormat1 */
64 FT_UInt first_cov, last_cov;
65 FT_UInt first_idx, last_idx;
69 Coverage = table + FT_NEXT_USHORT( p );
70 DeltaGlyphID = FT_NEXT_SHORT( p );
72 otv_Coverage_validate( Coverage, otvalid, -1 );
74 first_cov = otv_Coverage_get_first( Coverage );
75 last_cov = otv_Coverage_get_last( Coverage );
77 /* These additions are modulo 65536. */
78 first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU;
79 last_idx = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU;
81 /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */
82 /* the largest possible glyph index is 65534. For this */
83 /* reason there can't be a wrap-around region, which would */
84 /* imply the use of the invalid glyph index 65535. */
85 if ( first_idx > last_idx )
88 if ( last_idx >= otvalid->glyph_count )
93 case 2: /* SingleSubstFormat2 */
95 FT_UInt Coverage, GlyphCount;
99 Coverage = FT_NEXT_USHORT( p );
100 GlyphCount = FT_NEXT_USHORT( p );
102 OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
104 otv_Coverage_validate( table + Coverage,
106 (FT_Int)GlyphCount );
108 OTV_LIMIT_CHECK( GlyphCount * 2 );
111 for ( ; GlyphCount > 0; GlyphCount-- )
112 if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
125 /*************************************************************************/
126 /*************************************************************************/
128 /***** GSUB LOOKUP TYPE 2 *****/
130 /*************************************************************************/
131 /*************************************************************************/
133 /* sets otvalid->extra1 (glyph count) */
136 otv_MultipleSubst_validate( FT_Bytes table,
137 OTV_Validator otvalid )
143 OTV_NAME_ENTER( "MultipleSubst" );
145 OTV_LIMIT_CHECK( 2 );
146 SubstFormat = FT_NEXT_USHORT( p );
148 OTV_TRACE(( " (format %d)\n", SubstFormat ));
150 switch ( SubstFormat )
153 otvalid->extra1 = otvalid->glyph_count;
154 OTV_NEST2( MultipleSubstFormat1, Sequence );
155 OTV_RUN( table, otvalid );
166 /*************************************************************************/
167 /*************************************************************************/
169 /***** GSUB LOOKUP TYPE 3 *****/
171 /*************************************************************************/
172 /*************************************************************************/
174 /* sets otvalid->extra1 (glyph count) */
177 otv_AlternateSubst_validate( FT_Bytes table,
178 OTV_Validator otvalid )
184 OTV_NAME_ENTER( "AlternateSubst" );
186 OTV_LIMIT_CHECK( 2 );
187 SubstFormat = FT_NEXT_USHORT( p );
189 OTV_TRACE(( " (format %d)\n", SubstFormat ));
191 switch ( SubstFormat )
194 otvalid->extra1 = otvalid->glyph_count;
195 OTV_NEST2( AlternateSubstFormat1, AlternateSet );
196 OTV_RUN( table, otvalid );
207 /*************************************************************************/
208 /*************************************************************************/
210 /***** GSUB LOOKUP TYPE 4 *****/
212 /*************************************************************************/
213 /*************************************************************************/
215 #define LigatureFunc otv_Ligature_validate
217 /* uses otvalid->glyph_count */
220 otv_Ligature_validate( FT_Bytes table,
221 OTV_Validator otvalid )
224 FT_UInt LigatureGlyph, CompCount;
229 OTV_LIMIT_CHECK( 4 );
230 LigatureGlyph = FT_NEXT_USHORT( p );
231 if ( LigatureGlyph >= otvalid->glyph_count )
234 CompCount = FT_NEXT_USHORT( p );
236 OTV_TRACE(( " (CompCount = %d)\n", CompCount ));
238 if ( CompCount == 0 )
243 OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */
245 /* no need to check the Component glyph indices */
252 otv_LigatureSubst_validate( FT_Bytes table,
253 OTV_Validator otvalid )
259 OTV_NAME_ENTER( "LigatureSubst" );
261 OTV_LIMIT_CHECK( 2 );
262 SubstFormat = FT_NEXT_USHORT( p );
264 OTV_TRACE(( " (format %d)\n", SubstFormat ));
266 switch ( SubstFormat )
269 OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature );
270 OTV_RUN( table, otvalid );
281 /*************************************************************************/
282 /*************************************************************************/
284 /***** GSUB LOOKUP TYPE 5 *****/
286 /*************************************************************************/
287 /*************************************************************************/
289 /* sets otvalid->extra1 (lookup count) */
292 otv_ContextSubst_validate( FT_Bytes table,
293 OTV_Validator otvalid )
299 OTV_NAME_ENTER( "ContextSubst" );
301 OTV_LIMIT_CHECK( 2 );
302 SubstFormat = FT_NEXT_USHORT( p );
304 OTV_TRACE(( " (format %d)\n", SubstFormat ));
306 switch ( SubstFormat )
309 /* no need to check glyph indices/classes used as input for these */
310 /* context rules since even invalid glyph indices/classes return */
311 /* meaningful results */
313 otvalid->extra1 = otvalid->lookup_count;
314 OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule );
315 OTV_RUN( table, otvalid );
319 /* no need to check glyph indices/classes used as input for these */
320 /* context rules since even invalid glyph indices/classes return */
321 /* meaningful results */
323 OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule );
324 OTV_RUN( table, otvalid );
328 OTV_NEST1( ContextSubstFormat3 );
329 OTV_RUN( table, otvalid );
340 /*************************************************************************/
341 /*************************************************************************/
343 /***** GSUB LOOKUP TYPE 6 *****/
345 /*************************************************************************/
346 /*************************************************************************/
348 /* sets otvalid->extra1 (lookup count) */
351 otv_ChainContextSubst_validate( FT_Bytes table,
352 OTV_Validator otvalid )
358 OTV_NAME_ENTER( "ChainContextSubst" );
360 OTV_LIMIT_CHECK( 2 );
361 SubstFormat = FT_NEXT_USHORT( p );
363 OTV_TRACE(( " (format %d)\n", SubstFormat ));
365 switch ( SubstFormat )
368 /* no need to check glyph indices/classes used as input for these */
369 /* context rules since even invalid glyph indices/classes return */
370 /* meaningful results */
372 otvalid->extra1 = otvalid->lookup_count;
373 OTV_NEST3( ChainContextSubstFormat1,
374 ChainSubRuleSet, ChainSubRule );
375 OTV_RUN( table, otvalid );
379 /* no need to check glyph indices/classes used as input for these */
380 /* context rules since even invalid glyph indices/classes return */
381 /* meaningful results */
383 OTV_NEST3( ChainContextSubstFormat2,
384 ChainSubClassSet, ChainSubClassRule );
385 OTV_RUN( table, otvalid );
389 OTV_NEST1( ChainContextSubstFormat3 );
390 OTV_RUN( table, otvalid );
401 /*************************************************************************/
402 /*************************************************************************/
404 /***** GSUB LOOKUP TYPE 7 *****/
406 /*************************************************************************/
407 /*************************************************************************/
409 /* uses otvalid->type_funcs */
412 otv_ExtensionSubst_validate( FT_Bytes table,
413 OTV_Validator otvalid )
419 OTV_NAME_ENTER( "ExtensionSubst" );
421 OTV_LIMIT_CHECK( 2 );
422 SubstFormat = FT_NEXT_USHORT( p );
424 OTV_TRACE(( " (format %d)\n", SubstFormat ));
426 switch ( SubstFormat )
428 case 1: /* ExtensionSubstFormat1 */
430 FT_UInt ExtensionLookupType;
431 FT_ULong ExtensionOffset;
432 OTV_Validate_Func validate;
435 OTV_LIMIT_CHECK( 6 );
436 ExtensionLookupType = FT_NEXT_USHORT( p );
437 ExtensionOffset = FT_NEXT_ULONG( p );
439 if ( ExtensionLookupType == 0 ||
440 ExtensionLookupType == 7 ||
441 ExtensionLookupType > 8 )
444 validate = otvalid->type_funcs[ExtensionLookupType - 1];
445 validate( table + ExtensionOffset, otvalid );
457 /*************************************************************************/
458 /*************************************************************************/
460 /***** GSUB LOOKUP TYPE 8 *****/
462 /*************************************************************************/
463 /*************************************************************************/
465 /* uses otvalid->glyph_count */
468 otv_ReverseChainSingleSubst_validate( FT_Bytes table,
469 OTV_Validator otvalid )
471 FT_Bytes p = table, Coverage;
473 FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount;
476 OTV_NAME_ENTER( "ReverseChainSingleSubst" );
478 OTV_LIMIT_CHECK( 2 );
479 SubstFormat = FT_NEXT_USHORT( p );
481 OTV_TRACE(( " (format %d)\n", SubstFormat ));
483 switch ( SubstFormat )
485 case 1: /* ReverseChainSingleSubstFormat1 */
486 OTV_LIMIT_CHECK( 4 );
487 Coverage = table + FT_NEXT_USHORT( p );
488 BacktrackGlyphCount = FT_NEXT_USHORT( p );
490 OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount ));
492 otv_Coverage_validate( Coverage, otvalid, -1 );
494 OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
496 for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
497 otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
499 LookaheadGlyphCount = FT_NEXT_USHORT( p );
501 OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount ));
503 OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 );
505 for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- )
506 otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
508 GlyphCount = FT_NEXT_USHORT( p );
510 OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
512 if ( GlyphCount != otv_Coverage_get_count( Coverage ) )
515 OTV_LIMIT_CHECK( GlyphCount * 2 );
518 for ( ; GlyphCount > 0; GlyphCount-- )
519 if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
532 static const OTV_Validate_Func otv_gsub_validate_funcs[8] =
534 otv_SingleSubst_validate,
535 otv_MultipleSubst_validate,
536 otv_AlternateSubst_validate,
537 otv_LigatureSubst_validate,
538 otv_ContextSubst_validate,
539 otv_ChainContextSubst_validate,
540 otv_ExtensionSubst_validate,
541 otv_ReverseChainSingleSubst_validate
545 /*************************************************************************/
546 /*************************************************************************/
548 /***** GSUB TABLE *****/
550 /*************************************************************************/
551 /*************************************************************************/
553 /* sets otvalid->type_count */
554 /* sets otvalid->type_funcs */
555 /* sets otvalid->glyph_count */
558 otv_GSUB_validate( FT_Bytes table,
560 FT_Validator ftvalid )
562 OTV_ValidatorRec otvalidrec;
563 OTV_Validator otvalid = &otvalidrec;
567 FT_UInt ScriptList, FeatureList, LookupList;
569 OTV_OPTIONAL_TABLE32( featureVariations );
572 otvalid->root = ftvalid;
574 FT_TRACE3(( "validating GSUB table\n" ));
577 OTV_LIMIT_CHECK( 4 );
579 if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */
582 version = FT_NEXT_USHORT( p ); /* minorVersion */
588 OTV_LIMIT_CHECK( 6 );
592 OTV_LIMIT_CHECK( 10 );
600 ScriptList = FT_NEXT_USHORT( p );
601 FeatureList = FT_NEXT_USHORT( p );
602 LookupList = FT_NEXT_USHORT( p );
604 otvalid->type_count = 8;
605 otvalid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs;
606 otvalid->glyph_count = glyph_count;
608 otv_LookupList_validate( table + LookupList,
610 otv_FeatureList_validate( table + FeatureList, table + LookupList,
612 otv_ScriptList_validate( table + ScriptList, table + FeatureList,
617 OTV_OPTIONAL_OFFSET32( featureVariations );
618 OTV_SIZE_CHECK32( featureVariations );
619 if ( featureVariations )
620 OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */