1 /*******************************************************************
5 * TrueType Open GDEF table support.
7 * Copyright 1996-1999 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 ******************************************************************/
29 #define GDEF_ID Build_Extension_ID( 'G', 'D', 'E', 'F' )
32 static TT_Error
Load_AttachList( TTO_AttachList
* al
,
34 static TT_Error
Load_LigCaretList( TTO_LigCaretList
* lcl
,
37 static void Free_AttachList( TTO_AttachList
* al
);
38 static void Free_LigCaretList( TTO_LigCaretList
* lcl
);
40 static void Free_NewGlyphClasses( TTO_GDEFHeader
* gdef
);
44 /**********************
46 **********************/
49 static TT_Error
GDEF_Create( void* ext
,
52 DEFINE_LOAD_LOCALS( face
->stream
);
54 TTO_GDEFHeader
* gdef
= (TTO_GDEFHeader
*)ext
;
63 /* a null offset indicates that there is no GDEF table */
67 /* we store the start offset and the size of the subtable */
69 table
= TT_LookUp_Table( face
, TTAG_GDEF
);
71 return TT_Err_Ok
; /* The table is optional */
73 if ( FILE_Seek( face
->dirTables
[table
].Offset
) ||
77 gdef
->offset
= FILE_Pos() - 4L; /* undo ACCESS_Frame() */
78 gdef
->Version
= GET_ULong();
88 static TT_Error
GDEF_Destroy( void* ext
,
91 TTO_GDEFHeader
* gdef
= (TTO_GDEFHeader
*)ext
;
101 Free_LigCaretList( &gdef
->LigCaretList
);
102 Free_AttachList( &gdef
->AttachList
);
103 Free_ClassDefinition( &gdef
->GlyphClassDef
);
104 Free_ClassDefinition( &gdef
->MarkAttachClassDef
);
106 Free_NewGlyphClasses( gdef
);
114 TT_Error
TT_Init_GDEF_Extension( TT_Engine engine
)
116 PEngine_Instance _engine
= HANDLE_Engine( engine
);
120 return TT_Err_Invalid_Engine
;
122 return TT_Register_Extension( _engine
,
124 sizeof ( TTO_GDEFHeader
),
131 TT_Error
TT_Load_GDEF_Table( TT_Face face
,
132 TTO_GDEFHeader
* retptr
)
134 ULong cur_offset
, new_offset
, base_offset
;
138 TTO_GDEFHeader
* gdef
;
140 PFace faze
= HANDLE_Face( face
);
144 return TT_Err_Invalid_Argument
;
147 return TT_Err_Invalid_Face_Handle
;
149 error
= TT_Extension_Get( faze
, GDEF_ID
, (void**)&gdef
);
153 if ( gdef
->offset
== 0 )
154 return TT_Err_Table_Missing
; /* no GDEF table; nothing to do */
156 /* now access stream */
158 if ( USE_Stream( faze
->stream
, stream
) )
161 base_offset
= gdef
->offset
;
165 if ( FILE_Seek( base_offset
+ 4L ) ||
169 new_offset
= GET_UShort();
173 /* all GDEF subtables are optional */
177 new_offset
+= base_offset
;
179 /* only classes 1-4 are allowed here */
181 cur_offset
= FILE_Pos();
182 if ( FILE_Seek( new_offset
) ||
183 ( error
= Load_ClassDefinition( &gdef
->GlyphClassDef
, 5,
184 faze
) ) != TT_Err_Ok
)
186 (void)FILE_Seek( cur_offset
);
189 gdef
->GlyphClassDef
.loaded
= FALSE
;
191 if ( ACCESS_Frame( 2L ) )
194 new_offset
= GET_UShort();
200 new_offset
+= base_offset
;
202 cur_offset
= FILE_Pos();
203 if ( FILE_Seek( new_offset
) ||
204 ( error
= Load_AttachList( &gdef
->AttachList
,
205 faze
) ) != TT_Err_Ok
)
207 (void)FILE_Seek( cur_offset
);
210 gdef
->AttachList
.loaded
= FALSE
;
212 if ( ACCESS_Frame( 2L ) )
215 new_offset
= GET_UShort();
221 new_offset
+= base_offset
;
223 cur_offset
= FILE_Pos();
224 if ( FILE_Seek( new_offset
) ||
225 ( error
= Load_LigCaretList( &gdef
->LigCaretList
,
226 faze
) ) != TT_Err_Ok
)
228 (void)FILE_Seek( cur_offset
);
231 gdef
->LigCaretList
.loaded
= FALSE
;
233 /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We
234 first have to scan the LookupFlag values to find out whether we
235 must load it or not. Here we only store the current file offset. */
237 gdef
->MarkAttachClassDef_offset
= FILE_Pos();
238 gdef
->MarkAttachClassDef
.loaded
= FALSE
;
241 gdef
->NewGlyphClasses
= NULL
;
245 DONE_Stream( stream
);
250 Free_AttachList( &gdef
->AttachList
);
253 Free_ClassDefinition( &gdef
->GlyphClassDef
);
257 DONE_Stream( stream
);
264 /*******************************
265 * AttachList related functions
266 *******************************/
271 static TT_Error
Load_AttachPoint( TTO_AttachPoint
* ap
,
274 DEFINE_LOAD_LOCALS( input
->stream
);
280 if ( ACCESS_Frame( 2L ) )
283 count
= ap
->PointCount
= GET_UShort();
287 ap
->PointIndex
= NULL
;
291 if ( ALLOC_ARRAY( ap
->PointIndex
, count
, UShort
) )
296 if ( ACCESS_Frame( count
* 2L ) )
302 for ( n
= 0; n
< count
; n
++ )
303 pi
[n
] = GET_UShort();
312 static void Free_AttachPoint( TTO_AttachPoint
* ap
)
314 FREE( ap
->PointIndex
);
320 static TT_Error
Load_AttachList( TTO_AttachList
* al
,
323 DEFINE_LOAD_LOCALS( input
->stream
);
326 ULong cur_offset
, new_offset
, base_offset
;
331 base_offset
= FILE_Pos();
333 if ( ACCESS_Frame( 2L ) )
336 new_offset
= GET_UShort() + base_offset
;
340 cur_offset
= FILE_Pos();
341 if ( FILE_Seek( new_offset
) ||
342 ( error
= Load_Coverage( &al
->Coverage
, input
) ) != TT_Err_Ok
)
344 (void)FILE_Seek( cur_offset
);
346 if ( ACCESS_Frame( 2L ) )
349 count
= al
->GlyphCount
= GET_UShort();
353 al
->AttachPoint
= NULL
;
355 if ( ALLOC_ARRAY( al
->AttachPoint
, count
, TTO_AttachPoint
) )
358 ap
= al
->AttachPoint
;
360 for ( n
= 0; n
< count
; n
++ )
362 if ( ACCESS_Frame( 2L ) )
365 new_offset
= GET_UShort() + base_offset
;
369 cur_offset
= FILE_Pos();
370 if ( FILE_Seek( new_offset
) ||
371 ( error
= Load_AttachPoint( &ap
[n
], input
) ) != TT_Err_Ok
)
373 (void)FILE_Seek( cur_offset
);
381 for ( n
= 0; n
< count
; n
++ )
382 Free_AttachPoint( &ap
[n
] );
387 Free_Coverage( &al
->Coverage
);
392 static void Free_AttachList( TTO_AttachList
* al
)
402 if ( al
->AttachPoint
)
404 count
= al
->GlyphCount
;
405 ap
= al
->AttachPoint
;
407 for ( n
= 0; n
< count
; n
++ )
408 Free_AttachPoint( &ap
[n
] );
413 Free_Coverage( &al
->Coverage
);
418 /*********************************
419 * LigCaretList related functions
420 *********************************/
423 /* CaretValueFormat1 */
424 /* CaretValueFormat2 */
425 /* CaretValueFormat3 */
426 /* CaretValueFormat4 */
428 static TT_Error
Load_CaretValue( TTO_CaretValue
* cv
,
431 DEFINE_LOAD_LOCALS( input
->stream
);
433 ULong cur_offset
, new_offset
, base_offset
;
436 base_offset
= FILE_Pos();
438 if ( ACCESS_Frame( 2L ) )
441 cv
->CaretValueFormat
= GET_UShort();
445 switch ( cv
->CaretValueFormat
)
448 if ( ACCESS_Frame( 2L ) )
451 cv
->cvf
.cvf1
.Coordinate
= GET_Short();
458 if ( ACCESS_Frame( 2L ) )
461 cv
->cvf
.cvf2
.CaretValuePoint
= GET_UShort();
468 if ( ACCESS_Frame( 4L ) )
471 cv
->cvf
.cvf3
.Coordinate
= GET_Short();
473 new_offset
= GET_UShort() + base_offset
;
477 cur_offset
= FILE_Pos();
478 if ( FILE_Seek( new_offset
) ||
479 ( error
= Load_Device( &cv
->cvf
.cvf3
.Device
,
480 input
) ) != TT_Err_Ok
)
482 (void)FILE_Seek( cur_offset
);
487 if ( ACCESS_Frame( 2L ) )
490 cv
->cvf
.cvf4
.IdCaretValue
= GET_UShort();
496 return TTO_Err_Invalid_GDEF_SubTable_Format
;
503 static void Free_CaretValue( TTO_CaretValue
* cv
)
505 if ( cv
->CaretValueFormat
== 3 )
506 Free_Device( &cv
->cvf
.cvf3
.Device
);
512 static TT_Error
Load_LigGlyph( TTO_LigGlyph
* lg
,
515 DEFINE_LOAD_LOCALS( input
->stream
);
518 ULong cur_offset
, new_offset
, base_offset
;
523 base_offset
= FILE_Pos();
525 if ( ACCESS_Frame( 2L ) )
528 count
= lg
->CaretCount
= GET_UShort();
532 lg
->CaretValue
= NULL
;
534 if ( ALLOC_ARRAY( lg
->CaretValue
, count
, TTO_CaretValue
) )
539 for ( n
= 0; n
< count
; n
++ )
541 if ( ACCESS_Frame( 2L ) )
544 new_offset
= GET_UShort() + base_offset
;
548 cur_offset
= FILE_Pos();
549 if ( FILE_Seek( new_offset
) ||
550 ( error
= Load_CaretValue( &cv
[n
], input
) ) != TT_Err_Ok
)
552 (void)FILE_Seek( cur_offset
);
558 for ( n
= 0; n
< count
; n
++ )
559 Free_CaretValue( &cv
[n
] );
566 static void Free_LigGlyph( TTO_LigGlyph
* lg
)
573 if ( lg
->CaretValue
)
575 count
= lg
->CaretCount
;
578 for ( n
= 0; n
< count
; n
++ )
579 Free_CaretValue( &cv
[n
] );
588 static TT_Error
Load_LigCaretList( TTO_LigCaretList
* lcl
,
591 DEFINE_LOAD_LOCALS( input
->stream
);
594 ULong cur_offset
, new_offset
, base_offset
;
599 base_offset
= FILE_Pos();
601 if ( ACCESS_Frame( 2L ) )
604 new_offset
= GET_UShort() + base_offset
;
608 cur_offset
= FILE_Pos();
609 if ( FILE_Seek( new_offset
) ||
610 ( error
= Load_Coverage( &lcl
->Coverage
, input
) ) != TT_Err_Ok
)
612 (void)FILE_Seek( cur_offset
);
614 if ( ACCESS_Frame( 2L ) )
617 count
= lcl
->LigGlyphCount
= GET_UShort();
621 lcl
->LigGlyph
= NULL
;
623 if ( ALLOC_ARRAY( lcl
->LigGlyph
, count
, TTO_LigGlyph
) )
628 for ( n
= 0; n
< count
; n
++ )
630 if ( ACCESS_Frame( 2L ) )
633 new_offset
= GET_UShort() + base_offset
;
637 cur_offset
= FILE_Pos();
638 if ( FILE_Seek( new_offset
) ||
639 ( error
= Load_LigGlyph( &lg
[n
], input
) ) != TT_Err_Ok
)
641 (void)FILE_Seek( cur_offset
);
649 for ( n
= 0; n
< count
; n
++ )
650 Free_LigGlyph( &lg
[n
] );
655 Free_Coverage( &lcl
->Coverage
);
660 static void Free_LigCaretList( TTO_LigCaretList
* lcl
)
672 count
= lcl
->LigGlyphCount
;
675 for ( n
= 0; n
< count
; n
++ )
676 Free_LigGlyph( &lg
[n
] );
681 Free_Coverage( &lcl
->Coverage
);
691 static UShort
Get_New_Class( TTO_GDEFHeader
* gdef
,
695 UShort glyph_index
, array_index
;
698 TTO_ClassRangeRecord
* gcrr
;
702 if ( glyphID
>= gdef
->LastGlyph
)
705 gcrr
= gdef
->GlyphClassDef
.cd
.cd2
.ClassRangeRecord
;
706 ngc
= gdef
->NewGlyphClasses
;
708 if ( glyphID
< gcrr
[index
].Start
)
712 glyph_index
= glyphID
;
714 glyph_index
= glyphID
- gcrr
[index
- 1].End
- 1;
718 array_index
= index
+ 1;
719 glyph_index
= glyphID
- gcrr
[index
].End
- 1;
722 byte
= ngc
[array_index
][glyph_index
/ 4 + 1];
723 bits
= byte
>> ( 16 - ( glyph_index
% 4 + 1 ) * 4 );
725 return bits
& 0x000F;
730 TT_Error
TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader
* gdef
,
732 TT_UShort
* property
)
739 if ( !gdef
|| !property
)
740 return TT_Err_Invalid_Argument
;
742 /* first, we check for mark attach classes */
744 if ( gdef
->MarkAttachClassDef
.loaded
)
746 error
= Get_Class( &gdef
->MarkAttachClassDef
, glyphID
, &class, &index
);
747 if ( error
&& error
!= TTO_Err_Not_Covered
)
751 *property
= class << 8;
756 error
= Get_Class( &gdef
->GlyphClassDef
, glyphID
, &class, &index
);
757 if ( error
&& error
!= TTO_Err_Not_Covered
)
760 /* if we have a constructed class table, check whether additional
761 values have been assigned */
763 if ( error
== TTO_Err_Not_Covered
&& gdef
->NewGlyphClasses
)
764 class = Get_New_Class( gdef
, glyphID
, index
);
768 case UNCLASSIFIED_GLYPH
:
773 *property
= TTO_BASE_GLYPH
;
777 *property
= TTO_LIGATURE
;
781 *property
= TTO_MARK
;
784 case COMPONENT_GLYPH
:
785 *property
= TTO_COMPONENT
;
793 static TT_Error
Make_ClassRange( TTO_ClassDefinition
* cd
,
801 TTO_ClassDefFormat2
* cdf2
;
802 TTO_ClassRangeRecord
* crr
;
807 cdf2
->ClassRangeCount
++;
809 if ( REALLOC_ARRAY( cdf2
->ClassRangeRecord
, cdf2
->ClassRangeCount
,
810 TTO_ClassRangeRecord
) )
813 crr
= cdf2
->ClassRangeRecord
;
814 index
= cdf2
->ClassRangeCount
- 1;
816 crr
[index
].Start
= start
;
817 crr
[index
].End
= end
;
818 crr
[index
].Class
= class;
820 cd
->Defined
[class] = TRUE
;
827 TT_Error
TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader
* gdef
,
828 TT_UShort num_glyphs
,
829 TT_UShort glyph_count
,
830 TT_UShort
* glyph_array
,
831 TT_UShort
* class_array
)
833 UShort start
, curr_glyph
, curr_class
;
837 TTO_ClassDefinition
* gcd
;
838 TTO_ClassRangeRecord
* gcrr
;
842 if ( !gdef
|| !glyph_array
|| !class_array
)
843 return TT_Err_Invalid_Argument
;
845 gcd
= &gdef
->GlyphClassDef
;
847 /* We build a format 2 table */
849 gcd
->ClassFormat
= 2;
851 /* A GlyphClassDef table contains at most 5 different class values */
853 if ( ALLOC_ARRAY( gcd
->Defined
, 5, Bool
) )
856 gcd
->cd
.cd2
.ClassRangeCount
= 0;
857 gcd
->cd
.cd2
.ClassRangeRecord
= NULL
;
859 start
= glyph_array
[0];
860 curr_class
= class_array
[0];
863 if ( curr_class
>= 5 )
865 error
= TT_Err_Invalid_Argument
;
871 for ( n
= 0; n
<= glyph_count
; n
++ )
873 if ( curr_glyph
== glyph_array
[n
] && curr_class
== class_array
[n
] )
875 if ( n
== glyph_count
)
877 if ( ( error
= Make_ClassRange( gcd
, start
,
879 curr_class
) ) != TT_Err_Ok
)
884 if ( curr_glyph
== 0xFFFF )
886 error
= TT_Err_Invalid_Argument
;
895 if ( ( error
= Make_ClassRange( gcd
, start
,
897 curr_class
) ) != TT_Err_Ok
)
900 if ( curr_glyph
> glyph_array
[n
] )
902 error
= TT_Err_Invalid_Argument
;
906 start
= glyph_array
[n
];
907 curr_class
= class_array
[n
];
910 if ( curr_class
>= 5 )
912 error
= TT_Err_Invalid_Argument
;
916 if ( n
== glyph_count
)
918 if ( ( error
= Make_ClassRange( gcd
, start
,
920 curr_class
) ) != TT_Err_Ok
)
925 if ( curr_glyph
== 0xFFFF )
927 error
= TT_Err_Invalid_Argument
;
936 /* now prepare the arrays for class values assigned during the lookup
939 if ( ALLOC_ARRAY( gdef
->NewGlyphClasses
,
940 gcd
->cd
.cd2
.ClassRangeCount
+ 1, UShort
* ) )
943 count
= gcd
->cd
.cd2
.ClassRangeCount
;
944 gcrr
= gcd
->cd
.cd2
.ClassRangeRecord
;
945 ngc
= gdef
->NewGlyphClasses
;
947 /* We allocate arrays for all glyphs not covered by the class range
948 records. Each element holds four class values. */
952 if ( ALLOC_ARRAY( ngc
[0], gcrr
[0].Start
/ 4 + 1, UShort
) )
956 for ( n
= 1; n
< count
; n
++ )
958 if ( gcrr
[n
].Start
- gcrr
[n
- 1].End
> 1 )
959 if ( ALLOC_ARRAY( ngc
[n
],
960 ( gcrr
[n
].Start
- gcrr
[n
- 1].End
- 1 ) / 4 + 1,
965 if ( gcrr
[count
- 1].End
!= num_glyphs
- 1 )
967 if ( ALLOC_ARRAY( ngc
[count
],
968 ( num_glyphs
- gcrr
[count
- 1].End
- 1 ) / 4 + 1,
973 gdef
->LastGlyph
= num_glyphs
- 1;
975 gdef
->MarkAttachClassDef_offset
= 0L;
976 gdef
->MarkAttachClassDef
.loaded
= FALSE
;
981 for ( n
= 0; n
< count
; n
++ )
985 FREE( gdef
->NewGlyphClasses
);
988 FREE( gcd
->cd
.cd2
.ClassRangeRecord
);
991 FREE( gcd
->Defined
);
996 static void Free_NewGlyphClasses( TTO_GDEFHeader
* gdef
)
1002 if ( gdef
->NewGlyphClasses
)
1004 count
= gdef
->GlyphClassDef
.cd
.cd2
.ClassRangeCount
+ 1;
1005 ngc
= gdef
->NewGlyphClasses
;
1007 for ( n
= 0; n
< count
; n
++ )
1015 TT_Error
Add_Glyph_Property( TTO_GDEFHeader
* gdef
,
1020 UShort
class, new_class
, index
;
1021 UShort byte
, bits
, mask
;
1022 UShort array_index
, glyph_index
;
1024 TTO_ClassRangeRecord
* gcrr
;
1028 error
= Get_Class( &gdef
->GlyphClassDef
, glyphID
, &class, &index
);
1029 if ( error
&& error
!= TTO_Err_Not_Covered
)
1032 /* we don't accept glyphs covered in `GlyphClassDef' */
1035 return TTO_Err_Not_Covered
;
1040 new_class
= UNCLASSIFIED_GLYPH
;
1043 case TTO_BASE_GLYPH
:
1044 new_class
= SIMPLE_GLYPH
;
1048 new_class
= LIGATURE_GLYPH
;
1052 new_class
= MARK_GLYPH
;
1056 new_class
= COMPONENT_GLYPH
;
1060 return TT_Err_Invalid_Argument
;
1063 gcrr
= gdef
->GlyphClassDef
.cd
.cd2
.ClassRangeRecord
;
1064 ngc
= gdef
->NewGlyphClasses
;
1066 if ( glyphID
< gcrr
[index
].Start
)
1070 glyph_index
= glyphID
;
1072 glyph_index
= glyphID
- gcrr
[index
- 1].End
- 1;
1076 array_index
= index
+ 1;
1077 glyph_index
= glyphID
- gcrr
[index
].End
- 1;
1080 byte
= ngc
[array_index
][glyph_index
/ 4 + 1];
1081 bits
= byte
>> ( 16 - ( glyph_index
% 4 + 1 ) * 4 );
1082 class = bits
& 0x000F;
1084 /* we don't overwrite existing entries */
1088 bits
= new_class
<< ( 16 - ( glyph_index
% 4 + 1 ) * 4 );
1089 mask
= ~( 0x000F << ( 16 - ( glyph_index
% 4 + 1 ) * 4 ) );
1091 ngc
[array_index
][glyph_index
/ 4 + 1] &= mask
;
1092 ngc
[array_index
][glyph_index
/ 4 + 1] |= bits
;