Home | History | Annotate | Download | only in hb-old
      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 */
   1164