• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
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     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 
Free_CaretValue(HB_CaretValue * cv)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 
Load_LigGlyph(HB_LigGlyph * lg,HB_Stream stream)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 
Free_LigGlyph(HB_LigGlyph * lg)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 
Load_LigCaretList(HB_LigCaretList * lcl,HB_Stream stream)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 
Free_LigCaretList(HB_LigCaretList * lcl)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 
Get_New_Class(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort index)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 
HB_GDEF_Get_Glyph_Property(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort * property)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 
Make_ClassRange(HB_ClassDefinition * cd,HB_UShort start,HB_UShort end,HB_UShort class)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 
HB_GDEF_Build_ClassDefinition(HB_GDEFHeader * gdef,HB_UShort num_glyphs,HB_UShort glyph_count,HB_UShort * glyph_array,HB_UShort * class_array)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 
Free_NewGlyphClasses(HB_GDEFHeader * gdef)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
_HB_GDEF_Add_Glyph_Property(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort property)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
_HB_GDEF_Check_Property(HB_GDEFHeader * gdef,HB_GlyphItem gitem,HB_UShort flags,HB_UShort * property)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
_HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags(HB_GDEFHeader * gdef,HB_Stream stream,HB_Lookup * lo,HB_UShort num_lookups)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 */
1160