Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / third_party / harfbuzz / src / harfbuzz-gdef.c
blob966b167b90d87043e17619759c08a82f28dcbfd5
1 /*
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
17 * DAMAGE.
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,
31 HB_Stream stream );
32 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl,
33 HB_Stream stream );
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
47 #define MARK_GLYPH 3
48 #define COMPONENT_GLYPH 4
55 HB_Error HB_New_GDEF_Table( HB_GDEFHeader** retptr )
57 HB_Error error;
59 HB_GDEFHeader* gdef;
61 if ( !retptr )
62 return ERR(HB_Err_Invalid_Argument);
64 if ( ALLOC( gdef, sizeof( *gdef ) ) )
65 return error;
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;
73 gdef->LastGlyph = 0;
74 gdef->NewGlyphClasses = NULL;
76 *retptr = gdef;
78 return HB_Err_Ok;
82 HB_Error HB_Load_GDEF_Table( HB_Stream stream,
83 HB_GDEFHeader** retptr )
85 HB_Error error;
86 HB_UInt cur_offset, new_offset, base_offset;
88 HB_GDEFHeader* gdef;
91 if ( !retptr )
92 return ERR(HB_Err_Invalid_Argument);
94 if ( GOTO_Table( TTAG_GDEF ) )
95 return error;
97 if (( error = HB_New_GDEF_Table ( &gdef ) ))
98 return error;
100 base_offset = FILE_Pos();
102 /* skip version */
104 if ( FILE_Seek( base_offset + 4L ) ||
105 ACCESS_Frame( 2L ) )
106 goto Fail0;
108 new_offset = GET_UShort();
110 FORGET_Frame();
112 /* all GDEF subtables are optional */
114 if ( new_offset )
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 )
124 goto Fail0;
125 (void)FILE_Seek( cur_offset );
128 if ( ACCESS_Frame( 2L ) )
129 goto Fail1;
131 new_offset = GET_UShort();
133 FORGET_Frame();
135 if ( new_offset )
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 )
143 goto Fail1;
144 (void)FILE_Seek( cur_offset );
147 if ( ACCESS_Frame( 2L ) )
148 goto Fail2;
150 new_offset = GET_UShort();
152 FORGET_Frame();
154 if ( new_offset )
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 )
162 goto Fail2;
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 ) )
171 goto Fail3;
173 new_offset = GET_UShort();
175 FORGET_Frame();
177 if ( new_offset )
178 gdef->MarkAttachClassDef_offset = new_offset + base_offset;
179 else
180 gdef->MarkAttachClassDef_offset = 0;
182 *retptr = gdef;
184 return HB_Err_Ok;
186 Fail3:
187 Free_LigCaretList( &gdef->LigCaretList );
189 Fail2:
190 Free_AttachList( &gdef->AttachList );
192 Fail1:
193 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
195 Fail0:
196 FREE( gdef );
198 return error;
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 );
211 FREE( gdef );
213 return HB_Err_Ok;
219 /*******************************
220 * AttachList related functions
221 *******************************/
224 /* AttachPoint */
226 static HB_Error Load_AttachPoint( HB_AttachPoint* ap,
227 HB_Stream stream )
229 HB_Error error;
231 HB_UShort n, count;
232 HB_UShort* pi;
235 if ( ACCESS_Frame( 2L ) )
236 return error;
238 count = ap->PointCount = GET_UShort();
240 FORGET_Frame();
242 ap->PointIndex = NULL;
244 if ( count )
246 if ( ALLOC_ARRAY( ap->PointIndex, count, HB_UShort ) )
247 return error;
249 pi = ap->PointIndex;
251 if ( ACCESS_Frame( count * 2L ) )
253 FREE( pi );
254 return error;
257 for ( n = 0; n < count; n++ )
258 pi[n] = GET_UShort();
260 FORGET_Frame();
263 return HB_Err_Ok;
267 static void Free_AttachPoint( HB_AttachPoint* ap )
269 FREE( ap->PointIndex );
273 /* AttachList */
275 static HB_Error Load_AttachList( HB_AttachList* al,
276 HB_Stream stream )
278 HB_Error error;
280 HB_UShort n, m, count;
281 HB_UInt cur_offset, new_offset, base_offset;
283 HB_AttachPoint* ap;
286 base_offset = FILE_Pos();
288 if ( ACCESS_Frame( 2L ) )
289 return error;
291 new_offset = GET_UShort() + base_offset;
293 FORGET_Frame();
295 cur_offset = FILE_Pos();
296 if ( FILE_Seek( new_offset ) ||
297 ( error = _HB_OPEN_Load_Coverage( &al->Coverage, stream ) ) != HB_Err_Ok )
298 return error;
299 (void)FILE_Seek( cur_offset );
301 if ( ACCESS_Frame( 2L ) )
302 goto Fail2;
304 count = al->GlyphCount = GET_UShort();
306 FORGET_Frame();
308 al->AttachPoint = NULL;
310 if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) )
311 goto Fail2;
313 ap = al->AttachPoint;
315 for ( n = 0; n < count; n++ )
317 if ( ACCESS_Frame( 2L ) )
318 goto Fail1;
320 new_offset = GET_UShort() + base_offset;
322 FORGET_Frame();
324 cur_offset = FILE_Pos();
325 if ( FILE_Seek( new_offset ) ||
326 ( error = Load_AttachPoint( &ap[n], stream ) ) != HB_Err_Ok )
327 goto Fail1;
328 (void)FILE_Seek( cur_offset );
331 al->loaded = TRUE;
333 return HB_Err_Ok;
335 Fail1:
336 for ( m = 0; m < n; m++ )
337 Free_AttachPoint( &ap[m] );
339 FREE( ap );
341 Fail2:
342 _HB_OPEN_Free_Coverage( &al->Coverage );
343 return error;
347 static void Free_AttachList( HB_AttachList* al)
349 HB_UShort n, count;
351 HB_AttachPoint* ap;
354 if ( !al->loaded )
355 return;
357 if ( al->AttachPoint )
359 count = al->GlyphCount;
360 ap = al->AttachPoint;
362 for ( n = 0; n < count; n++ )
363 Free_AttachPoint( &ap[n] );
365 FREE( ap );
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,
384 HB_Stream stream )
386 HB_Error error;
388 HB_UInt cur_offset, new_offset, base_offset;
391 base_offset = FILE_Pos();
393 if ( ACCESS_Frame( 2L ) )
394 return error;
396 cv->CaretValueFormat = GET_UShort();
398 FORGET_Frame();
400 switch ( cv->CaretValueFormat )
402 case 1:
403 if ( ACCESS_Frame( 2L ) )
404 return error;
406 cv->cvf.cvf1.Coordinate = GET_Short();
408 FORGET_Frame();
410 break;
412 case 2:
413 if ( ACCESS_Frame( 2L ) )
414 return error;
416 cv->cvf.cvf2.CaretValuePoint = GET_UShort();
418 FORGET_Frame();
420 break;
422 case 3:
423 if ( ACCESS_Frame( 4L ) )
424 return error;
426 cv->cvf.cvf3.Coordinate = GET_Short();
428 new_offset = GET_UShort() + base_offset;
430 FORGET_Frame();
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 )
436 return error;
437 (void)FILE_Seek( cur_offset );
439 break;
441 case 4:
442 if ( ACCESS_Frame( 2L ) )
443 return error;
445 #ifdef HB_SUPPORT_MULTIPLE_MASTER
446 cv->cvf.cvf4.IdCaretValue = GET_UShort();
447 #else
448 (void) GET_UShort();
449 #endif
451 FORGET_Frame();
452 break;
454 default:
455 return ERR(HB_Err_Invalid_SubTable_Format);
458 return HB_Err_Ok;
462 static void Free_CaretValue( HB_CaretValue* cv)
464 if ( cv->CaretValueFormat == 3 )
465 _HB_OPEN_Free_Device( cv->cvf.cvf3.Device );
469 /* LigGlyph */
471 static HB_Error Load_LigGlyph( HB_LigGlyph* lg,
472 HB_Stream stream )
474 HB_Error error;
476 HB_UShort n, m, count;
477 HB_UInt cur_offset, new_offset, base_offset;
479 HB_CaretValue* cv;
482 base_offset = FILE_Pos();
484 if ( ACCESS_Frame( 2L ) )
485 return error;
487 count = lg->CaretCount = GET_UShort();
489 FORGET_Frame();
491 lg->CaretValue = NULL;
493 if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) )
494 return error;
496 cv = lg->CaretValue;
498 for ( n = 0; n < count; n++ )
500 if ( ACCESS_Frame( 2L ) )
501 goto Fail;
503 new_offset = GET_UShort() + base_offset;
505 FORGET_Frame();
507 cur_offset = FILE_Pos();
508 if ( FILE_Seek( new_offset ) ||
509 ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok )
510 goto Fail;
511 (void)FILE_Seek( cur_offset );
514 return HB_Err_Ok;
516 Fail:
517 for ( m = 0; m < n; m++ )
518 Free_CaretValue( &cv[m] );
520 FREE( cv );
521 return error;
525 static void Free_LigGlyph( HB_LigGlyph* lg)
527 HB_UShort n, count;
529 HB_CaretValue* cv;
532 if ( lg->CaretValue )
534 count = lg->CaretCount;
535 cv = lg->CaretValue;
537 for ( n = 0; n < count; n++ )
538 Free_CaretValue( &cv[n] );
540 FREE( cv );
545 /* LigCaretList */
547 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl,
548 HB_Stream stream )
550 HB_Error error;
552 HB_UShort m, n, count;
553 HB_UInt cur_offset, new_offset, base_offset;
555 HB_LigGlyph* lg;
558 base_offset = FILE_Pos();
560 if ( ACCESS_Frame( 2L ) )
561 return error;
563 new_offset = GET_UShort() + base_offset;
565 FORGET_Frame();
567 cur_offset = FILE_Pos();
568 if ( FILE_Seek( new_offset ) ||
569 ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok )
570 return error;
571 (void)FILE_Seek( cur_offset );
573 if ( ACCESS_Frame( 2L ) )
574 goto Fail2;
576 count = lcl->LigGlyphCount = GET_UShort();
578 FORGET_Frame();
580 lcl->LigGlyph = NULL;
582 if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) )
583 goto Fail2;
585 lg = lcl->LigGlyph;
587 for ( n = 0; n < count; n++ )
589 if ( ACCESS_Frame( 2L ) )
590 goto Fail1;
592 new_offset = GET_UShort() + base_offset;
594 FORGET_Frame();
596 cur_offset = FILE_Pos();
597 if ( FILE_Seek( new_offset ) ||
598 ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok )
599 goto Fail1;
600 (void)FILE_Seek( cur_offset );
603 lcl->loaded = TRUE;
605 return HB_Err_Ok;
607 Fail1:
608 for ( m = 0; m < n; m++ )
609 Free_LigGlyph( &lg[m] );
611 FREE( lg );
613 Fail2:
614 _HB_OPEN_Free_Coverage( &lcl->Coverage );
615 return error;
619 static void Free_LigCaretList( HB_LigCaretList* lcl )
621 HB_UShort n, count;
623 HB_LigGlyph* lg;
626 if ( !lcl->loaded )
627 return;
629 if ( lcl->LigGlyph )
631 count = lcl->LigGlyphCount;
632 lg = lcl->LigGlyph;
634 for ( n = 0; n < count; n++ )
635 Free_LigGlyph( &lg[n] );
637 FREE( lg );
640 _HB_OPEN_Free_Coverage( &lcl->Coverage );
645 /***********
646 * GDEF API
647 ***********/
650 static HB_UShort Get_New_Class( HB_GDEFHeader* gdef,
651 HB_UShort glyphID,
652 HB_UShort index )
654 HB_UShort glyph_index, array_index, count;
655 HB_UShort byte, bits;
657 HB_ClassRangeRecord* gcrr;
658 HB_UShort** ngc;
661 if ( glyphID >= gdef->LastGlyph )
662 return 0;
664 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
665 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
666 ngc = gdef->NewGlyphClasses;
668 if ( index < count && glyphID < gcrr[index].Start )
670 array_index = index;
671 if ( index == 0 )
672 glyph_index = glyphID;
673 else
674 glyph_index = glyphID - gcrr[index - 1].End - 1;
676 else
678 array_index = index + 1;
679 glyph_index = glyphID - gcrr[index].End - 1;
682 byte = ngc[array_index][glyph_index / 4];
683 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
685 return bits & 0x000F;
690 HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef,
691 HB_UShort glyphID,
692 HB_UShort* property )
694 HB_UShort class = 0, index = 0; /* shut compiler up */
696 HB_Error error;
699 if ( !gdef || !property )
700 return ERR(HB_Err_Invalid_Argument);
702 /* first, we check for mark attach classes */
704 if ( gdef->MarkAttachClassDef.loaded )
706 error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
707 if ( error && error != HB_Err_Not_Covered )
708 return error;
709 if ( !error )
711 *property = class << 8;
712 return HB_Err_Ok;
716 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
717 if ( error && error != HB_Err_Not_Covered )
718 return error;
720 /* if we have a constructed class table, check whether additional
721 values have been assigned */
723 if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses )
724 class = Get_New_Class( gdef, glyphID, index );
726 switch ( class )
728 default:
729 case UNCLASSIFIED_GLYPH:
730 *property = 0;
731 break;
733 case SIMPLE_GLYPH:
734 *property = HB_GDEF_BASE_GLYPH;
735 break;
737 case LIGATURE_GLYPH:
738 *property = HB_GDEF_LIGATURE;
739 break;
741 case MARK_GLYPH:
742 *property = HB_GDEF_MARK;
743 break;
745 case COMPONENT_GLYPH:
746 *property = HB_GDEF_COMPONENT;
747 break;
750 return HB_Err_Ok;
754 static HB_Error Make_ClassRange( HB_ClassDefinition* cd,
755 HB_UShort start,
756 HB_UShort end,
757 HB_UShort class )
759 HB_Error error;
760 HB_UShort index;
762 HB_ClassDefFormat2* cdf2;
763 HB_ClassRangeRecord* crr;
766 cdf2 = &cd->cd.cd2;
768 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
769 cdf2->ClassRangeCount + 1 ,
770 HB_ClassRangeRecord ) )
771 return error;
773 cdf2->ClassRangeCount++;
775 crr = cdf2->ClassRangeRecord;
776 index = cdf2->ClassRangeCount - 1;
778 crr[index].Start = start;
779 crr[index].End = end;
780 crr[index].Class = class;
782 return HB_Err_Ok;
787 HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef,
788 HB_UShort num_glyphs,
789 HB_UShort glyph_count,
790 HB_UShort* glyph_array,
791 HB_UShort* class_array )
793 HB_UShort start, curr_glyph, curr_class;
794 HB_UShort n, m, count;
795 HB_Error error;
797 HB_ClassDefinition* gcd;
798 HB_ClassRangeRecord* gcrr;
799 HB_UShort** ngc;
802 if ( !gdef || !glyph_array || !class_array )
803 return ERR(HB_Err_Invalid_Argument);
805 gcd = &gdef->GlyphClassDef;
807 /* We build a format 2 table */
809 gcd->ClassFormat = 2;
811 gcd->cd.cd2.ClassRangeCount = 0;
812 gcd->cd.cd2.ClassRangeRecord = NULL;
814 start = glyph_array[0];
815 curr_class = class_array[0];
816 curr_glyph = start;
818 if ( curr_class >= 5 )
820 error = ERR(HB_Err_Invalid_Argument);
821 goto Fail4;
824 glyph_count--;
826 for ( n = 0; n < glyph_count + 1; n++ )
828 if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
830 if ( n == glyph_count )
832 if ( ( error = Make_ClassRange( gcd, start,
833 curr_glyph,
834 curr_class) ) != HB_Err_Ok )
835 goto Fail3;
837 else
839 if ( curr_glyph == 0xFFFF )
841 error = ERR(HB_Err_Invalid_Argument);
842 goto Fail3;
844 else
845 curr_glyph++;
848 else
850 if ( ( error = Make_ClassRange( gcd, start,
851 curr_glyph - 1,
852 curr_class) ) != HB_Err_Ok )
853 goto Fail3;
855 if ( curr_glyph > glyph_array[n] )
857 error = ERR(HB_Err_Invalid_Argument);
858 goto Fail3;
861 start = glyph_array[n];
862 curr_class = class_array[n];
863 curr_glyph = start;
865 if ( curr_class >= 5 )
867 error = ERR(HB_Err_Invalid_Argument);
868 goto Fail3;
871 if ( n == glyph_count )
873 if ( ( error = Make_ClassRange( gcd, start,
874 curr_glyph,
875 curr_class) ) != HB_Err_Ok )
876 goto Fail3;
878 else
880 if ( curr_glyph == 0xFFFF )
882 error = ERR(HB_Err_Invalid_Argument);
883 goto Fail3;
885 else
886 curr_glyph++;
891 /* now prepare the arrays for class values assigned during the lookup
892 process */
894 if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
895 gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) )
896 goto Fail3;
898 count = gcd->cd.cd2.ClassRangeCount;
899 gcrr = gcd->cd.cd2.ClassRangeRecord;
900 ngc = gdef->NewGlyphClasses;
902 /* We allocate arrays for all glyphs not covered by the class range
903 records. Each element holds four class values. */
905 if ( count > 0 )
907 if ( gcrr[0].Start )
909 if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) )
910 goto Fail2;
913 for ( n = 1; n < count; n++ )
915 if ( gcrr[n].Start - gcrr[n - 1].End > 1 )
916 if ( ALLOC_ARRAY( ngc[n],
917 ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4,
918 HB_UShort ) )
919 goto Fail1;
922 if ( gcrr[count - 1].End != num_glyphs - 1 )
924 if ( ALLOC_ARRAY( ngc[count],
925 ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
926 HB_UShort ) )
927 goto Fail1;
930 else if ( num_glyphs > 0 )
932 if ( ALLOC_ARRAY( ngc[count],
933 ( num_glyphs + 3 ) / 4,
934 HB_UShort ) )
935 goto Fail2;
938 gdef->LastGlyph = num_glyphs - 1;
940 gdef->MarkAttachClassDef_offset = 0L;
941 gdef->MarkAttachClassDef.loaded = FALSE;
943 gcd->loaded = TRUE;
945 return HB_Err_Ok;
947 Fail1:
948 for ( m = 0; m < n; m++ )
949 FREE( ngc[m] );
951 Fail2:
952 FREE( gdef->NewGlyphClasses );
954 Fail3:
955 FREE( gcd->cd.cd2.ClassRangeRecord );
957 Fail4:
958 return error;
962 static void Free_NewGlyphClasses( HB_GDEFHeader* gdef )
964 HB_UShort** ngc;
965 HB_UShort n, count;
968 if ( gdef->NewGlyphClasses )
970 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
971 ngc = gdef->NewGlyphClasses;
973 for ( n = 0; n < count; n++ )
974 FREE( ngc[n] );
976 FREE( ngc );
981 HB_INTERNAL HB_Error
982 _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef,
983 HB_UShort glyphID,
984 HB_UShort property )
986 HB_Error error;
987 HB_UShort class, new_class, index = 0; /* shut compiler up */
988 HB_UShort byte, bits, mask;
989 HB_UShort array_index, glyph_index, count;
991 HB_ClassRangeRecord* gcrr;
992 HB_UShort** ngc;
995 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
996 if ( error && error != HB_Err_Not_Covered )
997 return error;
999 /* we don't accept glyphs covered in `GlyphClassDef' */
1001 if ( !error )
1002 return HB_Err_Not_Covered;
1004 switch ( property )
1006 case 0:
1007 new_class = UNCLASSIFIED_GLYPH;
1008 break;
1010 case HB_GDEF_BASE_GLYPH:
1011 new_class = SIMPLE_GLYPH;
1012 break;
1014 case HB_GDEF_LIGATURE:
1015 new_class = LIGATURE_GLYPH;
1016 break;
1018 case HB_GDEF_MARK:
1019 new_class = MARK_GLYPH;
1020 break;
1022 case HB_GDEF_COMPONENT:
1023 new_class = COMPONENT_GLYPH;
1024 break;
1026 default:
1027 return ERR(HB_Err_Invalid_Argument);
1030 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
1031 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
1032 ngc = gdef->NewGlyphClasses;
1034 if ( index < count && glyphID < gcrr[index].Start )
1036 array_index = index;
1037 if ( index == 0 )
1038 glyph_index = glyphID;
1039 else
1040 glyph_index = glyphID - gcrr[index - 1].End - 1;
1042 else
1044 array_index = index + 1;
1045 glyph_index = glyphID - gcrr[index].End - 1;
1048 byte = ngc[array_index][glyph_index / 4];
1049 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1050 class = bits & 0x000F;
1052 /* we don't overwrite existing entries */
1054 if ( !class )
1056 bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1057 mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
1059 ngc[array_index][glyph_index / 4] &= mask;
1060 ngc[array_index][glyph_index / 4] |= bits;
1063 return HB_Err_Ok;
1067 HB_INTERNAL HB_Error
1068 _HB_GDEF_Check_Property( HB_GDEFHeader* gdef,
1069 HB_GlyphItem gitem,
1070 HB_UShort flags,
1071 HB_UShort* property )
1073 HB_Error error;
1075 if ( gdef )
1077 HB_UShort basic_glyph_class;
1078 HB_UShort desired_attachment_class;
1080 if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
1082 error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
1083 if ( error )
1084 return error;
1087 *property = gitem->gproperties;
1089 /* If the glyph was found in the MarkAttachmentClass table,
1090 * then that class value is the high byte of the result,
1091 * otherwise the low byte contains the basic type of the glyph
1092 * as defined by the GlyphClassDef table.
1094 if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
1095 basic_glyph_class = HB_GDEF_MARK;
1096 else
1097 basic_glyph_class = *property;
1099 /* Return Not_Covered, if, for example, basic_glyph_class
1100 * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
1102 if ( flags & basic_glyph_class )
1103 return HB_Err_Not_Covered;
1105 /* The high byte of LookupFlags has the meaning
1106 * "ignore marks of attachment type different than
1107 * the attachment type specified."
1109 desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
1110 if ( desired_attachment_class )
1112 if ( basic_glyph_class == HB_GDEF_MARK &&
1113 *property != desired_attachment_class )
1114 return HB_Err_Not_Covered;
1116 } else {
1117 *property = 0;
1120 return HB_Err_Ok;
1123 HB_INTERNAL HB_Error
1124 _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef,
1125 HB_Stream stream,
1126 HB_Lookup* lo,
1127 HB_UShort num_lookups)
1129 HB_Error error = HB_Err_Ok;
1130 HB_UShort i;
1132 /* We now check the LookupFlags for values larger than 0xFF to find
1133 out whether we need to load the `MarkAttachClassDef' field of the
1134 GDEF table -- this hack is necessary for OpenType 1.2 tables since
1135 the version field of the GDEF table hasn't been incremented.
1137 For constructed GDEF tables, we only load it if
1138 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
1139 a constructed mark attach table is not supported currently). */
1141 if ( gdef &&
1142 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
1144 for ( i = 0; i < num_lookups; i++ )
1147 if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
1149 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
1150 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
1151 256, stream ) ) != HB_Err_Ok )
1152 goto Done;
1154 break;
1159 Done:
1160 return error;
1163 /* END */