2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
5 * This is part of HarfBuzz, an OpenType Layout engine library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 #include "harfbuzz-impl.h"
27 #include "harfbuzz-gdef-private.h"
28 #include "harfbuzz-open-private.h"
30 static HB_Error Load_AttachList( HB_AttachList* al,
32 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl,
35 static void Free_AttachList( HB_AttachList* al);
36 static void Free_LigCaretList( HB_LigCaretList* lcl);
38 static void Free_NewGlyphClasses( HB_GDEFHeader* gdef);
42 /* GDEF glyph classes */
44 #define UNCLASSIFIED_GLYPH 0
45 #define SIMPLE_GLYPH 1
46 #define LIGATURE_GLYPH 2
48 #define COMPONENT_GLYPH 4
55 HB_Error HB_New_GDEF_Table( HB_GDEFHeader** retptr )
62 return ERR(HB_Err_Invalid_Argument);
64 if ( ALLOC( gdef, sizeof( *gdef ) ) )
67 gdef->GlyphClassDef.loaded = FALSE;
68 gdef->AttachList.loaded = FALSE;
69 gdef->LigCaretList.loaded = FALSE;
70 gdef->MarkAttachClassDef_offset = 0;
71 gdef->MarkAttachClassDef.loaded = FALSE;
74 gdef->NewGlyphClasses = NULL;
82 HB_Error HB_Load_GDEF_Table( HB_Stream stream,
83 HB_GDEFHeader** retptr )
86 HB_UInt cur_offset, new_offset, base_offset;
92 return ERR(HB_Err_Invalid_Argument);
94 if ( GOTO_Table( TTAG_GDEF ) )
97 if (( error = HB_New_GDEF_Table ( &gdef ) ))
100 base_offset = FILE_Pos();
104 if ( FILE_Seek( base_offset + 4L ) ||
108 new_offset = GET_UShort();
112 /* all GDEF subtables are optional */
116 new_offset += base_offset;
118 /* only classes 1-4 are allowed here */
120 cur_offset = FILE_Pos();
121 if ( FILE_Seek( new_offset ) ||
122 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->GlyphClassDef, 5,
123 stream ) ) != HB_Err_Ok )
125 (void)FILE_Seek( cur_offset );
128 if ( ACCESS_Frame( 2L ) )
131 new_offset = GET_UShort();
137 new_offset += base_offset;
139 cur_offset = FILE_Pos();
140 if ( FILE_Seek( new_offset ) ||
141 ( error = Load_AttachList( &gdef->AttachList,
142 stream ) ) != HB_Err_Ok )
144 (void)FILE_Seek( cur_offset );
147 if ( ACCESS_Frame( 2L ) )
150 new_offset = GET_UShort();
156 new_offset += base_offset;
158 cur_offset = FILE_Pos();
159 if ( FILE_Seek( new_offset ) ||
160 ( error = Load_LigCaretList( &gdef->LigCaretList,
161 stream ) ) != HB_Err_Ok )
163 (void)FILE_Seek( cur_offset );
166 /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We
167 first have to scan the LookupFlag values to find out whether we
168 must load it or not. Here we only store the offset of the table. */
170 if ( ACCESS_Frame( 2L ) )
173 new_offset = GET_UShort();
178 gdef->MarkAttachClassDef_offset = new_offset + base_offset;
180 gdef->MarkAttachClassDef_offset = 0;
187 Free_LigCaretList( &gdef->LigCaretList );
190 Free_AttachList( &gdef->AttachList );
193 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
202 HB_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef )
204 Free_LigCaretList( &gdef->LigCaretList );
205 Free_AttachList( &gdef->AttachList );
206 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
207 _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef );
209 Free_NewGlyphClasses( gdef );
219 /*******************************
220 * AttachList related functions
221 *******************************/
226 static HB_Error Load_AttachPoint( HB_AttachPoint* ap,
235 if ( ACCESS_Frame( 2L ) )
238 count = ap->PointCount = GET_UShort();
242 ap->PointIndex = NULL;
246 if ( ALLOC_ARRAY( ap->PointIndex, count, HB_UShort ) )
251 if ( ACCESS_Frame( count * 2L ) )
257 for ( n = 0; n < count; n++ )
258 pi[n] = GET_UShort();
267 static void Free_AttachPoint( HB_AttachPoint* ap )
269 FREE( ap->PointIndex );
275 static HB_Error Load_AttachList( HB_AttachList* al,
280 HB_UShort n, m, count;
281 HB_UInt cur_offset, new_offset, base_offset;
286 base_offset = FILE_Pos();
288 if ( ACCESS_Frame( 2L ) )
291 new_offset = GET_UShort() + base_offset;
295 cur_offset = FILE_Pos();
296 if ( FILE_Seek( new_offset ) ||
297 ( error = _HB_OPEN_Load_Coverage( &al->Coverage, stream ) ) != HB_Err_Ok )
299 (void)FILE_Seek( cur_offset );
301 if ( ACCESS_Frame( 2L ) )
304 count = al->GlyphCount = GET_UShort();
308 al->AttachPoint = NULL;
310 if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) )
313 ap = al->AttachPoint;
315 for ( n = 0; n < count; n++ )
317 if ( ACCESS_Frame( 2L ) )
320 new_offset = GET_UShort() + base_offset;
324 cur_offset = FILE_Pos();
325 if ( FILE_Seek( new_offset ) ||
326 ( error = Load_AttachPoint( &ap[n], stream ) ) != HB_Err_Ok )
328 (void)FILE_Seek( cur_offset );
336 for ( m = 0; m < n; m++ )
337 Free_AttachPoint( &ap[m] );
342 _HB_OPEN_Free_Coverage( &al->Coverage );
347 static void Free_AttachList( HB_AttachList* al)
357 if ( al->AttachPoint )
359 count = al->GlyphCount;
360 ap = al->AttachPoint;
362 for ( n = 0; n < count; n++ )
363 Free_AttachPoint( &ap[n] );
368 _HB_OPEN_Free_Coverage( &al->Coverage );
373 /*********************************
374 * LigCaretList related functions
375 *********************************/
378 /* CaretValueFormat1 */
379 /* CaretValueFormat2 */
380 /* CaretValueFormat3 */
381 /* CaretValueFormat4 */
383 static HB_Error Load_CaretValue( HB_CaretValue* cv,
388 HB_UInt cur_offset, new_offset, base_offset;
391 base_offset = FILE_Pos();
393 if ( ACCESS_Frame( 2L ) )
396 cv->CaretValueFormat = GET_UShort();
400 switch ( cv->CaretValueFormat )
403 if ( ACCESS_Frame( 2L ) )
406 cv->cvf.cvf1.Coordinate = GET_Short();
413 if ( ACCESS_Frame( 2L ) )
416 cv->cvf.cvf2.CaretValuePoint = GET_UShort();
423 if ( ACCESS_Frame( 4L ) )
426 cv->cvf.cvf3.Coordinate = GET_Short();
428 new_offset = GET_UShort() + base_offset;
432 cur_offset = FILE_Pos();
433 if ( FILE_Seek( new_offset ) ||
434 ( error = _HB_OPEN_Load_Device( &cv->cvf.cvf3.Device,
435 stream ) ) != HB_Err_Ok )
437 (void)FILE_Seek( cur_offset );
442 if ( ACCESS_Frame( 2L ) )
445 cv->cvf.cvf4.IdCaretValue = GET_UShort();
451 return ERR(HB_Err_Invalid_SubTable_Format);
458 static void Free_CaretValue( HB_CaretValue* cv)
460 if ( cv->CaretValueFormat == 3 )
461 _HB_OPEN_Free_Device( &cv->cvf.cvf3.Device );
467 static HB_Error Load_LigGlyph( HB_LigGlyph* lg,
472 HB_UShort n, m, count;
473 HB_UInt cur_offset, new_offset, base_offset;
478 base_offset = FILE_Pos();
480 if ( ACCESS_Frame( 2L ) )
483 count = lg->CaretCount = GET_UShort();
487 lg->CaretValue = NULL;
489 if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) )
494 for ( n = 0; n < count; n++ )
496 if ( ACCESS_Frame( 2L ) )
499 new_offset = GET_UShort() + base_offset;
503 cur_offset = FILE_Pos();
504 if ( FILE_Seek( new_offset ) ||
505 ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok )
507 (void)FILE_Seek( cur_offset );
513 for ( m = 0; m < n; m++ )
514 Free_CaretValue( &cv[m] );
521 static void Free_LigGlyph( HB_LigGlyph* lg)
528 if ( lg->CaretValue )
530 count = lg->CaretCount;
533 for ( n = 0; n < count; n++ )
534 Free_CaretValue( &cv[n] );
543 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl,
548 HB_UShort m, n, count;
549 HB_UInt cur_offset, new_offset, base_offset;
554 base_offset = FILE_Pos();
556 if ( ACCESS_Frame( 2L ) )
559 new_offset = GET_UShort() + base_offset;
563 cur_offset = FILE_Pos();
564 if ( FILE_Seek( new_offset ) ||
565 ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok )
567 (void)FILE_Seek( cur_offset );
569 if ( ACCESS_Frame( 2L ) )
572 count = lcl->LigGlyphCount = GET_UShort();
576 lcl->LigGlyph = NULL;
578 if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) )
583 for ( n = 0; n < count; n++ )
585 if ( ACCESS_Frame( 2L ) )
588 new_offset = GET_UShort() + base_offset;
592 cur_offset = FILE_Pos();
593 if ( FILE_Seek( new_offset ) ||
594 ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok )
596 (void)FILE_Seek( cur_offset );
604 for ( m = 0; m < n; m++ )
605 Free_LigGlyph( &lg[m] );
610 _HB_OPEN_Free_Coverage( &lcl->Coverage );
615 static void Free_LigCaretList( HB_LigCaretList* lcl )
627 count = lcl->LigGlyphCount;
630 for ( n = 0; n < count; n++ )
631 Free_LigGlyph( &lg[n] );
636 _HB_OPEN_Free_Coverage( &lcl->Coverage );
646 static HB_UShort Get_New_Class( HB_GDEFHeader* gdef,
650 HB_UShort glyph_index, array_index, count;
651 HB_UShort byte, bits;
653 HB_ClassRangeRecord* gcrr;
657 if ( glyphID >= gdef->LastGlyph )
660 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
661 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
662 ngc = gdef->NewGlyphClasses;
664 if ( index < count && glyphID < gcrr[index].Start )
668 glyph_index = glyphID;
670 glyph_index = glyphID - gcrr[index - 1].End - 1;
674 array_index = index + 1;
675 glyph_index = glyphID - gcrr[index].End - 1;
678 byte = ngc[array_index][glyph_index / 4];
679 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
681 return bits & 0x000F;
686 HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef,
688 HB_UShort* property )
690 HB_UShort class = 0, index = 0; /* shut compiler up */
695 if ( !gdef || !property )
696 return ERR(HB_Err_Invalid_Argument);
698 /* first, we check for mark attach classes */
700 if ( gdef->MarkAttachClassDef.loaded )
702 error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
703 if ( error && error != HB_Err_Not_Covered )
707 *property = class << 8;
712 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
713 if ( error && error != HB_Err_Not_Covered )
716 /* if we have a constructed class table, check whether additional
717 values have been assigned */
719 if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses )
720 class = Get_New_Class( gdef, glyphID, index );
725 case UNCLASSIFIED_GLYPH:
730 *property = HB_GDEF_BASE_GLYPH;
734 *property = HB_GDEF_LIGATURE;
738 *property = HB_GDEF_MARK;
741 case COMPONENT_GLYPH:
742 *property = HB_GDEF_COMPONENT;
750 static HB_Error Make_ClassRange( HB_ClassDefinition* cd,
758 HB_ClassDefFormat2* cdf2;
759 HB_ClassRangeRecord* crr;
764 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
765 cdf2->ClassRangeCount + 1 ,
766 HB_ClassRangeRecord ) )
769 cdf2->ClassRangeCount++;
771 crr = cdf2->ClassRangeRecord;
772 index = cdf2->ClassRangeCount - 1;
774 crr[index].Start = start;
775 crr[index].End = end;
776 crr[index].Class = class;
783 HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef,
784 HB_UShort num_glyphs,
785 HB_UShort glyph_count,
786 HB_UShort* glyph_array,
787 HB_UShort* class_array )
789 HB_UShort start, curr_glyph, curr_class;
790 HB_UShort n, m, count;
793 HB_ClassDefinition* gcd;
794 HB_ClassRangeRecord* gcrr;
798 if ( !gdef || !glyph_array || !class_array )
799 return ERR(HB_Err_Invalid_Argument);
801 gcd = &gdef->GlyphClassDef;
803 /* We build a format 2 table */
805 gcd->ClassFormat = 2;
807 gcd->cd.cd2.ClassRangeCount = 0;
808 gcd->cd.cd2.ClassRangeRecord = NULL;
810 start = glyph_array[0];
811 curr_class = class_array[0];
814 if ( curr_class >= 5 )
816 error = ERR(HB_Err_Invalid_Argument);
822 for ( n = 0; n < glyph_count + 1; n++ )
824 if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
826 if ( n == glyph_count )
828 if ( ( error = Make_ClassRange( gcd, start,
830 curr_class) ) != HB_Err_Ok )
835 if ( curr_glyph == 0xFFFF )
837 error = ERR(HB_Err_Invalid_Argument);
846 if ( ( error = Make_ClassRange( gcd, start,
848 curr_class) ) != HB_Err_Ok )
851 if ( curr_glyph > glyph_array[n] )
853 error = ERR(HB_Err_Invalid_Argument);
857 start = glyph_array[n];
858 curr_class = class_array[n];
861 if ( curr_class >= 5 )
863 error = ERR(HB_Err_Invalid_Argument);
867 if ( n == glyph_count )
869 if ( ( error = Make_ClassRange( gcd, start,
871 curr_class) ) != HB_Err_Ok )
876 if ( curr_glyph == 0xFFFF )
878 error = ERR(HB_Err_Invalid_Argument);
887 /* now prepare the arrays for class values assigned during the lookup
890 if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
891 gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) )
894 count = gcd->cd.cd2.ClassRangeCount;
895 gcrr = gcd->cd.cd2.ClassRangeRecord;
896 ngc = gdef->NewGlyphClasses;
898 /* We allocate arrays for all glyphs not covered by the class range
899 records. Each element holds four class values. */
905 if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) )
909 for ( n = 1; n < count; n++ )
911 if ( gcrr[n].Start - gcrr[n - 1].End > 1 )
912 if ( ALLOC_ARRAY( ngc[n],
913 ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4,
918 if ( gcrr[count - 1].End != num_glyphs - 1 )
920 if ( ALLOC_ARRAY( ngc[count],
921 ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
926 else if ( num_glyphs > 0 )
928 if ( ALLOC_ARRAY( ngc[count],
929 ( num_glyphs + 3 ) / 4,
934 gdef->LastGlyph = num_glyphs - 1;
936 gdef->MarkAttachClassDef_offset = 0L;
937 gdef->MarkAttachClassDef.loaded = FALSE;
944 for ( m = 0; m < n; m++ )
948 FREE( gdef->NewGlyphClasses );
951 FREE( gcd->cd.cd2.ClassRangeRecord );
958 static void Free_NewGlyphClasses( HB_GDEFHeader* gdef )
964 if ( gdef->NewGlyphClasses )
966 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
967 ngc = gdef->NewGlyphClasses;
969 for ( n = 0; n < count; n++ )
978 _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef,
983 HB_UShort class, new_class, index = 0; /* shut compiler up */
984 HB_UShort byte, bits, mask;
985 HB_UShort array_index, glyph_index, count;
987 HB_ClassRangeRecord* gcrr;
991 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
992 if ( error && error != HB_Err_Not_Covered )
995 /* we don't accept glyphs covered in `GlyphClassDef' */
998 return HB_Err_Not_Covered;
1003 new_class = UNCLASSIFIED_GLYPH;
1006 case HB_GDEF_BASE_GLYPH:
1007 new_class = SIMPLE_GLYPH;
1010 case HB_GDEF_LIGATURE:
1011 new_class = LIGATURE_GLYPH;
1015 new_class = MARK_GLYPH;
1018 case HB_GDEF_COMPONENT:
1019 new_class = COMPONENT_GLYPH;
1023 return ERR(HB_Err_Invalid_Argument);
1026 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
1027 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
1028 ngc = gdef->NewGlyphClasses;
1030 if ( index < count && glyphID < gcrr[index].Start )
1032 array_index = index;
1034 glyph_index = glyphID;
1036 glyph_index = glyphID - gcrr[index - 1].End - 1;
1040 array_index = index + 1;
1041 glyph_index = glyphID - gcrr[index].End - 1;
1044 byte = ngc[array_index][glyph_index / 4];
1045 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1046 class = bits & 0x000F;
1048 /* we don't overwrite existing entries */
1052 bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1053 mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
1055 ngc[array_index][glyph_index / 4] &= mask;
1056 ngc[array_index][glyph_index / 4] |= bits;
1063 HB_INTERNAL HB_Error
1064 _HB_GDEF_Check_Property( HB_GDEFHeader* gdef,
1067 HB_UShort* property )
1073 HB_UShort basic_glyph_class;
1074 HB_UShort desired_attachment_class;
1076 if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
1078 error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
1083 *property = gitem->gproperties;
1085 /* If the glyph was found in the MarkAttachmentClass table,
1086 * then that class value is the high byte of the result,
1087 * otherwise the low byte contains the basic type of the glyph
1088 * as defined by the GlyphClassDef table.
1090 if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
1091 basic_glyph_class = HB_GDEF_MARK;
1093 basic_glyph_class = *property;
1095 /* Return Not_Covered, if, for example, basic_glyph_class
1096 * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
1098 if ( flags & basic_glyph_class )
1099 return HB_Err_Not_Covered;
1101 /* The high byte of LookupFlags has the meaning
1102 * "ignore marks of attachment type different than
1103 * the attachment type specified."
1105 desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
1106 if ( desired_attachment_class )
1108 if ( basic_glyph_class == HB_GDEF_MARK &&
1109 *property != desired_attachment_class )
1110 return HB_Err_Not_Covered;
1119 HB_INTERNAL HB_Error
1120 _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef,
1123 HB_UShort num_lookups)
1125 HB_Error error = HB_Err_Ok;
1128 /* We now check the LookupFlags for values larger than 0xFF to find
1129 out whether we need to load the `MarkAttachClassDef' field of the
1130 GDEF table -- this hack is necessary for OpenType 1.2 tables since
1131 the version field of the GDEF table hasn't been incremented.
1133 For constructed GDEF tables, we only load it if
1134 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
1135 a constructed mark attach table is not supported currently). */
1138 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
1140 for ( i = 0; i < num_lookups; i++ )
1143 if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
1145 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
1146 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
1147 256, stream ) ) != HB_Err_Ok )