Imported Upstream version 0.9.3
[platform/upstream/libHarfBuzzSharp.git] / src / hb-old / harfbuzz-gdef.c
1 /*
2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
3  * Copyright (C) 2006  Behdad Esfahbod
4  *
5  * This is part of HarfBuzz, an OpenType Layout engine library.
6  *
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.
12  *
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.
18  *
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.
24  */
25
26 #include "harfbuzz-impl.h"
27 #include "harfbuzz-gdef-private.h"
28 #include "harfbuzz-open-private.h"
29
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 );
34
35 static void  Free_AttachList( HB_AttachList*  al);
36 static void  Free_LigCaretList( HB_LigCaretList*  lcl);
37
38 static void  Free_NewGlyphClasses( HB_GDEFHeader*  gdef);
39
40
41
42 /* GDEF glyph classes */
43
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
49
50
51
52
53
54
55 HB_Error  HB_New_GDEF_Table( HB_GDEFHeader** retptr )
56 {
57   HB_Error         error;
58
59   HB_GDEFHeader*  gdef;
60
61   if ( !retptr )
62     return ERR(HB_Err_Invalid_Argument);
63
64   if ( ALLOC( gdef, sizeof( *gdef ) ) )
65     return error;
66
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;
72
73   gdef->LastGlyph = 0;
74   gdef->NewGlyphClasses = NULL;
75
76   *retptr = gdef;
77
78   return HB_Err_Ok;
79 }
80
81
82 HB_Error  HB_Load_GDEF_Table( HB_Stream stream, 
83                               HB_GDEFHeader** retptr )
84 {
85   HB_Error         error;
86   HB_UInt         cur_offset, new_offset, base_offset;
87
88   HB_GDEFHeader*  gdef;
89
90
91   if ( !retptr )
92     return ERR(HB_Err_Invalid_Argument);
93
94   if ( GOTO_Table( TTAG_GDEF ) )
95     return error;
96
97   if (( error = HB_New_GDEF_Table ( &gdef ) ))
98     return error;
99
100   base_offset = FILE_Pos();
101
102   /* skip version */
103
104   if ( FILE_Seek( base_offset + 4L ) ||
105        ACCESS_Frame( 2L ) )
106     goto Fail0;
107
108   new_offset = GET_UShort();
109
110   FORGET_Frame();
111
112   /* all GDEF subtables are optional */
113
114   if ( new_offset )
115   {
116     new_offset += base_offset;
117
118     /* only classes 1-4 are allowed here */
119
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 );
126   }
127
128   if ( ACCESS_Frame( 2L ) )
129     goto Fail1;
130
131   new_offset = GET_UShort();
132
133   FORGET_Frame();
134
135   if ( new_offset )
136   {
137     new_offset += base_offset;
138
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 );
145   }
146
147   if ( ACCESS_Frame( 2L ) )
148     goto Fail2;
149
150   new_offset = GET_UShort();
151
152   FORGET_Frame();
153
154   if ( new_offset )
155   {
156     new_offset += base_offset;
157
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 );
164   }
165
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. */
169
170   if ( ACCESS_Frame( 2L ) )
171     goto Fail3;
172
173   new_offset = GET_UShort();
174
175   FORGET_Frame();
176
177   if ( new_offset )
178     gdef->MarkAttachClassDef_offset = new_offset + base_offset;
179   else
180     gdef->MarkAttachClassDef_offset = 0;
181
182   *retptr = gdef;
183
184   return HB_Err_Ok;
185
186 Fail3:
187   Free_LigCaretList( &gdef->LigCaretList );
188   
189 Fail2:
190   Free_AttachList( &gdef->AttachList );
191
192 Fail1:
193   _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
194
195 Fail0:
196   FREE( gdef );
197
198   return error;
199 }
200
201
202 HB_Error  HB_Done_GDEF_Table ( HB_GDEFHeader* gdef ) 
203 {  
204   Free_LigCaretList( &gdef->LigCaretList );
205   Free_AttachList( &gdef->AttachList );
206   _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
207   _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef );
208   
209   Free_NewGlyphClasses( gdef );
210
211   FREE( gdef );
212
213   return HB_Err_Ok;
214 }
215
216
217
218
219 /*******************************
220  * AttachList related functions
221  *******************************/
222
223
224 /* AttachPoint */
225
226 static HB_Error  Load_AttachPoint( HB_AttachPoint*  ap,
227                                    HB_Stream         stream )
228 {
229   HB_Error  error;
230
231   HB_UShort   n, count;
232   HB_UShort*  pi;
233
234
235   if ( ACCESS_Frame( 2L ) )
236     return error;
237
238   count = ap->PointCount = GET_UShort();
239
240   FORGET_Frame();
241
242   ap->PointIndex = NULL;
243
244   if ( count )
245   {
246     if ( ALLOC_ARRAY( ap->PointIndex, count, HB_UShort ) )
247       return error;
248
249     pi = ap->PointIndex;
250
251     if ( ACCESS_Frame( count * 2L ) )
252     {
253       FREE( pi );
254       return error;
255     }
256
257     for ( n = 0; n < count; n++ )
258       pi[n] = GET_UShort();
259
260     FORGET_Frame();
261   }
262
263   return HB_Err_Ok;
264 }
265
266
267 static void  Free_AttachPoint( HB_AttachPoint*  ap )
268 {
269   FREE( ap->PointIndex );
270 }
271
272
273 /* AttachList */
274
275 static HB_Error  Load_AttachList( HB_AttachList*  al,
276                                   HB_Stream        stream )
277 {
278   HB_Error  error;
279
280   HB_UShort         n, m, count;
281   HB_UInt          cur_offset, new_offset, base_offset;
282
283   HB_AttachPoint*  ap;
284
285
286   base_offset = FILE_Pos();
287
288   if ( ACCESS_Frame( 2L ) )
289     return error;
290
291   new_offset = GET_UShort() + base_offset;
292
293   FORGET_Frame();
294
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 );
300
301   if ( ACCESS_Frame( 2L ) )
302     goto Fail2;
303
304   count = al->GlyphCount = GET_UShort();
305
306   FORGET_Frame();
307
308   al->AttachPoint = NULL;
309
310   if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) )
311     goto Fail2;
312
313   ap = al->AttachPoint;
314
315   for ( n = 0; n < count; n++ )
316   {
317     if ( ACCESS_Frame( 2L ) )
318       goto Fail1;
319
320     new_offset = GET_UShort() + base_offset;
321
322     FORGET_Frame();
323
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 );
329   }
330
331   al->loaded = TRUE;
332
333   return HB_Err_Ok;
334
335 Fail1:
336   for ( m = 0; m < n; m++ )
337     Free_AttachPoint( &ap[m] );
338
339   FREE( ap );
340
341 Fail2:
342   _HB_OPEN_Free_Coverage( &al->Coverage );
343   return error;
344 }
345
346
347 static void  Free_AttachList( HB_AttachList*  al)
348 {
349   HB_UShort         n, count;
350
351   HB_AttachPoint*  ap;
352
353
354   if ( !al->loaded )
355     return;
356
357   if ( al->AttachPoint )
358   {
359     count = al->GlyphCount;
360     ap    = al->AttachPoint;
361
362     for ( n = 0; n < count; n++ )
363       Free_AttachPoint( &ap[n] );
364
365     FREE( ap );
366   }
367
368   _HB_OPEN_Free_Coverage( &al->Coverage );
369 }
370
371
372
373 /*********************************
374  * LigCaretList related functions
375  *********************************/
376
377
378 /* CaretValueFormat1 */
379 /* CaretValueFormat2 */
380 /* CaretValueFormat3 */
381 /* CaretValueFormat4 */
382
383 static HB_Error  Load_CaretValue( HB_CaretValue*  cv,
384                                   HB_Stream        stream )
385 {
386   HB_Error  error;
387
388   HB_UInt cur_offset, new_offset, base_offset;
389
390
391   base_offset = FILE_Pos();
392
393   if ( ACCESS_Frame( 2L ) )
394     return error;
395
396   cv->CaretValueFormat = GET_UShort();
397
398   FORGET_Frame();
399
400   switch ( cv->CaretValueFormat )
401   {
402   case 1:
403     if ( ACCESS_Frame( 2L ) )
404       return error;
405
406     cv->cvf.cvf1.Coordinate = GET_Short();
407
408     FORGET_Frame();
409
410     break;
411
412   case 2:
413     if ( ACCESS_Frame( 2L ) )
414       return error;
415
416     cv->cvf.cvf2.CaretValuePoint = GET_UShort();
417
418     FORGET_Frame();
419
420     break;
421
422   case 3:
423     if ( ACCESS_Frame( 4L ) )
424       return error;
425
426     cv->cvf.cvf3.Coordinate = GET_Short();
427
428     new_offset = GET_UShort() + base_offset;
429
430     FORGET_Frame();
431
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 );
438
439     break;
440
441   case 4:
442     if ( ACCESS_Frame( 2L ) )
443       return error;
444
445 #ifdef HB_SUPPORT_MULTIPLE_MASTER
446     cv->cvf.cvf4.IdCaretValue = GET_UShort();
447 #else
448     (void) GET_UShort();
449 #endif
450
451     FORGET_Frame();
452     break;
453
454   default:
455     return ERR(HB_Err_Invalid_SubTable_Format);
456   }
457
458   return HB_Err_Ok;
459 }
460
461
462 static void  Free_CaretValue( HB_CaretValue*  cv)
463 {
464   if ( cv->CaretValueFormat == 3 )
465     _HB_OPEN_Free_Device( cv->cvf.cvf3.Device );
466 }
467
468
469 /* LigGlyph */
470
471 static HB_Error  Load_LigGlyph( HB_LigGlyph*  lg,
472                                 HB_Stream      stream )
473 {
474   HB_Error  error;
475
476   HB_UShort        n, m, count;
477   HB_UInt         cur_offset, new_offset, base_offset;
478
479   HB_CaretValue*  cv;
480
481
482   base_offset = FILE_Pos();
483
484   if ( ACCESS_Frame( 2L ) )
485     return error;
486
487   count = lg->CaretCount = GET_UShort();
488
489   FORGET_Frame();
490
491   lg->CaretValue = NULL;
492
493   if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) )
494     return error;
495
496   cv = lg->CaretValue;
497
498   for ( n = 0; n < count; n++ )
499   {
500     if ( ACCESS_Frame( 2L ) )
501       goto Fail;
502
503     new_offset = GET_UShort() + base_offset;
504
505     FORGET_Frame();
506
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 );
512   }
513
514   return HB_Err_Ok;
515
516 Fail:
517   for ( m = 0; m < n; m++ )
518     Free_CaretValue( &cv[m] );
519
520   FREE( cv );
521   return error;
522 }
523
524
525 static void  Free_LigGlyph( HB_LigGlyph*  lg)
526 {
527   HB_UShort        n, count;
528
529   HB_CaretValue*  cv;
530
531
532   if ( lg->CaretValue )
533   {
534     count = lg->CaretCount;
535     cv    = lg->CaretValue;
536
537     for ( n = 0; n < count; n++ )
538       Free_CaretValue( &cv[n] );
539
540     FREE( cv );
541   }
542 }
543
544
545 /* LigCaretList */
546
547 static HB_Error  Load_LigCaretList( HB_LigCaretList*  lcl,
548                                     HB_Stream          stream )
549 {
550   HB_Error  error;
551
552   HB_UShort      m, n, count;
553   HB_UInt       cur_offset, new_offset, base_offset;
554
555   HB_LigGlyph*  lg;
556
557
558   base_offset = FILE_Pos();
559
560   if ( ACCESS_Frame( 2L ) )
561     return error;
562
563   new_offset = GET_UShort() + base_offset;
564
565   FORGET_Frame();
566
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 );
572
573   if ( ACCESS_Frame( 2L ) )
574     goto Fail2;
575
576   count = lcl->LigGlyphCount = GET_UShort();
577
578   FORGET_Frame();
579
580   lcl->LigGlyph = NULL;
581
582   if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) )
583     goto Fail2;
584
585   lg = lcl->LigGlyph;
586
587   for ( n = 0; n < count; n++ )
588   {
589     if ( ACCESS_Frame( 2L ) )
590       goto Fail1;
591
592     new_offset = GET_UShort() + base_offset;
593
594     FORGET_Frame();
595
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 );
601   }
602
603   lcl->loaded = TRUE;
604
605   return HB_Err_Ok;
606
607 Fail1:
608   for ( m = 0; m < n; m++ )
609     Free_LigGlyph( &lg[m] );
610
611   FREE( lg );
612
613 Fail2:
614   _HB_OPEN_Free_Coverage( &lcl->Coverage );
615   return error;
616 }
617
618
619 static void  Free_LigCaretList( HB_LigCaretList*  lcl )
620 {
621   HB_UShort      n, count;
622
623   HB_LigGlyph*  lg;
624
625
626   if ( !lcl->loaded )
627     return;
628
629   if ( lcl->LigGlyph )
630   {
631     count = lcl->LigGlyphCount;
632     lg    = lcl->LigGlyph;
633
634     for ( n = 0; n < count; n++ )
635       Free_LigGlyph( &lg[n] );
636
637     FREE( lg );
638   }
639
640   _HB_OPEN_Free_Coverage( &lcl->Coverage );
641 }
642
643
644
645 /***********
646  * GDEF API
647  ***********/
648
649
650 static HB_UShort  Get_New_Class( HB_GDEFHeader*  gdef,
651                                  HB_UShort        glyphID,
652                                  HB_UShort        index )
653 {
654   HB_UShort              glyph_index, array_index, count;
655   HB_UShort              byte, bits;
656   
657   HB_ClassRangeRecord*  gcrr;
658   HB_UShort**            ngc;
659
660
661   if ( glyphID >= gdef->LastGlyph )
662     return 0;
663
664   count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
665   gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
666   ngc  = gdef->NewGlyphClasses;
667
668   if ( index < count && glyphID < gcrr[index].Start )
669   {
670     array_index = index;
671     if ( index == 0 )
672       glyph_index = glyphID;
673     else
674       glyph_index = glyphID - gcrr[index - 1].End - 1;
675   }
676   else
677   {
678     array_index = index + 1;
679     glyph_index = glyphID - gcrr[index].End - 1;
680   }
681
682   byte = ngc[array_index][glyph_index / 4];
683   bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
684
685   return bits & 0x000F;
686 }
687
688
689
690 HB_Error  HB_GDEF_Get_Glyph_Property( HB_GDEFHeader*  gdef,
691                                       HB_UShort        glyphID,
692                                       HB_UShort*       property )
693 {
694   HB_UShort class = 0, index = 0; /* shut compiler up */
695
696   HB_Error  error;
697
698
699   if ( !gdef || !property )
700     return ERR(HB_Err_Invalid_Argument);
701
702   /* first, we check for mark attach classes */
703
704   if ( gdef->MarkAttachClassDef.loaded )
705   {
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 )
710     {
711       *property = class << 8;
712       return HB_Err_Ok;
713     }
714   }
715
716   error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
717   if ( error && error != HB_Err_Not_Covered )
718     return error;
719
720   /* if we have a constructed class table, check whether additional
721      values have been assigned                                      */
722
723   if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses )
724     class = Get_New_Class( gdef, glyphID, index );
725
726   switch ( class )
727   {
728   default:
729   case UNCLASSIFIED_GLYPH:
730     *property = 0;
731     break;
732
733   case SIMPLE_GLYPH:
734     *property = HB_GDEF_BASE_GLYPH;
735     break;
736
737   case LIGATURE_GLYPH:
738     *property = HB_GDEF_LIGATURE;
739     break;
740
741   case MARK_GLYPH:
742     *property = HB_GDEF_MARK;
743     break;
744
745   case COMPONENT_GLYPH:
746     *property = HB_GDEF_COMPONENT;
747     break;
748   }
749
750   return HB_Err_Ok;
751 }
752
753
754 static HB_Error  Make_ClassRange( HB_ClassDefinition*  cd,
755                                   HB_UShort             start,
756                                   HB_UShort             end,
757                                   HB_UShort             class )
758 {
759   HB_Error               error;
760   HB_UShort              index;
761
762   HB_ClassDefFormat2*   cdf2;
763   HB_ClassRangeRecord*  crr;
764
765
766   cdf2 = &cd->cd.cd2;
767
768   if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
769                       cdf2->ClassRangeCount + 1 ,
770                       HB_ClassRangeRecord ) )
771     return error;
772
773   cdf2->ClassRangeCount++;
774
775   crr   = cdf2->ClassRangeRecord;
776   index = cdf2->ClassRangeCount - 1;
777
778   crr[index].Start = start;
779   crr[index].End   = end;
780   crr[index].Class = class;
781
782   return HB_Err_Ok;
783 }
784
785
786
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 )
792 {
793   HB_UShort              start, curr_glyph, curr_class;
794   HB_UShort              n, m, count;
795   HB_Error               error;
796
797   HB_ClassDefinition*   gcd;
798   HB_ClassRangeRecord*  gcrr;
799   HB_UShort**            ngc;
800
801
802   if ( !gdef || !glyph_array || !class_array )
803     return ERR(HB_Err_Invalid_Argument);
804
805   gcd = &gdef->GlyphClassDef;
806
807   /* We build a format 2 table */
808
809   gcd->ClassFormat = 2;
810
811   gcd->cd.cd2.ClassRangeCount  = 0;
812   gcd->cd.cd2.ClassRangeRecord = NULL;
813
814   start      = glyph_array[0];
815   curr_class = class_array[0];
816   curr_glyph = start;
817
818   if ( curr_class >= 5 )
819   {
820     error = ERR(HB_Err_Invalid_Argument);
821     goto Fail4;
822   }
823
824   glyph_count--;
825
826   for ( n = 0; n < glyph_count + 1; n++ )
827   {
828     if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
829     {
830       if ( n == glyph_count )
831       {
832         if ( ( error = Make_ClassRange( gcd, start,
833                                         curr_glyph,
834                                         curr_class) ) != HB_Err_Ok )
835           goto Fail3;
836       }
837       else
838       {
839         if ( curr_glyph == 0xFFFF )
840         {
841           error = ERR(HB_Err_Invalid_Argument);
842           goto Fail3;
843         }
844         else
845           curr_glyph++;
846       }
847     }
848     else
849     {
850       if ( ( error = Make_ClassRange( gcd, start,
851                                       curr_glyph - 1,
852                                       curr_class) ) != HB_Err_Ok )
853         goto Fail3;
854
855       if ( curr_glyph > glyph_array[n] )
856       {
857         error = ERR(HB_Err_Invalid_Argument);
858         goto Fail3;
859       }
860
861       start      = glyph_array[n];
862       curr_class = class_array[n];
863       curr_glyph = start;
864
865       if ( curr_class >= 5 )
866       {
867         error = ERR(HB_Err_Invalid_Argument);
868         goto Fail3;
869       }
870
871       if ( n == glyph_count )
872       {
873         if ( ( error = Make_ClassRange( gcd, start,
874                                         curr_glyph,
875                                         curr_class) ) != HB_Err_Ok )
876           goto Fail3;
877       }
878       else
879       {
880         if ( curr_glyph == 0xFFFF )
881         {
882           error = ERR(HB_Err_Invalid_Argument);
883           goto Fail3;
884         }
885         else
886           curr_glyph++;
887       }
888     }
889   }
890
891   /* now prepare the arrays for class values assigned during the lookup
892      process                                                            */
893
894   if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
895                     gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) )
896     goto Fail3;
897
898   count = gcd->cd.cd2.ClassRangeCount;
899   gcrr  = gcd->cd.cd2.ClassRangeRecord;
900   ngc   = gdef->NewGlyphClasses;
901
902   /* We allocate arrays for all glyphs not covered by the class range
903      records.  Each element holds four class values.                  */
904
905   if ( count > 0 )
906   {
907       if ( gcrr[0].Start )
908       {
909         if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) )
910           goto Fail2;
911       }
912
913       for ( n = 1; n < count; n++ )
914       {
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;
920       }
921
922       if ( gcrr[count - 1].End != num_glyphs - 1 )
923       {
924         if ( ALLOC_ARRAY( ngc[count],
925                           ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
926                           HB_UShort ) )
927             goto Fail1;
928       }
929   }
930   else if ( num_glyphs > 0 )
931   {
932       if ( ALLOC_ARRAY( ngc[count],
933                         ( num_glyphs + 3 ) / 4,
934                         HB_UShort ) )
935           goto Fail2;
936   }
937       
938   gdef->LastGlyph = num_glyphs - 1;
939
940   gdef->MarkAttachClassDef_offset = 0L;
941   gdef->MarkAttachClassDef.loaded = FALSE;
942
943   gcd->loaded = TRUE;
944
945   return HB_Err_Ok;
946
947 Fail1:
948   for ( m = 0; m < n; m++ )
949     FREE( ngc[m] );
950
951 Fail2:
952   FREE( gdef->NewGlyphClasses );
953
954 Fail3:
955   FREE( gcd->cd.cd2.ClassRangeRecord );
956
957 Fail4:
958   return error;
959 }
960
961
962 static void  Free_NewGlyphClasses( HB_GDEFHeader*  gdef )
963 {
964   HB_UShort**  ngc;
965   HB_UShort    n, count;
966
967
968   if ( gdef->NewGlyphClasses )
969   {
970     count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
971     ngc   = gdef->NewGlyphClasses;
972
973     for ( n = 0; n < count; n++ )
974       FREE( ngc[n] );
975
976     FREE( ngc );
977   }
978 }
979
980
981 HB_INTERNAL HB_Error
982 _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef,
983                               HB_UShort        glyphID,
984                               HB_UShort        property )
985 {
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;
990
991   HB_ClassRangeRecord*  gcrr;
992   HB_UShort**            ngc;
993
994
995   error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
996   if ( error && error != HB_Err_Not_Covered )
997     return error;
998
999   /* we don't accept glyphs covered in `GlyphClassDef' */
1000
1001   if ( !error )
1002     return HB_Err_Not_Covered;
1003
1004   switch ( property )
1005   {
1006   case 0:
1007     new_class = UNCLASSIFIED_GLYPH;
1008     break;
1009
1010   case HB_GDEF_BASE_GLYPH:
1011     new_class = SIMPLE_GLYPH;
1012     break;
1013
1014   case HB_GDEF_LIGATURE:
1015     new_class = LIGATURE_GLYPH;
1016     break;
1017
1018   case HB_GDEF_MARK:
1019     new_class = MARK_GLYPH;
1020     break;
1021
1022   case HB_GDEF_COMPONENT:
1023     new_class = COMPONENT_GLYPH;
1024     break;
1025
1026   default:
1027     return ERR(HB_Err_Invalid_Argument);
1028   }
1029
1030   count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
1031   gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
1032   ngc  = gdef->NewGlyphClasses;
1033
1034   if ( index < count && glyphID < gcrr[index].Start )
1035   {
1036     array_index = index;
1037     if ( index == 0 )
1038       glyph_index = glyphID;
1039     else
1040       glyph_index = glyphID - gcrr[index - 1].End - 1;
1041   }
1042   else
1043   {
1044     array_index = index + 1;
1045     glyph_index = glyphID - gcrr[index].End - 1;
1046   }
1047
1048   byte  = ngc[array_index][glyph_index / 4];
1049   bits  = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1050   class = bits & 0x000F;
1051
1052   /* we don't overwrite existing entries */
1053
1054   if ( !class )
1055   {
1056     bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1057     mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
1058
1059     ngc[array_index][glyph_index / 4] &= mask;
1060     ngc[array_index][glyph_index / 4] |= bits;
1061   }
1062
1063   return HB_Err_Ok;
1064 }
1065
1066
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 )
1072 {
1073   HB_Error  error;
1074
1075   if ( gdef )
1076   {
1077     HB_UShort basic_glyph_class;
1078     HB_UShort desired_attachment_class;
1079
1080     if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
1081     {
1082       error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
1083       if ( error )
1084         return error;
1085     }
1086
1087     *property = gitem->gproperties;
1088
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.
1093      */
1094     if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS  )
1095       basic_glyph_class = HB_GDEF_MARK;
1096     else
1097       basic_glyph_class = *property;
1098
1099     /* Return Not_Covered, if, for example, basic_glyph_class
1100      * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
1101      */
1102     if ( flags & basic_glyph_class )
1103       return HB_Err_Not_Covered;
1104     
1105     /* The high byte of LookupFlags has the meaning
1106      * "ignore marks of attachment type different than
1107      * the attachment type specified."
1108      */
1109     desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
1110     if ( desired_attachment_class )
1111     {
1112       if ( basic_glyph_class == HB_GDEF_MARK &&
1113            *property != desired_attachment_class )
1114         return HB_Err_Not_Covered;
1115     }
1116   } else {
1117       *property = 0;
1118   }
1119
1120   return HB_Err_Ok;
1121 }
1122
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)
1128 {
1129   HB_Error   error = HB_Err_Ok;
1130   HB_UShort  i;
1131
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.
1136
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).       */
1140
1141   if ( gdef &&
1142        gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
1143   {
1144     for ( i = 0; i < num_lookups; i++ )
1145     {
1146
1147       if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
1148       {
1149         if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
1150              ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
1151                                              256, stream ) ) != HB_Err_Ok )
1152           goto Done;
1153
1154         break;
1155       }
1156     }
1157   }
1158
1159 Done:
1160   return error;
1161 }
1162
1163 /* END */