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 
HB_New_GDEF_Table(HB_GDEFHeader ** retptr)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 
HB_Load_GDEF_Table(HB_Stream stream,HB_GDEFHeader ** retptr)82 HB_Error  HB_Load_GDEF_Table( HB_Stream stream,
83 			      HB_GDEFHeader** retptr )
84 {
85   HB_Error         error = HB_Err_Ok;
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 
HB_Done_GDEF_Table(HB_GDEFHeader * gdef)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 
Load_AttachPoint(HB_AttachPoint * ap,HB_Stream stream)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 
Free_AttachPoint(HB_AttachPoint * ap)267 static void  Free_AttachPoint( HB_AttachPoint*  ap )
268 {
269   FREE( ap->PointIndex );
270 }
271 
272 
273 /* AttachList */
274 
Load_AttachList(HB_AttachList * al,HB_Stream stream)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 
Free_AttachList(HB_AttachList * al)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 
Load_CaretValue(HB_CaretValue * cv,HB_Stream stream)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 
Free_CaretValue(HB_CaretValue * cv)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 
Load_LigGlyph(HB_LigGlyph * lg,HB_Stream stream)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 
Free_LigGlyph(HB_LigGlyph * lg)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 
Load_LigCaretList(HB_LigCaretList * lcl,HB_Stream stream)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 
Free_LigCaretList(HB_LigCaretList * lcl)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 
Get_New_Class(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort index)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 
HB_GDEF_Get_Glyph_Property(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort * property)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 
Make_ClassRange(HB_ClassDefinition * cd,HB_UShort start,HB_UShort end,HB_UShort class)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 
HB_GDEF_Build_ClassDefinition(HB_GDEFHeader * gdef,HB_UShort num_glyphs,HB_UShort glyph_count,HB_UShort * glyph_array,HB_UShort * class_array)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 
Free_NewGlyphClasses(HB_GDEFHeader * gdef)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
_HB_GDEF_Add_Glyph_Property(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort property)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
_HB_GDEF_Check_Property(HB_GDEFHeader * gdef,HB_GlyphItem gitem,HB_UShort flags,HB_UShort * property)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
_HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags(HB_GDEFHeader * gdef,HB_Stream stream,HB_Lookup * lo,HB_UShort num_lookups)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 */
1164