1 /***************************************************************************/
5 /* TrueTypeGX/AAT kern table validation (body). */
7 /* Copyright 2004, 2005, 2006, 2007 */
8 /* by suzuki toshiya, Masatake YAMATO, Red Hat K.K., */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
17 /***************************************************************************/
19 /***************************************************************************/
21 /* gxvalid is derived from both gxlayout module and otvalid module. */
22 /* Development of gxlayout is supported by the Information-technology */
23 /* Promotion Agency(IPA), Japan. */
25 /***************************************************************************/
31 #include FT_SFNT_NAMES_H
32 #include FT_SERVICE_GX_VALIDATE_H
35 /*************************************************************************/
37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
39 /* messages during execution. */
42 #define FT_COMPONENT trace_gxvkern
45 /*************************************************************************/
46 /*************************************************************************/
48 /***** Data and Types *****/
50 /*************************************************************************/
51 /*************************************************************************/
53 typedef enum GXV_kern_Version_
55 KERN_VERSION_CLASSIC
= 0x0000,
56 KERN_VERSION_NEW
= 0x0001
61 typedef enum GXV_kern_Dialect_
63 KERN_DIALECT_UNKNOWN
= 0,
64 KERN_DIALECT_MS
= FT_VALIDATE_MS
,
65 KERN_DIALECT_APPLE
= FT_VALIDATE_APPLE
,
66 KERN_DIALECT_ANY
= FT_VALIDATE_CKERN
71 typedef struct GXV_kern_DataRec_
73 GXV_kern_Version version
;
75 GXV_kern_Dialect dialect_request
;
77 } GXV_kern_DataRec
, *GXV_kern_Data
;
80 #define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field )
82 #define KERN_IS_CLASSIC( valid ) \
83 ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
84 #define KERN_IS_NEW( valid ) \
85 ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) )
87 #define KERN_DIALECT( valid ) \
88 GXV_KERN_DATA( dialect_request )
89 #define KERN_ALLOWS_MS( valid ) \
90 ( KERN_DIALECT( valid ) & KERN_DIALECT_MS )
91 #define KERN_ALLOWS_APPLE( valid ) \
92 ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE )
94 #define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 4 )
95 #define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 6 )
98 /*************************************************************************/
99 /*************************************************************************/
101 /***** SUBTABLE VALIDATORS *****/
103 /*************************************************************************/
104 /*************************************************************************/
107 /* ============================= format 0 ============================== */
110 gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table
,
113 GXV_Validator valid
)
118 FT_UShort last_gid_left
= 0;
119 FT_UShort last_gid_right
= 0;
124 GXV_NAME_ENTER( "kern format 0 pairs" );
126 for ( i
= 0; i
< nPairs
; i
++ )
134 gid_left
= FT_NEXT_USHORT( p
);
135 gxv_glyphid_validate( gid_left
, valid
);
138 gid_right
= FT_NEXT_USHORT( p
);
139 gxv_glyphid_validate( gid_right
, valid
);
141 /* Pairs of left and right GIDs must be unique and sorted. */
142 GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left
, gid_right
));
143 if ( gid_left
== last_gid_left
)
145 if ( last_gid_right
< gid_right
)
146 last_gid_right
= gid_right
;
150 else if ( last_gid_left
< gid_left
)
152 last_gid_left
= gid_left
;
153 last_gid_right
= gid_right
;
158 /* skip the kern value */
159 kernValue
= FT_NEXT_SHORT( p
);
166 gxv_kern_subtable_fmt0_validate( FT_Bytes table
,
168 GXV_Validator valid
)
170 FT_Bytes p
= table
+ GXV_KERN_SUBTABLE_HEADER_SIZE
;
176 GXV_NAME_ENTER( "kern subtable format 0" );
178 unitSize
= 2 + 2 + 2;
181 /* nPairs, searchRange, entrySelector, rangeShift */
182 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
183 gxv_BinSrchHeader_validate( p
, limit
, &unitSize
, &nPairs
, valid
);
186 gxv_kern_subtable_fmt0_pairs_validate( p
, limit
, nPairs
, valid
);
192 /* ============================= format 1 ============================== */
195 typedef struct GXV_kern_fmt1_StateOptRec_
197 FT_UShort valueTable
;
198 FT_UShort valueTable_length
;
200 } GXV_kern_fmt1_StateOptRec
, *GXV_kern_fmt1_StateOptRecData
;
204 gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table
,
206 GXV_Validator valid
)
209 GXV_kern_fmt1_StateOptRecData optdata
=
210 (GXV_kern_fmt1_StateOptRecData
)valid
->statetable
.optdata
;
213 GXV_LIMIT_CHECK( 2 );
214 optdata
->valueTable
= FT_NEXT_USHORT( p
);
219 * passed tables_size covers whole StateTable, including kern fmt1 header
222 gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size
,
223 FT_UShort classTable
,
224 FT_UShort stateArray
,
225 FT_UShort entryTable
,
226 FT_UShort
* classTable_length_p
,
227 FT_UShort
* stateArray_length_p
,
228 FT_UShort
* entryTable_length_p
,
229 GXV_Validator valid
)
235 GXV_kern_fmt1_StateOptRecData optdata
=
236 (GXV_kern_fmt1_StateOptRecData
)valid
->statetable
.optdata
;
242 o
[3] = optdata
->valueTable
;
243 l
[0] = classTable_length_p
;
244 l
[1] = stateArray_length_p
;
245 l
[2] = entryTable_length_p
;
246 l
[3] = &(optdata
->valueTable_length
);
248 gxv_set_length_by_ushort_offset( o
, l
, buff
, 4, table_size
, valid
);
253 * passed table & limit are of whole StateTable, not including subtables
256 gxv_kern_subtable_fmt1_entry_validate(
259 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p
,
262 GXV_Validator valid
)
265 FT_UShort dontAdvance
;
266 FT_UShort valueOffset
;
267 FT_UShort kernAction
;
271 FT_UNUSED( glyphOffset_p
);
274 push
= (FT_UShort
)( ( flags
>> 15 ) & 1 );
275 dontAdvance
= (FT_UShort
)( ( flags
>> 14 ) & 1 );
276 valueOffset
= (FT_UShort
)( flags
& 0x3FFF );
279 GXV_kern_fmt1_StateOptRecData vt_rec
=
280 (GXV_kern_fmt1_StateOptRecData
)valid
->statetable
.optdata
;
284 if ( valueOffset
< vt_rec
->valueTable
)
287 p
= table
+ valueOffset
;
288 limit
= table
+ vt_rec
->valueTable
+ vt_rec
->valueTable_length
;
290 GXV_LIMIT_CHECK( 2 + 2 );
291 kernAction
= FT_NEXT_USHORT( p
);
292 kernValue
= FT_NEXT_USHORT( p
);
298 gxv_kern_subtable_fmt1_validate( FT_Bytes table
,
300 GXV_Validator valid
)
303 GXV_kern_fmt1_StateOptRec vt_rec
;
306 GXV_NAME_ENTER( "kern subtable format 1" );
308 valid
->statetable
.optdata
=
310 valid
->statetable
.optdata_load_func
=
311 gxv_kern_subtable_fmt1_valueTable_load
;
312 valid
->statetable
.subtable_setup_func
=
313 gxv_kern_subtable_fmt1_subtable_setup
;
314 valid
->statetable
.entry_glyphoffset_fmt
=
315 GXV_GLYPHOFFSET_NONE
;
316 valid
->statetable
.entry_validate_func
=
317 gxv_kern_subtable_fmt1_entry_validate
;
319 gxv_StateTable_validate( p
, limit
, valid
);
325 /* ================ Data for Class-Based Subtables 2, 3 ================ */
327 typedef enum GXV_kern_ClassSpec_
332 } GXV_kern_ClassSpec
;
335 /* ============================= format 2 ============================== */
337 /* ---------------------- format 2 specific data ----------------------- */
339 typedef struct GXV_kern_subtable_fmt2_DataRec_
343 FT_UShort offset_min
[2];
344 FT_UShort offset_max
[2];
345 const FT_String
* class_tag
[2];
346 GXV_odtect_Range odtect
;
348 } GXV_kern_subtable_fmt2_DataRec
, *GXV_kern_subtable_fmt2_Data
;
351 #define GXV_KERN_FMT2_DATA( field ) \
352 ( ( (GXV_kern_subtable_fmt2_DataRec *) \
353 ( GXV_KERN_DATA( subtable_data ) ) )->field )
356 /* -------------------------- utility functions ----------------------- */
359 gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table
,
361 GXV_kern_ClassSpec spec
,
362 GXV_Validator valid
)
364 const FT_String
* tag
= GXV_KERN_FMT2_DATA( class_tag
[spec
] );
365 GXV_odtect_Range odtect
= GXV_KERN_FMT2_DATA( odtect
);
368 FT_UShort firstGlyph
;
372 GXV_NAME_ENTER( "kern format 2 classTable" );
374 GXV_LIMIT_CHECK( 2 + 2 );
375 firstGlyph
= FT_NEXT_USHORT( p
);
376 nGlyphs
= FT_NEXT_USHORT( p
);
377 GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n",
378 tag
, firstGlyph
, nGlyphs
));
380 gxv_glyphid_validate( firstGlyph
, valid
);
381 gxv_glyphid_validate( (FT_UShort
)( firstGlyph
+ nGlyphs
- 1 ), valid
);
383 gxv_array_getlimits_ushort( p
, p
+ ( 2 * nGlyphs
),
384 &( GXV_KERN_FMT2_DATA( offset_min
[spec
] ) ),
385 &( GXV_KERN_FMT2_DATA( offset_max
[spec
] ) ),
388 gxv_odtect_add_range( table
, 2 * nGlyphs
, tag
, odtect
);
395 gxv_kern_subtable_fmt2_validate( FT_Bytes table
,
397 GXV_Validator valid
)
399 GXV_ODTECT( 3, odtect
);
400 GXV_kern_subtable_fmt2_DataRec fmt2_rec
=
401 { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL
};
403 FT_Bytes p
= table
+ GXV_KERN_SUBTABLE_HEADER_SIZE
;
404 FT_UShort leftOffsetTable
;
405 FT_UShort rightOffsetTable
;
408 GXV_NAME_ENTER( "kern subtable format 2" );
410 GXV_ODTECT_INIT( odtect
);
411 fmt2_rec
.odtect
= odtect
;
412 GXV_KERN_DATA( subtable_data
) = &fmt2_rec
;
414 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
415 GXV_KERN_FMT2_DATA( rowWidth
) = FT_NEXT_USHORT( p
);
416 leftOffsetTable
= FT_NEXT_USHORT( p
);
417 rightOffsetTable
= FT_NEXT_USHORT( p
);
418 GXV_KERN_FMT2_DATA( array
) = FT_NEXT_USHORT( p
);
420 GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth
) ));
423 GXV_LIMIT_CHECK( leftOffsetTable
);
424 GXV_LIMIT_CHECK( rightOffsetTable
);
425 GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array
) );
427 gxv_kern_subtable_fmt2_clstbl_validate( table
+ leftOffsetTable
, limit
,
428 GXV_KERN_CLS_L
, valid
);
430 gxv_kern_subtable_fmt2_clstbl_validate( table
+ rightOffsetTable
, limit
,
431 GXV_KERN_CLS_R
, valid
);
433 if ( GXV_KERN_FMT2_DATA( offset_min
[GXV_KERN_CLS_L
] ) +
434 GXV_KERN_FMT2_DATA( offset_min
[GXV_KERN_CLS_R
] )
435 < GXV_KERN_FMT2_DATA( array
) )
438 gxv_odtect_add_range( table
+ GXV_KERN_FMT2_DATA( array
),
439 GXV_KERN_FMT2_DATA( offset_max
[GXV_KERN_CLS_L
] )
440 + GXV_KERN_FMT2_DATA( offset_max
[GXV_KERN_CLS_R
] )
441 - GXV_KERN_FMT2_DATA( array
),
444 gxv_odtect_validate( odtect
, valid
);
450 /* ============================= format 3 ============================== */
453 gxv_kern_subtable_fmt3_validate( FT_Bytes table
,
455 GXV_Validator valid
)
457 FT_Bytes p
= table
+ GXV_KERN_SUBTABLE_HEADER_SIZE
;
458 FT_UShort glyphCount
;
459 FT_Byte kernValueCount
;
460 FT_Byte leftClassCount
;
461 FT_Byte rightClassCount
;
465 GXV_NAME_ENTER( "kern subtable format 3" );
467 GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
468 glyphCount
= FT_NEXT_USHORT( p
);
469 kernValueCount
= FT_NEXT_BYTE( p
);
470 leftClassCount
= FT_NEXT_BYTE( p
);
471 rightClassCount
= FT_NEXT_BYTE( p
);
472 flags
= FT_NEXT_BYTE( p
);
474 if ( valid
->face
->num_glyphs
!= glyphCount
)
476 GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n",
477 valid
->face
->num_glyphs
, glyphCount
));
478 if ( valid
->root
->level
>= FT_VALIDATE_PARANOID
)
483 * just skip kernValue[kernValueCount]
485 GXV_LIMIT_CHECK( 2 * kernValueCount
);
486 p
+= 2 * kernValueCount
;
489 * check leftClass[gid] < leftClassCount
495 GXV_LIMIT_CHECK( glyphCount
);
496 gxv_array_getlimits_byte( p
, p
+ glyphCount
, &min
, &max
, valid
);
497 p
+= valid
->subtable_length
;
499 if ( leftClassCount
< max
)
504 * check rightClass[gid] < rightClassCount
510 GXV_LIMIT_CHECK( glyphCount
);
511 gxv_array_getlimits_byte( p
, p
+ glyphCount
, &min
, &max
, valid
);
512 p
+= valid
->subtable_length
;
514 if ( rightClassCount
< max
)
519 * check kernIndex[i, j] < kernValueCount
525 for ( i
= 0; i
< leftClassCount
; i
++ )
527 for ( j
= 0; j
< rightClassCount
; j
++ )
529 GXV_LIMIT_CHECK( 1 );
530 if ( kernValueCount
< FT_NEXT_BYTE( p
) )
536 valid
->subtable_length
= p
- table
;
543 gxv_kern_coverage_new_apple_validate( FT_UShort coverage
,
545 GXV_Validator valid
)
547 /* new Apple-dialect */
548 FT_Bool kernVertical
;
549 FT_Bool kernCrossStream
;
550 FT_Bool kernVariation
;
555 /* reserved bits = 0 */
556 if ( coverage
& 0x1FFC )
559 kernVertical
= FT_BOOL( ( coverage
>> 15 ) & 1 );
560 kernCrossStream
= FT_BOOL( ( coverage
>> 14 ) & 1 );
561 kernVariation
= FT_BOOL( ( coverage
>> 13 ) & 1 );
563 *format
= (FT_UShort
)( coverage
& 0x0003 );
565 GXV_TRACE(( "new Apple-dialect: "
566 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
567 !kernVertical
, kernCrossStream
, kernVariation
, *format
));
569 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
576 gxv_kern_coverage_classic_apple_validate( FT_UShort coverage
,
578 GXV_Validator valid
)
580 /* classic Apple-dialect */
582 FT_Bool cross_stream
;
585 /* check expected flags, but don't check if MS-dialect is impossible */
586 if ( !( coverage
& 0xFD00 ) && KERN_ALLOWS_MS( valid
) )
589 /* reserved bits = 0 */
590 if ( coverage
& 0x02FC )
593 horizontal
= FT_BOOL( ( coverage
>> 15 ) & 1 );
594 cross_stream
= FT_BOOL( ( coverage
>> 13 ) & 1 );
596 *format
= (FT_UShort
)( coverage
& 0x0003 );
598 GXV_TRACE(( "classic Apple-dialect: "
599 "horizontal=%d, cross-stream=%d, format=%d\n",
600 horizontal
, cross_stream
, *format
));
602 /* format 1 requires GX State Machine, too new for classic */
606 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
613 gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage
,
615 GXV_Validator valid
)
617 /* classic Microsoft-dialect */
620 FT_Bool cross_stream
;
626 /* reserved bits = 0 */
627 if ( coverage
& 0xFDF0 )
630 horizontal
= FT_BOOL( coverage
& 1 );
631 minimum
= FT_BOOL( ( coverage
>> 1 ) & 1 );
632 cross_stream
= FT_BOOL( ( coverage
>> 2 ) & 1 );
633 override
= FT_BOOL( ( coverage
>> 3 ) & 1 );
635 *format
= (FT_UShort
)( ( coverage
>> 8 ) & 0x0003 );
637 GXV_TRACE(( "classic Microsoft-dialect: "
638 "horizontal=%d, minimum=%d, cross-stream=%d, "
639 "override=%d, format=%d\n",
640 horizontal
, minimum
, cross_stream
, override
, *format
));
644 "kerning values in Microsoft format 2 subtable are ignored\n" ));
650 /*************************************************************************/
651 /*************************************************************************/
655 /*************************************************************************/
656 /*************************************************************************/
658 static GXV_kern_Dialect
659 gxv_kern_coverage_validate( FT_UShort coverage
,
661 GXV_Validator valid
)
663 GXV_kern_Dialect result
= KERN_DIALECT_UNKNOWN
;
666 GXV_NAME_ENTER( "validating coverage" );
668 GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage
));
670 if ( KERN_IS_NEW( valid
) )
672 if ( gxv_kern_coverage_new_apple_validate( coverage
,
676 result
= KERN_DIALECT_APPLE
;
681 if ( KERN_IS_CLASSIC( valid
) && KERN_ALLOWS_APPLE( valid
) )
683 if ( gxv_kern_coverage_classic_apple_validate( coverage
,
687 result
= KERN_DIALECT_APPLE
;
692 if ( KERN_IS_CLASSIC( valid
) && KERN_ALLOWS_MS( valid
) )
694 if ( gxv_kern_coverage_classic_microsoft_validate( coverage
,
698 result
= KERN_DIALECT_MS
;
703 GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
712 gxv_kern_subtable_validate( FT_Bytes table
,
714 GXV_Validator valid
)
717 FT_UShort version
= 0; /* MS only: subtable version, unused */
718 FT_ULong length
; /* MS: 16bit, Apple: 32bit*/
720 FT_UShort tupleIndex
= 0; /* Apple only */
722 FT_UShort format
= 255; /* subtable format */
725 GXV_NAME_ENTER( "kern subtable" );
727 GXV_LIMIT_CHECK( 2 + 2 + 2 );
728 u16
[0] = FT_NEXT_USHORT( p
); /* Apple: length_hi MS: version */
729 u16
[1] = FT_NEXT_USHORT( p
); /* Apple: length_lo MS: length */
730 coverage
= FT_NEXT_USHORT( p
);
732 switch ( gxv_kern_coverage_validate( coverage
, &format
, valid
) )
734 case KERN_DIALECT_MS
:
738 GXV_TRACE(( "Subtable version = %d\n", version
));
739 GXV_TRACE(( "Subtable length = %d\n", length
));
742 case KERN_DIALECT_APPLE
:
744 length
= ( u16
[0] << 16 ) + u16
[1];
746 GXV_TRACE(( "Subtable length = %d\n", length
));
748 if ( KERN_IS_NEW( valid
) )
750 GXV_LIMIT_CHECK( 2 );
751 tupleIndex
= FT_NEXT_USHORT( p
);
752 GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex
));
758 GXV_TRACE(( "cannot detect subtable dialect, "
759 "just skip %d byte\n", length
));
763 /* formats 1, 2, 3 require the position of the start of this subtable */
765 gxv_kern_subtable_fmt0_validate( table
, table
+ length
, valid
);
766 else if ( format
== 1 )
767 gxv_kern_subtable_fmt1_validate( table
, table
+ length
, valid
);
768 else if ( format
== 2 )
769 gxv_kern_subtable_fmt2_validate( table
, table
+ length
, valid
);
770 else if ( format
== 3 )
771 gxv_kern_subtable_fmt3_validate( table
, table
+ length
, valid
);
776 valid
->subtable_length
= length
;
781 /*************************************************************************/
782 /*************************************************************************/
784 /***** kern TABLE *****/
786 /*************************************************************************/
787 /*************************************************************************/
790 gxv_kern_validate_generic( FT_Bytes table
,
792 FT_Bool classic_only
,
793 GXV_kern_Dialect dialect_request
,
794 FT_Validator ftvalid
)
796 GXV_ValidatorRec validrec
;
797 GXV_Validator valid
= &validrec
;
799 GXV_kern_DataRec kernrec
;
800 GXV_kern_Data kern
= &kernrec
;
805 FT_ULong nTables
= 0;
809 valid
->root
= ftvalid
;
810 valid
->table_data
= kern
;
813 FT_TRACE3(( "validating `kern' table\n" ));
815 KERN_DIALECT( valid
) = dialect_request
;
817 GXV_LIMIT_CHECK( 2 );
818 GXV_KERN_DATA( version
) = (GXV_kern_Version
)FT_NEXT_USHORT( p
);
819 GXV_TRACE(( "version 0x%04x (higher 16bit)\n",
820 GXV_KERN_DATA( version
) ));
822 if ( 0x0001 < GXV_KERN_DATA( version
) )
824 else if ( KERN_IS_CLASSIC( valid
) )
826 GXV_LIMIT_CHECK( 2 );
827 nTables
= FT_NEXT_USHORT( p
);
829 else if ( KERN_IS_NEW( valid
) )
834 if ( 0x0000 != FT_NEXT_USHORT( p
) )
837 GXV_LIMIT_CHECK( 4 );
838 nTables
= FT_NEXT_ULONG( p
);
841 for ( i
= 0; i
< nTables
; i
++ )
843 GXV_TRACE(( "validating subtable %d/%d\n", i
, nTables
));
844 /* p should be 32bit-aligned? */
845 gxv_kern_subtable_validate( p
, 0, valid
);
846 p
+= valid
->subtable_length
;
854 gxv_kern_validate( FT_Bytes table
,
856 FT_Validator ftvalid
)
858 gxv_kern_validate_generic( table
, face
, 0, KERN_DIALECT_ANY
, ftvalid
);
863 gxv_kern_validate_classic( FT_Bytes table
,
865 FT_Int dialect_flags
,
866 FT_Validator ftvalid
)
868 GXV_kern_Dialect dialect_request
;
871 dialect_request
= (GXV_kern_Dialect
)dialect_flags
;
872 gxv_kern_validate_generic( table
, face
, 1, dialect_request
, ftvalid
);