contrib/OWB: add correct SDL dependency, fix compilers used
[AROS-Contrib.git] / freetype1 / lib / extend / ftxgdef.c
blob9f94e96b85554f8794b3624bc374ae810fd6c904
1 /*******************************************************************
3 * ftxgdef.c
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 ******************************************************************/
18 #include "tttypes.h"
19 #include "tttags.h"
20 #include "ttload.h"
21 #include "ttextend.h"
22 #include "ttmemory.h"
23 #include "ttfile.h"
25 #include "ftxopen.h"
26 #include "ftxopenf.h"
29 #define GDEF_ID Build_Extension_ID( 'G', 'D', 'E', 'F' )
32 static TT_Error Load_AttachList( TTO_AttachList* al,
33 PFace input );
34 static TT_Error Load_LigCaretList( TTO_LigCaretList* lcl,
35 PFace input );
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 /**********************
45 * Extension Functions
46 **********************/
49 static TT_Error GDEF_Create( void* ext,
50 PFace face )
52 DEFINE_LOAD_LOCALS( face->stream );
54 TTO_GDEFHeader* gdef = (TTO_GDEFHeader*)ext;
55 Long table;
58 /* by convention */
60 if ( !gdef )
61 return TT_Err_Ok;
63 /* a null offset indicates that there is no GDEF table */
65 gdef->offset = 0;
67 /* we store the start offset and the size of the subtable */
69 table = TT_LookUp_Table( face, TTAG_GDEF );
70 if ( table < 0 )
71 return TT_Err_Ok; /* The table is optional */
73 if ( FILE_Seek( face->dirTables[table].Offset ) ||
74 ACCESS_Frame( 4L ) )
75 return error;
77 gdef->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
78 gdef->Version = GET_ULong();
80 FORGET_Frame();
82 gdef->loaded = FALSE;
84 return TT_Err_Ok;
88 static TT_Error GDEF_Destroy( void* ext,
89 PFace face )
91 TTO_GDEFHeader* gdef = (TTO_GDEFHeader*)ext;
94 /* by convention */
96 if ( !gdef )
97 return TT_Err_Ok;
99 if ( gdef->loaded )
101 Free_LigCaretList( &gdef->LigCaretList );
102 Free_AttachList( &gdef->AttachList );
103 Free_ClassDefinition( &gdef->GlyphClassDef );
104 Free_ClassDefinition( &gdef->MarkAttachClassDef );
106 Free_NewGlyphClasses( gdef );
109 return TT_Err_Ok;
113 EXPORT_FUNC
114 TT_Error TT_Init_GDEF_Extension( TT_Engine engine )
116 PEngine_Instance _engine = HANDLE_Engine( engine );
119 if ( !_engine )
120 return TT_Err_Invalid_Engine;
122 return TT_Register_Extension( _engine,
123 GDEF_ID,
124 sizeof ( TTO_GDEFHeader ),
125 GDEF_Create,
126 GDEF_Destroy );
130 EXPORT_FUNC
131 TT_Error TT_Load_GDEF_Table( TT_Face face,
132 TTO_GDEFHeader* retptr )
134 ULong cur_offset, new_offset, base_offset;
136 TT_Error error;
137 TT_Stream stream;
138 TTO_GDEFHeader* gdef;
140 PFace faze = HANDLE_Face( face );
143 if ( !retptr )
144 return TT_Err_Invalid_Argument;
146 if ( !faze )
147 return TT_Err_Invalid_Face_Handle;
149 error = TT_Extension_Get( faze, GDEF_ID, (void**)&gdef );
150 if ( error )
151 return error;
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 ) )
159 return error;
161 base_offset = gdef->offset;
163 /* skip version */
165 if ( FILE_Seek( base_offset + 4L ) ||
166 ACCESS_Frame( 2L ) )
167 return error;
169 new_offset = GET_UShort();
171 FORGET_Frame();
173 /* all GDEF subtables are optional */
175 if ( new_offset )
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 )
185 return error;
186 (void)FILE_Seek( cur_offset );
188 else
189 gdef->GlyphClassDef.loaded = FALSE;
191 if ( ACCESS_Frame( 2L ) )
192 return error;
194 new_offset = GET_UShort();
196 FORGET_Frame();
198 if ( new_offset )
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 )
206 goto Fail1;
207 (void)FILE_Seek( cur_offset );
209 else
210 gdef->AttachList.loaded = FALSE;
212 if ( ACCESS_Frame( 2L ) )
213 return error;
215 new_offset = GET_UShort();
217 FORGET_Frame();
219 if ( new_offset )
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 )
227 goto Fail2;
228 (void)FILE_Seek( cur_offset );
230 else
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;
240 gdef->LastGlyph = 0;
241 gdef->NewGlyphClasses = NULL;
242 gdef->loaded = TRUE;
244 *retptr = *gdef;
245 DONE_Stream( stream );
247 return TT_Err_Ok;
249 Fail2:
250 Free_AttachList( &gdef->AttachList );
252 Fail1:
253 Free_ClassDefinition( &gdef->GlyphClassDef );
255 /* release stream */
257 DONE_Stream( stream );
259 return error;
264 /*******************************
265 * AttachList related functions
266 *******************************/
269 /* AttachPoint */
271 static TT_Error Load_AttachPoint( TTO_AttachPoint* ap,
272 PFace input )
274 DEFINE_LOAD_LOCALS( input->stream );
276 UShort n, count;
277 UShort* pi;
280 if ( ACCESS_Frame( 2L ) )
281 return error;
283 count = ap->PointCount = GET_UShort();
285 FORGET_Frame();
287 ap->PointIndex = NULL;
289 if ( count )
291 if ( ALLOC_ARRAY( ap->PointIndex, count, UShort ) )
292 return error;
294 pi = ap->PointIndex;
296 if ( ACCESS_Frame( count * 2L ) )
298 FREE( pi );
299 return error;
302 for ( n = 0; n < count; n++ )
303 pi[n] = GET_UShort();
305 FORGET_Frame();
308 return TT_Err_Ok;
312 static void Free_AttachPoint( TTO_AttachPoint* ap )
314 FREE( ap->PointIndex );
318 /* AttachList */
320 static TT_Error Load_AttachList( TTO_AttachList* al,
321 PFace input )
323 DEFINE_LOAD_LOCALS( input->stream );
325 UShort n, count;
326 ULong cur_offset, new_offset, base_offset;
328 TTO_AttachPoint* ap;
331 base_offset = FILE_Pos();
333 if ( ACCESS_Frame( 2L ) )
334 return error;
336 new_offset = GET_UShort() + base_offset;
338 FORGET_Frame();
340 cur_offset = FILE_Pos();
341 if ( FILE_Seek( new_offset ) ||
342 ( error = Load_Coverage( &al->Coverage, input ) ) != TT_Err_Ok )
343 return error;
344 (void)FILE_Seek( cur_offset );
346 if ( ACCESS_Frame( 2L ) )
347 goto Fail2;
349 count = al->GlyphCount = GET_UShort();
351 FORGET_Frame();
353 al->AttachPoint = NULL;
355 if ( ALLOC_ARRAY( al->AttachPoint, count, TTO_AttachPoint ) )
356 goto Fail2;
358 ap = al->AttachPoint;
360 for ( n = 0; n < count; n++ )
362 if ( ACCESS_Frame( 2L ) )
363 goto Fail1;
365 new_offset = GET_UShort() + base_offset;
367 FORGET_Frame();
369 cur_offset = FILE_Pos();
370 if ( FILE_Seek( new_offset ) ||
371 ( error = Load_AttachPoint( &ap[n], input ) ) != TT_Err_Ok )
372 goto Fail1;
373 (void)FILE_Seek( cur_offset );
376 al->loaded = TRUE;
378 return TT_Err_Ok;
380 Fail1:
381 for ( n = 0; n < count; n++ )
382 Free_AttachPoint( &ap[n] );
384 FREE( ap );
386 Fail2:
387 Free_Coverage( &al->Coverage );
388 return error;
392 static void Free_AttachList( TTO_AttachList* al )
394 UShort n, count;
396 TTO_AttachPoint* ap;
399 if ( !al->loaded )
400 return;
402 if ( al->AttachPoint )
404 count = al->GlyphCount;
405 ap = al->AttachPoint;
407 for ( n = 0; n < count; n++ )
408 Free_AttachPoint( &ap[n] );
410 FREE( ap );
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,
429 PFace input )
431 DEFINE_LOAD_LOCALS( input->stream );
433 ULong cur_offset, new_offset, base_offset;
436 base_offset = FILE_Pos();
438 if ( ACCESS_Frame( 2L ) )
439 return error;
441 cv->CaretValueFormat = GET_UShort();
443 FORGET_Frame();
445 switch ( cv->CaretValueFormat )
447 case 1:
448 if ( ACCESS_Frame( 2L ) )
449 return error;
451 cv->cvf.cvf1.Coordinate = GET_Short();
453 FORGET_Frame();
455 break;
457 case 2:
458 if ( ACCESS_Frame( 2L ) )
459 return error;
461 cv->cvf.cvf2.CaretValuePoint = GET_UShort();
463 FORGET_Frame();
465 break;
467 case 3:
468 if ( ACCESS_Frame( 4L ) )
469 return error;
471 cv->cvf.cvf3.Coordinate = GET_Short();
473 new_offset = GET_UShort() + base_offset;
475 FORGET_Frame();
477 cur_offset = FILE_Pos();
478 if ( FILE_Seek( new_offset ) ||
479 ( error = Load_Device( &cv->cvf.cvf3.Device,
480 input ) ) != TT_Err_Ok )
481 return error;
482 (void)FILE_Seek( cur_offset );
484 break;
486 case 4:
487 if ( ACCESS_Frame( 2L ) )
488 return error;
490 cv->cvf.cvf4.IdCaretValue = GET_UShort();
492 FORGET_Frame();
493 break;
495 default:
496 return TTO_Err_Invalid_GDEF_SubTable_Format;
499 return TT_Err_Ok;
503 static void Free_CaretValue( TTO_CaretValue* cv )
505 if ( cv->CaretValueFormat == 3 )
506 Free_Device( &cv->cvf.cvf3.Device );
510 /* LigGlyph */
512 static TT_Error Load_LigGlyph( TTO_LigGlyph* lg,
513 PFace input )
515 DEFINE_LOAD_LOCALS( input->stream );
517 UShort n, count;
518 ULong cur_offset, new_offset, base_offset;
520 TTO_CaretValue* cv;
523 base_offset = FILE_Pos();
525 if ( ACCESS_Frame( 2L ) )
526 return error;
528 count = lg->CaretCount = GET_UShort();
530 FORGET_Frame();
532 lg->CaretValue = NULL;
534 if ( ALLOC_ARRAY( lg->CaretValue, count, TTO_CaretValue ) )
535 return error;
537 cv = lg->CaretValue;
539 for ( n = 0; n < count; n++ )
541 if ( ACCESS_Frame( 2L ) )
542 goto Fail;
544 new_offset = GET_UShort() + base_offset;
546 FORGET_Frame();
548 cur_offset = FILE_Pos();
549 if ( FILE_Seek( new_offset ) ||
550 ( error = Load_CaretValue( &cv[n], input ) ) != TT_Err_Ok )
551 goto Fail;
552 (void)FILE_Seek( cur_offset );
555 return TT_Err_Ok;
557 Fail:
558 for ( n = 0; n < count; n++ )
559 Free_CaretValue( &cv[n] );
561 FREE( cv );
562 return error;
566 static void Free_LigGlyph( TTO_LigGlyph* lg )
568 UShort n, count;
570 TTO_CaretValue* cv;
573 if ( lg->CaretValue )
575 count = lg->CaretCount;
576 cv = lg->CaretValue;
578 for ( n = 0; n < count; n++ )
579 Free_CaretValue( &cv[n] );
581 FREE( cv );
586 /* LigCaretList */
588 static TT_Error Load_LigCaretList( TTO_LigCaretList* lcl,
589 PFace input )
591 DEFINE_LOAD_LOCALS( input->stream );
593 UShort n, count;
594 ULong cur_offset, new_offset, base_offset;
596 TTO_LigGlyph* lg;
599 base_offset = FILE_Pos();
601 if ( ACCESS_Frame( 2L ) )
602 return error;
604 new_offset = GET_UShort() + base_offset;
606 FORGET_Frame();
608 cur_offset = FILE_Pos();
609 if ( FILE_Seek( new_offset ) ||
610 ( error = Load_Coverage( &lcl->Coverage, input ) ) != TT_Err_Ok )
611 return error;
612 (void)FILE_Seek( cur_offset );
614 if ( ACCESS_Frame( 2L ) )
615 goto Fail2;
617 count = lcl->LigGlyphCount = GET_UShort();
619 FORGET_Frame();
621 lcl->LigGlyph = NULL;
623 if ( ALLOC_ARRAY( lcl->LigGlyph, count, TTO_LigGlyph ) )
624 goto Fail2;
626 lg = lcl->LigGlyph;
628 for ( n = 0; n < count; n++ )
630 if ( ACCESS_Frame( 2L ) )
631 goto Fail1;
633 new_offset = GET_UShort() + base_offset;
635 FORGET_Frame();
637 cur_offset = FILE_Pos();
638 if ( FILE_Seek( new_offset ) ||
639 ( error = Load_LigGlyph( &lg[n], input ) ) != TT_Err_Ok )
640 goto Fail1;
641 (void)FILE_Seek( cur_offset );
644 lcl->loaded = TRUE;
646 return TT_Err_Ok;
648 Fail1:
649 for ( n = 0; n < count; n++ )
650 Free_LigGlyph( &lg[n] );
652 FREE( lg );
654 Fail2:
655 Free_Coverage( &lcl->Coverage );
656 return error;
660 static void Free_LigCaretList( TTO_LigCaretList* lcl )
662 UShort n, count;
664 TTO_LigGlyph* lg;
667 if ( !lcl->loaded )
668 return;
670 if ( lcl->LigGlyph )
672 count = lcl->LigGlyphCount;
673 lg = lcl->LigGlyph;
675 for ( n = 0; n < count; n++ )
676 Free_LigGlyph( &lg[n] );
678 FREE( lg );
681 Free_Coverage( &lcl->Coverage );
686 /***********
687 * GDEF API
688 ***********/
691 static UShort Get_New_Class( TTO_GDEFHeader* gdef,
692 UShort glyphID,
693 UShort index )
695 UShort glyph_index, array_index;
696 UShort byte, bits;
698 TTO_ClassRangeRecord* gcrr;
699 UShort** ngc;
702 if ( glyphID >= gdef->LastGlyph )
703 return 0;
705 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
706 ngc = gdef->NewGlyphClasses;
708 if ( glyphID < gcrr[index].Start )
710 array_index = 0;
711 if ( index == 0 )
712 glyph_index = glyphID;
713 else
714 glyph_index = glyphID - gcrr[index - 1].End - 1;
716 else
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;
729 EXPORT_FUNC
730 TT_Error TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader* gdef,
731 TT_UShort glyphID,
732 TT_UShort* property )
734 UShort class, index;
736 TT_Error error;
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 )
748 return error;
749 if ( !error )
751 *property = class << 8;
752 return TT_Err_Ok;
756 error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
757 if ( error && error != TTO_Err_Not_Covered )
758 return error;
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 );
766 switch ( class )
768 case UNCLASSIFIED_GLYPH:
769 *property = 0;
770 break;
772 case SIMPLE_GLYPH:
773 *property = TTO_BASE_GLYPH;
774 break;
776 case LIGATURE_GLYPH:
777 *property = TTO_LIGATURE;
778 break;
780 case MARK_GLYPH:
781 *property = TTO_MARK;
782 break;
784 case COMPONENT_GLYPH:
785 *property = TTO_COMPONENT;
786 break;
789 return TT_Err_Ok;
793 static TT_Error Make_ClassRange( TTO_ClassDefinition* cd,
794 UShort start,
795 UShort end,
796 UShort class )
798 TT_Error error;
799 UShort index;
801 TTO_ClassDefFormat2* cdf2;
802 TTO_ClassRangeRecord* crr;
805 cdf2 = &cd->cd.cd2;
807 cdf2->ClassRangeCount++;
809 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, cdf2->ClassRangeCount,
810 TTO_ClassRangeRecord ) )
811 return error;
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;
822 return TT_Err_Ok;
826 EXPORT_FUNC
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;
834 UShort n, count;
835 TT_Error error;
837 TTO_ClassDefinition* gcd;
838 TTO_ClassRangeRecord* gcrr;
839 UShort** ngc;
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 ) )
854 return error;
856 gcd->cd.cd2.ClassRangeCount = 0;
857 gcd->cd.cd2.ClassRangeRecord = NULL;
859 start = glyph_array[0];
860 curr_class = class_array[0];
861 curr_glyph = start;
863 if ( curr_class >= 5 )
865 error = TT_Err_Invalid_Argument;
866 goto Fail4;
869 glyph_count--;
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,
878 curr_glyph,
879 curr_class ) ) != TT_Err_Ok )
880 goto Fail3;
882 else
884 if ( curr_glyph == 0xFFFF )
886 error = TT_Err_Invalid_Argument;
887 goto Fail3;
889 else
890 curr_glyph++;
893 else
895 if ( ( error = Make_ClassRange( gcd, start,
896 curr_glyph - 1,
897 curr_class ) ) != TT_Err_Ok )
898 goto Fail3;
900 if ( curr_glyph > glyph_array[n] )
902 error = TT_Err_Invalid_Argument;
903 goto Fail3;
906 start = glyph_array[n];
907 curr_class = class_array[n];
908 curr_glyph = start;
910 if ( curr_class >= 5 )
912 error = TT_Err_Invalid_Argument;
913 goto Fail3;
916 if ( n == glyph_count )
918 if ( ( error = Make_ClassRange( gcd, start,
919 curr_glyph,
920 curr_class ) ) != TT_Err_Ok )
921 goto Fail3;
923 else
925 if ( curr_glyph == 0xFFFF )
927 error = TT_Err_Invalid_Argument;
928 goto Fail3;
930 else
931 curr_glyph++;
936 /* now prepare the arrays for class values assigned during the lookup
937 process */
939 if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
940 gcd->cd.cd2.ClassRangeCount + 1, UShort* ) )
941 goto Fail2;
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. */
950 if ( gcrr[0].Start )
952 if ( ALLOC_ARRAY( ngc[0], gcrr[0].Start / 4 + 1, UShort ) )
953 goto Fail1;
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,
961 UShort ) )
962 goto Fail1;
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,
969 UShort ) )
970 goto Fail1;
973 gdef->LastGlyph = num_glyphs - 1;
975 gdef->MarkAttachClassDef_offset = 0L;
976 gdef->MarkAttachClassDef.loaded = FALSE;
978 return TT_Err_Ok;
980 Fail1:
981 for ( n = 0; n < count; n++ )
982 FREE( ngc[n] );
984 Fail2:
985 FREE( gdef->NewGlyphClasses );
987 Fail3:
988 FREE( gcd->cd.cd2.ClassRangeRecord );
990 Fail4:
991 FREE( gcd->Defined );
992 return error;
996 static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef )
998 UShort** ngc;
999 UShort n, count;
1002 if ( gdef->NewGlyphClasses )
1004 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
1005 ngc = gdef->NewGlyphClasses;
1007 for ( n = 0; n < count; n++ )
1008 FREE( ngc[n] );
1010 FREE( ngc );
1015 TT_Error Add_Glyph_Property( TTO_GDEFHeader* gdef,
1016 UShort glyphID,
1017 UShort property )
1019 TT_Error error;
1020 UShort class, new_class, index;
1021 UShort byte, bits, mask;
1022 UShort array_index, glyph_index;
1024 TTO_ClassRangeRecord* gcrr;
1025 UShort** ngc;
1028 error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
1029 if ( error && error != TTO_Err_Not_Covered )
1030 return error;
1032 /* we don't accept glyphs covered in `GlyphClassDef' */
1034 if ( !error )
1035 return TTO_Err_Not_Covered;
1037 switch ( property )
1039 case 0:
1040 new_class = UNCLASSIFIED_GLYPH;
1041 break;
1043 case TTO_BASE_GLYPH:
1044 new_class = SIMPLE_GLYPH;
1045 break;
1047 case TTO_LIGATURE:
1048 new_class = LIGATURE_GLYPH;
1049 break;
1051 case TTO_MARK:
1052 new_class = MARK_GLYPH;
1053 break;
1055 case TTO_COMPONENT:
1056 new_class = COMPONENT_GLYPH;
1057 break;
1059 default:
1060 return TT_Err_Invalid_Argument;
1063 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
1064 ngc = gdef->NewGlyphClasses;
1066 if ( glyphID < gcrr[index].Start )
1068 array_index = 0;
1069 if ( index == 0 )
1070 glyph_index = glyphID;
1071 else
1072 glyph_index = glyphID - gcrr[index - 1].End - 1;
1074 else
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 */
1086 if ( !class )
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;
1095 return TT_Err_Ok;
1099 /* END */