Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / third_party / harfbuzz / src / 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     cv->cvf.cvf4.IdCaretValue = GET_UShort();
446
447     FORGET_Frame();
448     break;
449
450   default:
451     return ERR(HB_Err_Invalid_SubTable_Format);
452   }
453
454   return HB_Err_Ok;
455 }
456
457
458 static void  Free_CaretValue( HB_CaretValue*  cv)
459 {
460   if ( cv->CaretValueFormat == 3 )
461     _HB_OPEN_Free_Device( &cv->cvf.cvf3.Device );
462 }
463
464
465 /* LigGlyph */
466
467 static HB_Error  Load_LigGlyph( HB_LigGlyph*  lg,
468                                 HB_Stream      stream )
469 {
470   HB_Error  error;
471
472   HB_UShort        n, m, count;
473   HB_UInt         cur_offset, new_offset, base_offset;
474
475   HB_CaretValue*  cv;
476
477
478   base_offset = FILE_Pos();
479
480   if ( ACCESS_Frame( 2L ) )
481     return error;
482
483   count = lg->CaretCount = GET_UShort();
484
485   FORGET_Frame();
486
487   lg->CaretValue = NULL;
488
489   if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) )
490     return error;
491
492   cv = lg->CaretValue;
493
494   for ( n = 0; n < count; n++ )
495   {
496     if ( ACCESS_Frame( 2L ) )
497       goto Fail;
498
499     new_offset = GET_UShort() + base_offset;
500
501     FORGET_Frame();
502
503     cur_offset = FILE_Pos();
504     if ( FILE_Seek( new_offset ) ||
505          ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok )
506       goto Fail;
507     (void)FILE_Seek( cur_offset );
508   }
509
510   return HB_Err_Ok;
511
512 Fail:
513   for ( m = 0; m < n; m++ )
514     Free_CaretValue( &cv[m] );
515
516   FREE( cv );
517   return error;
518 }
519
520
521 static void  Free_LigGlyph( HB_LigGlyph*  lg)
522 {
523   HB_UShort        n, count;
524
525   HB_CaretValue*  cv;
526
527
528   if ( lg->CaretValue )
529   {
530     count = lg->CaretCount;
531     cv    = lg->CaretValue;
532
533     for ( n = 0; n < count; n++ )
534       Free_CaretValue( &cv[n] );
535
536     FREE( cv );
537   }
538 }
539
540
541 /* LigCaretList */
542
543 static HB_Error  Load_LigCaretList( HB_LigCaretList*  lcl,
544                                     HB_Stream          stream )
545 {
546   HB_Error  error;
547
548   HB_UShort      m, n, count;
549   HB_UInt       cur_offset, new_offset, base_offset;
550
551   HB_LigGlyph*  lg;
552
553
554   base_offset = FILE_Pos();
555
556   if ( ACCESS_Frame( 2L ) )
557     return error;
558
559   new_offset = GET_UShort() + base_offset;
560
561   FORGET_Frame();
562
563   cur_offset = FILE_Pos();
564   if ( FILE_Seek( new_offset ) ||
565        ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok )
566     return error;
567   (void)FILE_Seek( cur_offset );
568
569   if ( ACCESS_Frame( 2L ) )
570     goto Fail2;
571
572   count = lcl->LigGlyphCount = GET_UShort();
573
574   FORGET_Frame();
575
576   lcl->LigGlyph = NULL;
577
578   if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) )
579     goto Fail2;
580
581   lg = lcl->LigGlyph;
582
583   for ( n = 0; n < count; n++ )
584   {
585     if ( ACCESS_Frame( 2L ) )
586       goto Fail1;
587
588     new_offset = GET_UShort() + base_offset;
589
590     FORGET_Frame();
591
592     cur_offset = FILE_Pos();
593     if ( FILE_Seek( new_offset ) ||
594          ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok )
595       goto Fail1;
596     (void)FILE_Seek( cur_offset );
597   }
598
599   lcl->loaded = TRUE;
600
601   return HB_Err_Ok;
602
603 Fail1:
604   for ( m = 0; m < n; m++ )
605     Free_LigGlyph( &lg[m] );
606
607   FREE( lg );
608
609 Fail2:
610   _HB_OPEN_Free_Coverage( &lcl->Coverage );
611   return error;
612 }
613
614
615 static void  Free_LigCaretList( HB_LigCaretList*  lcl )
616 {
617   HB_UShort      n, count;
618
619   HB_LigGlyph*  lg;
620
621
622   if ( !lcl->loaded )
623     return;
624
625   if ( lcl->LigGlyph )
626   {
627     count = lcl->LigGlyphCount;
628     lg    = lcl->LigGlyph;
629
630     for ( n = 0; n < count; n++ )
631       Free_LigGlyph( &lg[n] );
632
633     FREE( lg );
634   }
635
636   _HB_OPEN_Free_Coverage( &lcl->Coverage );
637 }
638
639
640
641 /***********
642  * GDEF API
643  ***********/
644
645
646 static HB_UShort  Get_New_Class( HB_GDEFHeader*  gdef,
647                                  HB_UShort        glyphID,
648                                  HB_UShort        index )
649 {
650   HB_UShort              glyph_index, array_index, count;
651   HB_UShort              byte, bits;
652   
653   HB_ClassRangeRecord*  gcrr;
654   HB_UShort**            ngc;
655
656
657   if ( glyphID >= gdef->LastGlyph )
658     return 0;
659
660   count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
661   gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
662   ngc  = gdef->NewGlyphClasses;
663
664   if ( index < count && glyphID < gcrr[index].Start )
665   {
666     array_index = index;
667     if ( index == 0 )
668       glyph_index = glyphID;
669     else
670       glyph_index = glyphID - gcrr[index - 1].End - 1;
671   }
672   else
673   {
674     array_index = index + 1;
675     glyph_index = glyphID - gcrr[index].End - 1;
676   }
677
678   byte = ngc[array_index][glyph_index / 4];
679   bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
680
681   return bits & 0x000F;
682 }
683
684
685
686 HB_Error  HB_GDEF_Get_Glyph_Property( HB_GDEFHeader*  gdef,
687                                       HB_UShort        glyphID,
688                                       HB_UShort*       property )
689 {
690   HB_UShort class = 0, index = 0; /* shut compiler up */
691
692   HB_Error  error;
693
694
695   if ( !gdef || !property )
696     return ERR(HB_Err_Invalid_Argument);
697
698   /* first, we check for mark attach classes */
699
700   if ( gdef->MarkAttachClassDef.loaded )
701   {
702     error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
703     if ( error && error != HB_Err_Not_Covered )
704       return error;
705     if ( !error )
706     {
707       *property = class << 8;
708       return HB_Err_Ok;
709     }
710   }
711
712   error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
713   if ( error && error != HB_Err_Not_Covered )
714     return error;
715
716   /* if we have a constructed class table, check whether additional
717      values have been assigned                                      */
718
719   if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses )
720     class = Get_New_Class( gdef, glyphID, index );
721
722   switch ( class )
723   {
724   default:
725   case UNCLASSIFIED_GLYPH:
726     *property = 0;
727     break;
728
729   case SIMPLE_GLYPH:
730     *property = HB_GDEF_BASE_GLYPH;
731     break;
732
733   case LIGATURE_GLYPH:
734     *property = HB_GDEF_LIGATURE;
735     break;
736
737   case MARK_GLYPH:
738     *property = HB_GDEF_MARK;
739     break;
740
741   case COMPONENT_GLYPH:
742     *property = HB_GDEF_COMPONENT;
743     break;
744   }
745
746   return HB_Err_Ok;
747 }
748
749
750 static HB_Error  Make_ClassRange( HB_ClassDefinition*  cd,
751                                   HB_UShort             start,
752                                   HB_UShort             end,
753                                   HB_UShort             class )
754 {
755   HB_Error               error;
756   HB_UShort              index;
757
758   HB_ClassDefFormat2*   cdf2;
759   HB_ClassRangeRecord*  crr;
760
761
762   cdf2 = &cd->cd.cd2;
763
764   if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
765                       cdf2->ClassRangeCount + 1 ,
766                       HB_ClassRangeRecord ) )
767     return error;
768
769   cdf2->ClassRangeCount++;
770
771   crr   = cdf2->ClassRangeRecord;
772   index = cdf2->ClassRangeCount - 1;
773
774   crr[index].Start = start;
775   crr[index].End   = end;
776   crr[index].Class = class;
777
778   return HB_Err_Ok;
779 }
780
781
782
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 )
788 {
789   HB_UShort              start, curr_glyph, curr_class;
790   HB_UShort              n, m, count;
791   HB_Error               error;
792
793   HB_ClassDefinition*   gcd;
794   HB_ClassRangeRecord*  gcrr;
795   HB_UShort**            ngc;
796
797
798   if ( !gdef || !glyph_array || !class_array )
799     return ERR(HB_Err_Invalid_Argument);
800
801   gcd = &gdef->GlyphClassDef;
802
803   /* We build a format 2 table */
804
805   gcd->ClassFormat = 2;
806
807   gcd->cd.cd2.ClassRangeCount  = 0;
808   gcd->cd.cd2.ClassRangeRecord = NULL;
809
810   start      = glyph_array[0];
811   curr_class = class_array[0];
812   curr_glyph = start;
813
814   if ( curr_class >= 5 )
815   {
816     error = ERR(HB_Err_Invalid_Argument);
817     goto Fail4;
818   }
819
820   glyph_count--;
821
822   for ( n = 0; n < glyph_count + 1; n++ )
823   {
824     if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
825     {
826       if ( n == glyph_count )
827       {
828         if ( ( error = Make_ClassRange( gcd, start,
829                                         curr_glyph,
830                                         curr_class) ) != HB_Err_Ok )
831           goto Fail3;
832       }
833       else
834       {
835         if ( curr_glyph == 0xFFFF )
836         {
837           error = ERR(HB_Err_Invalid_Argument);
838           goto Fail3;
839         }
840         else
841           curr_glyph++;
842       }
843     }
844     else
845     {
846       if ( ( error = Make_ClassRange( gcd, start,
847                                       curr_glyph - 1,
848                                       curr_class) ) != HB_Err_Ok )
849         goto Fail3;
850
851       if ( curr_glyph > glyph_array[n] )
852       {
853         error = ERR(HB_Err_Invalid_Argument);
854         goto Fail3;
855       }
856
857       start      = glyph_array[n];
858       curr_class = class_array[n];
859       curr_glyph = start;
860
861       if ( curr_class >= 5 )
862       {
863         error = ERR(HB_Err_Invalid_Argument);
864         goto Fail3;
865       }
866
867       if ( n == glyph_count )
868       {
869         if ( ( error = Make_ClassRange( gcd, start,
870                                         curr_glyph,
871                                         curr_class) ) != HB_Err_Ok )
872           goto Fail3;
873       }
874       else
875       {
876         if ( curr_glyph == 0xFFFF )
877         {
878           error = ERR(HB_Err_Invalid_Argument);
879           goto Fail3;
880         }
881         else
882           curr_glyph++;
883       }
884     }
885   }
886
887   /* now prepare the arrays for class values assigned during the lookup
888      process                                                            */
889
890   if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
891                     gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) )
892     goto Fail3;
893
894   count = gcd->cd.cd2.ClassRangeCount;
895   gcrr  = gcd->cd.cd2.ClassRangeRecord;
896   ngc   = gdef->NewGlyphClasses;
897
898   /* We allocate arrays for all glyphs not covered by the class range
899      records.  Each element holds four class values.                  */
900
901   if ( count > 0 )
902   {
903       if ( gcrr[0].Start )
904       {
905         if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) )
906           goto Fail2;
907       }
908
909       for ( n = 1; n < count; n++ )
910       {
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,
914                             HB_UShort ) )
915             goto Fail1;
916       }
917
918       if ( gcrr[count - 1].End != num_glyphs - 1 )
919       {
920         if ( ALLOC_ARRAY( ngc[count],
921                           ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
922                           HB_UShort ) )
923             goto Fail1;
924       }
925   }
926   else if ( num_glyphs > 0 )
927   {
928       if ( ALLOC_ARRAY( ngc[count],
929                         ( num_glyphs + 3 ) / 4,
930                         HB_UShort ) )
931           goto Fail2;
932   }
933       
934   gdef->LastGlyph = num_glyphs - 1;
935
936   gdef->MarkAttachClassDef_offset = 0L;
937   gdef->MarkAttachClassDef.loaded = FALSE;
938
939   gcd->loaded = TRUE;
940
941   return HB_Err_Ok;
942
943 Fail1:
944   for ( m = 0; m < n; m++ )
945     FREE( ngc[m] );
946
947 Fail2:
948   FREE( gdef->NewGlyphClasses );
949
950 Fail3:
951   FREE( gcd->cd.cd2.ClassRangeRecord );
952
953 Fail4:
954   return error;
955 }
956
957
958 static void  Free_NewGlyphClasses( HB_GDEFHeader*  gdef )
959 {
960   HB_UShort**  ngc;
961   HB_UShort    n, count;
962
963
964   if ( gdef->NewGlyphClasses )
965   {
966     count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
967     ngc   = gdef->NewGlyphClasses;
968
969     for ( n = 0; n < count; n++ )
970       FREE( ngc[n] );
971
972     FREE( ngc );
973   }
974 }
975
976
977 HB_INTERNAL HB_Error
978 _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef,
979                               HB_UShort        glyphID,
980                               HB_UShort        property )
981 {
982   HB_Error               error;
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;
986
987   HB_ClassRangeRecord*  gcrr;
988   HB_UShort**            ngc;
989
990
991   error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
992   if ( error && error != HB_Err_Not_Covered )
993     return error;
994
995   /* we don't accept glyphs covered in `GlyphClassDef' */
996
997   if ( !error )
998     return HB_Err_Not_Covered;
999
1000   switch ( property )
1001   {
1002   case 0:
1003     new_class = UNCLASSIFIED_GLYPH;
1004     break;
1005
1006   case HB_GDEF_BASE_GLYPH:
1007     new_class = SIMPLE_GLYPH;
1008     break;
1009
1010   case HB_GDEF_LIGATURE:
1011     new_class = LIGATURE_GLYPH;
1012     break;
1013
1014   case HB_GDEF_MARK:
1015     new_class = MARK_GLYPH;
1016     break;
1017
1018   case HB_GDEF_COMPONENT:
1019     new_class = COMPONENT_GLYPH;
1020     break;
1021
1022   default:
1023     return ERR(HB_Err_Invalid_Argument);
1024   }
1025
1026   count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
1027   gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
1028   ngc  = gdef->NewGlyphClasses;
1029
1030   if ( index < count && glyphID < gcrr[index].Start )
1031   {
1032     array_index = index;
1033     if ( index == 0 )
1034       glyph_index = glyphID;
1035     else
1036       glyph_index = glyphID - gcrr[index - 1].End - 1;
1037   }
1038   else
1039   {
1040     array_index = index + 1;
1041     glyph_index = glyphID - gcrr[index].End - 1;
1042   }
1043
1044   byte  = ngc[array_index][glyph_index / 4];
1045   bits  = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1046   class = bits & 0x000F;
1047
1048   /* we don't overwrite existing entries */
1049
1050   if ( !class )
1051   {
1052     bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
1053     mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
1054
1055     ngc[array_index][glyph_index / 4] &= mask;
1056     ngc[array_index][glyph_index / 4] |= bits;
1057   }
1058
1059   return HB_Err_Ok;
1060 }
1061
1062
1063 HB_INTERNAL HB_Error
1064 _HB_GDEF_Check_Property( HB_GDEFHeader* gdef,
1065                           HB_GlyphItem    gitem,
1066                           HB_UShort        flags,
1067                           HB_UShort*       property )
1068 {
1069   HB_Error  error;
1070
1071   if ( gdef )
1072   {
1073     HB_UShort basic_glyph_class;
1074     HB_UShort desired_attachment_class;
1075
1076     if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
1077     {
1078       error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
1079       if ( error )
1080         return error;
1081     }
1082
1083     *property = gitem->gproperties;
1084
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.
1089      */
1090     if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS  )
1091       basic_glyph_class = HB_GDEF_MARK;
1092     else
1093       basic_glyph_class = *property;
1094
1095     /* Return Not_Covered, if, for example, basic_glyph_class
1096      * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
1097      */
1098     if ( flags & basic_glyph_class )
1099       return HB_Err_Not_Covered;
1100     
1101     /* The high byte of LookupFlags has the meaning
1102      * "ignore marks of attachment type different than
1103      * the attachment type specified."
1104      */
1105     desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
1106     if ( desired_attachment_class )
1107     {
1108       if ( basic_glyph_class == HB_GDEF_MARK &&
1109            *property != desired_attachment_class )
1110         return HB_Err_Not_Covered;
1111     }
1112   } else {
1113       *property = 0;
1114   }
1115
1116   return HB_Err_Ok;
1117 }
1118
1119 HB_INTERNAL HB_Error
1120 _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef,
1121                                                   HB_Stream      stream,
1122                                                   HB_Lookup*     lo,
1123                                                   HB_UShort      num_lookups)
1124 {
1125   HB_Error   error = HB_Err_Ok;
1126   HB_UShort  i;
1127
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.
1132
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).       */
1136
1137   if ( gdef &&
1138        gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
1139   {
1140     for ( i = 0; i < num_lookups; i++ )
1141     {
1142
1143       if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
1144       {
1145         if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
1146              ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
1147                                              256, stream ) ) != HB_Err_Ok )
1148           goto Done;
1149
1150         break;
1151       }
1152     }
1153   }
1154
1155 Done:
1156   return error;
1157 }
1158
1159 /* END */