1 /*******************************************************************
5 * TrueType Open GDEF table support.
7 * Copyright 1996-2000 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 ******************************************************************/
18 #include <freetype/tttags.h>
20 #include <freetype/internal/ftstream.h>
21 #include <freetype/internal/ftmemory.h>
22 #include <freetype/internal/tterrors.h>
23 #include <freetype/internal/tttypes.h>
28 #define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' )
30 static FT_Error Load_AttachList( TTO_AttachList* al,
32 static FT_Error Load_LigCaretList( TTO_LigCaretList* lcl,
35 static void Free_AttachList( TTO_AttachList* al,
37 static void Free_LigCaretList( TTO_LigCaretList* lcl,
40 static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef,
45 /**********************
47 **********************/
50 #define GDEF_ID Build_Extension_ID( 'G', 'D', 'E', 'F' )
53 static FT_Error GDEF_Create( void* ext,
56 DEFINE_LOAD_LOCALS( face->stream );
58 TTO_GDEFHeader* gdef = (TTO_GDEFHeader*)ext;
67 /* a null offset indicates that there is no GDEF table */
71 /* we store the start offset and the size of the subtable */
73 table = TT_LookUp_Table( face, TTAG_GDEF );
75 return TT_Err_Ok; /* The table is optional */
77 if ( FILE_Seek( face->dirTables[table].Offset ) ||
81 gdef->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
82 gdef->Version = GET_ULong();
92 static FT_Error GDEF_Destroy( void* ext,
95 TTO_GDEFHeader* gdef = (TTO_GDEFHeader*)ext;
105 Free_LigCaretList( &gdef->LigCaretList, memory );
106 Free_AttachList( &gdef->AttachList, memory );
107 Free_ClassDefinition( &gdef->GlyphClassDef, memory );
108 Free_ClassDefinition( &gdef->MarkAttachClassDef, memory );
110 Free_NewGlyphClasses( gdef, memory );
118 FT_Error TT_Init_GDEF_Extension( TT_Engine engine )
120 PEngine_Instance _engine = HANDLE_Engine( engine );
124 return TT_Err_Invalid_Engine;
126 return TT_Register_Extension( _engine,
128 sizeof ( TTO_GDEFHeader ),
135 FT_Error TT_Load_GDEF_Table( FT_Face face,
136 TTO_GDEFHeader** retptr )
139 FT_Memory memory = face->memory;
140 FT_Stream stream = face->stream;
141 TT_Face tt_face = (TT_Face)face;
142 FT_ULong cur_offset, new_offset, base_offset;
144 TTO_GDEFHeader* gdef;
148 return TT_Err_Invalid_Argument;
150 if (( error = tt_face->goto_table( tt_face, TTAG_GDEF, stream, 0 ) ))
153 if ( ALLOC( gdef, sizeof( *gdef ) ) )
156 gdef->memory = face->memory;
158 base_offset = FILE_Pos();
162 if ( FILE_Seek( base_offset + 4L ) ||
166 new_offset = GET_UShort();
170 /* all GDEF subtables are optional */
174 new_offset += base_offset;
176 /* only classes 1-4 are allowed here */
178 cur_offset = FILE_Pos();
179 if ( FILE_Seek( new_offset ) ||
180 ( error = Load_ClassDefinition( &gdef->GlyphClassDef, 5,
181 stream ) ) != TT_Err_Ok )
183 (void)FILE_Seek( cur_offset );
186 gdef->GlyphClassDef.loaded = FALSE;
188 if ( ACCESS_Frame( 2L ) )
191 new_offset = GET_UShort();
197 new_offset += base_offset;
199 cur_offset = FILE_Pos();
200 if ( FILE_Seek( new_offset ) ||
201 ( error = Load_AttachList( &gdef->AttachList,
202 stream ) ) != TT_Err_Ok )
204 (void)FILE_Seek( cur_offset );
207 gdef->AttachList.loaded = FALSE;
209 if ( ACCESS_Frame( 2L ) )
212 new_offset = GET_UShort();
218 new_offset += base_offset;
220 cur_offset = FILE_Pos();
221 if ( FILE_Seek( new_offset ) ||
222 ( error = Load_LigCaretList( &gdef->LigCaretList,
223 stream ) ) != TT_Err_Ok )
225 (void)FILE_Seek( cur_offset );
228 gdef->LigCaretList.loaded = FALSE;
230 /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We
231 first have to scan the LookupFlag values to find out whether we
232 must load it or not. Here we only store the current file offset. */
234 gdef->MarkAttachClassDef_offset = FILE_Pos();
235 gdef->MarkAttachClassDef.loaded = FALSE;
238 gdef->NewGlyphClasses = NULL;
241 DONE_Stream( stream );
246 Free_AttachList( &gdef->AttachList, memory );
249 Free_ClassDefinition( &gdef->GlyphClassDef, memory );
258 FT_Error TT_Done_GDEF_Table ( TTO_GDEFHeader* gdef )
260 FT_Memory memory = gdef->memory;
262 Free_LigCaretList( &gdef->LigCaretList, memory );
263 Free_AttachList( &gdef->AttachList, memory );
264 Free_ClassDefinition( &gdef->GlyphClassDef, memory );
265 Free_ClassDefinition( &gdef->MarkAttachClassDef, memory );
267 Free_NewGlyphClasses( gdef, memory );
275 /*******************************
276 * AttachList related functions
277 *******************************/
282 static FT_Error Load_AttachPoint( TTO_AttachPoint* ap,
285 FT_Memory memory = stream->memory;
292 if ( ACCESS_Frame( 2L ) )
295 count = ap->PointCount = GET_UShort();
299 ap->PointIndex = NULL;
303 if ( ALLOC_ARRAY( ap->PointIndex, count, FT_UShort ) )
308 if ( ACCESS_Frame( count * 2L ) )
314 for ( n = 0; n < count; n++ )
315 pi[n] = GET_UShort();
324 static void Free_AttachPoint( TTO_AttachPoint* ap,
327 FREE( ap->PointIndex );
333 static FT_Error Load_AttachList( TTO_AttachList* al,
336 FT_Memory memory = stream->memory;
340 FT_ULong cur_offset, new_offset, base_offset;
345 base_offset = FILE_Pos();
347 if ( ACCESS_Frame( 2L ) )
350 new_offset = GET_UShort() + base_offset;
354 cur_offset = FILE_Pos();
355 if ( FILE_Seek( new_offset ) ||
356 ( error = Load_Coverage( &al->Coverage, stream ) ) != TT_Err_Ok )
358 (void)FILE_Seek( cur_offset );
360 if ( ACCESS_Frame( 2L ) )
363 count = al->GlyphCount = GET_UShort();
367 al->AttachPoint = NULL;
369 if ( ALLOC_ARRAY( al->AttachPoint, count, TTO_AttachPoint ) )
372 ap = al->AttachPoint;
374 for ( n = 0; n < count; n++ )
376 if ( ACCESS_Frame( 2L ) )
379 new_offset = GET_UShort() + base_offset;
383 cur_offset = FILE_Pos();
384 if ( FILE_Seek( new_offset ) ||
385 ( error = Load_AttachPoint( &ap[n], stream ) ) != TT_Err_Ok )
387 (void)FILE_Seek( cur_offset );
395 for ( n = 0; n < count; n++ )
396 Free_AttachPoint( &ap[n], memory );
401 Free_Coverage( &al->Coverage, memory );
406 static void Free_AttachList( TTO_AttachList* al,
417 if ( al->AttachPoint )
419 count = al->GlyphCount;
420 ap = al->AttachPoint;
422 for ( n = 0; n < count; n++ )
423 Free_AttachPoint( &ap[n], memory );
428 Free_Coverage( &al->Coverage, memory );
433 /*********************************
434 * LigCaretList related functions
435 *********************************/
438 /* CaretValueFormat1 */
439 /* CaretValueFormat2 */
440 /* CaretValueFormat3 */
441 /* CaretValueFormat4 */
443 static FT_Error Load_CaretValue( TTO_CaretValue* cv,
448 FT_ULong cur_offset, new_offset, base_offset;
451 base_offset = FILE_Pos();
453 if ( ACCESS_Frame( 2L ) )
456 cv->CaretValueFormat = GET_UShort();
460 switch ( cv->CaretValueFormat )
463 if ( ACCESS_Frame( 2L ) )
466 cv->cvf.cvf1.Coordinate = GET_Short();
473 if ( ACCESS_Frame( 2L ) )
476 cv->cvf.cvf2.CaretValuePoint = GET_UShort();
483 if ( ACCESS_Frame( 4L ) )
486 cv->cvf.cvf3.Coordinate = GET_Short();
488 new_offset = GET_UShort() + base_offset;
492 cur_offset = FILE_Pos();
493 if ( FILE_Seek( new_offset ) ||
494 ( error = Load_Device( &cv->cvf.cvf3.Device,
495 stream ) ) != TT_Err_Ok )
497 (void)FILE_Seek( cur_offset );
502 if ( ACCESS_Frame( 2L ) )
505 cv->cvf.cvf4.IdCaretValue = GET_UShort();
511 return TTO_Err_Invalid_GDEF_SubTable_Format;
518 static void Free_CaretValue( TTO_CaretValue* cv,
521 if ( cv->CaretValueFormat == 3 )
522 Free_Device( &cv->cvf.cvf3.Device, memory );
528 static FT_Error Load_LigGlyph( TTO_LigGlyph* lg,
531 FT_Memory memory = stream->memory;
535 FT_ULong cur_offset, new_offset, base_offset;
540 base_offset = FILE_Pos();
542 if ( ACCESS_Frame( 2L ) )
545 count = lg->CaretCount = GET_UShort();
549 lg->CaretValue = NULL;
551 if ( ALLOC_ARRAY( lg->CaretValue, count, TTO_CaretValue ) )
556 for ( n = 0; n < count; n++ )
558 if ( ACCESS_Frame( 2L ) )
561 new_offset = GET_UShort() + base_offset;
565 cur_offset = FILE_Pos();
566 if ( FILE_Seek( new_offset ) ||
567 ( error = Load_CaretValue( &cv[n], stream ) ) != TT_Err_Ok )
569 (void)FILE_Seek( cur_offset );
575 for ( n = 0; n < count; n++ )
576 Free_CaretValue( &cv[n], memory );
583 static void Free_LigGlyph( TTO_LigGlyph* lg,
591 if ( lg->CaretValue )
593 count = lg->CaretCount;
596 for ( n = 0; n < count; n++ )
597 Free_CaretValue( &cv[n], memory );
606 static FT_Error Load_LigCaretList( TTO_LigCaretList* lcl,
609 FT_Memory memory = stream->memory;
613 FT_ULong cur_offset, new_offset, base_offset;
618 base_offset = FILE_Pos();
620 if ( ACCESS_Frame( 2L ) )
623 new_offset = GET_UShort() + base_offset;
627 cur_offset = FILE_Pos();
628 if ( FILE_Seek( new_offset ) ||
629 ( error = Load_Coverage( &lcl->Coverage, stream ) ) != TT_Err_Ok )
631 (void)FILE_Seek( cur_offset );
633 if ( ACCESS_Frame( 2L ) )
636 count = lcl->LigGlyphCount = GET_UShort();
640 lcl->LigGlyph = NULL;
642 if ( ALLOC_ARRAY( lcl->LigGlyph, count, TTO_LigGlyph ) )
647 for ( n = 0; n < count; n++ )
649 if ( ACCESS_Frame( 2L ) )
652 new_offset = GET_UShort() + base_offset;
656 cur_offset = FILE_Pos();
657 if ( FILE_Seek( new_offset ) ||
658 ( error = Load_LigGlyph( &lg[n], stream ) ) != TT_Err_Ok )
660 (void)FILE_Seek( cur_offset );
668 for ( n = 0; n < count; n++ )
669 Free_LigGlyph( &lg[n], memory );
674 Free_Coverage( &lcl->Coverage, memory );
679 static void Free_LigCaretList( TTO_LigCaretList* lcl,
692 count = lcl->LigGlyphCount;
695 for ( n = 0; n < count; n++ )
696 Free_LigGlyph( &lg[n], memory );
701 Free_Coverage( &lcl->Coverage, memory );
711 static FT_UShort Get_New_Class( TTO_GDEFHeader* gdef,
715 FT_UShort glyph_index, array_index;
716 FT_UShort byte, bits;
718 TTO_ClassRangeRecord* gcrr;
722 if ( glyphID >= gdef->LastGlyph )
725 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
726 ngc = gdef->NewGlyphClasses;
728 if ( glyphID < gcrr[index].Start )
732 glyph_index = glyphID;
734 glyph_index = glyphID - gcrr[index - 1].End - 1;
738 array_index = index + 1;
739 glyph_index = glyphID - gcrr[index].End - 1;
742 byte = ngc[array_index][glyph_index / 4 + 1];
743 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
745 return bits & 0x000F;
750 FT_Error TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader* gdef,
752 FT_UShort* property )
754 FT_UShort class, index;
759 if ( !gdef || !property )
760 return TT_Err_Invalid_Argument;
762 /* first, we check for mark attach classes */
764 if ( gdef->MarkAttachClassDef.loaded )
766 error = Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
767 if ( error && error != TTO_Err_Not_Covered )
771 *property = class << 8;
776 error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
777 if ( error && error != TTO_Err_Not_Covered )
780 /* if we have a constructed class table, check whether additional
781 values have been assigned */
783 if ( error == TTO_Err_Not_Covered && gdef->NewGlyphClasses )
784 class = Get_New_Class( gdef, glyphID, index );
788 case UNCLASSIFIED_GLYPH:
793 *property = TTO_BASE_GLYPH;
797 *property = TTO_LIGATURE;
801 *property = TTO_MARK;
804 case COMPONENT_GLYPH:
805 *property = TTO_COMPONENT;
813 static FT_Error Make_ClassRange( TTO_ClassDefinition* cd,
822 TTO_ClassDefFormat2* cdf2;
823 TTO_ClassRangeRecord* crr;
828 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
829 cdf2->ClassRangeCount,
830 cdf2->ClassRangeCount + 1 ,
831 TTO_ClassRangeRecord ) )
834 cdf2->ClassRangeCount++;
836 crr = cdf2->ClassRangeRecord;
837 index = cdf2->ClassRangeCount - 1;
839 crr[index].Start = start;
840 crr[index].End = end;
841 crr[index].Class = class;
843 cd->Defined[class] = TRUE;
850 FT_Error TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader* gdef,
851 FT_UShort num_glyphs,
852 FT_UShort glyph_count,
853 FT_UShort* glyph_array,
854 FT_UShort* class_array )
856 FT_UShort start, curr_glyph, curr_class;
859 FT_Memory memory = gdef->memory;
861 TTO_ClassDefinition* gcd;
862 TTO_ClassRangeRecord* gcrr;
866 if ( !gdef || !glyph_array || !class_array )
867 return TT_Err_Invalid_Argument;
869 gcd = &gdef->GlyphClassDef;
871 /* We build a format 2 table */
873 gcd->ClassFormat = 2;
875 /* A GlyphClassDef table contains at most 5 different class values */
877 if ( ALLOC_ARRAY( gcd->Defined, 5, FT_Bool ) )
880 gcd->cd.cd2.ClassRangeCount = 0;
881 gcd->cd.cd2.ClassRangeRecord = NULL;
883 start = glyph_array[0];
884 curr_class = class_array[0];
887 if ( curr_class >= 5 )
889 error = TT_Err_Invalid_Argument;
895 for ( n = 0; n <= glyph_count; n++ )
897 if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
899 if ( n == glyph_count )
901 if ( ( error = Make_ClassRange( gcd, start,
904 memory ) ) != TT_Err_Ok )
909 if ( curr_glyph == 0xFFFF )
911 error = TT_Err_Invalid_Argument;
920 if ( ( error = Make_ClassRange( gcd, start,
923 memory ) ) != TT_Err_Ok )
926 if ( curr_glyph > glyph_array[n] )
928 error = TT_Err_Invalid_Argument;
932 start = glyph_array[n];
933 curr_class = class_array[n];
936 if ( curr_class >= 5 )
938 error = TT_Err_Invalid_Argument;
942 if ( n == glyph_count )
944 if ( ( error = Make_ClassRange( gcd, start,
947 memory ) ) != TT_Err_Ok )
952 if ( curr_glyph == 0xFFFF )
954 error = TT_Err_Invalid_Argument;
963 /* now prepare the arrays for class values assigned during the lookup
966 if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
967 gcd->cd.cd2.ClassRangeCount + 1, FT_UShort* ) )
970 count = gcd->cd.cd2.ClassRangeCount;
971 gcrr = gcd->cd.cd2.ClassRangeRecord;
972 ngc = gdef->NewGlyphClasses;
974 /* We allocate arrays for all glyphs not covered by the class range
975 records. Each element holds four class values. */
979 if ( ALLOC_ARRAY( ngc[0], gcrr[0].Start / 4 + 1, FT_UShort ) )
983 for ( n = 1; n < count; n++ )
985 if ( gcrr[n].Start - gcrr[n - 1].End > 1 )
986 if ( ALLOC_ARRAY( ngc[n],
987 ( gcrr[n].Start - gcrr[n - 1].End - 1 ) / 4 + 1,
992 if ( gcrr[count - 1].End != num_glyphs - 1 )
994 if ( ALLOC_ARRAY( ngc[count],
995 ( num_glyphs - gcrr[count - 1].End - 1 ) / 4 + 1,
1000 gdef->LastGlyph = num_glyphs - 1;
1002 gdef->MarkAttachClassDef_offset = 0L;
1003 gdef->MarkAttachClassDef.loaded = FALSE;
1008 for ( n = 0; n < count; n++ )
1012 FREE( gdef->NewGlyphClasses );
1015 FREE( gcd->cd.cd2.ClassRangeRecord );
1018 FREE( gcd->Defined );
1023 static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef,
1030 if ( gdef->NewGlyphClasses )
1032 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
1033 ngc = gdef->NewGlyphClasses;
1035 for ( n = 0; n < count; n++ )
1043 FT_Error Add_Glyph_Property( TTO_GDEFHeader* gdef,
1045 FT_UShort property )
1048 FT_UShort class, new_class, index;
1049 FT_UShort byte, bits, mask;
1050 FT_UShort array_index, glyph_index;
1052 TTO_ClassRangeRecord* gcrr;
1056 error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
1057 if ( error && error != TTO_Err_Not_Covered )
1060 /* we don't accept glyphs covered in `GlyphClassDef' */
1063 return TTO_Err_Not_Covered;
1068 new_class = UNCLASSIFIED_GLYPH;
1071 case TTO_BASE_GLYPH:
1072 new_class = SIMPLE_GLYPH;
1076 new_class = LIGATURE_GLYPH;
1080 new_class = MARK_GLYPH;
1084 new_class = COMPONENT_GLYPH;
1088 return TT_Err_Invalid_Argument;
1091 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
1092 ngc = gdef->NewGlyphClasses;
1094 if ( glyphID < gcrr[index].Start )
1098 glyph_index = glyphID;
1100 glyph_index = glyphID - gcrr[index - 1].End - 1;
1104 array_index = index + 1;
1105 glyph_index = glyphID - gcrr[index].End - 1;
1108 byte = ngc[array_index][glyph_index / 4 + 1];
1109 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1110 class = bits & 0x000F;
1112 /* we don't overwrite existing entries */
1116 bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1117 mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
1119 ngc[array_index][glyph_index / 4 + 1] &= mask;
1120 ngc[array_index][glyph_index / 4 + 1] |= bits;
1127 FT_Error Check_Property( TTO_GDEFHeader* gdef,
1130 FT_UShort* property )
1137 error = TT_GDEF_Get_Glyph_Property( gdef, index, property );
1141 /* This is OpenType 1.2 */
1143 if ( flags & IGNORE_SPECIAL_MARKS )
1144 if ( (flags & 0xFF00) != *property )
1145 return TTO_Err_Not_Covered;
1147 if ( flags & *property )
1148 return TTO_Err_Not_Covered;