Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
      3  * Copyright (C) 2006  Behdad Esfahbod
      4  * Copyright (C) 2007  Red Hat, Inc.
      5  *
      6  * This is part of HarfBuzz, an OpenType Layout engine library.
      7  *
      8  * Permission is hereby granted, without written agreement and without
      9  * license or royalty fees, to use, copy, modify, and distribute this
     10  * software and its documentation for any purpose, provided that the
     11  * above copyright notice and the following two paragraphs appear in
     12  * all copies of this software.
     13  *
     14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     18  * DAMAGE.
     19  *
     20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     25  *
     26  * Red Hat Author(s): Behdad Esfahbod
     27  */
     28 
     29 #include "harfbuzz-impl.h"
     30 #include "harfbuzz-gpos-private.h"
     31 #include "harfbuzz-open-private.h"
     32 #include "harfbuzz-gdef-private.h"
     33 #include "harfbuzz-shaper.h"
     34 
     35 struct  GPOS_Instance_
     36 {
     37   HB_GPOSHeader*  gpos;
     38   HB_Font          font;
     39   HB_Bool          dvi;
     40   HB_UShort        load_flags;  /* how the glyph should be loaded */
     41   HB_Bool          r2l;
     42 
     43   HB_UShort        last;        /* the last valid glyph -- used
     44 				   with cursive positioning     */
     45   HB_Fixed           anchor_x;    /* the coordinates of the anchor point */
     46   HB_Fixed           anchor_y;    /* of the last valid glyph             */
     47 };
     48 
     49 typedef struct GPOS_Instance_  GPOS_Instance;
     50 
     51 
     52 static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
     53 				       HB_UShort         lookup_index,
     54 				       HB_Buffer        buffer,
     55 				       HB_UShort         context_length,
     56 				       int               nesting_level );
     57 
     58 
     59 
     60 /* the client application must replace this with something more
     61    meaningful if multiple master fonts are to be supported.     */
     62 
     63 static HB_Error  default_mmfunc( HB_Font      font,
     64 				 HB_UShort    metric_id,
     65 				 HB_Fixed*      metric_value,
     66 				 void*        data )
     67 {
     68   HB_UNUSED(font);
     69   HB_UNUSED(metric_id);
     70   HB_UNUSED(metric_value);
     71   HB_UNUSED(data);
     72   return ERR(HB_Err_Not_Covered); /* ERR() call intended */
     73 }
     74 
     75 
     76 
     77 HB_Error  HB_Load_GPOS_Table( HB_Stream stream,
     78 			      HB_GPOSHeader** retptr,
     79 			      HB_GDEFHeader*  gdef,
     80 			      HB_Stream       gdefStream )
     81 {
     82   HB_UInt         cur_offset, new_offset, base_offset;
     83 
     84   HB_GPOSHeader*  gpos;
     85 
     86   HB_Error   error;
     87 
     88 
     89   if ( !retptr )
     90     return ERR(HB_Err_Invalid_Argument);
     91 
     92   if ( GOTO_Table( TTAG_GPOS ) )
     93     return error;
     94 
     95   base_offset = FILE_Pos();
     96 
     97   if ( ALLOC ( gpos, sizeof( *gpos ) ) )
     98     return error;
     99 
    100   gpos->mmfunc = default_mmfunc;
    101 
    102   /* skip version */
    103 
    104   if ( FILE_Seek( base_offset + 4L ) ||
    105        ACCESS_Frame( 2L ) )
    106     goto Fail4;
    107 
    108   new_offset = GET_UShort() + base_offset;
    109 
    110   FORGET_Frame();
    111 
    112   cur_offset = FILE_Pos();
    113   if ( FILE_Seek( new_offset ) ||
    114        ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
    115 				  stream ) ) != HB_Err_Ok )
    116     goto Fail4;
    117   (void)FILE_Seek( cur_offset );
    118 
    119   if ( ACCESS_Frame( 2L ) )
    120     goto Fail3;
    121 
    122   new_offset = GET_UShort() + base_offset;
    123 
    124   FORGET_Frame();
    125 
    126   cur_offset = FILE_Pos();
    127   if ( FILE_Seek( new_offset ) ||
    128        ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
    129 				   stream ) ) != HB_Err_Ok )
    130     goto Fail3;
    131   (void)FILE_Seek( cur_offset );
    132 
    133   if ( ACCESS_Frame( 2L ) )
    134     goto Fail2;
    135 
    136   new_offset = GET_UShort() + base_offset;
    137 
    138   FORGET_Frame();
    139 
    140   cur_offset = FILE_Pos();
    141   if ( FILE_Seek( new_offset ) ||
    142        ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
    143 				  stream, HB_Type_GPOS ) ) != HB_Err_Ok )
    144     goto Fail2;
    145 
    146   gpos->gdef = gdef;      /* can be NULL */
    147 
    148   if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
    149 								     gpos->LookupList.Lookup,
    150 								     gpos->LookupList.LookupCount ) ) )
    151     goto Fail1;
    152 
    153   *retptr = gpos;
    154 
    155   return HB_Err_Ok;
    156 
    157 Fail1:
    158   _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
    159 
    160 Fail2:
    161   _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
    162 
    163 Fail3:
    164   _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
    165 
    166 Fail4:
    167   FREE( gpos );
    168 
    169   return error;
    170 }
    171 
    172 
    173 HB_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
    174 {
    175   _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
    176   _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
    177   _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
    178 
    179   FREE( gpos );
    180 
    181   return HB_Err_Ok;
    182 }
    183 
    184 
    185 /*****************************
    186  * SubTable related functions
    187  *****************************/
    188 
    189 /* shared tables */
    190 
    191 /* ValueRecord */
    192 
    193 /* There is a subtle difference in the specs between a `table' and a
    194    `record' -- offsets for device tables in ValueRecords are taken from
    195    the parent table and not the parent record.                          */
    196 
    197 static HB_Error  Load_ValueRecord( HB_ValueRecord*  vr,
    198 				   HB_UShort         format,
    199 				   HB_UInt          base_offset,
    200 				   HB_Stream         stream )
    201 {
    202   HB_Error  error;
    203 
    204   HB_UInt cur_offset, new_offset;
    205 
    206 
    207   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
    208   {
    209     if ( ACCESS_Frame( 2L ) )
    210       return error;
    211 
    212     vr->XPlacement = GET_Short();
    213 
    214     FORGET_Frame();
    215   }
    216   else
    217     vr->XPlacement = 0;
    218 
    219   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
    220   {
    221     if ( ACCESS_Frame( 2L ) )
    222       return error;
    223 
    224     vr->YPlacement = GET_Short();
    225 
    226     FORGET_Frame();
    227   }
    228   else
    229     vr->YPlacement = 0;
    230 
    231   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
    232   {
    233     if ( ACCESS_Frame( 2L ) )
    234       return error;
    235 
    236     vr->XAdvance = GET_Short();
    237 
    238     FORGET_Frame();
    239   }
    240   else
    241     vr->XAdvance = 0;
    242 
    243   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
    244   {
    245     if ( ACCESS_Frame( 2L ) )
    246       return error;
    247 
    248     vr->YAdvance = GET_Short();
    249 
    250     FORGET_Frame();
    251   }
    252   else
    253     vr->YAdvance = 0;
    254 
    255   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
    256   {
    257     if ( ACCESS_Frame( 2L ) )
    258       return error;
    259 
    260     new_offset = GET_UShort();
    261 
    262     FORGET_Frame();
    263 
    264     if ( new_offset )
    265     {
    266       new_offset += base_offset;
    267 
    268       cur_offset = FILE_Pos();
    269       if ( FILE_Seek( new_offset ) ||
    270 	   ( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
    271 				  stream ) ) != HB_Err_Ok )
    272 	return error;
    273       (void)FILE_Seek( cur_offset );
    274     }
    275     else
    276       goto empty1;
    277   }
    278   else
    279   {
    280   empty1:
    281     vr->XPlacementDevice.StartSize  = 0;
    282     vr->XPlacementDevice.EndSize    = 0;
    283     vr->XPlacementDevice.DeltaValue = NULL;
    284   }
    285 
    286   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
    287   {
    288     if ( ACCESS_Frame( 2L ) )
    289       goto Fail3;
    290 
    291     new_offset = GET_UShort();
    292 
    293     FORGET_Frame();
    294 
    295     if ( new_offset )
    296     {
    297       new_offset += base_offset;
    298 
    299       cur_offset = FILE_Pos();
    300       if ( FILE_Seek( new_offset ) ||
    301 	   ( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
    302 				  stream ) ) != HB_Err_Ok )
    303 	goto Fail3;
    304       (void)FILE_Seek( cur_offset );
    305     }
    306     else
    307       goto empty2;
    308   }
    309   else
    310   {
    311   empty2:
    312     vr->YPlacementDevice.StartSize  = 0;
    313     vr->YPlacementDevice.EndSize    = 0;
    314     vr->YPlacementDevice.DeltaValue = NULL;
    315   }
    316 
    317   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
    318   {
    319     if ( ACCESS_Frame( 2L ) )
    320       goto Fail2;
    321 
    322     new_offset = GET_UShort();
    323 
    324     FORGET_Frame();
    325 
    326     if ( new_offset )
    327     {
    328       new_offset += base_offset;
    329 
    330       cur_offset = FILE_Pos();
    331       if ( FILE_Seek( new_offset ) ||
    332 	   ( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice,
    333 				  stream ) ) != HB_Err_Ok )
    334 	goto Fail2;
    335       (void)FILE_Seek( cur_offset );
    336     }
    337     else
    338       goto empty3;
    339   }
    340   else
    341   {
    342   empty3:
    343     vr->XAdvanceDevice.StartSize  = 0;
    344     vr->XAdvanceDevice.EndSize    = 0;
    345     vr->XAdvanceDevice.DeltaValue = NULL;
    346   }
    347 
    348   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
    349   {
    350     if ( ACCESS_Frame( 2L ) )
    351       goto Fail1;
    352 
    353     new_offset = GET_UShort();
    354 
    355     FORGET_Frame();
    356 
    357     if ( new_offset )
    358     {
    359       new_offset += base_offset;
    360 
    361       cur_offset = FILE_Pos();
    362       if ( FILE_Seek( new_offset ) ||
    363 	   ( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
    364 				  stream ) ) != HB_Err_Ok )
    365 	goto Fail1;
    366       (void)FILE_Seek( cur_offset );
    367     }
    368     else
    369       goto empty4;
    370   }
    371   else
    372   {
    373   empty4:
    374     vr->YAdvanceDevice.StartSize  = 0;
    375     vr->YAdvanceDevice.EndSize    = 0;
    376     vr->YAdvanceDevice.DeltaValue = NULL;
    377   }
    378 
    379   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
    380   {
    381     if ( ACCESS_Frame( 2L ) )
    382       goto Fail1;
    383 
    384     vr->XIdPlacement = GET_UShort();
    385 
    386     FORGET_Frame();
    387   }
    388   else
    389     vr->XIdPlacement = 0;
    390 
    391   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
    392   {
    393     if ( ACCESS_Frame( 2L ) )
    394       goto Fail1;
    395 
    396     vr->YIdPlacement = GET_UShort();
    397 
    398     FORGET_Frame();
    399   }
    400   else
    401     vr->YIdPlacement = 0;
    402 
    403   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
    404   {
    405     if ( ACCESS_Frame( 2L ) )
    406       goto Fail1;
    407 
    408     vr->XIdAdvance = GET_UShort();
    409 
    410     FORGET_Frame();
    411   }
    412   else
    413     vr->XIdAdvance = 0;
    414 
    415   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
    416   {
    417     if ( ACCESS_Frame( 2L ) )
    418       goto Fail1;
    419 
    420     vr->YIdAdvance = GET_UShort();
    421 
    422     FORGET_Frame();
    423   }
    424   else
    425     vr->YIdAdvance = 0;
    426 
    427   return HB_Err_Ok;
    428 
    429 Fail1:
    430   _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
    431 
    432 Fail2:
    433   _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
    434 
    435 Fail3:
    436   _HB_OPEN_Free_Device( &vr->YPlacementDevice );
    437   return error;
    438 }
    439 
    440 
    441 static void  Free_ValueRecord( HB_ValueRecord*  vr,
    442 			       HB_UShort         format )
    443 {
    444   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
    445     _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
    446   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
    447     _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
    448   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
    449     _HB_OPEN_Free_Device( &vr->YPlacementDevice );
    450   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
    451     _HB_OPEN_Free_Device( &vr->XPlacementDevice );
    452 }
    453 
    454 
    455 static HB_Error  Get_ValueRecord( GPOS_Instance*    gpi,
    456 				  HB_ValueRecord*  vr,
    457 				  HB_UShort         format,
    458 				  HB_Position      gd )
    459 {
    460   HB_Fixed           value;
    461   HB_Short         pixel_value;
    462   HB_Error         error = HB_Err_Ok;
    463   HB_GPOSHeader*  gpos = gpi->gpos;
    464 
    465   HB_UShort  x_ppem, y_ppem;
    466   HB_16Dot16   x_scale, y_scale;
    467 
    468 
    469   if ( !format )
    470     return HB_Err_Ok;
    471 
    472   x_ppem  = gpi->font->x_ppem;
    473   y_ppem  = gpi->font->y_ppem;
    474   x_scale = gpi->font->x_scale;
    475   y_scale = gpi->font->y_scale;
    476 
    477   /* design units -> fractional pixel */
    478 
    479   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
    480     gd->x_pos += x_scale * vr->XPlacement / 0x10000;
    481   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
    482     gd->y_pos += y_scale * vr->YPlacement / 0x10000;
    483   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
    484     gd->x_advance += x_scale * vr->XAdvance / 0x10000;
    485   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
    486     gd->y_advance += y_scale * vr->YAdvance / 0x10000;
    487 
    488   if ( !gpi->dvi )
    489   {
    490     /* pixel -> fractional pixel */
    491 
    492     if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
    493     {
    494       _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
    495       gd->x_pos += pixel_value << 6;
    496     }
    497     if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
    498     {
    499       _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
    500       gd->y_pos += pixel_value << 6;
    501     }
    502     if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
    503     {
    504       _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
    505       gd->x_advance += pixel_value << 6;
    506     }
    507     if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
    508     {
    509       _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
    510       gd->y_advance += pixel_value << 6;
    511     }
    512   }
    513 
    514   /* values returned from mmfunc() are already in fractional pixels */
    515 
    516   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
    517   {
    518     error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
    519 			    &value, gpos->data );
    520     if ( error )
    521       return error;
    522     gd->x_pos += value;
    523   }
    524   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
    525   {
    526     error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
    527 			    &value, gpos->data );
    528     if ( error )
    529       return error;
    530     gd->y_pos += value;
    531   }
    532   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
    533   {
    534     error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
    535 			    &value, gpos->data );
    536     if ( error )
    537       return error;
    538     gd->x_advance += value;
    539   }
    540   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
    541   {
    542     error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
    543 			    &value, gpos->data );
    544     if ( error )
    545       return error;
    546     gd->y_advance += value;
    547   }
    548 
    549   return error;
    550 }
    551 
    552 
    553 /* AnchorFormat1 */
    554 /* AnchorFormat2 */
    555 /* AnchorFormat3 */
    556 /* AnchorFormat4 */
    557 
    558 static HB_Error  Load_Anchor( HB_Anchor*  an,
    559 			      HB_Stream    stream )
    560 {
    561   HB_Error  error;
    562 
    563   HB_UInt cur_offset, new_offset, base_offset;
    564 
    565 
    566   base_offset = FILE_Pos();
    567 
    568   if ( ACCESS_Frame( 2L ) )
    569     return error;
    570 
    571   an->PosFormat = GET_UShort();
    572 
    573   FORGET_Frame();
    574 
    575   switch ( an->PosFormat )
    576   {
    577   case 1:
    578     if ( ACCESS_Frame( 4L ) )
    579       return error;
    580 
    581     an->af.af1.XCoordinate = GET_Short();
    582     an->af.af1.YCoordinate = GET_Short();
    583 
    584     FORGET_Frame();
    585     break;
    586 
    587   case 2:
    588     if ( ACCESS_Frame( 6L ) )
    589       return error;
    590 
    591     an->af.af2.XCoordinate = GET_Short();
    592     an->af.af2.YCoordinate = GET_Short();
    593     an->af.af2.AnchorPoint = GET_UShort();
    594 
    595     FORGET_Frame();
    596     break;
    597 
    598   case 3:
    599     if ( ACCESS_Frame( 6L ) )
    600       return error;
    601 
    602     an->af.af3.XCoordinate = GET_Short();
    603     an->af.af3.YCoordinate = GET_Short();
    604 
    605     new_offset = GET_UShort();
    606 
    607     FORGET_Frame();
    608 
    609     if ( new_offset )
    610     {
    611       new_offset += base_offset;
    612 
    613       cur_offset = FILE_Pos();
    614       if ( FILE_Seek( new_offset ) ||
    615 	   ( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
    616 				  stream ) ) != HB_Err_Ok )
    617 	return error;
    618       (void)FILE_Seek( cur_offset );
    619     }
    620     else
    621     {
    622       an->af.af3.XDeviceTable.StartSize  = 0;
    623       an->af.af3.XDeviceTable.EndSize    = 0;
    624       an->af.af3.XDeviceTable.DeltaValue = NULL;
    625     }
    626 
    627     if ( ACCESS_Frame( 2L ) )
    628       goto Fail;
    629 
    630     new_offset = GET_UShort();
    631 
    632     FORGET_Frame();
    633 
    634     if ( new_offset )
    635     {
    636       new_offset += base_offset;
    637 
    638       cur_offset = FILE_Pos();
    639       if ( FILE_Seek( new_offset ) ||
    640 	   ( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
    641 				  stream ) ) != HB_Err_Ok )
    642 	goto Fail;
    643       (void)FILE_Seek( cur_offset );
    644     }
    645     else
    646     {
    647       an->af.af3.YDeviceTable.StartSize  = 0;
    648       an->af.af3.YDeviceTable.EndSize    = 0;
    649       an->af.af3.YDeviceTable.DeltaValue = NULL;
    650     }
    651     break;
    652 
    653   case 4:
    654     if ( ACCESS_Frame( 4L ) )
    655       return error;
    656 
    657     an->af.af4.XIdAnchor = GET_UShort();
    658     an->af.af4.YIdAnchor = GET_UShort();
    659 
    660     FORGET_Frame();
    661     break;
    662 
    663   default:
    664     return ERR(HB_Err_Invalid_SubTable_Format);
    665   }
    666 
    667   return HB_Err_Ok;
    668 
    669 Fail:
    670   _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
    671   return error;
    672 }
    673 
    674 
    675 static void  Free_Anchor( HB_Anchor*  an)
    676 {
    677   if ( an->PosFormat == 3 )
    678   {
    679     _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable );
    680     _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
    681   }
    682 }
    683 
    684 
    685 static HB_Error  Get_Anchor( GPOS_Instance*   gpi,
    686 			     HB_Anchor*      an,
    687 			     HB_UShort        glyph_index,
    688 			     HB_Fixed*          x_value,
    689 			     HB_Fixed*          y_value )
    690 {
    691   HB_Error  error = HB_Err_Ok;
    692 
    693   HB_GPOSHeader*  gpos = gpi->gpos;
    694   HB_UShort        ap;
    695 
    696   HB_Short         pixel_value;
    697 
    698   HB_UShort        x_ppem, y_ppem;
    699   HB_16Dot16         x_scale, y_scale;
    700 
    701 
    702   x_ppem  = gpi->font->x_ppem;
    703   y_ppem  = gpi->font->y_ppem;
    704   x_scale = gpi->font->x_scale;
    705   y_scale = gpi->font->y_scale;
    706 
    707   switch ( an->PosFormat )
    708   {
    709   case 0:
    710     /* The special case of an empty AnchorTable */
    711   default:
    712 
    713     return HB_Err_Not_Covered;
    714 
    715   case 1:
    716     *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
    717     *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
    718     break;
    719 
    720   case 2:
    721     if ( !gpi->dvi )
    722     {
    723       hb_uint32 n_points = 0;
    724       ap = an->af.af2.AnchorPoint;
    725       if (!gpi->font->klass->getPointInOutline)
    726           goto no_contour_point;
    727       error = gpi->font->klass->getPointInOutline(gpi->font, glyph_index, gpi->load_flags, ap, x_value, y_value, &n_points);
    728       if (error)
    729           return error;
    730       /* if n_points is set to zero, we use the design coordinate value pair.
    731        * This can happen e.g. for sbit glyphs. */
    732       if (!n_points)
    733           goto no_contour_point;
    734     }
    735     else
    736     {
    737     no_contour_point:
    738       *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
    739       *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
    740     }
    741     break;
    742 
    743   case 3:
    744     if ( !gpi->dvi )
    745     {
    746       _HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
    747       *x_value = pixel_value << 6;
    748       _HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
    749       *y_value = pixel_value << 6;
    750     }
    751     else
    752       *x_value = *y_value = 0;
    753 
    754     *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
    755     *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
    756     break;
    757 
    758   case 4:
    759     error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
    760 			    x_value, gpos->data );
    761     if ( error )
    762       return error;
    763 
    764     error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
    765 			    y_value, gpos->data );
    766     if ( error )
    767       return error;
    768     break;
    769   }
    770 
    771   return error;
    772 }
    773 
    774 
    775 /* MarkArray */
    776 
    777 static HB_Error  Load_MarkArray ( HB_MarkArray*  ma,
    778 				  HB_Stream       stream )
    779 {
    780   HB_Error  error;
    781 
    782   HB_UShort        n, m, count;
    783   HB_UInt         cur_offset, new_offset, base_offset;
    784 
    785   HB_MarkRecord*  mr;
    786 
    787 
    788   base_offset = FILE_Pos();
    789 
    790   if ( ACCESS_Frame( 2L ) )
    791     return error;
    792 
    793   count = ma->MarkCount = GET_UShort();
    794 
    795   FORGET_Frame();
    796 
    797   ma->MarkRecord = NULL;
    798 
    799   if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
    800     return error;
    801 
    802   mr = ma->MarkRecord;
    803 
    804   for ( n = 0; n < count; n++ )
    805   {
    806     if ( ACCESS_Frame( 4L ) )
    807       goto Fail;
    808 
    809     mr[n].Class = GET_UShort();
    810     new_offset  = GET_UShort() + base_offset;
    811 
    812     FORGET_Frame();
    813 
    814     cur_offset = FILE_Pos();
    815     if ( FILE_Seek( new_offset ) ||
    816 	 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
    817       goto Fail;
    818     (void)FILE_Seek( cur_offset );
    819   }
    820 
    821   return HB_Err_Ok;
    822 
    823 Fail:
    824   for ( m = 0; m < n; m++ )
    825     Free_Anchor( &mr[m].MarkAnchor );
    826 
    827   FREE( mr );
    828   return error;
    829 }
    830 
    831 
    832 static void  Free_MarkArray( HB_MarkArray*  ma )
    833 {
    834   HB_UShort        n, count;
    835 
    836   HB_MarkRecord*  mr;
    837 
    838 
    839   if ( ma->MarkRecord )
    840   {
    841     count = ma->MarkCount;
    842     mr    = ma->MarkRecord;
    843 
    844     for ( n = 0; n < count; n++ )
    845       Free_Anchor( &mr[n].MarkAnchor );
    846 
    847     FREE( mr );
    848   }
    849 }
    850 
    851 
    852 /* LookupType 1 */
    853 
    854 /* SinglePosFormat1 */
    855 /* SinglePosFormat2 */
    856 
    857 static HB_Error  Load_SinglePos( HB_GPOS_SubTable* st,
    858 				 HB_Stream       stream )
    859 {
    860   HB_Error  error;
    861   HB_SinglePos*   sp = &st->single;
    862 
    863   HB_UShort         n, m, count, format;
    864   HB_UInt          cur_offset, new_offset, base_offset;
    865 
    866   HB_ValueRecord*  vr;
    867 
    868 
    869   base_offset = FILE_Pos();
    870 
    871   if ( ACCESS_Frame( 6L ) )
    872     return error;
    873 
    874   sp->PosFormat = GET_UShort();
    875   new_offset    = GET_UShort() + base_offset;
    876 
    877   format = sp->ValueFormat = GET_UShort();
    878 
    879   FORGET_Frame();
    880 
    881   if ( !format )
    882     return ERR(HB_Err_Invalid_SubTable);
    883 
    884   cur_offset = FILE_Pos();
    885   if ( FILE_Seek( new_offset ) ||
    886        ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
    887     return error;
    888   (void)FILE_Seek( cur_offset );
    889 
    890   switch ( sp->PosFormat )
    891   {
    892   case 1:
    893     error = Load_ValueRecord( &sp->spf.spf1.Value, format,
    894 			      base_offset, stream );
    895     if ( error )
    896       goto Fail2;
    897     break;
    898 
    899   case 2:
    900     if ( ACCESS_Frame( 2L ) )
    901       goto Fail2;
    902 
    903     count = sp->spf.spf2.ValueCount = GET_UShort();
    904 
    905     FORGET_Frame();
    906 
    907     sp->spf.spf2.Value = NULL;
    908 
    909     if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
    910       goto Fail2;
    911 
    912     vr = sp->spf.spf2.Value;
    913 
    914     for ( n = 0; n < count; n++ )
    915     {
    916       error = Load_ValueRecord( &vr[n], format, base_offset, stream );
    917       if ( error )
    918 	goto Fail1;
    919     }
    920     break;
    921 
    922   default:
    923     return ERR(HB_Err_Invalid_SubTable_Format);
    924   }
    925 
    926   return HB_Err_Ok;
    927 
    928 Fail1:
    929   for ( m = 0; m < n; m++ )
    930     Free_ValueRecord( &vr[m], format );
    931 
    932   FREE( vr );
    933 
    934 Fail2:
    935   _HB_OPEN_Free_Coverage( &sp->Coverage );
    936   return error;
    937 }
    938 
    939 
    940 static void  Free_SinglePos( HB_GPOS_SubTable* st )
    941 {
    942   HB_UShort         n, count, format;
    943   HB_SinglePos*   sp = &st->single;
    944 
    945   HB_ValueRecord*  v;
    946 
    947 
    948   format = sp->ValueFormat;
    949 
    950   switch ( sp->PosFormat )
    951   {
    952   case 1:
    953     Free_ValueRecord( &sp->spf.spf1.Value, format );
    954     break;
    955 
    956   case 2:
    957     if ( sp->spf.spf2.Value )
    958     {
    959       count = sp->spf.spf2.ValueCount;
    960       v     = sp->spf.spf2.Value;
    961 
    962       for ( n = 0; n < count; n++ )
    963 	Free_ValueRecord( &v[n], format );
    964 
    965       FREE( v );
    966     }
    967     break;
    968   default:
    969     break;
    970   }
    971 
    972   _HB_OPEN_Free_Coverage( &sp->Coverage );
    973 }
    974 
    975 static HB_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
    976 				   HB_GPOS_SubTable* st,
    977 				   HB_Buffer        buffer,
    978 				   HB_UShort         flags,
    979 				   HB_UShort         context_length,
    980 				   int               nesting_level )
    981 {
    982   HB_UShort        index, property;
    983   HB_Error         error;
    984   HB_GPOSHeader*  gpos = gpi->gpos;
    985   HB_SinglePos*   sp = &st->single;
    986 
    987   HB_UNUSED(nesting_level);
    988 
    989   if ( context_length != 0xFFFF && context_length < 1 )
    990     return HB_Err_Not_Covered;
    991 
    992   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
    993     return error;
    994 
    995   error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
    996   if ( error )
    997     return error;
    998 
    999   switch ( sp->PosFormat )
   1000   {
   1001   case 1:
   1002     error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
   1003 			     sp->ValueFormat, POSITION( buffer->in_pos ) );
   1004     if ( error )
   1005       return error;
   1006     break;
   1007 
   1008   case 2:
   1009     if ( index >= sp->spf.spf2.ValueCount )
   1010       return ERR(HB_Err_Invalid_SubTable);
   1011     error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
   1012 			     sp->ValueFormat, POSITION( buffer->in_pos ) );
   1013     if ( error )
   1014       return error;
   1015     break;
   1016 
   1017   default:
   1018     return ERR(HB_Err_Invalid_SubTable);
   1019   }
   1020 
   1021   (buffer->in_pos)++;
   1022 
   1023   return HB_Err_Ok;
   1024 }
   1025 
   1026 
   1027 /* LookupType 2 */
   1028 
   1029 /* PairSet */
   1030 
   1031 static HB_Error  Load_PairSet ( HB_PairSet*  ps,
   1032 				HB_UShort     format1,
   1033 				HB_UShort     format2,
   1034 				HB_Stream     stream )
   1035 {
   1036   HB_Error  error;
   1037 
   1038   HB_UShort             n, m, count;
   1039   HB_UInt              base_offset;
   1040 
   1041   HB_PairValueRecord*  pvr;
   1042 
   1043 
   1044   base_offset = FILE_Pos();
   1045 
   1046   if ( ACCESS_Frame( 2L ) )
   1047     return error;
   1048 
   1049   count = ps->PairValueCount = GET_UShort();
   1050 
   1051   FORGET_Frame();
   1052 
   1053   ps->PairValueRecord = NULL;
   1054 
   1055   if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
   1056     return error;
   1057 
   1058   pvr = ps->PairValueRecord;
   1059 
   1060   for ( n = 0; n < count; n++ )
   1061   {
   1062     if ( ACCESS_Frame( 2L ) )
   1063       goto Fail;
   1064 
   1065     pvr[n].SecondGlyph = GET_UShort();
   1066 
   1067     FORGET_Frame();
   1068 
   1069     if ( format1 )
   1070     {
   1071       error = Load_ValueRecord( &pvr[n].Value1, format1,
   1072 				base_offset, stream );
   1073       if ( error )
   1074 	goto Fail;
   1075     }
   1076     if ( format2 )
   1077     {
   1078       error = Load_ValueRecord( &pvr[n].Value2, format2,
   1079 				base_offset, stream );
   1080       if ( error )
   1081       {
   1082 	if ( format1 )
   1083 	  Free_ValueRecord( &pvr[n].Value1, format1 );
   1084 	goto Fail;
   1085       }
   1086     }
   1087   }
   1088 
   1089   return HB_Err_Ok;
   1090 
   1091 Fail:
   1092   for ( m = 0; m < n; m++ )
   1093   {
   1094     if ( format1 )
   1095       Free_ValueRecord( &pvr[m].Value1, format1 );
   1096     if ( format2 )
   1097       Free_ValueRecord( &pvr[m].Value2, format2 );
   1098   }
   1099 
   1100   FREE( pvr );
   1101   return error;
   1102 }
   1103 
   1104 
   1105 static void  Free_PairSet( HB_PairSet*  ps,
   1106 			   HB_UShort     format1,
   1107 			   HB_UShort     format2 )
   1108 {
   1109   HB_UShort             n, count;
   1110 
   1111   HB_PairValueRecord*  pvr;
   1112 
   1113 
   1114   if ( ps->PairValueRecord )
   1115   {
   1116     count = ps->PairValueCount;
   1117     pvr   = ps->PairValueRecord;
   1118 
   1119     for ( n = 0; n < count; n++ )
   1120     {
   1121       if ( format1 )
   1122 	Free_ValueRecord( &pvr[n].Value1, format1 );
   1123       if ( format2 )
   1124 	Free_ValueRecord( &pvr[n].Value2, format2 );
   1125     }
   1126 
   1127     FREE( pvr );
   1128   }
   1129 }
   1130 
   1131 
   1132 /* PairPosFormat1 */
   1133 
   1134 static HB_Error  Load_PairPos1( HB_PairPosFormat1*  ppf1,
   1135 				HB_UShort            format1,
   1136 				HB_UShort            format2,
   1137 				HB_Stream            stream )
   1138 {
   1139   HB_Error  error;
   1140 
   1141   HB_UShort     n, m, count;
   1142   HB_UInt      cur_offset, new_offset, base_offset;
   1143 
   1144   HB_PairSet*  ps;
   1145 
   1146 
   1147   base_offset = FILE_Pos() - 8L;
   1148 
   1149   if ( ACCESS_Frame( 2L ) )
   1150     return error;
   1151 
   1152   count = ppf1->PairSetCount = GET_UShort();
   1153 
   1154   FORGET_Frame();
   1155 
   1156   ppf1->PairSet = NULL;
   1157 
   1158   if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
   1159     return error;
   1160 
   1161   ps = ppf1->PairSet;
   1162 
   1163   for ( n = 0; n < count; n++ )
   1164   {
   1165     if ( ACCESS_Frame( 2L ) )
   1166       goto Fail;
   1167 
   1168     new_offset = GET_UShort() + base_offset;
   1169 
   1170     FORGET_Frame();
   1171 
   1172     cur_offset = FILE_Pos();
   1173     if ( FILE_Seek( new_offset ) ||
   1174 	 ( error = Load_PairSet( &ps[n], format1,
   1175 				 format2, stream ) ) != HB_Err_Ok )
   1176       goto Fail;
   1177     (void)FILE_Seek( cur_offset );
   1178   }
   1179 
   1180   return HB_Err_Ok;
   1181 
   1182 Fail:
   1183   for ( m = 0; m < n; m++ )
   1184     Free_PairSet( &ps[m], format1, format2 );
   1185 
   1186   FREE( ps );
   1187   return error;
   1188 }
   1189 
   1190 
   1191 static void  Free_PairPos1( HB_PairPosFormat1*  ppf1,
   1192 			    HB_UShort            format1,
   1193 			    HB_UShort            format2 )
   1194 {
   1195   HB_UShort     n, count;
   1196 
   1197   HB_PairSet*  ps;
   1198 
   1199 
   1200   if ( ppf1->PairSet )
   1201   {
   1202     count = ppf1->PairSetCount;
   1203     ps    = ppf1->PairSet;
   1204 
   1205     for ( n = 0; n < count; n++ )
   1206       Free_PairSet( &ps[n], format1, format2 );
   1207 
   1208     FREE( ps );
   1209   }
   1210 }
   1211 
   1212 
   1213 /* PairPosFormat2 */
   1214 
   1215 static HB_Error  Load_PairPos2( HB_PairPosFormat2*  ppf2,
   1216 				HB_UShort            format1,
   1217 				HB_UShort            format2,
   1218 				HB_Stream            stream )
   1219 {
   1220   HB_Error  error;
   1221 
   1222   HB_UShort          m, n, k, count1, count2;
   1223   HB_UInt           cur_offset, new_offset1, new_offset2, base_offset;
   1224 
   1225   HB_Class1Record*  c1r;
   1226   HB_Class2Record*  c2r;
   1227 
   1228 
   1229   base_offset = FILE_Pos() - 8L;
   1230 
   1231   if ( ACCESS_Frame( 8L ) )
   1232     return error;
   1233 
   1234   new_offset1 = GET_UShort() + base_offset;
   1235   new_offset2 = GET_UShort() + base_offset;
   1236 
   1237   /* `Class1Count' and `Class2Count' are the upper limits for class
   1238      values, thus we read it now to make additional safety checks.  */
   1239 
   1240   count1 = ppf2->Class1Count = GET_UShort();
   1241   count2 = ppf2->Class2Count = GET_UShort();
   1242 
   1243   FORGET_Frame();
   1244 
   1245   cur_offset = FILE_Pos();
   1246   if ( FILE_Seek( new_offset1 ) ||
   1247        ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
   1248 				       stream ) ) != HB_Err_Ok )
   1249     return error;
   1250   if ( FILE_Seek( new_offset2 ) ||
   1251        ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
   1252 				       stream ) ) != HB_Err_Ok )
   1253     goto Fail3;
   1254   (void)FILE_Seek( cur_offset );
   1255 
   1256   ppf2->Class1Record = NULL;
   1257 
   1258   if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
   1259     goto Fail2;
   1260 
   1261   c1r = ppf2->Class1Record;
   1262 
   1263   for ( m = 0; m < count1; m++ )
   1264   {
   1265     c1r[m].Class2Record = NULL;
   1266 
   1267     if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
   1268       goto Fail1;
   1269 
   1270     c2r = c1r[m].Class2Record;
   1271 
   1272     for ( n = 0; n < count2; n++ )
   1273     {
   1274       if ( format1 )
   1275       {
   1276 	error = Load_ValueRecord( &c2r[n].Value1, format1,
   1277 				  base_offset, stream );
   1278 	if ( error )
   1279 	  goto Fail0;
   1280       }
   1281       if ( format2 )
   1282       {
   1283 	error = Load_ValueRecord( &c2r[n].Value2, format2,
   1284 				  base_offset, stream );
   1285 	if ( error )
   1286 	{
   1287 	  if ( format1 )
   1288 	    Free_ValueRecord( &c2r[n].Value1, format1 );
   1289 	  goto Fail0;
   1290 	}
   1291       }
   1292     }
   1293 
   1294     continue;
   1295 
   1296   Fail0:
   1297     for ( k = 0; k < n; k++ )
   1298     {
   1299       if ( format1 )
   1300 	Free_ValueRecord( &c2r[k].Value1, format1 );
   1301       if ( format2 )
   1302 	Free_ValueRecord( &c2r[k].Value2, format2 );
   1303     }
   1304     goto Fail1;
   1305   }
   1306 
   1307   return HB_Err_Ok;
   1308 
   1309 Fail1:
   1310   for ( k = 0; k < m; k++ )
   1311   {
   1312     c2r = c1r[k].Class2Record;
   1313 
   1314     for ( n = 0; n < count2; n++ )
   1315     {
   1316       if ( format1 )
   1317 	Free_ValueRecord( &c2r[n].Value1, format1 );
   1318       if ( format2 )
   1319 	Free_ValueRecord( &c2r[n].Value2, format2 );
   1320     }
   1321 
   1322     FREE( c2r );
   1323   }
   1324 
   1325   FREE( c1r );
   1326 Fail2:
   1327 
   1328   _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
   1329 
   1330 Fail3:
   1331   _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
   1332   return error;
   1333 }
   1334 
   1335 
   1336 static void  Free_PairPos2( HB_PairPosFormat2*  ppf2,
   1337 			    HB_UShort            format1,
   1338 			    HB_UShort            format2)
   1339 {
   1340   HB_UShort          m, n, count1, count2;
   1341 
   1342   HB_Class1Record*  c1r;
   1343   HB_Class2Record*  c2r;
   1344 
   1345 
   1346   if ( ppf2->Class1Record )
   1347   {
   1348     c1r    = ppf2->Class1Record;
   1349     count1 = ppf2->Class1Count;
   1350     count2 = ppf2->Class2Count;
   1351 
   1352     for ( m = 0; m < count1; m++ )
   1353     {
   1354       c2r = c1r[m].Class2Record;
   1355 
   1356       for ( n = 0; n < count2; n++ )
   1357       {
   1358 	if ( format1 )
   1359 	  Free_ValueRecord( &c2r[n].Value1, format1 );
   1360 	if ( format2 )
   1361 	  Free_ValueRecord( &c2r[n].Value2, format2 );
   1362       }
   1363 
   1364       FREE( c2r );
   1365     }
   1366 
   1367     FREE( c1r );
   1368 
   1369     _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
   1370     _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
   1371   }
   1372 }
   1373 
   1374 
   1375 static HB_Error  Load_PairPos( HB_GPOS_SubTable* st,
   1376 			       HB_Stream     stream )
   1377 {
   1378   HB_Error  error;
   1379   HB_PairPos*     pp = &st->pair;
   1380 
   1381   HB_UShort         format1, format2;
   1382   HB_UInt          cur_offset, new_offset, base_offset;
   1383 
   1384 
   1385   base_offset = FILE_Pos();
   1386 
   1387   if ( ACCESS_Frame( 8L ) )
   1388     return error;
   1389 
   1390   pp->PosFormat = GET_UShort();
   1391   new_offset    = GET_UShort() + base_offset;
   1392 
   1393   format1 = pp->ValueFormat1 = GET_UShort();
   1394   format2 = pp->ValueFormat2 = GET_UShort();
   1395 
   1396   FORGET_Frame();
   1397 
   1398   cur_offset = FILE_Pos();
   1399   if ( FILE_Seek( new_offset ) ||
   1400        ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
   1401     return error;
   1402   (void)FILE_Seek( cur_offset );
   1403 
   1404   switch ( pp->PosFormat )
   1405   {
   1406   case 1:
   1407     error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
   1408     if ( error )
   1409       goto Fail;
   1410     break;
   1411 
   1412   case 2:
   1413     error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
   1414     if ( error )
   1415       goto Fail;
   1416     break;
   1417 
   1418   default:
   1419     return ERR(HB_Err_Invalid_SubTable_Format);
   1420   }
   1421 
   1422   return HB_Err_Ok;
   1423 
   1424 Fail:
   1425   _HB_OPEN_Free_Coverage( &pp->Coverage );
   1426   return error;
   1427 }
   1428 
   1429 
   1430 static void  Free_PairPos( HB_GPOS_SubTable* st )
   1431 {
   1432   HB_UShort  format1, format2;
   1433   HB_PairPos*     pp = &st->pair;
   1434 
   1435 
   1436   format1 = pp->ValueFormat1;
   1437   format2 = pp->ValueFormat2;
   1438 
   1439   switch ( pp->PosFormat )
   1440   {
   1441   case 1:
   1442     Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
   1443     break;
   1444 
   1445   case 2:
   1446     Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
   1447     break;
   1448 
   1449   default:
   1450     break;
   1451   }
   1452 
   1453   _HB_OPEN_Free_Coverage( &pp->Coverage );
   1454 }
   1455 
   1456 
   1457 static HB_Error  Lookup_PairPos1( GPOS_Instance*       gpi,
   1458 				  HB_PairPosFormat1*  ppf1,
   1459 				  HB_Buffer           buffer,
   1460 				  HB_UInt              first_pos,
   1461 				  HB_UShort            index,
   1462 				  HB_UShort            format1,
   1463 				  HB_UShort            format2 )
   1464 {
   1465   HB_Error              error;
   1466   HB_UShort             numpvr, glyph2;
   1467 
   1468   HB_PairValueRecord*  pvr;
   1469 
   1470 
   1471   if ( index >= ppf1->PairSetCount )
   1472      return ERR(HB_Err_Invalid_SubTable);
   1473 
   1474   pvr = ppf1->PairSet[index].PairValueRecord;
   1475   if ( !pvr )
   1476     return ERR(HB_Err_Invalid_SubTable);
   1477 
   1478   glyph2 = IN_CURGLYPH();
   1479 
   1480   for ( numpvr = ppf1->PairSet[index].PairValueCount;
   1481 	numpvr;
   1482 	numpvr--, pvr++ )
   1483   {
   1484     if ( glyph2 == pvr->SecondGlyph )
   1485     {
   1486       error = Get_ValueRecord( gpi, &pvr->Value1, format1,
   1487 			       POSITION( first_pos ) );
   1488       if ( error )
   1489 	return error;
   1490       return Get_ValueRecord( gpi, &pvr->Value2, format2,
   1491 			      POSITION( buffer->in_pos ) );
   1492     }
   1493   }
   1494 
   1495   return HB_Err_Not_Covered;
   1496 }
   1497 
   1498 
   1499 static HB_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
   1500 				  HB_PairPosFormat2*  ppf2,
   1501 				  HB_Buffer           buffer,
   1502 				  HB_UInt              first_pos,
   1503 				  HB_UShort            format1,
   1504 				  HB_UShort            format2 )
   1505 {
   1506   HB_Error           error;
   1507   HB_UShort          cl1 = 0, cl2 = 0; /* shut compiler up */
   1508 
   1509   HB_Class1Record*  c1r;
   1510   HB_Class2Record*  c2r;
   1511 
   1512 
   1513   error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
   1514 		     &cl1, NULL );
   1515   if ( error && error != HB_Err_Not_Covered )
   1516     return error;
   1517   error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
   1518 		     &cl2, NULL );
   1519   if ( error && error != HB_Err_Not_Covered )
   1520     return error;
   1521 
   1522   c1r = &ppf2->Class1Record[cl1];
   1523   if ( !c1r )
   1524     return ERR(HB_Err_Invalid_SubTable);
   1525   c2r = &c1r->Class2Record[cl2];
   1526 
   1527   error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
   1528   if ( error )
   1529     return error;
   1530   return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
   1531 }
   1532 
   1533 
   1534 static HB_Error  Lookup_PairPos( GPOS_Instance*    gpi,
   1535 				 HB_GPOS_SubTable* st,
   1536 				 HB_Buffer        buffer,
   1537 				 HB_UShort         flags,
   1538 				 HB_UShort         context_length,
   1539 				 int               nesting_level )
   1540 {
   1541   HB_Error         error;
   1542   HB_UShort        index, property;
   1543   HB_UInt          first_pos;
   1544   HB_GPOSHeader*  gpos = gpi->gpos;
   1545   HB_PairPos*     pp = &st->pair;
   1546 
   1547   HB_UNUSED(nesting_level);
   1548 
   1549   if ( buffer->in_pos >= buffer->in_length - 1 )
   1550     return HB_Err_Not_Covered;           /* Not enough glyphs in stream */
   1551 
   1552   if ( context_length != 0xFFFF && context_length < 2 )
   1553     return HB_Err_Not_Covered;
   1554 
   1555   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   1556     return error;
   1557 
   1558   error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
   1559   if ( error )
   1560     return error;
   1561 
   1562   /* second glyph */
   1563 
   1564   first_pos = buffer->in_pos;
   1565   (buffer->in_pos)++;
   1566 
   1567   while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
   1568 			  flags, &property ) )
   1569   {
   1570     if ( error && error != HB_Err_Not_Covered )
   1571       return error;
   1572 
   1573     if ( buffer->in_pos == buffer->in_length )
   1574       {
   1575 	buffer->in_pos = first_pos;
   1576         return HB_Err_Not_Covered;
   1577       }
   1578     (buffer->in_pos)++;
   1579 
   1580   }
   1581 
   1582   switch ( pp->PosFormat )
   1583   {
   1584   case 1:
   1585     error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
   1586 			     first_pos, index,
   1587 			     pp->ValueFormat1, pp->ValueFormat2 );
   1588     break;
   1589 
   1590   case 2:
   1591     error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
   1592 			     pp->ValueFormat1, pp->ValueFormat2 );
   1593     break;
   1594 
   1595   default:
   1596     return ERR(HB_Err_Invalid_SubTable_Format);
   1597   }
   1598 
   1599   /* if we don't have coverage for the second glyph don't skip it for
   1600      further lookups but reset in_pos back to the first_glyph and let
   1601      the caller in Do_String_Lookup increment in_pos */
   1602   if ( error == HB_Err_Not_Covered )
   1603       buffer->in_pos = first_pos;
   1604 
   1605   /* adjusting the `next' glyph */
   1606 
   1607   if ( pp->ValueFormat2 )
   1608     (buffer->in_pos)++;
   1609 
   1610   return error;
   1611 }
   1612 
   1613 
   1614 /* LookupType 3 */
   1615 
   1616 /* CursivePosFormat1 */
   1617 
   1618 static HB_Error  Load_CursivePos( HB_GPOS_SubTable* st,
   1619 				  HB_Stream        stream )
   1620 {
   1621   HB_Error  error;
   1622   HB_CursivePos*  cp = &st->cursive;
   1623 
   1624   HB_UShort             n, m, count;
   1625   HB_UInt              cur_offset, new_offset, base_offset;
   1626 
   1627   HB_EntryExitRecord*  eer;
   1628 
   1629 
   1630   base_offset = FILE_Pos();
   1631 
   1632   if ( ACCESS_Frame( 4L ) )
   1633     return error;
   1634 
   1635   cp->PosFormat = GET_UShort();
   1636   new_offset    = GET_UShort() + base_offset;
   1637 
   1638   FORGET_Frame();
   1639 
   1640   cur_offset = FILE_Pos();
   1641   if ( FILE_Seek( new_offset ) ||
   1642        ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
   1643     return error;
   1644   (void)FILE_Seek( cur_offset );
   1645 
   1646   if ( ACCESS_Frame( 2L ) )
   1647     goto Fail2;
   1648 
   1649   count = cp->EntryExitCount = GET_UShort();
   1650 
   1651   FORGET_Frame();
   1652 
   1653   cp->EntryExitRecord = NULL;
   1654 
   1655   if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
   1656     goto Fail2;
   1657 
   1658   eer = cp->EntryExitRecord;
   1659 
   1660   for ( n = 0; n < count; n++ )
   1661   {
   1662     HB_UInt entry_offset;
   1663 
   1664     if ( ACCESS_Frame( 2L ) )
   1665       return error;
   1666 
   1667     entry_offset = new_offset = GET_UShort();
   1668 
   1669     FORGET_Frame();
   1670 
   1671     if ( new_offset )
   1672     {
   1673       new_offset += base_offset;
   1674 
   1675       cur_offset = FILE_Pos();
   1676       if ( FILE_Seek( new_offset ) ||
   1677 	   ( error = Load_Anchor( &eer[n].EntryAnchor,
   1678 				  stream ) ) != HB_Err_Ok )
   1679 	goto Fail1;
   1680       (void)FILE_Seek( cur_offset );
   1681     }
   1682     else
   1683       eer[n].EntryAnchor.PosFormat   = 0;
   1684 
   1685     if ( ACCESS_Frame( 2L ) )
   1686       return error;
   1687 
   1688     new_offset = GET_UShort();
   1689 
   1690     FORGET_Frame();
   1691 
   1692     if ( new_offset )
   1693     {
   1694       new_offset += base_offset;
   1695 
   1696       cur_offset = FILE_Pos();
   1697       if ( FILE_Seek( new_offset ) ||
   1698 	   ( error = Load_Anchor( &eer[n].ExitAnchor,
   1699 				  stream ) ) != HB_Err_Ok )
   1700       {
   1701 	if ( entry_offset )
   1702 	  Free_Anchor( &eer[n].EntryAnchor );
   1703 	goto Fail1;
   1704       }
   1705       (void)FILE_Seek( cur_offset );
   1706     }
   1707     else
   1708       eer[n].ExitAnchor.PosFormat   = 0;
   1709   }
   1710 
   1711   return HB_Err_Ok;
   1712 
   1713 Fail1:
   1714   for ( m = 0; m < n; m++ )
   1715   {
   1716     Free_Anchor( &eer[m].EntryAnchor );
   1717     Free_Anchor( &eer[m].ExitAnchor );
   1718   }
   1719 
   1720   FREE( eer );
   1721 
   1722 Fail2:
   1723   _HB_OPEN_Free_Coverage( &cp->Coverage );
   1724   return error;
   1725 }
   1726 
   1727 
   1728 static void  Free_CursivePos( HB_GPOS_SubTable* st )
   1729 {
   1730   HB_UShort             n, count;
   1731   HB_CursivePos*  cp = &st->cursive;
   1732 
   1733   HB_EntryExitRecord*  eer;
   1734 
   1735 
   1736   if ( cp->EntryExitRecord )
   1737   {
   1738     count = cp->EntryExitCount;
   1739     eer   = cp->EntryExitRecord;
   1740 
   1741     for ( n = 0; n < count; n++ )
   1742     {
   1743       Free_Anchor( &eer[n].EntryAnchor );
   1744       Free_Anchor( &eer[n].ExitAnchor );
   1745     }
   1746 
   1747     FREE( eer );
   1748   }
   1749 
   1750   _HB_OPEN_Free_Coverage( &cp->Coverage );
   1751 }
   1752 
   1753 
   1754 static HB_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
   1755 				    HB_GPOS_SubTable* st,
   1756 				    HB_Buffer        buffer,
   1757 				    HB_UShort         flags,
   1758 				    HB_UShort         context_length,
   1759 				    int               nesting_level )
   1760 {
   1761   HB_UShort        index, property;
   1762   HB_Error         error;
   1763   HB_GPOSHeader*  gpos = gpi->gpos;
   1764   HB_CursivePos*  cp = &st->cursive;
   1765 
   1766   HB_EntryExitRecord*  eer;
   1767   HB_Fixed                entry_x, entry_y;
   1768   HB_Fixed                exit_x, exit_y;
   1769 
   1770   HB_UNUSED(nesting_level);
   1771 
   1772   if ( context_length != 0xFFFF && context_length < 1 )
   1773   {
   1774     gpi->last = 0xFFFF;
   1775     return HB_Err_Not_Covered;
   1776   }
   1777 
   1778   /* Glyphs not having the right GDEF properties will be ignored, i.e.,
   1779      gpi->last won't be reset (contrary to user defined properties). */
   1780 
   1781   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   1782     return error;
   1783 
   1784   /* We don't handle mark glyphs here.  According to Andrei, this isn't
   1785      possible, but who knows...                                         */
   1786 
   1787   if ( property == HB_GDEF_MARK )
   1788   {
   1789     gpi->last = 0xFFFF;
   1790     return HB_Err_Not_Covered;
   1791   }
   1792 
   1793   error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
   1794   if ( error )
   1795   {
   1796     gpi->last = 0xFFFF;
   1797     return error;
   1798   }
   1799 
   1800   if ( index >= cp->EntryExitCount )
   1801     return ERR(HB_Err_Invalid_SubTable);
   1802 
   1803   eer = &cp->EntryExitRecord[index];
   1804 
   1805   /* Now comes the messiest part of the whole OpenType
   1806      specification.  At first glance, cursive connections seem easy
   1807      to understand, but there are pitfalls!  The reason is that
   1808      the specs don't mention how to compute the advance values
   1809      resp. glyph offsets.  I was told it would be an omission, to
   1810      be fixed in the next OpenType version...  Again many thanks to
   1811      Andrei Burago <andreib (at) microsoft.com> for clarifications.
   1812 
   1813      Consider the following example:
   1814 
   1815 		      |  xadv1    |
   1816 		       +---------+
   1817 		       |         |
   1818 		 +-----+--+ 1    |
   1819 		 |     | .|      |
   1820 		 |    0+--+------+
   1821 		 |   2    |
   1822 		 |        |
   1823 		0+--------+
   1824 		|  xadv2   |
   1825 
   1826        glyph1: advance width = 12
   1827 	       anchor point = (3,1)
   1828 
   1829        glyph2: advance width = 11
   1830 	       anchor point = (9,4)
   1831 
   1832        LSB is 1 for both glyphs (so the boxes drawn above are glyph
   1833        bboxes).  Writing direction is R2L; `0' denotes the glyph's
   1834        coordinate origin.
   1835 
   1836      Now the surprising part: The advance width of the *left* glyph
   1837      (resp. of the *bottom* glyph) will be modified, no matter
   1838      whether the writing direction is L2R or R2L (resp. T2B or
   1839      B2T)!  This assymetry is caused by the fact that the glyph's
   1840      coordinate origin is always the lower left corner for all
   1841      writing directions.
   1842 
   1843      Continuing the above example, we can compute the new
   1844      (horizontal) advance width of glyph2 as
   1845 
   1846        9 - 3 = 6  ,
   1847 
   1848      and the new vertical offset of glyph2 as
   1849 
   1850        1 - 4 = -3  .
   1851 
   1852 
   1853      Vertical writing direction is far more complicated:
   1854 
   1855      a) Assuming that we recompute the advance height of the lower glyph:
   1856 
   1857 				  --
   1858 		       +---------+
   1859 	      --       |         |
   1860 		 +-----+--+ 1    | yadv1
   1861 		 |     | .|      |
   1862 	   yadv2 |    0+--+------+        -- BSB1  --
   1863 		 |   2    |       --      --        y_offset
   1864 		 |        |
   1865    BSB2 --      0+--------+                        --
   1866 	--    --
   1867 
   1868        glyph1: advance height = 6
   1869 	       anchor point = (3,1)
   1870 
   1871        glyph2: advance height = 7
   1872 	       anchor point = (9,4)
   1873 
   1874        TSB is 1 for both glyphs; writing direction is T2B.
   1875 
   1876 
   1877 	 BSB1     = yadv1 - (TSB1 + ymax1)
   1878 	 BSB2     = yadv2 - (TSB2 + ymax2)
   1879 	 y_offset = y2 - y1
   1880 
   1881        vertical advance width of glyph2
   1882 	 = y_offset + BSB2 - BSB1
   1883 	 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
   1884 	 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
   1885 	 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
   1886 
   1887 
   1888      b) Assuming that we recompute the advance height of the upper glyph:
   1889 
   1890 				  --      --
   1891 		       +---------+        -- TSB1
   1892 	--    --       |         |
   1893    TSB2 --       +-----+--+ 1    | yadv1   ymax1
   1894 		 |     | .|      |
   1895 	   yadv2 |    0+--+------+        --       --
   1896     ymax2        |   2    |       --                y_offset
   1897 		 |        |
   1898 	--      0+--------+                        --
   1899 	      --
   1900 
   1901        glyph1: advance height = 6
   1902 	       anchor point = (3,1)
   1903 
   1904        glyph2: advance height = 7
   1905 	       anchor point = (9,4)
   1906 
   1907        TSB is 1 for both glyphs; writing direction is T2B.
   1908 
   1909        y_offset = y2 - y1
   1910 
   1911        vertical advance width of glyph2
   1912 	 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
   1913 	 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
   1914 
   1915 
   1916      Comparing a) with b) shows that b) is easier to compute.  I'll wait
   1917      for a reply from Andrei to see what should really be implemented...
   1918 
   1919      Since horizontal advance widths or vertical advance heights
   1920      can be used alone but not together, no ambiguity occurs.        */
   1921 
   1922   if ( gpi->last == 0xFFFF )
   1923     goto end;
   1924 
   1925   /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
   1926      table.                                                         */
   1927 
   1928   error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
   1929 		      &entry_x, &entry_y );
   1930   if ( error == HB_Err_Not_Covered )
   1931     goto end;
   1932   if ( error )
   1933     return error;
   1934 
   1935   if ( gpi->r2l )
   1936   {
   1937     POSITION( buffer->in_pos )->x_advance   = entry_x - gpi->anchor_x;
   1938     POSITION( buffer->in_pos )->new_advance = TRUE;
   1939   }
   1940   else
   1941   {
   1942     POSITION( gpi->last )->x_advance   = gpi->anchor_x - entry_x;
   1943     POSITION( gpi->last )->new_advance = TRUE;
   1944   }
   1945 
   1946   if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
   1947   {
   1948     POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
   1949     POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
   1950   }
   1951   else
   1952   {
   1953     POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
   1954     POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
   1955   }
   1956 
   1957 end:
   1958   error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
   1959 		      &exit_x, &exit_y );
   1960   if ( error == HB_Err_Not_Covered )
   1961     gpi->last = 0xFFFF;
   1962   else
   1963   {
   1964     gpi->last     = buffer->in_pos;
   1965     gpi->anchor_x = exit_x;
   1966     gpi->anchor_y = exit_y;
   1967   }
   1968   if ( error )
   1969     return error;
   1970 
   1971   (buffer->in_pos)++;
   1972 
   1973   return HB_Err_Ok;
   1974 }
   1975 
   1976 
   1977 /* LookupType 4 */
   1978 
   1979 /* BaseArray */
   1980 
   1981 static HB_Error  Load_BaseArray( HB_BaseArray*  ba,
   1982 				 HB_UShort       num_classes,
   1983 				 HB_Stream       stream )
   1984 {
   1985   HB_Error  error;
   1986 
   1987   HB_UShort       m, n, count;
   1988   HB_UInt         cur_offset, new_offset, base_offset;
   1989 
   1990   HB_BaseRecord  *br;
   1991   HB_Anchor      *ban, *bans;
   1992 
   1993 
   1994   base_offset = FILE_Pos();
   1995 
   1996   if ( ACCESS_Frame( 2L ) )
   1997     return error;
   1998 
   1999   count = ba->BaseCount = GET_UShort();
   2000 
   2001   FORGET_Frame();
   2002 
   2003   ba->BaseRecord = NULL;
   2004 
   2005   if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
   2006     return error;
   2007 
   2008   br = ba->BaseRecord;
   2009 
   2010   bans = NULL;
   2011 
   2012   if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
   2013     goto Fail;
   2014 
   2015   for ( m = 0; m < count; m++ )
   2016   {
   2017     br[m].BaseAnchor = NULL;
   2018 
   2019     ban = br[m].BaseAnchor = bans + m * num_classes;
   2020 
   2021     for ( n = 0; n < num_classes; n++ )
   2022     {
   2023       if ( ACCESS_Frame( 2L ) )
   2024 	goto Fail;
   2025 
   2026       new_offset = GET_UShort() + base_offset;
   2027 
   2028       FORGET_Frame();
   2029 
   2030       if (new_offset == base_offset) {
   2031 	/* XXX
   2032 	 * Doulos SIL Regular is buggy and has zero offsets here.
   2033 	 * Skip it
   2034 	 */
   2035 	ban[n].PosFormat = 0;
   2036 	continue;
   2037       }
   2038 
   2039       cur_offset = FILE_Pos();
   2040       if ( FILE_Seek( new_offset ) ||
   2041 	   ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
   2042 	goto Fail;
   2043       (void)FILE_Seek( cur_offset );
   2044     }
   2045   }
   2046 
   2047   return HB_Err_Ok;
   2048 
   2049 Fail:
   2050   FREE( bans );
   2051   FREE( br );
   2052   return error;
   2053 }
   2054 
   2055 
   2056 static void  Free_BaseArray( HB_BaseArray*  ba,
   2057 			     HB_UShort       num_classes )
   2058 {
   2059   HB_BaseRecord  *br;
   2060   HB_Anchor      *bans;
   2061 
   2062   if ( ba->BaseRecord )
   2063   {
   2064     br    = ba->BaseRecord;
   2065 
   2066     if ( ba->BaseCount )
   2067     {
   2068       HB_UShort i, count;
   2069       count = num_classes * ba->BaseCount;
   2070       bans = br[0].BaseAnchor;
   2071       for (i = 0; i < count; i++)
   2072         Free_Anchor (&bans[i]);
   2073       FREE( bans );
   2074     }
   2075 
   2076     FREE( br );
   2077   }
   2078 }
   2079 
   2080 
   2081 /* MarkBasePosFormat1 */
   2082 
   2083 static HB_Error  Load_MarkBasePos( HB_GPOS_SubTable* st,
   2084 				   HB_Stream         stream )
   2085 {
   2086   HB_Error  error;
   2087   HB_MarkBasePos* mbp = &st->markbase;
   2088 
   2089   HB_UInt  cur_offset, new_offset, base_offset;
   2090 
   2091 
   2092   base_offset = FILE_Pos();
   2093 
   2094   if ( ACCESS_Frame( 4L ) )
   2095     return error;
   2096 
   2097   mbp->PosFormat = GET_UShort();
   2098   new_offset     = GET_UShort() + base_offset;
   2099 
   2100   FORGET_Frame();
   2101 
   2102   if (mbp->PosFormat != 1)
   2103     return ERR(HB_Err_Invalid_SubTable_Format);
   2104 
   2105   cur_offset = FILE_Pos();
   2106   if ( FILE_Seek( new_offset ) ||
   2107        ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
   2108     return error;
   2109   (void)FILE_Seek( cur_offset );
   2110 
   2111   if ( ACCESS_Frame( 2L ) )
   2112     goto Fail3;
   2113 
   2114   new_offset = GET_UShort() + base_offset;
   2115 
   2116   FORGET_Frame();
   2117 
   2118   cur_offset = FILE_Pos();
   2119   if ( FILE_Seek( new_offset ) ||
   2120        ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
   2121     goto Fail3;
   2122   (void)FILE_Seek( cur_offset );
   2123 
   2124   if ( ACCESS_Frame( 4L ) )
   2125     goto Fail2;
   2126 
   2127   mbp->ClassCount = GET_UShort();
   2128   new_offset      = GET_UShort() + base_offset;
   2129 
   2130   FORGET_Frame();
   2131 
   2132   cur_offset = FILE_Pos();
   2133   if ( FILE_Seek( new_offset ) ||
   2134        ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
   2135     goto Fail2;
   2136   (void)FILE_Seek( cur_offset );
   2137 
   2138   if ( ACCESS_Frame( 2L ) )
   2139     goto Fail1;
   2140 
   2141   new_offset = GET_UShort() + base_offset;
   2142 
   2143   FORGET_Frame();
   2144 
   2145   cur_offset = FILE_Pos();
   2146   if ( FILE_Seek( new_offset ) ||
   2147        ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
   2148 				 stream ) ) != HB_Err_Ok )
   2149     goto Fail1;
   2150 
   2151   return HB_Err_Ok;
   2152 
   2153 Fail1:
   2154   Free_MarkArray( &mbp->MarkArray );
   2155 
   2156 Fail2:
   2157   _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
   2158 
   2159 Fail3:
   2160   _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
   2161   return error;
   2162 }
   2163 
   2164 
   2165 static void  Free_MarkBasePos( HB_GPOS_SubTable* st )
   2166 {
   2167   HB_MarkBasePos* mbp = &st->markbase;
   2168 
   2169   Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
   2170   Free_MarkArray( &mbp->MarkArray );
   2171   _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
   2172   _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
   2173 }
   2174 
   2175 
   2176 static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
   2177 				     HB_GPOS_SubTable* st,
   2178 				     HB_Buffer        buffer,
   2179 				     HB_UShort         flags,
   2180 				     HB_UShort         context_length,
   2181 				     int               nesting_level )
   2182 {
   2183   HB_UShort        i, j, mark_index, base_index, property, class;
   2184   HB_Fixed           x_mark_value, y_mark_value, x_base_value, y_base_value;
   2185   HB_Error         error;
   2186   HB_GPOSHeader*  gpos = gpi->gpos;
   2187   HB_MarkBasePos* mbp = &st->markbase;
   2188 
   2189   HB_MarkArray*   ma;
   2190   HB_BaseArray*   ba;
   2191   HB_BaseRecord*  br;
   2192   HB_Anchor*      mark_anchor;
   2193   HB_Anchor*      base_anchor;
   2194 
   2195   HB_Position     o;
   2196 
   2197   HB_UNUSED(nesting_level);
   2198 
   2199   if ( context_length != 0xFFFF && context_length < 1 )
   2200     return HB_Err_Not_Covered;
   2201 
   2202   if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
   2203     return HB_Err_Not_Covered;
   2204 
   2205   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
   2206 		       flags, &property ) )
   2207     return error;
   2208 
   2209   error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
   2210 			  &mark_index );
   2211   if ( error )
   2212     return error;
   2213 
   2214   /* now we search backwards for a non-mark glyph */
   2215 
   2216   i = 1;
   2217   j = buffer->in_pos - 1;
   2218 
   2219   while ( i <= buffer->in_pos )
   2220   {
   2221     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
   2222 					&property );
   2223     if ( error )
   2224       return error;
   2225 
   2226     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   2227       break;
   2228 
   2229     i++;
   2230     j--;
   2231   }
   2232 
   2233   /* The following assertion is too strong -- at least for mangal.ttf. */
   2234 #if 0
   2235   if ( property != HB_GDEF_BASE_GLYPH )
   2236     return HB_Err_Not_Covered;
   2237 #endif
   2238 
   2239   if ( i > buffer->in_pos )
   2240     return HB_Err_Not_Covered;
   2241 
   2242   error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
   2243 			  &base_index );
   2244   if ( error )
   2245     return error;
   2246 
   2247   ma = &mbp->MarkArray;
   2248 
   2249   if ( mark_index >= ma->MarkCount )
   2250     return ERR(HB_Err_Invalid_SubTable);
   2251 
   2252   class       = ma->MarkRecord[mark_index].Class;
   2253   mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
   2254 
   2255   if ( class >= mbp->ClassCount )
   2256     return ERR(HB_Err_Invalid_SubTable);
   2257 
   2258   ba = &mbp->BaseArray;
   2259 
   2260   if ( base_index >= ba->BaseCount )
   2261     return ERR(HB_Err_Invalid_SubTable);
   2262 
   2263   br          = &ba->BaseRecord[base_index];
   2264   base_anchor = &br->BaseAnchor[class];
   2265 
   2266   error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
   2267 		      &x_mark_value, &y_mark_value );
   2268   if ( error )
   2269     return error;
   2270 
   2271   error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
   2272 		      &x_base_value, &y_base_value );
   2273   if ( error )
   2274     return error;
   2275 
   2276   /* anchor points are not cumulative */
   2277 
   2278   o = POSITION( buffer->in_pos );
   2279 
   2280   o->x_pos     = x_base_value - x_mark_value;
   2281   o->y_pos     = y_base_value - y_mark_value;
   2282   o->x_advance = 0;
   2283   o->y_advance = 0;
   2284   o->back      = i;
   2285 
   2286   (buffer->in_pos)++;
   2287 
   2288   return HB_Err_Ok;
   2289 }
   2290 
   2291 
   2292 /* LookupType 5 */
   2293 
   2294 /* LigatureAttach */
   2295 
   2296 static HB_Error  Load_LigatureAttach( HB_LigatureAttach*  lat,
   2297 				      HB_UShort            num_classes,
   2298 				      HB_Stream            stream )
   2299 {
   2300   HB_Error  error;
   2301 
   2302   HB_UShort             m, n, k, count;
   2303   HB_UInt              cur_offset, new_offset, base_offset;
   2304 
   2305   HB_ComponentRecord*  cr;
   2306   HB_Anchor*           lan;
   2307 
   2308 
   2309   base_offset = FILE_Pos();
   2310 
   2311   if ( ACCESS_Frame( 2L ) )
   2312     return error;
   2313 
   2314   count = lat->ComponentCount = GET_UShort();
   2315 
   2316   FORGET_Frame();
   2317 
   2318   lat->ComponentRecord = NULL;
   2319 
   2320   if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
   2321     return error;
   2322 
   2323   cr = lat->ComponentRecord;
   2324 
   2325   for ( m = 0; m < count; m++ )
   2326   {
   2327     cr[m].LigatureAnchor = NULL;
   2328 
   2329     if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
   2330       goto Fail;
   2331 
   2332     lan = cr[m].LigatureAnchor;
   2333 
   2334     for ( n = 0; n < num_classes; n++ )
   2335     {
   2336       if ( ACCESS_Frame( 2L ) )
   2337 	goto Fail0;
   2338 
   2339       new_offset = GET_UShort();
   2340 
   2341       FORGET_Frame();
   2342 
   2343       if ( new_offset )
   2344       {
   2345 	new_offset += base_offset;
   2346 
   2347 	cur_offset = FILE_Pos();
   2348 	if ( FILE_Seek( new_offset ) ||
   2349 	     ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
   2350 	  goto Fail0;
   2351 	(void)FILE_Seek( cur_offset );
   2352       }
   2353       else
   2354 	lan[n].PosFormat = 0;
   2355     }
   2356 
   2357     continue;
   2358   Fail0:
   2359     for ( k = 0; k < n; k++ )
   2360       Free_Anchor( &lan[k] );
   2361     goto Fail;
   2362   }
   2363 
   2364   return HB_Err_Ok;
   2365 
   2366 Fail:
   2367   for ( k = 0; k < m; k++ )
   2368   {
   2369     lan = cr[k].LigatureAnchor;
   2370 
   2371     for ( n = 0; n < num_classes; n++ )
   2372       Free_Anchor( &lan[n] );
   2373 
   2374     FREE( lan );
   2375   }
   2376 
   2377   FREE( cr );
   2378   return error;
   2379 }
   2380 
   2381 
   2382 static void  Free_LigatureAttach( HB_LigatureAttach*  lat,
   2383 				  HB_UShort            num_classes )
   2384 {
   2385   HB_UShort        m, n, count;
   2386 
   2387   HB_ComponentRecord*  cr;
   2388   HB_Anchor*           lan;
   2389 
   2390 
   2391   if ( lat->ComponentRecord )
   2392   {
   2393     count = lat->ComponentCount;
   2394     cr    = lat->ComponentRecord;
   2395 
   2396     for ( m = 0; m < count; m++ )
   2397     {
   2398       lan = cr[m].LigatureAnchor;
   2399 
   2400       for ( n = 0; n < num_classes; n++ )
   2401 	Free_Anchor( &lan[n] );
   2402 
   2403       FREE( lan );
   2404     }
   2405 
   2406     FREE( cr );
   2407   }
   2408 }
   2409 
   2410 
   2411 /* LigatureArray */
   2412 
   2413 static HB_Error  Load_LigatureArray( HB_LigatureArray*  la,
   2414 				     HB_UShort           num_classes,
   2415 				     HB_Stream           stream )
   2416 {
   2417   HB_Error  error;
   2418 
   2419   HB_UShort            n, m, count;
   2420   HB_UInt             cur_offset, new_offset, base_offset;
   2421 
   2422   HB_LigatureAttach*  lat;
   2423 
   2424 
   2425   base_offset = FILE_Pos();
   2426 
   2427   if ( ACCESS_Frame( 2L ) )
   2428     return error;
   2429 
   2430   count = la->LigatureCount = GET_UShort();
   2431 
   2432   FORGET_Frame();
   2433 
   2434   la->LigatureAttach = NULL;
   2435 
   2436   if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
   2437     return error;
   2438 
   2439   lat = la->LigatureAttach;
   2440 
   2441   for ( n = 0; n < count; n++ )
   2442   {
   2443     if ( ACCESS_Frame( 2L ) )
   2444       goto Fail;
   2445 
   2446     new_offset = GET_UShort() + base_offset;
   2447 
   2448     FORGET_Frame();
   2449 
   2450     cur_offset = FILE_Pos();
   2451     if ( FILE_Seek( new_offset ) ||
   2452 	 ( error = Load_LigatureAttach( &lat[n], num_classes,
   2453 					stream ) ) != HB_Err_Ok )
   2454       goto Fail;
   2455     (void)FILE_Seek( cur_offset );
   2456   }
   2457 
   2458   return HB_Err_Ok;
   2459 
   2460 Fail:
   2461   for ( m = 0; m < n; m++ )
   2462     Free_LigatureAttach( &lat[m], num_classes );
   2463 
   2464   FREE( lat );
   2465   return error;
   2466 }
   2467 
   2468 
   2469 static void  Free_LigatureArray( HB_LigatureArray*  la,
   2470 				 HB_UShort           num_classes )
   2471 {
   2472   HB_UShort            n, count;
   2473 
   2474   HB_LigatureAttach*  lat;
   2475 
   2476 
   2477   if ( la->LigatureAttach )
   2478   {
   2479     count = la->LigatureCount;
   2480     lat   = la->LigatureAttach;
   2481 
   2482     for ( n = 0; n < count; n++ )
   2483       Free_LigatureAttach( &lat[n], num_classes );
   2484 
   2485     FREE( lat );
   2486   }
   2487 }
   2488 
   2489 
   2490 /* MarkLigPosFormat1 */
   2491 
   2492 static HB_Error  Load_MarkLigPos( HB_GPOS_SubTable* st,
   2493 				  HB_Stream        stream )
   2494 {
   2495   HB_Error  error;
   2496   HB_MarkLigPos*  mlp = &st->marklig;
   2497 
   2498   HB_UInt  cur_offset, new_offset, base_offset;
   2499 
   2500 
   2501   base_offset = FILE_Pos();
   2502 
   2503   if ( ACCESS_Frame( 4L ) )
   2504     return error;
   2505 
   2506   mlp->PosFormat = GET_UShort();
   2507   new_offset     = GET_UShort() + base_offset;
   2508 
   2509   FORGET_Frame();
   2510 
   2511   cur_offset = FILE_Pos();
   2512   if ( FILE_Seek( new_offset ) ||
   2513        ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
   2514     return error;
   2515   (void)FILE_Seek( cur_offset );
   2516 
   2517   if ( ACCESS_Frame( 2L ) )
   2518     goto Fail3;
   2519 
   2520   new_offset = GET_UShort() + base_offset;
   2521 
   2522   FORGET_Frame();
   2523 
   2524   cur_offset = FILE_Pos();
   2525   if ( FILE_Seek( new_offset ) ||
   2526        ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
   2527 				stream ) ) != HB_Err_Ok )
   2528     goto Fail3;
   2529   (void)FILE_Seek( cur_offset );
   2530 
   2531   if ( ACCESS_Frame( 4L ) )
   2532     goto Fail2;
   2533 
   2534   mlp->ClassCount = GET_UShort();
   2535   new_offset      = GET_UShort() + base_offset;
   2536 
   2537   FORGET_Frame();
   2538 
   2539   cur_offset = FILE_Pos();
   2540   if ( FILE_Seek( new_offset ) ||
   2541        ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
   2542     goto Fail2;
   2543   (void)FILE_Seek( cur_offset );
   2544 
   2545   if ( ACCESS_Frame( 2L ) )
   2546     goto Fail1;
   2547 
   2548   new_offset = GET_UShort() + base_offset;
   2549 
   2550   FORGET_Frame();
   2551 
   2552   cur_offset = FILE_Pos();
   2553   if ( FILE_Seek( new_offset ) ||
   2554        ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
   2555 				     stream ) ) != HB_Err_Ok )
   2556     goto Fail1;
   2557 
   2558   return HB_Err_Ok;
   2559 
   2560 Fail1:
   2561   Free_MarkArray( &mlp->MarkArray );
   2562 
   2563 Fail2:
   2564   _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
   2565 
   2566 Fail3:
   2567   _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
   2568   return error;
   2569 }
   2570 
   2571 
   2572 static void  Free_MarkLigPos( HB_GPOS_SubTable* st)
   2573 {
   2574   HB_MarkLigPos*  mlp = &st->marklig;
   2575 
   2576   Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
   2577   Free_MarkArray( &mlp->MarkArray );
   2578   _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
   2579   _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
   2580 }
   2581 
   2582 
   2583 static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
   2584 				    HB_GPOS_SubTable* st,
   2585 				    HB_Buffer        buffer,
   2586 				    HB_UShort         flags,
   2587 				    HB_UShort         context_length,
   2588 				    int               nesting_level )
   2589 {
   2590   HB_UShort        i, j, mark_index, lig_index, property, class;
   2591   HB_UShort        mark_glyph;
   2592   HB_Fixed           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
   2593   HB_Error         error;
   2594   HB_GPOSHeader*  gpos = gpi->gpos;
   2595   HB_MarkLigPos*  mlp = &st->marklig;
   2596 
   2597   HB_MarkArray*        ma;
   2598   HB_LigatureArray*    la;
   2599   HB_LigatureAttach*   lat;
   2600   HB_ComponentRecord*  cr;
   2601   HB_UShort             comp_index;
   2602   HB_Anchor*           mark_anchor;
   2603   HB_Anchor*           lig_anchor;
   2604 
   2605   HB_Position    o;
   2606 
   2607   HB_UNUSED(nesting_level);
   2608 
   2609   if ( context_length != 0xFFFF && context_length < 1 )
   2610     return HB_Err_Not_Covered;
   2611 
   2612   if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
   2613     return HB_Err_Not_Covered;
   2614 
   2615   mark_glyph = IN_CURGLYPH();
   2616 
   2617   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   2618     return error;
   2619 
   2620   error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
   2621   if ( error )
   2622     return error;
   2623 
   2624   /* now we search backwards for a non-mark glyph */
   2625 
   2626   i = 1;
   2627   j = buffer->in_pos - 1;
   2628 
   2629   while ( i <= buffer->in_pos )
   2630   {
   2631     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
   2632 					&property );
   2633     if ( error )
   2634       return error;
   2635 
   2636     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   2637       break;
   2638 
   2639     i++;
   2640     j--;
   2641   }
   2642 
   2643   /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
   2644      too strong, thus it is commented out.                             */
   2645 #if 0
   2646   if ( property != HB_GDEF_LIGATURE )
   2647     return HB_Err_Not_Covered;
   2648 #endif
   2649 
   2650   if ( i > buffer->in_pos )
   2651     return HB_Err_Not_Covered;
   2652 
   2653   error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
   2654 			  &lig_index );
   2655   if ( error )
   2656     return error;
   2657 
   2658   ma = &mlp->MarkArray;
   2659 
   2660   if ( mark_index >= ma->MarkCount )
   2661     return ERR(HB_Err_Invalid_SubTable);
   2662 
   2663   class       = ma->MarkRecord[mark_index].Class;
   2664   mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
   2665 
   2666   if ( class >= mlp->ClassCount )
   2667     return ERR(HB_Err_Invalid_SubTable);
   2668 
   2669   la = &mlp->LigatureArray;
   2670 
   2671   if ( lig_index >= la->LigatureCount )
   2672     return ERR(HB_Err_Invalid_SubTable);
   2673 
   2674   lat = &la->LigatureAttach[lig_index];
   2675 
   2676   /* We must now check whether the ligature ID of the current mark glyph
   2677      is identical to the ligature ID of the found ligature.  If yes, we
   2678      can directly use the component index.  If not, we attach the mark
   2679      glyph to the last component of the ligature.                        */
   2680 
   2681   if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
   2682   {
   2683     comp_index = IN_COMPONENT( buffer->in_pos );
   2684     if ( comp_index >= lat->ComponentCount )
   2685       return HB_Err_Not_Covered;
   2686   }
   2687   else
   2688     comp_index = lat->ComponentCount - 1;
   2689 
   2690   cr         = &lat->ComponentRecord[comp_index];
   2691   lig_anchor = &cr->LigatureAnchor[class];
   2692 
   2693   error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
   2694 		      &x_mark_value, &y_mark_value );
   2695   if ( error )
   2696     return error;
   2697   error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
   2698 		      &x_lig_value, &y_lig_value );
   2699   if ( error )
   2700     return error;
   2701 
   2702   /* anchor points are not cumulative */
   2703 
   2704   o = POSITION( buffer->in_pos );
   2705 
   2706   o->x_pos     = x_lig_value - x_mark_value;
   2707   o->y_pos     = y_lig_value - y_mark_value;
   2708   o->x_advance = 0;
   2709   o->y_advance = 0;
   2710   o->back      = i;
   2711 
   2712   (buffer->in_pos)++;
   2713 
   2714   return HB_Err_Ok;
   2715 }
   2716 
   2717 
   2718 /* LookupType 6 */
   2719 
   2720 /* Mark2Array */
   2721 
   2722 static HB_Error  Load_Mark2Array( HB_Mark2Array*  m2a,
   2723 				  HB_UShort        num_classes,
   2724 				  HB_Stream        stream )
   2725 {
   2726   HB_Error  error;
   2727 
   2728   HB_UShort        m, n, count;
   2729   HB_UInt          cur_offset, new_offset, base_offset;
   2730 
   2731   HB_Mark2Record  *m2r;
   2732   HB_Anchor       *m2an, *m2ans;
   2733 
   2734 
   2735   base_offset = FILE_Pos();
   2736 
   2737   if ( ACCESS_Frame( 2L ) )
   2738     return error;
   2739 
   2740   count = m2a->Mark2Count = GET_UShort();
   2741 
   2742   FORGET_Frame();
   2743 
   2744   m2a->Mark2Record = NULL;
   2745 
   2746   if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
   2747     return error;
   2748 
   2749   m2r = m2a->Mark2Record;
   2750 
   2751   m2ans = NULL;
   2752 
   2753   if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
   2754     goto Fail;
   2755 
   2756   for ( m = 0; m < count; m++ )
   2757   {
   2758     m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
   2759 
   2760     for ( n = 0; n < num_classes; n++ )
   2761     {
   2762       if ( ACCESS_Frame( 2L ) )
   2763 	goto Fail;
   2764 
   2765       new_offset = GET_UShort() + base_offset;
   2766 
   2767       FORGET_Frame();
   2768 
   2769       if (new_offset == base_offset) {
   2770         /* Anchor table not provided.  Skip loading.
   2771 	 * Some versions of FreeSans hit this. */
   2772         m2an[n].PosFormat = 0;
   2773 	continue;
   2774       }
   2775 
   2776       cur_offset = FILE_Pos();
   2777       if ( FILE_Seek( new_offset ) ||
   2778 	   ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
   2779 	goto Fail;
   2780       (void)FILE_Seek( cur_offset );
   2781     }
   2782   }
   2783 
   2784   return HB_Err_Ok;
   2785 
   2786 Fail:
   2787   FREE( m2ans );
   2788   FREE( m2r );
   2789   return error;
   2790 }
   2791 
   2792 
   2793 static void  Free_Mark2Array( HB_Mark2Array*  m2a,
   2794 			      HB_UShort        num_classes )
   2795 {
   2796   HB_Mark2Record  *m2r;
   2797   HB_Anchor       *m2ans;
   2798 
   2799   HB_UNUSED(num_classes);
   2800 
   2801   if ( m2a->Mark2Record )
   2802   {
   2803     m2r   = m2a->Mark2Record;
   2804 
   2805     if ( m2a->Mark2Count )
   2806     {
   2807       m2ans = m2r[0].Mark2Anchor;
   2808       FREE( m2ans );
   2809     }
   2810 
   2811     FREE( m2r );
   2812   }
   2813 }
   2814 
   2815 
   2816 /* MarkMarkPosFormat1 */
   2817 
   2818 static HB_Error  Load_MarkMarkPos( HB_GPOS_SubTable* st,
   2819 				   HB_Stream         stream )
   2820 {
   2821   HB_Error  error;
   2822   HB_MarkMarkPos* mmp = &st->markmark;
   2823 
   2824   HB_UInt  cur_offset, new_offset, base_offset;
   2825 
   2826 
   2827   base_offset = FILE_Pos();
   2828 
   2829   if ( ACCESS_Frame( 4L ) )
   2830     return error;
   2831 
   2832   mmp->PosFormat = GET_UShort();
   2833   new_offset     = GET_UShort() + base_offset;
   2834 
   2835   FORGET_Frame();
   2836 
   2837   cur_offset = FILE_Pos();
   2838   if ( FILE_Seek( new_offset ) ||
   2839        ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
   2840 				stream ) ) != HB_Err_Ok )
   2841     return error;
   2842   (void)FILE_Seek( cur_offset );
   2843 
   2844   if ( ACCESS_Frame( 2L ) )
   2845     goto Fail3;
   2846 
   2847   new_offset = GET_UShort() + base_offset;
   2848 
   2849   FORGET_Frame();
   2850 
   2851   cur_offset = FILE_Pos();
   2852   if ( FILE_Seek( new_offset ) ||
   2853        ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
   2854 				stream ) ) != HB_Err_Ok )
   2855     goto Fail3;
   2856   (void)FILE_Seek( cur_offset );
   2857 
   2858   if ( ACCESS_Frame( 4L ) )
   2859     goto Fail2;
   2860 
   2861   mmp->ClassCount = GET_UShort();
   2862   new_offset      = GET_UShort() + base_offset;
   2863 
   2864   FORGET_Frame();
   2865 
   2866   cur_offset = FILE_Pos();
   2867   if ( FILE_Seek( new_offset ) ||
   2868        ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
   2869     goto Fail2;
   2870   (void)FILE_Seek( cur_offset );
   2871 
   2872   if ( ACCESS_Frame( 2L ) )
   2873     goto Fail1;
   2874 
   2875   new_offset = GET_UShort() + base_offset;
   2876 
   2877   FORGET_Frame();
   2878 
   2879   cur_offset = FILE_Pos();
   2880   if ( FILE_Seek( new_offset ) ||
   2881        ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
   2882 				  stream ) ) != HB_Err_Ok )
   2883     goto Fail1;
   2884 
   2885   return HB_Err_Ok;
   2886 
   2887 Fail1:
   2888   Free_MarkArray( &mmp->Mark1Array );
   2889 
   2890 Fail2:
   2891   _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
   2892 
   2893 Fail3:
   2894   _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
   2895   return error;
   2896 }
   2897 
   2898 
   2899 static void  Free_MarkMarkPos( HB_GPOS_SubTable* st)
   2900 {
   2901   HB_MarkMarkPos* mmp = &st->markmark;
   2902 
   2903   Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
   2904   Free_MarkArray( &mmp->Mark1Array );
   2905   _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
   2906   _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
   2907 }
   2908 
   2909 
   2910 static HB_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
   2911 				     HB_GPOS_SubTable* st,
   2912 				     HB_Buffer        buffer,
   2913 				     HB_UShort         flags,
   2914 				     HB_UShort         context_length,
   2915 				     int               nesting_level )
   2916 {
   2917   HB_UShort        i, j, mark1_index, mark2_index, property, class;
   2918   HB_Fixed           x_mark1_value, y_mark1_value,
   2919 		   x_mark2_value, y_mark2_value;
   2920   HB_Error         error;
   2921   HB_GPOSHeader*  gpos = gpi->gpos;
   2922   HB_MarkMarkPos* mmp = &st->markmark;
   2923 
   2924   HB_MarkArray*    ma1;
   2925   HB_Mark2Array*   ma2;
   2926   HB_Mark2Record*  m2r;
   2927   HB_Anchor*       mark1_anchor;
   2928   HB_Anchor*       mark2_anchor;
   2929 
   2930   HB_Position    o;
   2931 
   2932   HB_UNUSED(nesting_level);
   2933 
   2934   if ( context_length != 0xFFFF && context_length < 1 )
   2935     return HB_Err_Not_Covered;
   2936 
   2937   if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
   2938     return HB_Err_Not_Covered;
   2939 
   2940   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
   2941 		       flags, &property ) )
   2942     return error;
   2943 
   2944   error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
   2945 			  &mark1_index );
   2946   if ( error )
   2947     return error;
   2948 
   2949   /* now we search backwards for a suitable mark glyph until a non-mark
   2950      glyph                                                */
   2951 
   2952   if ( buffer->in_pos == 0 )
   2953     return HB_Err_Not_Covered;
   2954 
   2955   i = 1;
   2956   j = buffer->in_pos - 1;
   2957   while ( i <= buffer->in_pos )
   2958   {
   2959     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
   2960 					&property );
   2961     if ( error )
   2962       return error;
   2963 
   2964     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   2965       return HB_Err_Not_Covered;
   2966 
   2967     if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
   2968     {
   2969       if ( property == (flags & 0xFF00) )
   2970         break;
   2971     }
   2972     else
   2973       break;
   2974 
   2975     i++;
   2976     j--;
   2977   }
   2978 
   2979   error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
   2980 			  &mark2_index );
   2981   if ( error )
   2982     return error;
   2983 
   2984   ma1 = &mmp->Mark1Array;
   2985 
   2986   if ( mark1_index >= ma1->MarkCount )
   2987     return ERR(HB_Err_Invalid_SubTable);
   2988 
   2989   class        = ma1->MarkRecord[mark1_index].Class;
   2990   mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
   2991 
   2992   if ( class >= mmp->ClassCount )
   2993     return ERR(HB_Err_Invalid_SubTable);
   2994 
   2995   ma2 = &mmp->Mark2Array;
   2996 
   2997   if ( mark2_index >= ma2->Mark2Count )
   2998     return ERR(HB_Err_Invalid_SubTable);
   2999 
   3000   m2r          = &ma2->Mark2Record[mark2_index];
   3001   mark2_anchor = &m2r->Mark2Anchor[class];
   3002 
   3003   error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
   3004 		      &x_mark1_value, &y_mark1_value );
   3005   if ( error )
   3006     return error;
   3007   error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
   3008 		      &x_mark2_value, &y_mark2_value );
   3009   if ( error )
   3010     return error;
   3011 
   3012   /* anchor points are not cumulative */
   3013 
   3014   o = POSITION( buffer->in_pos );
   3015 
   3016   o->x_pos     = x_mark2_value - x_mark1_value;
   3017   o->y_pos     = y_mark2_value - y_mark1_value;
   3018   o->x_advance = 0;
   3019   o->y_advance = 0;
   3020   o->back      = 1;
   3021 
   3022   (buffer->in_pos)++;
   3023 
   3024   return HB_Err_Ok;
   3025 }
   3026 
   3027 
   3028 /* Do the actual positioning for a context positioning (either format
   3029    7 or 8).  This is only called after we've determined that the stream
   3030    matches the subrule.                                                 */
   3031 
   3032 static HB_Error  Do_ContextPos( GPOS_Instance*        gpi,
   3033 				HB_UShort             GlyphCount,
   3034 				HB_UShort             PosCount,
   3035 				HB_PosLookupRecord*  pos,
   3036 				HB_Buffer            buffer,
   3037 				int                   nesting_level )
   3038 {
   3039   HB_Error  error;
   3040   HB_UInt   i, old_pos;
   3041 
   3042 
   3043   i = 0;
   3044 
   3045   while ( i < GlyphCount )
   3046   {
   3047     if ( PosCount && i == pos->SequenceIndex )
   3048     {
   3049       old_pos = buffer->in_pos;
   3050 
   3051       /* Do a positioning */
   3052 
   3053       error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
   3054 				    GlyphCount, nesting_level );
   3055 
   3056       if ( error )
   3057 	return error;
   3058 
   3059       pos++;
   3060       PosCount--;
   3061       i += buffer->in_pos - old_pos;
   3062     }
   3063     else
   3064     {
   3065       i++;
   3066       (buffer->in_pos)++;
   3067     }
   3068   }
   3069 
   3070   return HB_Err_Ok;
   3071 }
   3072 
   3073 
   3074 /* LookupType 7 */
   3075 
   3076 /* PosRule */
   3077 
   3078 static HB_Error  Load_PosRule( HB_PosRule*  pr,
   3079 			       HB_Stream     stream )
   3080 {
   3081   HB_Error  error;
   3082 
   3083   HB_UShort             n, count;
   3084   HB_UShort*            i;
   3085 
   3086   HB_PosLookupRecord*  plr;
   3087 
   3088 
   3089   if ( ACCESS_Frame( 4L ) )
   3090     return error;
   3091 
   3092   pr->GlyphCount = GET_UShort();
   3093   pr->PosCount   = GET_UShort();
   3094 
   3095   FORGET_Frame();
   3096 
   3097   pr->Input = NULL;
   3098 
   3099   count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
   3100 
   3101   if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
   3102     return error;
   3103 
   3104   i = pr->Input;
   3105 
   3106   if ( ACCESS_Frame( count * 2L ) )
   3107     goto Fail2;
   3108 
   3109   for ( n = 0; n < count; n++ )
   3110     i[n] = GET_UShort();
   3111 
   3112   FORGET_Frame();
   3113 
   3114   pr->PosLookupRecord = NULL;
   3115 
   3116   count = pr->PosCount;
   3117 
   3118   if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
   3119     goto Fail2;
   3120 
   3121   plr = pr->PosLookupRecord;
   3122 
   3123   if ( ACCESS_Frame( count * 4L ) )
   3124     goto Fail1;
   3125 
   3126   for ( n = 0; n < count; n++ )
   3127   {
   3128     plr[n].SequenceIndex   = GET_UShort();
   3129     plr[n].LookupListIndex = GET_UShort();
   3130   }
   3131 
   3132   FORGET_Frame();
   3133 
   3134   return HB_Err_Ok;
   3135 
   3136 Fail1:
   3137   FREE( plr );
   3138 
   3139 Fail2:
   3140   FREE( i );
   3141   return error;
   3142 }
   3143 
   3144 
   3145 static void  Free_PosRule( HB_PosRule*  pr )
   3146 {
   3147   FREE( pr->PosLookupRecord );
   3148   FREE( pr->Input );
   3149 }
   3150 
   3151 
   3152 /* PosRuleSet */
   3153 
   3154 static HB_Error  Load_PosRuleSet( HB_PosRuleSet*  prs,
   3155 				  HB_Stream        stream )
   3156 {
   3157   HB_Error  error;
   3158 
   3159   HB_UShort     n, m, count;
   3160   HB_UInt      cur_offset, new_offset, base_offset;
   3161 
   3162   HB_PosRule*  pr;
   3163 
   3164 
   3165   base_offset = FILE_Pos();
   3166 
   3167   if ( ACCESS_Frame( 2L ) )
   3168     return error;
   3169 
   3170   count = prs->PosRuleCount = GET_UShort();
   3171 
   3172   FORGET_Frame();
   3173 
   3174   prs->PosRule = NULL;
   3175 
   3176   if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
   3177     return error;
   3178 
   3179   pr = prs->PosRule;
   3180 
   3181   for ( n = 0; n < count; n++ )
   3182   {
   3183     if ( ACCESS_Frame( 2L ) )
   3184       goto Fail;
   3185 
   3186     new_offset = GET_UShort() + base_offset;
   3187 
   3188     FORGET_Frame();
   3189 
   3190     cur_offset = FILE_Pos();
   3191     if ( FILE_Seek( new_offset ) ||
   3192 	 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
   3193       goto Fail;
   3194     (void)FILE_Seek( cur_offset );
   3195   }
   3196 
   3197   return HB_Err_Ok;
   3198 
   3199 Fail:
   3200   for ( m = 0; m < n; m++ )
   3201     Free_PosRule( &pr[m] );
   3202 
   3203   FREE( pr );
   3204   return error;
   3205 }
   3206 
   3207 
   3208 static void  Free_PosRuleSet( HB_PosRuleSet*  prs )
   3209 {
   3210   HB_UShort     n, count;
   3211 
   3212   HB_PosRule*  pr;
   3213 
   3214 
   3215   if ( prs->PosRule )
   3216   {
   3217     count = prs->PosRuleCount;
   3218     pr    = prs->PosRule;
   3219 
   3220     for ( n = 0; n < count; n++ )
   3221       Free_PosRule( &pr[n] );
   3222 
   3223     FREE( pr );
   3224   }
   3225 }
   3226 
   3227 
   3228 /* ContextPosFormat1 */
   3229 
   3230 static HB_Error  Load_ContextPos1( HB_ContextPosFormat1*  cpf1,
   3231 				   HB_Stream               stream )
   3232 {
   3233   HB_Error  error;
   3234 
   3235   HB_UShort        n, m, count;
   3236   HB_UInt         cur_offset, new_offset, base_offset;
   3237 
   3238   HB_PosRuleSet*  prs;
   3239 
   3240 
   3241   base_offset = FILE_Pos() - 2L;
   3242 
   3243   if ( ACCESS_Frame( 2L ) )
   3244     return error;
   3245 
   3246   new_offset = GET_UShort() + base_offset;
   3247 
   3248   FORGET_Frame();
   3249 
   3250   cur_offset = FILE_Pos();
   3251   if ( FILE_Seek( new_offset ) ||
   3252        ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
   3253     return error;
   3254   (void)FILE_Seek( cur_offset );
   3255 
   3256   if ( ACCESS_Frame( 2L ) )
   3257     goto Fail2;
   3258 
   3259   count = cpf1->PosRuleSetCount = GET_UShort();
   3260 
   3261   FORGET_Frame();
   3262 
   3263   cpf1->PosRuleSet = NULL;
   3264 
   3265   if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
   3266     goto Fail2;
   3267 
   3268   prs = cpf1->PosRuleSet;
   3269 
   3270   for ( n = 0; n < count; n++ )
   3271   {
   3272     if ( ACCESS_Frame( 2L ) )
   3273       goto Fail1;
   3274 
   3275     new_offset = GET_UShort() + base_offset;
   3276 
   3277     FORGET_Frame();
   3278 
   3279     cur_offset = FILE_Pos();
   3280     if ( FILE_Seek( new_offset ) ||
   3281 	 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
   3282       goto Fail1;
   3283     (void)FILE_Seek( cur_offset );
   3284   }
   3285 
   3286   return HB_Err_Ok;
   3287 
   3288 Fail1:
   3289   for ( m = 0; m < n; m++ )
   3290     Free_PosRuleSet( &prs[m] );
   3291 
   3292   FREE( prs );
   3293 
   3294 Fail2:
   3295   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
   3296   return error;
   3297 }
   3298 
   3299 
   3300 static void  Free_ContextPos1( HB_ContextPosFormat1*  cpf1 )
   3301 {
   3302   HB_UShort        n, count;
   3303 
   3304   HB_PosRuleSet*  prs;
   3305 
   3306 
   3307   if ( cpf1->PosRuleSet )
   3308   {
   3309     count = cpf1->PosRuleSetCount;
   3310     prs   = cpf1->PosRuleSet;
   3311 
   3312     for ( n = 0; n < count; n++ )
   3313       Free_PosRuleSet( &prs[n] );
   3314 
   3315     FREE( prs );
   3316   }
   3317 
   3318   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
   3319 }
   3320 
   3321 
   3322 /* PosClassRule */
   3323 
   3324 static HB_Error  Load_PosClassRule( HB_ContextPosFormat2*  cpf2,
   3325 				    HB_PosClassRule*       pcr,
   3326 				    HB_Stream               stream )
   3327 {
   3328   HB_Error  error;
   3329 
   3330   HB_UShort             n, count;
   3331 
   3332   HB_UShort*            c;
   3333   HB_PosLookupRecord*  plr;
   3334 
   3335 
   3336   if ( ACCESS_Frame( 4L ) )
   3337     return error;
   3338 
   3339   pcr->GlyphCount = GET_UShort();
   3340   pcr->PosCount   = GET_UShort();
   3341 
   3342   FORGET_Frame();
   3343 
   3344   if ( pcr->GlyphCount > cpf2->MaxContextLength )
   3345     cpf2->MaxContextLength = pcr->GlyphCount;
   3346 
   3347   pcr->Class = NULL;
   3348 
   3349   count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
   3350 
   3351   if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
   3352     return error;
   3353 
   3354   c = pcr->Class;
   3355 
   3356   if ( ACCESS_Frame( count * 2L ) )
   3357     goto Fail2;
   3358 
   3359   for ( n = 0; n < count; n++ )
   3360     c[n] = GET_UShort();
   3361 
   3362   FORGET_Frame();
   3363 
   3364   pcr->PosLookupRecord = NULL;
   3365 
   3366   count = pcr->PosCount;
   3367 
   3368   if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
   3369     goto Fail2;
   3370 
   3371   plr = pcr->PosLookupRecord;
   3372 
   3373   if ( ACCESS_Frame( count * 4L ) )
   3374     goto Fail1;
   3375 
   3376   for ( n = 0; n < count; n++ )
   3377   {
   3378     plr[n].SequenceIndex   = GET_UShort();
   3379     plr[n].LookupListIndex = GET_UShort();
   3380   }
   3381 
   3382   FORGET_Frame();
   3383 
   3384   return HB_Err_Ok;
   3385 
   3386 Fail1:
   3387   FREE( plr );
   3388 
   3389 Fail2:
   3390   FREE( c );
   3391   return error;
   3392 }
   3393 
   3394 
   3395 static void  Free_PosClassRule( HB_PosClassRule*  pcr )
   3396 {
   3397   FREE( pcr->PosLookupRecord );
   3398   FREE( pcr->Class );
   3399 }
   3400 
   3401 
   3402 /* PosClassSet */
   3403 
   3404 static HB_Error  Load_PosClassSet( HB_ContextPosFormat2*  cpf2,
   3405 				   HB_PosClassSet*        pcs,
   3406 				   HB_Stream               stream )
   3407 {
   3408   HB_Error  error;
   3409 
   3410   HB_UShort          n, m, count;
   3411   HB_UInt           cur_offset, new_offset, base_offset;
   3412 
   3413   HB_PosClassRule*  pcr;
   3414 
   3415 
   3416   base_offset = FILE_Pos();
   3417 
   3418   if ( ACCESS_Frame( 2L ) )
   3419     return error;
   3420 
   3421   count = pcs->PosClassRuleCount = GET_UShort();
   3422 
   3423   FORGET_Frame();
   3424 
   3425   pcs->PosClassRule = NULL;
   3426 
   3427   if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
   3428     return error;
   3429 
   3430   pcr = pcs->PosClassRule;
   3431 
   3432   for ( n = 0; n < count; n++ )
   3433   {
   3434     if ( ACCESS_Frame( 2L ) )
   3435       goto Fail;
   3436 
   3437     new_offset = GET_UShort() + base_offset;
   3438 
   3439     FORGET_Frame();
   3440 
   3441     cur_offset = FILE_Pos();
   3442     if ( FILE_Seek( new_offset ) ||
   3443 	 ( error = Load_PosClassRule( cpf2, &pcr[n],
   3444 				      stream ) ) != HB_Err_Ok )
   3445       goto Fail;
   3446     (void)FILE_Seek( cur_offset );
   3447   }
   3448 
   3449   return HB_Err_Ok;
   3450 
   3451 Fail:
   3452   for ( m = 0; m < n; m++ )
   3453     Free_PosClassRule( &pcr[m] );
   3454 
   3455   FREE( pcr );
   3456   return error;
   3457 }
   3458 
   3459 
   3460 static void  Free_PosClassSet( HB_PosClassSet*  pcs )
   3461 {
   3462   HB_UShort          n, count;
   3463 
   3464   HB_PosClassRule*  pcr;
   3465 
   3466 
   3467   if ( pcs->PosClassRule )
   3468   {
   3469     count = pcs->PosClassRuleCount;
   3470     pcr   = pcs->PosClassRule;
   3471 
   3472     for ( n = 0; n < count; n++ )
   3473       Free_PosClassRule( &pcr[n] );
   3474 
   3475     FREE( pcr );
   3476   }
   3477 }
   3478 
   3479 
   3480 /* ContextPosFormat2 */
   3481 
   3482 static HB_Error  Load_ContextPos2( HB_ContextPosFormat2*  cpf2,
   3483 				   HB_Stream               stream )
   3484 {
   3485   HB_Error  error;
   3486 
   3487   HB_UShort         n, m, count;
   3488   HB_UInt          cur_offset, new_offset, base_offset;
   3489 
   3490   HB_PosClassSet*  pcs;
   3491 
   3492 
   3493   base_offset = FILE_Pos() - 2;
   3494 
   3495   if ( ACCESS_Frame( 2L ) )
   3496     return error;
   3497 
   3498   new_offset = GET_UShort() + base_offset;
   3499 
   3500   FORGET_Frame();
   3501 
   3502   cur_offset = FILE_Pos();
   3503   if ( FILE_Seek( new_offset ) ||
   3504        ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
   3505     return error;
   3506   (void)FILE_Seek( cur_offset );
   3507 
   3508   if ( ACCESS_Frame( 4L ) )
   3509     goto Fail3;
   3510 
   3511   new_offset = GET_UShort() + base_offset;
   3512 
   3513   /* `PosClassSetCount' is the upper limit for class values, thus we
   3514      read it now to make an additional safety check.                 */
   3515 
   3516   count = cpf2->PosClassSetCount = GET_UShort();
   3517 
   3518   FORGET_Frame();
   3519 
   3520   cur_offset = FILE_Pos();
   3521   if ( FILE_Seek( new_offset ) ||
   3522        ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
   3523 				       stream ) ) != HB_Err_Ok )
   3524     goto Fail3;
   3525   (void)FILE_Seek( cur_offset );
   3526 
   3527   cpf2->PosClassSet      = NULL;
   3528   cpf2->MaxContextLength = 0;
   3529 
   3530   if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
   3531     goto Fail2;
   3532 
   3533   pcs = cpf2->PosClassSet;
   3534 
   3535   for ( n = 0; n < count; n++ )
   3536   {
   3537     if ( ACCESS_Frame( 2L ) )
   3538       goto Fail1;
   3539 
   3540     new_offset = GET_UShort() + base_offset;
   3541 
   3542     FORGET_Frame();
   3543 
   3544     if ( new_offset != base_offset )      /* not a NULL offset */
   3545     {
   3546       cur_offset = FILE_Pos();
   3547       if ( FILE_Seek( new_offset ) ||
   3548 	   ( error = Load_PosClassSet( cpf2, &pcs[n],
   3549 				       stream ) ) != HB_Err_Ok )
   3550 	goto Fail1;
   3551       (void)FILE_Seek( cur_offset );
   3552     }
   3553     else
   3554     {
   3555       /* we create a PosClassSet table with no entries */
   3556 
   3557       cpf2->PosClassSet[n].PosClassRuleCount = 0;
   3558       cpf2->PosClassSet[n].PosClassRule      = NULL;
   3559     }
   3560   }
   3561 
   3562   return HB_Err_Ok;
   3563 
   3564 Fail1:
   3565   for ( m = 0; m < n; n++ )
   3566     Free_PosClassSet( &pcs[m] );
   3567 
   3568   FREE( pcs );
   3569 
   3570 Fail2:
   3571   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
   3572 
   3573 Fail3:
   3574   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
   3575   return error;
   3576 }
   3577 
   3578 
   3579 static void  Free_ContextPos2( HB_ContextPosFormat2*  cpf2 )
   3580 {
   3581   HB_UShort         n, count;
   3582 
   3583   HB_PosClassSet*  pcs;
   3584 
   3585 
   3586   if ( cpf2->PosClassSet )
   3587   {
   3588     count = cpf2->PosClassSetCount;
   3589     pcs   = cpf2->PosClassSet;
   3590 
   3591     for ( n = 0; n < count; n++ )
   3592       Free_PosClassSet( &pcs[n] );
   3593 
   3594     FREE( pcs );
   3595   }
   3596 
   3597   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
   3598   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
   3599 }
   3600 
   3601 
   3602 /* ContextPosFormat3 */
   3603 
   3604 static HB_Error  Load_ContextPos3( HB_ContextPosFormat3*  cpf3,
   3605 				   HB_Stream               stream )
   3606 {
   3607   HB_Error  error;
   3608 
   3609   HB_UShort             n, count;
   3610   HB_UInt              cur_offset, new_offset, base_offset;
   3611 
   3612   HB_Coverage*         c;
   3613   HB_PosLookupRecord*  plr;
   3614 
   3615 
   3616   base_offset = FILE_Pos() - 2L;
   3617 
   3618   if ( ACCESS_Frame( 4L ) )
   3619     return error;
   3620 
   3621   cpf3->GlyphCount = GET_UShort();
   3622   cpf3->PosCount   = GET_UShort();
   3623 
   3624   FORGET_Frame();
   3625 
   3626   cpf3->Coverage = NULL;
   3627 
   3628   count = cpf3->GlyphCount;
   3629 
   3630   if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
   3631     return error;
   3632 
   3633   c = cpf3->Coverage;
   3634 
   3635   for ( n = 0; n < count; n++ )
   3636   {
   3637     if ( ACCESS_Frame( 2L ) )
   3638       goto Fail2;
   3639 
   3640     new_offset = GET_UShort() + base_offset;
   3641 
   3642     FORGET_Frame();
   3643 
   3644     cur_offset = FILE_Pos();
   3645     if ( FILE_Seek( new_offset ) ||
   3646 	 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
   3647       goto Fail2;
   3648     (void)FILE_Seek( cur_offset );
   3649   }
   3650 
   3651   cpf3->PosLookupRecord = NULL;
   3652 
   3653   count = cpf3->PosCount;
   3654 
   3655   if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
   3656     goto Fail2;
   3657 
   3658   plr = cpf3->PosLookupRecord;
   3659 
   3660   if ( ACCESS_Frame( count * 4L ) )
   3661     goto Fail1;
   3662 
   3663   for ( n = 0; n < count; n++ )
   3664   {
   3665     plr[n].SequenceIndex   = GET_UShort();
   3666     plr[n].LookupListIndex = GET_UShort();
   3667   }
   3668 
   3669   FORGET_Frame();
   3670 
   3671   return HB_Err_Ok;
   3672 
   3673 Fail1:
   3674   FREE( plr );
   3675 
   3676 Fail2:
   3677   for ( n = 0; n < count; n++ )
   3678     _HB_OPEN_Free_Coverage( &c[n] );
   3679 
   3680   FREE( c );
   3681   return error;
   3682 }
   3683 
   3684 
   3685 static void  Free_ContextPos3( HB_ContextPosFormat3*  cpf3 )
   3686 {
   3687   HB_UShort      n, count;
   3688 
   3689   HB_Coverage*  c;
   3690 
   3691 
   3692   FREE( cpf3->PosLookupRecord );
   3693 
   3694   if ( cpf3->Coverage )
   3695   {
   3696     count = cpf3->GlyphCount;
   3697     c     = cpf3->Coverage;
   3698 
   3699     for ( n = 0; n < count; n++ )
   3700       _HB_OPEN_Free_Coverage( &c[n] );
   3701 
   3702     FREE( c );
   3703   }
   3704 }
   3705 
   3706 
   3707 /* ContextPos */
   3708 
   3709 static HB_Error  Load_ContextPos( HB_GPOS_SubTable* st,
   3710 				  HB_Stream        stream )
   3711 {
   3712   HB_Error  error;
   3713   HB_ContextPos*   cp = &st->context;
   3714 
   3715 
   3716   if ( ACCESS_Frame( 2L ) )
   3717     return error;
   3718 
   3719   cp->PosFormat = GET_UShort();
   3720 
   3721   FORGET_Frame();
   3722 
   3723   switch ( cp->PosFormat )
   3724   {
   3725   case 1:
   3726     return Load_ContextPos1( &cp->cpf.cpf1, stream );
   3727 
   3728   case 2:
   3729     return Load_ContextPos2( &cp->cpf.cpf2, stream );
   3730 
   3731   case 3:
   3732     return Load_ContextPos3( &cp->cpf.cpf3, stream );
   3733 
   3734   default:
   3735     return ERR(HB_Err_Invalid_SubTable_Format);
   3736   }
   3737 
   3738   return HB_Err_Ok;               /* never reached */
   3739 }
   3740 
   3741 
   3742 static void  Free_ContextPos( HB_GPOS_SubTable* st )
   3743 {
   3744   HB_ContextPos*   cp = &st->context;
   3745 
   3746   switch ( cp->PosFormat )
   3747   {
   3748   case 1:  Free_ContextPos1( &cp->cpf.cpf1 ); break;
   3749   case 2:  Free_ContextPos2( &cp->cpf.cpf2 ); break;
   3750   case 3:  Free_ContextPos3( &cp->cpf.cpf3 ); break;
   3751   default:					      break;
   3752   }
   3753 }
   3754 
   3755 
   3756 static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
   3757 				     HB_ContextPosFormat1*  cpf1,
   3758 				     HB_Buffer              buffer,
   3759 				     HB_UShort               flags,
   3760 				     HB_UShort               context_length,
   3761 				     int                     nesting_level )
   3762 {
   3763   HB_UShort        index, property;
   3764   HB_UShort        i, j, k, numpr;
   3765   HB_Error         error;
   3766   HB_GPOSHeader*  gpos = gpi->gpos;
   3767 
   3768   HB_PosRule*     pr;
   3769   HB_GDEFHeader*  gdef;
   3770 
   3771 
   3772   gdef = gpos->gdef;
   3773 
   3774   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3775     return error;
   3776 
   3777   error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
   3778   if ( error )
   3779     return error;
   3780 
   3781   pr    = cpf1->PosRuleSet[index].PosRule;
   3782   numpr = cpf1->PosRuleSet[index].PosRuleCount;
   3783 
   3784   for ( k = 0; k < numpr; k++ )
   3785   {
   3786     if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
   3787       goto next_posrule;
   3788 
   3789     if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
   3790       goto next_posrule;                       /* context is too long */
   3791 
   3792     for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
   3793     {
   3794       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3795       {
   3796 	if ( error && error != HB_Err_Not_Covered )
   3797 	  return error;
   3798 
   3799 	if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
   3800 	  goto next_posrule;
   3801 	j++;
   3802       }
   3803 
   3804       if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
   3805 	goto next_posrule;
   3806     }
   3807 
   3808     return Do_ContextPos( gpi, pr[k].GlyphCount,
   3809 			  pr[k].PosCount, pr[k].PosLookupRecord,
   3810 			  buffer,
   3811 			  nesting_level );
   3812 
   3813     next_posrule:
   3814       ;
   3815   }
   3816 
   3817   return HB_Err_Not_Covered;
   3818 }
   3819 
   3820 
   3821 static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
   3822 				     HB_ContextPosFormat2*  cpf2,
   3823 				     HB_Buffer              buffer,
   3824 				     HB_UShort               flags,
   3825 				     HB_UShort               context_length,
   3826 				     int                     nesting_level )
   3827 {
   3828   HB_UShort          index, property;
   3829   HB_Error           error;
   3830   HB_UShort          i, j, k, known_classes;
   3831 
   3832   HB_UShort*         classes;
   3833   HB_UShort*         cl;
   3834   HB_GPOSHeader*    gpos = gpi->gpos;
   3835 
   3836   HB_PosClassSet*   pcs;
   3837   HB_PosClassRule*  pr;
   3838   HB_GDEFHeader*    gdef;
   3839 
   3840 
   3841   gdef = gpos->gdef;
   3842 
   3843   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3844     return error;
   3845 
   3846   /* Note: The coverage table in format 2 doesn't give an index into
   3847 	   anything.  It just lets us know whether or not we need to
   3848 	   do any lookup at all.                                     */
   3849 
   3850   error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
   3851   if ( error )
   3852     return error;
   3853 
   3854   if (cpf2->MaxContextLength < 1)
   3855     return HB_Err_Not_Covered;
   3856 
   3857   if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
   3858     return error;
   3859 
   3860   error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
   3861 		     &classes[0], NULL );
   3862   if ( error && error != HB_Err_Not_Covered )
   3863     goto End;
   3864   known_classes = 0;
   3865 
   3866   pcs = &cpf2->PosClassSet[classes[0]];
   3867   if ( !pcs )
   3868   {
   3869     error = ERR(HB_Err_Invalid_SubTable);
   3870     goto End;
   3871   }
   3872 
   3873   for ( k = 0; k < pcs->PosClassRuleCount; k++ )
   3874   {
   3875     pr = &pcs->PosClassRule[k];
   3876 
   3877     if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
   3878       goto next_posclassrule;
   3879 
   3880     if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
   3881       goto next_posclassrule;                /* context is too long */
   3882 
   3883     cl   = pr->Class;
   3884 
   3885     /* Start at 1 because [0] is implied */
   3886 
   3887     for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
   3888     {
   3889       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3890       {
   3891 	if ( error && error != HB_Err_Not_Covered )
   3892 	  goto End;
   3893 
   3894 	if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
   3895 	  goto next_posclassrule;
   3896 	j++;
   3897       }
   3898 
   3899       if ( i > known_classes )
   3900       {
   3901 	/* Keeps us from having to do this for each rule */
   3902 
   3903 	error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
   3904 	if ( error && error != HB_Err_Not_Covered )
   3905 	  goto End;
   3906 	known_classes = i;
   3907       }
   3908 
   3909       if ( cl[i - 1] != classes[i] )
   3910 	goto next_posclassrule;
   3911     }
   3912 
   3913     error = Do_ContextPos( gpi, pr->GlyphCount,
   3914 			   pr->PosCount, pr->PosLookupRecord,
   3915 			   buffer,
   3916 			   nesting_level );
   3917     goto End;
   3918 
   3919   next_posclassrule:
   3920     ;
   3921   }
   3922 
   3923   error = HB_Err_Not_Covered;
   3924 
   3925 End:
   3926   FREE( classes );
   3927   return error;
   3928 }
   3929 
   3930 
   3931 static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
   3932 				     HB_ContextPosFormat3*  cpf3,
   3933 				     HB_Buffer              buffer,
   3934 				     HB_UShort               flags,
   3935 				     HB_UShort               context_length,
   3936 				     int                     nesting_level )
   3937 {
   3938   HB_Error         error;
   3939   HB_UShort        index, i, j, property;
   3940   HB_GPOSHeader*  gpos = gpi->gpos;
   3941 
   3942   HB_Coverage*    c;
   3943   HB_GDEFHeader*  gdef;
   3944 
   3945 
   3946   gdef = gpos->gdef;
   3947 
   3948   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3949     return error;
   3950 
   3951   if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
   3952     return HB_Err_Not_Covered;
   3953 
   3954   if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
   3955     return HB_Err_Not_Covered;         /* context is too long */
   3956 
   3957   c    = cpf3->Coverage;
   3958 
   3959   for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
   3960   {
   3961     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3962     {
   3963       if ( error && error != HB_Err_Not_Covered )
   3964 	return error;
   3965 
   3966       if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
   3967 	return HB_Err_Not_Covered;
   3968       j++;
   3969     }
   3970 
   3971     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
   3972     if ( error )
   3973       return error;
   3974   }
   3975 
   3976   return Do_ContextPos( gpi, cpf3->GlyphCount,
   3977 			cpf3->PosCount, cpf3->PosLookupRecord,
   3978 			buffer,
   3979 			nesting_level );
   3980 }
   3981 
   3982 
   3983 static HB_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
   3984 				    HB_GPOS_SubTable* st,
   3985 				    HB_Buffer        buffer,
   3986 				    HB_UShort         flags,
   3987 				    HB_UShort         context_length,
   3988 				    int               nesting_level )
   3989 {
   3990   HB_ContextPos*   cp = &st->context;
   3991 
   3992   switch ( cp->PosFormat )
   3993   {
   3994   case 1:
   3995     return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
   3996 			       flags, context_length, nesting_level );
   3997 
   3998   case 2:
   3999     return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
   4000 			       flags, context_length, nesting_level );
   4001 
   4002   case 3:
   4003     return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
   4004 			       flags, context_length, nesting_level );
   4005 
   4006   default:
   4007     return ERR(HB_Err_Invalid_SubTable_Format);
   4008   }
   4009 
   4010   return HB_Err_Ok;               /* never reached */
   4011 }
   4012 
   4013 
   4014 /* LookupType 8 */
   4015 
   4016 /* ChainPosRule */
   4017 
   4018 static HB_Error  Load_ChainPosRule( HB_ChainPosRule*  cpr,
   4019 				    HB_Stream          stream )
   4020 {
   4021   HB_Error  error;
   4022 
   4023   HB_UShort             n, count;
   4024   HB_UShort*            b;
   4025   HB_UShort*            i;
   4026   HB_UShort*            l;
   4027 
   4028   HB_PosLookupRecord*  plr;
   4029 
   4030 
   4031   if ( ACCESS_Frame( 2L ) )
   4032     return error;
   4033 
   4034   cpr->BacktrackGlyphCount = GET_UShort();
   4035 
   4036   FORGET_Frame();
   4037 
   4038   cpr->Backtrack = NULL;
   4039 
   4040   count = cpr->BacktrackGlyphCount;
   4041 
   4042   if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
   4043     return error;
   4044 
   4045   b = cpr->Backtrack;
   4046 
   4047   if ( ACCESS_Frame( count * 2L ) )
   4048     goto Fail4;
   4049 
   4050   for ( n = 0; n < count; n++ )
   4051     b[n] = GET_UShort();
   4052 
   4053   FORGET_Frame();
   4054 
   4055   if ( ACCESS_Frame( 2L ) )
   4056     goto Fail4;
   4057 
   4058   cpr->InputGlyphCount = GET_UShort();
   4059 
   4060   FORGET_Frame();
   4061 
   4062   cpr->Input = NULL;
   4063 
   4064   count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
   4065 
   4066   if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
   4067     goto Fail4;
   4068 
   4069   i = cpr->Input;
   4070 
   4071   if ( ACCESS_Frame( count * 2L ) )
   4072     goto Fail3;
   4073 
   4074   for ( n = 0; n < count; n++ )
   4075     i[n] = GET_UShort();
   4076 
   4077   FORGET_Frame();
   4078 
   4079   if ( ACCESS_Frame( 2L ) )
   4080     goto Fail3;
   4081 
   4082   cpr->LookaheadGlyphCount = GET_UShort();
   4083 
   4084   FORGET_Frame();
   4085 
   4086   cpr->Lookahead = NULL;
   4087 
   4088   count = cpr->LookaheadGlyphCount;
   4089 
   4090   if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
   4091     goto Fail3;
   4092 
   4093   l = cpr->Lookahead;
   4094 
   4095   if ( ACCESS_Frame( count * 2L ) )
   4096     goto Fail2;
   4097 
   4098   for ( n = 0; n < count; n++ )
   4099     l[n] = GET_UShort();
   4100 
   4101   FORGET_Frame();
   4102 
   4103   if ( ACCESS_Frame( 2L ) )
   4104     goto Fail2;
   4105 
   4106   cpr->PosCount = GET_UShort();
   4107 
   4108   FORGET_Frame();
   4109 
   4110   cpr->PosLookupRecord = NULL;
   4111 
   4112   count = cpr->PosCount;
   4113 
   4114   if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
   4115     goto Fail2;
   4116 
   4117   plr = cpr->PosLookupRecord;
   4118 
   4119   if ( ACCESS_Frame( count * 4L ) )
   4120     goto Fail1;
   4121 
   4122   for ( n = 0; n < count; n++ )
   4123   {
   4124     plr[n].SequenceIndex   = GET_UShort();
   4125     plr[n].LookupListIndex = GET_UShort();
   4126   }
   4127 
   4128   FORGET_Frame();
   4129 
   4130   return HB_Err_Ok;
   4131 
   4132 Fail1:
   4133   FREE( plr );
   4134 
   4135 Fail2:
   4136   FREE( l );
   4137 
   4138 Fail3:
   4139   FREE( i );
   4140 
   4141 Fail4:
   4142   FREE( b );
   4143   return error;
   4144 }
   4145 
   4146 
   4147 static void  Free_ChainPosRule( HB_ChainPosRule*  cpr )
   4148 {
   4149   FREE( cpr->PosLookupRecord );
   4150   FREE( cpr->Lookahead );
   4151   FREE( cpr->Input );
   4152   FREE( cpr->Backtrack );
   4153 }
   4154 
   4155 
   4156 /* ChainPosRuleSet */
   4157 
   4158 static HB_Error  Load_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
   4159 				       HB_Stream             stream )
   4160 {
   4161   HB_Error  error;
   4162 
   4163   HB_UShort          n, m, count;
   4164   HB_UInt           cur_offset, new_offset, base_offset;
   4165 
   4166   HB_ChainPosRule*  cpr;
   4167 
   4168 
   4169   base_offset = FILE_Pos();
   4170 
   4171   if ( ACCESS_Frame( 2L ) )
   4172     return error;
   4173 
   4174   count = cprs->ChainPosRuleCount = GET_UShort();
   4175 
   4176   FORGET_Frame();
   4177 
   4178   cprs->ChainPosRule = NULL;
   4179 
   4180   if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
   4181     return error;
   4182 
   4183   cpr = cprs->ChainPosRule;
   4184 
   4185   for ( n = 0; n < count; n++ )
   4186   {
   4187     if ( ACCESS_Frame( 2L ) )
   4188       goto Fail;
   4189 
   4190     new_offset = GET_UShort() + base_offset;
   4191 
   4192     FORGET_Frame();
   4193 
   4194     cur_offset = FILE_Pos();
   4195     if ( FILE_Seek( new_offset ) ||
   4196 	 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
   4197       goto Fail;
   4198     (void)FILE_Seek( cur_offset );
   4199   }
   4200 
   4201   return HB_Err_Ok;
   4202 
   4203 Fail:
   4204   for ( m = 0; m < n; m++ )
   4205     Free_ChainPosRule( &cpr[m] );
   4206 
   4207   FREE( cpr );
   4208   return error;
   4209 }
   4210 
   4211 
   4212 static void  Free_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs )
   4213 {
   4214   HB_UShort          n, count;
   4215 
   4216   HB_ChainPosRule*  cpr;
   4217 
   4218 
   4219   if ( cprs->ChainPosRule )
   4220   {
   4221     count = cprs->ChainPosRuleCount;
   4222     cpr   = cprs->ChainPosRule;
   4223 
   4224     for ( n = 0; n < count; n++ )
   4225       Free_ChainPosRule( &cpr[n] );
   4226 
   4227     FREE( cpr );
   4228   }
   4229 }
   4230 
   4231 
   4232 /* ChainContextPosFormat1 */
   4233 
   4234 static HB_Error  Load_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
   4235 					HB_Stream                    stream )
   4236 {
   4237   HB_Error  error;
   4238 
   4239   HB_UShort             n, m, count;
   4240   HB_UInt              cur_offset, new_offset, base_offset;
   4241 
   4242   HB_ChainPosRuleSet*  cprs;
   4243 
   4244 
   4245   base_offset = FILE_Pos() - 2L;
   4246 
   4247   if ( ACCESS_Frame( 2L ) )
   4248     return error;
   4249 
   4250   new_offset = GET_UShort() + base_offset;
   4251 
   4252   FORGET_Frame();
   4253 
   4254   cur_offset = FILE_Pos();
   4255   if ( FILE_Seek( new_offset ) ||
   4256        ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
   4257     return error;
   4258   (void)FILE_Seek( cur_offset );
   4259 
   4260   if ( ACCESS_Frame( 2L ) )
   4261     goto Fail2;
   4262 
   4263   count = ccpf1->ChainPosRuleSetCount = GET_UShort();
   4264 
   4265   FORGET_Frame();
   4266 
   4267   ccpf1->ChainPosRuleSet = NULL;
   4268 
   4269   if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
   4270     goto Fail2;
   4271 
   4272   cprs = ccpf1->ChainPosRuleSet;
   4273 
   4274   for ( n = 0; n < count; n++ )
   4275   {
   4276     if ( ACCESS_Frame( 2L ) )
   4277       goto Fail1;
   4278 
   4279     new_offset = GET_UShort() + base_offset;
   4280 
   4281     FORGET_Frame();
   4282 
   4283     cur_offset = FILE_Pos();
   4284     if ( FILE_Seek( new_offset ) ||
   4285 	 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
   4286       goto Fail1;
   4287     (void)FILE_Seek( cur_offset );
   4288   }
   4289 
   4290   return HB_Err_Ok;
   4291 
   4292 Fail1:
   4293   for ( m = 0; m < n; m++ )
   4294     Free_ChainPosRuleSet( &cprs[m] );
   4295 
   4296   FREE( cprs );
   4297 
   4298 Fail2:
   4299   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
   4300   return error;
   4301 }
   4302 
   4303 
   4304 static void  Free_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1 )
   4305 {
   4306   HB_UShort             n, count;
   4307 
   4308   HB_ChainPosRuleSet*  cprs;
   4309 
   4310 
   4311   if ( ccpf1->ChainPosRuleSet )
   4312   {
   4313     count = ccpf1->ChainPosRuleSetCount;
   4314     cprs  = ccpf1->ChainPosRuleSet;
   4315 
   4316     for ( n = 0; n < count; n++ )
   4317       Free_ChainPosRuleSet( &cprs[n] );
   4318 
   4319     FREE( cprs );
   4320   }
   4321 
   4322   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
   4323 }
   4324 
   4325 
   4326 /* ChainPosClassRule */
   4327 
   4328 static HB_Error  Load_ChainPosClassRule(
   4329 		   HB_ChainContextPosFormat2*  ccpf2,
   4330 		   HB_ChainPosClassRule*       cpcr,
   4331 		   HB_Stream                    stream )
   4332 {
   4333   HB_Error  error;
   4334 
   4335   HB_UShort             n, count;
   4336 
   4337   HB_UShort*            b;
   4338   HB_UShort*            i;
   4339   HB_UShort*            l;
   4340   HB_PosLookupRecord*  plr;
   4341 
   4342 
   4343   if ( ACCESS_Frame( 2L ) )
   4344     return error;
   4345 
   4346   cpcr->BacktrackGlyphCount = GET_UShort();
   4347 
   4348   FORGET_Frame();
   4349 
   4350   if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
   4351     ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
   4352 
   4353   cpcr->Backtrack = NULL;
   4354 
   4355   count = cpcr->BacktrackGlyphCount;
   4356 
   4357   if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
   4358     return error;
   4359 
   4360   b = cpcr->Backtrack;
   4361 
   4362   if ( ACCESS_Frame( count * 2L ) )
   4363     goto Fail4;
   4364 
   4365   for ( n = 0; n < count; n++ )
   4366     b[n] = GET_UShort();
   4367 
   4368   FORGET_Frame();
   4369 
   4370   if ( ACCESS_Frame( 2L ) )
   4371     goto Fail4;
   4372 
   4373   cpcr->InputGlyphCount = GET_UShort();
   4374 
   4375   if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
   4376     ccpf2->MaxInputLength = cpcr->InputGlyphCount;
   4377 
   4378   FORGET_Frame();
   4379 
   4380   cpcr->Input = NULL;
   4381 
   4382   count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
   4383 
   4384   if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
   4385     goto Fail4;
   4386 
   4387   i = cpcr->Input;
   4388 
   4389   if ( ACCESS_Frame( count * 2L ) )
   4390     goto Fail3;
   4391 
   4392   for ( n = 0; n < count; n++ )
   4393     i[n] = GET_UShort();
   4394 
   4395   FORGET_Frame();
   4396 
   4397   if ( ACCESS_Frame( 2L ) )
   4398     goto Fail3;
   4399 
   4400   cpcr->LookaheadGlyphCount = GET_UShort();
   4401 
   4402   FORGET_Frame();
   4403 
   4404   if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
   4405     ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
   4406 
   4407   cpcr->Lookahead = NULL;
   4408 
   4409   count = cpcr->LookaheadGlyphCount;
   4410 
   4411   if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
   4412     goto Fail3;
   4413 
   4414   l = cpcr->Lookahead;
   4415 
   4416   if ( ACCESS_Frame( count * 2L ) )
   4417     goto Fail2;
   4418 
   4419   for ( n = 0; n < count; n++ )
   4420     l[n] = GET_UShort();
   4421 
   4422   FORGET_Frame();
   4423 
   4424   if ( ACCESS_Frame( 2L ) )
   4425     goto Fail2;
   4426 
   4427   cpcr->PosCount = GET_UShort();
   4428 
   4429   FORGET_Frame();
   4430 
   4431   cpcr->PosLookupRecord = NULL;
   4432 
   4433   count = cpcr->PosCount;
   4434 
   4435   if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
   4436     goto Fail2;
   4437 
   4438   plr = cpcr->PosLookupRecord;
   4439 
   4440   if ( ACCESS_Frame( count * 4L ) )
   4441     goto Fail1;
   4442 
   4443   for ( n = 0; n < count; n++ )
   4444   {
   4445     plr[n].SequenceIndex   = GET_UShort();
   4446     plr[n].LookupListIndex = GET_UShort();
   4447   }
   4448 
   4449   FORGET_Frame();
   4450 
   4451   return HB_Err_Ok;
   4452 
   4453 Fail1:
   4454   FREE( plr );
   4455 
   4456 Fail2:
   4457   FREE( l );
   4458 
   4459 Fail3:
   4460   FREE( i );
   4461 
   4462 Fail4:
   4463   FREE( b );
   4464   return error;
   4465 }
   4466 
   4467 
   4468 static void  Free_ChainPosClassRule( HB_ChainPosClassRule*  cpcr )
   4469 {
   4470   FREE( cpcr->PosLookupRecord );
   4471   FREE( cpcr->Lookahead );
   4472   FREE( cpcr->Input );
   4473   FREE( cpcr->Backtrack );
   4474 }
   4475 
   4476 
   4477 /* PosClassSet */
   4478 
   4479 static HB_Error  Load_ChainPosClassSet(
   4480 		   HB_ChainContextPosFormat2*  ccpf2,
   4481 		   HB_ChainPosClassSet*        cpcs,
   4482 		   HB_Stream                    stream )
   4483 {
   4484   HB_Error  error;
   4485 
   4486   HB_UShort               n, m, count;
   4487   HB_UInt                cur_offset, new_offset, base_offset;
   4488 
   4489   HB_ChainPosClassRule*  cpcr;
   4490 
   4491 
   4492   base_offset = FILE_Pos();
   4493 
   4494   if ( ACCESS_Frame( 2L ) )
   4495     return error;
   4496 
   4497   count = cpcs->ChainPosClassRuleCount = GET_UShort();
   4498 
   4499   FORGET_Frame();
   4500 
   4501   cpcs->ChainPosClassRule = NULL;
   4502 
   4503   if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
   4504 		    HB_ChainPosClassRule ) )
   4505     return error;
   4506 
   4507   cpcr = cpcs->ChainPosClassRule;
   4508 
   4509   for ( n = 0; n < count; n++ )
   4510   {
   4511     if ( ACCESS_Frame( 2L ) )
   4512       goto Fail;
   4513 
   4514     new_offset = GET_UShort() + base_offset;
   4515 
   4516     FORGET_Frame();
   4517 
   4518     cur_offset = FILE_Pos();
   4519     if ( FILE_Seek( new_offset ) ||
   4520 	 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
   4521 					   stream ) ) != HB_Err_Ok )
   4522       goto Fail;
   4523     (void)FILE_Seek( cur_offset );
   4524   }
   4525 
   4526   return HB_Err_Ok;
   4527 
   4528 Fail:
   4529   for ( m = 0; m < n; m++ )
   4530     Free_ChainPosClassRule( &cpcr[m] );
   4531 
   4532   FREE( cpcr );
   4533   return error;
   4534 }
   4535 
   4536 
   4537 static void  Free_ChainPosClassSet( HB_ChainPosClassSet*  cpcs )
   4538 {
   4539   HB_UShort               n, count;
   4540 
   4541   HB_ChainPosClassRule*  cpcr;
   4542 
   4543 
   4544   if ( cpcs->ChainPosClassRule )
   4545   {
   4546     count = cpcs->ChainPosClassRuleCount;
   4547     cpcr  = cpcs->ChainPosClassRule;
   4548 
   4549     for ( n = 0; n < count; n++ )
   4550       Free_ChainPosClassRule( &cpcr[n] );
   4551 
   4552     FREE( cpcr );
   4553   }
   4554 }
   4555 
   4556 
   4557 /* ChainContextPosFormat2 */
   4558 
   4559 static HB_Error  Load_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
   4560 					HB_Stream                    stream )
   4561 {
   4562   HB_Error  error;
   4563 
   4564   HB_UShort              n, m, count;
   4565   HB_UInt               cur_offset, new_offset, base_offset;
   4566   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
   4567 
   4568   HB_ChainPosClassSet*  cpcs;
   4569 
   4570 
   4571   base_offset = FILE_Pos() - 2;
   4572 
   4573   if ( ACCESS_Frame( 2L ) )
   4574     return error;
   4575 
   4576   new_offset = GET_UShort() + base_offset;
   4577 
   4578   FORGET_Frame();
   4579 
   4580   cur_offset = FILE_Pos();
   4581   if ( FILE_Seek( new_offset ) ||
   4582        ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
   4583     return error;
   4584   (void)FILE_Seek( cur_offset );
   4585 
   4586   if ( ACCESS_Frame( 8L ) )
   4587     goto Fail5;
   4588 
   4589   backtrack_offset = GET_UShort();
   4590   input_offset     = GET_UShort();
   4591   lookahead_offset = GET_UShort();
   4592 
   4593   /* `ChainPosClassSetCount' is the upper limit for input class values,
   4594      thus we read it now to make an additional safety check. No limit
   4595      is known or needed for the other two class definitions          */
   4596 
   4597   count = ccpf2->ChainPosClassSetCount = GET_UShort();
   4598 
   4599   FORGET_Frame();
   4600 
   4601   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
   4602 						       backtrack_offset, base_offset,
   4603 						       stream ) ) != HB_Err_Ok )
   4604     goto Fail5;
   4605   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
   4606 						       input_offset, base_offset,
   4607 						       stream ) ) != HB_Err_Ok )
   4608     goto Fail4;
   4609   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
   4610 						       lookahead_offset, base_offset,
   4611 						       stream ) ) != HB_Err_Ok )
   4612     goto Fail3;
   4613 
   4614   ccpf2->ChainPosClassSet   = NULL;
   4615   ccpf2->MaxBacktrackLength = 0;
   4616   ccpf2->MaxInputLength     = 0;
   4617   ccpf2->MaxLookaheadLength = 0;
   4618 
   4619   if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
   4620     goto Fail2;
   4621 
   4622   cpcs = ccpf2->ChainPosClassSet;
   4623 
   4624   for ( n = 0; n < count; n++ )
   4625   {
   4626     if ( ACCESS_Frame( 2L ) )
   4627       goto Fail1;
   4628 
   4629     new_offset = GET_UShort() + base_offset;
   4630 
   4631     FORGET_Frame();
   4632 
   4633     if ( new_offset != base_offset )      /* not a NULL offset */
   4634     {
   4635       cur_offset = FILE_Pos();
   4636       if ( FILE_Seek( new_offset ) ||
   4637 	   ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
   4638 					    stream ) ) != HB_Err_Ok )
   4639 	goto Fail1;
   4640       (void)FILE_Seek( cur_offset );
   4641     }
   4642     else
   4643     {
   4644       /* we create a ChainPosClassSet table with no entries */
   4645 
   4646       ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
   4647       ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
   4648     }
   4649   }
   4650 
   4651   return HB_Err_Ok;
   4652 
   4653 Fail1:
   4654   for ( m = 0; m < n; m++ )
   4655     Free_ChainPosClassSet( &cpcs[m] );
   4656 
   4657   FREE( cpcs );
   4658 
   4659 Fail2:
   4660   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
   4661 
   4662 Fail3:
   4663   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
   4664 
   4665 Fail4:
   4666   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
   4667 
   4668 Fail5:
   4669   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
   4670   return error;
   4671 }
   4672 
   4673 
   4674 static void  Free_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2 )
   4675 {
   4676   HB_UShort              n, count;
   4677 
   4678   HB_ChainPosClassSet*  cpcs;
   4679 
   4680 
   4681   if ( ccpf2->ChainPosClassSet )
   4682   {
   4683     count = ccpf2->ChainPosClassSetCount;
   4684     cpcs  = ccpf2->ChainPosClassSet;
   4685 
   4686     for ( n = 0; n < count; n++ )
   4687       Free_ChainPosClassSet( &cpcs[n] );
   4688 
   4689     FREE( cpcs );
   4690   }
   4691 
   4692   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
   4693   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
   4694   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
   4695 
   4696   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
   4697 }
   4698 
   4699 
   4700 /* ChainContextPosFormat3 */
   4701 
   4702 static HB_Error  Load_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
   4703 					HB_Stream                    stream )
   4704 {
   4705   HB_Error  error;
   4706 
   4707   HB_UShort             n, nb, ni, nl, m, count;
   4708   HB_UShort             backtrack_count, input_count, lookahead_count;
   4709   HB_UInt              cur_offset, new_offset, base_offset;
   4710 
   4711   HB_Coverage*         b;
   4712   HB_Coverage*         i;
   4713   HB_Coverage*         l;
   4714   HB_PosLookupRecord*  plr;
   4715 
   4716 
   4717   base_offset = FILE_Pos() - 2L;
   4718 
   4719   if ( ACCESS_Frame( 2L ) )
   4720     return error;
   4721 
   4722   ccpf3->BacktrackGlyphCount = GET_UShort();
   4723 
   4724   FORGET_Frame();
   4725 
   4726   ccpf3->BacktrackCoverage = NULL;
   4727 
   4728   backtrack_count = ccpf3->BacktrackGlyphCount;
   4729 
   4730   if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
   4731 		    HB_Coverage ) )
   4732     return error;
   4733 
   4734   b = ccpf3->BacktrackCoverage;
   4735 
   4736   for ( nb = 0; nb < backtrack_count; nb++ )
   4737   {
   4738     if ( ACCESS_Frame( 2L ) )
   4739       goto Fail4;
   4740 
   4741     new_offset = GET_UShort() + base_offset;
   4742 
   4743     FORGET_Frame();
   4744 
   4745     cur_offset = FILE_Pos();
   4746     if ( FILE_Seek( new_offset ) ||
   4747 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
   4748       goto Fail4;
   4749     (void)FILE_Seek( cur_offset );
   4750   }
   4751 
   4752   if ( ACCESS_Frame( 2L ) )
   4753     goto Fail4;
   4754 
   4755   ccpf3->InputGlyphCount = GET_UShort();
   4756 
   4757   FORGET_Frame();
   4758 
   4759   ccpf3->InputCoverage = NULL;
   4760 
   4761   input_count = ccpf3->InputGlyphCount;
   4762 
   4763   if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
   4764     goto Fail4;
   4765 
   4766   i = ccpf3->InputCoverage;
   4767 
   4768   for ( ni = 0; ni < input_count; ni++ )
   4769   {
   4770     if ( ACCESS_Frame( 2L ) )
   4771       goto Fail3;
   4772 
   4773     new_offset = GET_UShort() + base_offset;
   4774 
   4775     FORGET_Frame();
   4776 
   4777     cur_offset = FILE_Pos();
   4778     if ( FILE_Seek( new_offset ) ||
   4779 	 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
   4780       goto Fail3;
   4781     (void)FILE_Seek( cur_offset );
   4782   }
   4783 
   4784   if ( ACCESS_Frame( 2L ) )
   4785     goto Fail3;
   4786 
   4787   ccpf3->LookaheadGlyphCount = GET_UShort();
   4788 
   4789   FORGET_Frame();
   4790 
   4791   ccpf3->LookaheadCoverage = NULL;
   4792 
   4793   lookahead_count = ccpf3->LookaheadGlyphCount;
   4794 
   4795   if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
   4796 		    HB_Coverage ) )
   4797     goto Fail3;
   4798 
   4799   l = ccpf3->LookaheadCoverage;
   4800 
   4801   for ( nl = 0; nl < lookahead_count; nl++ )
   4802   {
   4803     if ( ACCESS_Frame( 2L ) )
   4804       goto Fail2;
   4805 
   4806     new_offset = GET_UShort() + base_offset;
   4807 
   4808     FORGET_Frame();
   4809 
   4810     cur_offset = FILE_Pos();
   4811     if ( FILE_Seek( new_offset ) ||
   4812 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
   4813       goto Fail2;
   4814     (void)FILE_Seek( cur_offset );
   4815   }
   4816 
   4817   if ( ACCESS_Frame( 2L ) )
   4818     goto Fail2;
   4819 
   4820   ccpf3->PosCount = GET_UShort();
   4821 
   4822   FORGET_Frame();
   4823 
   4824   ccpf3->PosLookupRecord = NULL;
   4825 
   4826   count = ccpf3->PosCount;
   4827 
   4828   if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
   4829     goto Fail2;
   4830 
   4831   plr = ccpf3->PosLookupRecord;
   4832 
   4833   if ( ACCESS_Frame( count * 4L ) )
   4834     goto Fail1;
   4835 
   4836   for ( n = 0; n < count; n++ )
   4837   {
   4838     plr[n].SequenceIndex   = GET_UShort();
   4839     plr[n].LookupListIndex = GET_UShort();
   4840   }
   4841 
   4842   FORGET_Frame();
   4843 
   4844   return HB_Err_Ok;
   4845 
   4846 Fail1:
   4847   FREE( plr );
   4848 
   4849 Fail2:
   4850   for ( m = 0; m < nl; m++ )
   4851     _HB_OPEN_Free_Coverage( &l[m] );
   4852 
   4853   FREE( l );
   4854 
   4855 Fail3:
   4856   for ( m = 0; m < ni; m++ )
   4857     _HB_OPEN_Free_Coverage( &i[m] );
   4858 
   4859   FREE( i );
   4860 
   4861 Fail4:
   4862   for ( m = 0; m < nb; m++ )
   4863     _HB_OPEN_Free_Coverage( &b[m] );
   4864 
   4865   FREE( b );
   4866   return error;
   4867 }
   4868 
   4869 
   4870 static void  Free_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3 )
   4871 {
   4872   HB_UShort      n, count;
   4873 
   4874   HB_Coverage*  c;
   4875 
   4876 
   4877   FREE( ccpf3->PosLookupRecord );
   4878 
   4879   if ( ccpf3->LookaheadCoverage )
   4880   {
   4881     count = ccpf3->LookaheadGlyphCount;
   4882     c     = ccpf3->LookaheadCoverage;
   4883 
   4884     for ( n = 0; n < count; n++ )
   4885       _HB_OPEN_Free_Coverage( &c[n] );
   4886 
   4887     FREE( c );
   4888   }
   4889 
   4890   if ( ccpf3->InputCoverage )
   4891   {
   4892     count = ccpf3->InputGlyphCount;
   4893     c     = ccpf3->InputCoverage;
   4894 
   4895     for ( n = 0; n < count; n++ )
   4896       _HB_OPEN_Free_Coverage( &c[n] );
   4897 
   4898     FREE( c );
   4899   }
   4900 
   4901   if ( ccpf3->BacktrackCoverage )
   4902   {
   4903     count = ccpf3->BacktrackGlyphCount;
   4904     c     = ccpf3->BacktrackCoverage;
   4905 
   4906     for ( n = 0; n < count; n++ )
   4907       _HB_OPEN_Free_Coverage( &c[n] );
   4908 
   4909     FREE( c );
   4910   }
   4911 }
   4912 
   4913 
   4914 /* ChainContextPos */
   4915 
   4916 static HB_Error  Load_ChainContextPos( HB_GPOS_SubTable* st,
   4917 				       HB_Stream             stream )
   4918 {
   4919   HB_Error  error;
   4920   HB_ChainContextPos*  ccp = &st->chain;
   4921 
   4922 
   4923   if ( ACCESS_Frame( 2L ) )
   4924     return error;
   4925 
   4926   ccp->PosFormat = GET_UShort();
   4927 
   4928   FORGET_Frame();
   4929 
   4930   switch ( ccp->PosFormat )
   4931   {
   4932   case 1:
   4933     return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
   4934 
   4935   case 2:
   4936     return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
   4937 
   4938   case 3:
   4939     return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
   4940 
   4941   default:
   4942     return ERR(HB_Err_Invalid_SubTable_Format);
   4943   }
   4944 
   4945   return HB_Err_Ok;               /* never reached */
   4946 }
   4947 
   4948 
   4949 static void  Free_ChainContextPos( HB_GPOS_SubTable* st )
   4950 {
   4951   HB_ChainContextPos*  ccp = &st->chain;
   4952 
   4953   switch ( ccp->PosFormat )
   4954   {
   4955   case 1:  Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
   4956   case 2:  Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
   4957   case 3:  Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
   4958   default:						      break;
   4959   }
   4960 }
   4961 
   4962 
   4963 static HB_Error  Lookup_ChainContextPos1(
   4964 		   GPOS_Instance*               gpi,
   4965 		   HB_ChainContextPosFormat1*  ccpf1,
   4966 		   HB_Buffer                   buffer,
   4967 		   HB_UShort                    flags,
   4968 		   HB_UShort                    context_length,
   4969 		   int                          nesting_level )
   4970 {
   4971   HB_UShort          index, property;
   4972   HB_UShort          i, j, k, num_cpr;
   4973   HB_UShort          bgc, igc, lgc;
   4974   HB_Error           error;
   4975   HB_GPOSHeader*    gpos = gpi->gpos;
   4976 
   4977   HB_ChainPosRule*  cpr;
   4978   HB_ChainPosRule   curr_cpr;
   4979   HB_GDEFHeader*    gdef;
   4980 
   4981 
   4982   gdef = gpos->gdef;
   4983 
   4984   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   4985     return error;
   4986 
   4987   error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
   4988   if ( error )
   4989     return error;
   4990 
   4991   cpr     = ccpf1->ChainPosRuleSet[index].ChainPosRule;
   4992   num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
   4993 
   4994   for ( k = 0; k < num_cpr; k++ )
   4995   {
   4996     curr_cpr = cpr[k];
   4997     bgc      = curr_cpr.BacktrackGlyphCount;
   4998     igc      = curr_cpr.InputGlyphCount;
   4999     lgc      = curr_cpr.LookaheadGlyphCount;
   5000 
   5001     if ( context_length != 0xFFFF && context_length < igc )
   5002       goto next_chainposrule;
   5003 
   5004     /* check whether context is too long; it is a first guess only */
   5005 
   5006     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   5007       goto next_chainposrule;
   5008 
   5009     if ( bgc )
   5010     {
   5011       /* Since we don't know in advance the number of glyphs to inspect,
   5012 	 we search backwards for matches in the backtrack glyph array    */
   5013 
   5014       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   5015       {
   5016 	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5017 	{
   5018 	  if ( error && error != HB_Err_Not_Covered )
   5019 	    return error;
   5020 
   5021 	  if ( j + 1 == bgc - i )
   5022 	    goto next_chainposrule;
   5023 	  j--;
   5024 	}
   5025 
   5026 	/* In OpenType 1.3, it is undefined whether the offsets of
   5027 	   backtrack glyphs is in logical order or not.  Version 1.4
   5028 	   will clarify this:
   5029 
   5030 	     Logical order -      a  b  c  d  e  f  g  h  i  j
   5031 					      i
   5032 	     Input offsets -                  0  1
   5033 	     Backtrack offsets -  3  2  1  0
   5034 	     Lookahead offsets -                    0  1  2  3           */
   5035 
   5036 	if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
   5037 	  goto next_chainposrule;
   5038       }
   5039     }
   5040 
   5041     /* Start at 1 because [0] is implied */
   5042 
   5043     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
   5044     {
   5045       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5046       {
   5047 	if ( error && error != HB_Err_Not_Covered )
   5048 	  return error;
   5049 
   5050 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   5051 	  goto next_chainposrule;
   5052 	j++;
   5053       }
   5054 
   5055       if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
   5056 	goto next_chainposrule;
   5057     }
   5058 
   5059     /* we are starting to check for lookahead glyphs right after the
   5060        last context glyph                                            */
   5061 
   5062     for ( i = 0; i < lgc; i++, j++ )
   5063     {
   5064       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5065       {
   5066 	if ( error && error != HB_Err_Not_Covered )
   5067 	  return error;
   5068 
   5069 	if ( j + lgc - i == (HB_Int)buffer->in_length )
   5070 	  goto next_chainposrule;
   5071 	j++;
   5072       }
   5073 
   5074       if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
   5075 	goto next_chainposrule;
   5076     }
   5077 
   5078     return Do_ContextPos( gpi, igc,
   5079 			  curr_cpr.PosCount,
   5080 			  curr_cpr.PosLookupRecord,
   5081 			  buffer,
   5082 			  nesting_level );
   5083 
   5084   next_chainposrule:
   5085     ;
   5086   }
   5087 
   5088   return HB_Err_Not_Covered;
   5089 }
   5090 
   5091 
   5092 static HB_Error  Lookup_ChainContextPos2(
   5093 		   GPOS_Instance*               gpi,
   5094 		   HB_ChainContextPosFormat2*  ccpf2,
   5095 		   HB_Buffer                   buffer,
   5096 		   HB_UShort                    flags,
   5097 		   HB_UShort                    context_length,
   5098 		   int                          nesting_level )
   5099 {
   5100   HB_UShort              index, property;
   5101   HB_Error               error;
   5102   HB_UShort              i, j, k;
   5103   HB_UShort              bgc, igc, lgc;
   5104   HB_UShort              known_backtrack_classes,
   5105 			 known_input_classes,
   5106 			 known_lookahead_classes;
   5107 
   5108   HB_UShort*             backtrack_classes;
   5109   HB_UShort*             input_classes;
   5110   HB_UShort*             lookahead_classes;
   5111 
   5112   HB_UShort*             bc;
   5113   HB_UShort*             ic;
   5114   HB_UShort*             lc;
   5115   HB_GPOSHeader*        gpos = gpi->gpos;
   5116 
   5117   HB_ChainPosClassSet*  cpcs;
   5118   HB_ChainPosClassRule  cpcr;
   5119   HB_GDEFHeader*        gdef;
   5120 
   5121 
   5122   gdef = gpos->gdef;
   5123 
   5124   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   5125     return error;
   5126 
   5127   /* Note: The coverage table in format 2 doesn't give an index into
   5128 	   anything.  It just lets us know whether or not we need to
   5129 	   do any lookup at all.                                     */
   5130 
   5131   error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
   5132   if ( error )
   5133     return error;
   5134 
   5135   if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
   5136     return error;
   5137   known_backtrack_classes = 0;
   5138 
   5139   if (ccpf2->MaxInputLength < 1)
   5140     return HB_Err_Not_Covered;
   5141 
   5142   if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
   5143     goto End3;
   5144   known_input_classes = 1;
   5145 
   5146   if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
   5147     goto End2;
   5148   known_lookahead_classes = 0;
   5149 
   5150   error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
   5151 		     &input_classes[0], NULL );
   5152   if ( error && error != HB_Err_Not_Covered )
   5153     goto End1;
   5154 
   5155   cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
   5156   if ( !cpcs )
   5157   {
   5158     error = ERR(HB_Err_Invalid_SubTable);
   5159     goto End1;
   5160   }
   5161 
   5162   for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
   5163   {
   5164     cpcr = cpcs->ChainPosClassRule[k];
   5165     bgc  = cpcr.BacktrackGlyphCount;
   5166     igc  = cpcr.InputGlyphCount;
   5167     lgc  = cpcr.LookaheadGlyphCount;
   5168 
   5169     if ( context_length != 0xFFFF && context_length < igc )
   5170       goto next_chainposclassrule;
   5171 
   5172     /* check whether context is too long; it is a first guess only */
   5173 
   5174     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   5175       goto next_chainposclassrule;
   5176 
   5177     if ( bgc )
   5178     {
   5179       /* Since we don't know in advance the number of glyphs to inspect,
   5180 	 we search backwards for matches in the backtrack glyph array.
   5181 	 Note that `known_backtrack_classes' starts at index 0.         */
   5182 
   5183       bc       = cpcr.Backtrack;
   5184 
   5185       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   5186       {
   5187 	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5188 	{
   5189 	  if ( error && error != HB_Err_Not_Covered )
   5190 	    goto End1;
   5191 
   5192 	  if ( j + 1 == bgc - i )
   5193 	    goto next_chainposclassrule;
   5194 	  j++;
   5195 	}
   5196 
   5197 	if ( i >= known_backtrack_classes )
   5198 	{
   5199 	  /* Keeps us from having to do this for each rule */
   5200 
   5201 	  error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
   5202 			     &backtrack_classes[i], NULL );
   5203 	  if ( error && error != HB_Err_Not_Covered )
   5204 	    goto End1;
   5205 	  known_backtrack_classes = i;
   5206 	}
   5207 
   5208 	if ( bc[i] != backtrack_classes[i] )
   5209 	  goto next_chainposclassrule;
   5210       }
   5211     }
   5212 
   5213     ic       = cpcr.Input;
   5214 
   5215     /* Start at 1 because [0] is implied */
   5216 
   5217     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
   5218     {
   5219       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5220       {
   5221 	if ( error && error != HB_Err_Not_Covered )
   5222 	  goto End1;
   5223 
   5224 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   5225 	  goto next_chainposclassrule;
   5226 	j++;
   5227       }
   5228 
   5229       if ( i >= known_input_classes )
   5230       {
   5231 	error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
   5232 			   &input_classes[i], NULL );
   5233 	if ( error && error != HB_Err_Not_Covered )
   5234 	  goto End1;
   5235 	known_input_classes = i;
   5236       }
   5237 
   5238       if ( ic[i - 1] != input_classes[i] )
   5239 	goto next_chainposclassrule;
   5240     }
   5241 
   5242     /* we are starting to check for lookahead glyphs right after the
   5243        last context glyph                                            */
   5244 
   5245     lc       = cpcr.Lookahead;
   5246 
   5247     for ( i = 0; i < lgc; i++, j++ )
   5248     {
   5249       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5250       {
   5251 	if ( error && error != HB_Err_Not_Covered )
   5252 	  goto End1;
   5253 
   5254 	if ( j + lgc - i == (HB_Int)buffer->in_length )
   5255 	  goto next_chainposclassrule;
   5256 	j++;
   5257       }
   5258 
   5259       if ( i >= known_lookahead_classes )
   5260       {
   5261 	error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
   5262 			   &lookahead_classes[i], NULL );
   5263 	if ( error && error != HB_Err_Not_Covered )
   5264 	  goto End1;
   5265 	known_lookahead_classes = i;
   5266       }
   5267 
   5268       if ( lc[i] != lookahead_classes[i] )
   5269 	goto next_chainposclassrule;
   5270     }
   5271 
   5272     error = Do_ContextPos( gpi, igc,
   5273 			   cpcr.PosCount,
   5274 			   cpcr.PosLookupRecord,
   5275 			   buffer,
   5276 			   nesting_level );
   5277     goto End1;
   5278 
   5279   next_chainposclassrule:
   5280     ;
   5281   }
   5282 
   5283   error = HB_Err_Not_Covered;
   5284 
   5285 End1:
   5286   FREE( lookahead_classes );
   5287 
   5288 End2:
   5289   FREE( input_classes );
   5290 
   5291 End3:
   5292   FREE( backtrack_classes );
   5293   return error;
   5294 }
   5295 
   5296 
   5297 static HB_Error  Lookup_ChainContextPos3(
   5298 		   GPOS_Instance*               gpi,
   5299 		   HB_ChainContextPosFormat3*  ccpf3,
   5300 		   HB_Buffer                   buffer,
   5301 		   HB_UShort                    flags,
   5302 		   HB_UShort                    context_length,
   5303 		   int                          nesting_level )
   5304 {
   5305   HB_UShort        index, i, j, property;
   5306   HB_UShort        bgc, igc, lgc;
   5307   HB_Error         error;
   5308   HB_GPOSHeader*  gpos = gpi->gpos;
   5309 
   5310   HB_Coverage*    bc;
   5311   HB_Coverage*    ic;
   5312   HB_Coverage*    lc;
   5313   HB_GDEFHeader*  gdef;
   5314 
   5315 
   5316   gdef = gpos->gdef;
   5317 
   5318   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   5319     return error;
   5320 
   5321   bgc = ccpf3->BacktrackGlyphCount;
   5322   igc = ccpf3->InputGlyphCount;
   5323   lgc = ccpf3->LookaheadGlyphCount;
   5324 
   5325   if ( context_length != 0xFFFF && context_length < igc )
   5326     return HB_Err_Not_Covered;
   5327 
   5328   /* check whether context is too long; it is a first guess only */
   5329 
   5330   if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   5331     return HB_Err_Not_Covered;
   5332 
   5333   if ( bgc )
   5334   {
   5335     /* Since we don't know in advance the number of glyphs to inspect,
   5336        we search backwards for matches in the backtrack glyph array    */
   5337 
   5338     bc       = ccpf3->BacktrackCoverage;
   5339 
   5340     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   5341     {
   5342       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5343       {
   5344 	if ( error && error != HB_Err_Not_Covered )
   5345 	  return error;
   5346 
   5347 	if ( j + 1 == bgc - i )
   5348 	  return HB_Err_Not_Covered;
   5349 	j--;
   5350       }
   5351 
   5352       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
   5353       if ( error )
   5354 	return error;
   5355     }
   5356   }
   5357 
   5358   ic       = ccpf3->InputCoverage;
   5359 
   5360   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
   5361   {
   5362     /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
   5363     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5364     {
   5365       if ( error && error != HB_Err_Not_Covered )
   5366 	return error;
   5367 
   5368       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   5369 	return HB_Err_Not_Covered;
   5370       j++;
   5371     }
   5372 
   5373     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
   5374     if ( error )
   5375       return error;
   5376   }
   5377 
   5378   /* we are starting to check for lookahead glyphs right after the
   5379      last context glyph                                            */
   5380 
   5381   lc       = ccpf3->LookaheadCoverage;
   5382 
   5383   for ( i = 0; i < lgc; i++, j++ )
   5384   {
   5385     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5386     {
   5387       if ( error && error != HB_Err_Not_Covered )
   5388 	return error;
   5389 
   5390       if ( j + lgc - i == (HB_Int)buffer->in_length )
   5391 	return HB_Err_Not_Covered;
   5392       j++;
   5393     }
   5394 
   5395     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
   5396     if ( error )
   5397       return error;
   5398   }
   5399 
   5400   return Do_ContextPos( gpi, igc,
   5401 			ccpf3->PosCount,
   5402 			ccpf3->PosLookupRecord,
   5403 			buffer,
   5404 			nesting_level );
   5405 }
   5406 
   5407 
   5408 static HB_Error  Lookup_ChainContextPos(
   5409 		   GPOS_Instance*        gpi,
   5410 		   HB_GPOS_SubTable* st,
   5411 		   HB_Buffer            buffer,
   5412 		   HB_UShort             flags,
   5413 		   HB_UShort             context_length,
   5414 		   int                   nesting_level )
   5415 {
   5416   HB_ChainContextPos*  ccp = &st->chain;
   5417 
   5418   switch ( ccp->PosFormat )
   5419   {
   5420   case 1:
   5421     return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
   5422 				    flags, context_length,
   5423 				    nesting_level );
   5424 
   5425   case 2:
   5426     return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
   5427 				    flags, context_length,
   5428 				    nesting_level );
   5429 
   5430   case 3:
   5431     return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
   5432 				    flags, context_length,
   5433 				    nesting_level );
   5434 
   5435   default:
   5436     return ERR(HB_Err_Invalid_SubTable_Format);
   5437   }
   5438 
   5439   return HB_Err_Ok;               /* never reached */
   5440 }
   5441 
   5442 
   5443 
   5444 /***********
   5445  * GPOS API
   5446  ***********/
   5447 
   5448 
   5449 
   5450 HB_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
   5451 				 HB_UInt         script_tag,
   5452 				 HB_UShort*       script_index )
   5453 {
   5454   HB_UShort          n;
   5455 
   5456   HB_ScriptList*    sl;
   5457   HB_ScriptRecord*  sr;
   5458 
   5459 
   5460   if ( !gpos || !script_index )
   5461     return ERR(HB_Err_Invalid_Argument);
   5462 
   5463   sl = &gpos->ScriptList;
   5464   sr = sl->ScriptRecord;
   5465 
   5466   for ( n = 0; n < sl->ScriptCount; n++ )
   5467     if ( script_tag == sr[n].ScriptTag )
   5468     {
   5469       *script_index = n;
   5470 
   5471       return HB_Err_Ok;
   5472     }
   5473 
   5474   return HB_Err_Not_Covered;
   5475 }
   5476 
   5477 
   5478 
   5479 HB_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
   5480 				   HB_UInt         language_tag,
   5481 				   HB_UShort        script_index,
   5482 				   HB_UShort*       language_index,
   5483 				   HB_UShort*       req_feature_index )
   5484 {
   5485   HB_UShort           n;
   5486 
   5487   HB_ScriptList*     sl;
   5488   HB_ScriptRecord*   sr;
   5489   HB_ScriptTable*         s;
   5490   HB_LangSysRecord*  lsr;
   5491 
   5492 
   5493   if ( !gpos || !language_index || !req_feature_index )
   5494     return ERR(HB_Err_Invalid_Argument);
   5495 
   5496   sl = &gpos->ScriptList;
   5497   sr = sl->ScriptRecord;
   5498 
   5499   if ( script_index >= sl->ScriptCount )
   5500     return ERR(HB_Err_Invalid_Argument);
   5501 
   5502   s   = &sr[script_index].Script;
   5503   lsr = s->LangSysRecord;
   5504 
   5505   for ( n = 0; n < s->LangSysCount; n++ )
   5506     if ( language_tag == lsr[n].LangSysTag )
   5507     {
   5508       *language_index = n;
   5509       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
   5510 
   5511       return HB_Err_Ok;
   5512     }
   5513 
   5514   return HB_Err_Not_Covered;
   5515 }
   5516 
   5517 
   5518 /* selecting 0xFFFF for language_index asks for the values of the
   5519    default language (DefaultLangSys)                              */
   5520 
   5521 
   5522 HB_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
   5523 				  HB_UInt         feature_tag,
   5524 				  HB_UShort        script_index,
   5525 				  HB_UShort        language_index,
   5526 				  HB_UShort*       feature_index )
   5527 {
   5528   HB_UShort           n;
   5529 
   5530   HB_ScriptList*     sl;
   5531   HB_ScriptRecord*   sr;
   5532   HB_ScriptTable*         s;
   5533   HB_LangSysRecord*  lsr;
   5534   HB_LangSys*        ls;
   5535   HB_UShort*          fi;
   5536 
   5537   HB_FeatureList*    fl;
   5538   HB_FeatureRecord*  fr;
   5539 
   5540 
   5541   if ( !gpos || !feature_index )
   5542     return ERR(HB_Err_Invalid_Argument);
   5543 
   5544   sl = &gpos->ScriptList;
   5545   sr = sl->ScriptRecord;
   5546 
   5547   fl = &gpos->FeatureList;
   5548   fr = fl->FeatureRecord;
   5549 
   5550   if ( script_index >= sl->ScriptCount )
   5551     return ERR(HB_Err_Invalid_Argument);
   5552 
   5553   s   = &sr[script_index].Script;
   5554   lsr = s->LangSysRecord;
   5555 
   5556   if ( language_index == 0xFFFF )
   5557     ls = &s->DefaultLangSys;
   5558   else
   5559   {
   5560     if ( language_index >= s->LangSysCount )
   5561       return ERR(HB_Err_Invalid_Argument);
   5562 
   5563     ls = &lsr[language_index].LangSys;
   5564   }
   5565 
   5566   fi = ls->FeatureIndex;
   5567 
   5568   for ( n = 0; n < ls->FeatureCount; n++ )
   5569   {
   5570     if ( fi[n] >= fl->FeatureCount )
   5571       return ERR(HB_Err_Invalid_SubTable_Format);
   5572 
   5573     if ( feature_tag == fr[fi[n]].FeatureTag )
   5574     {
   5575       *feature_index = fi[n];
   5576 
   5577       return HB_Err_Ok;
   5578     }
   5579   }
   5580 
   5581   return HB_Err_Not_Covered;
   5582 }
   5583 
   5584 
   5585 /* The next three functions return a null-terminated list */
   5586 
   5587 
   5588 HB_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
   5589 				 HB_UInt**       script_tag_list )
   5590 {
   5591   HB_Error           error;
   5592   HB_UShort          n;
   5593   HB_UInt*          stl;
   5594 
   5595   HB_ScriptList*    sl;
   5596   HB_ScriptRecord*  sr;
   5597 
   5598 
   5599   if ( !gpos || !script_tag_list )
   5600     return ERR(HB_Err_Invalid_Argument);
   5601 
   5602   sl = &gpos->ScriptList;
   5603   sr = sl->ScriptRecord;
   5604 
   5605   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
   5606     return error;
   5607 
   5608   for ( n = 0; n < sl->ScriptCount; n++ )
   5609     stl[n] = sr[n].ScriptTag;
   5610   stl[n] = 0;
   5611 
   5612   *script_tag_list = stl;
   5613 
   5614   return HB_Err_Ok;
   5615 }
   5616 
   5617 
   5618 
   5619 HB_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
   5620 				   HB_UShort        script_index,
   5621 				   HB_UInt**       language_tag_list )
   5622 {
   5623   HB_Error            error;
   5624   HB_UShort           n;
   5625   HB_UInt*           ltl;
   5626 
   5627   HB_ScriptList*     sl;
   5628   HB_ScriptRecord*   sr;
   5629   HB_ScriptTable*    s;
   5630   HB_LangSysRecord*  lsr;
   5631 
   5632 
   5633   if ( !gpos || !language_tag_list )
   5634     return ERR(HB_Err_Invalid_Argument);
   5635 
   5636   sl = &gpos->ScriptList;
   5637   sr = sl->ScriptRecord;
   5638 
   5639   if ( script_index >= sl->ScriptCount )
   5640     return ERR(HB_Err_Invalid_Argument);
   5641 
   5642   s   = &sr[script_index].Script;
   5643   lsr = s->LangSysRecord;
   5644 
   5645   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
   5646     return error;
   5647 
   5648   for ( n = 0; n < s->LangSysCount; n++ )
   5649     ltl[n] = lsr[n].LangSysTag;
   5650   ltl[n] = 0;
   5651 
   5652   *language_tag_list = ltl;
   5653 
   5654   return HB_Err_Ok;
   5655 }
   5656 
   5657 
   5658 /* selecting 0xFFFF for language_index asks for the values of the
   5659    default language (DefaultLangSys)                              */
   5660 
   5661 
   5662 HB_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
   5663 				  HB_UShort        script_index,
   5664 				  HB_UShort        language_index,
   5665 				  HB_UInt**       feature_tag_list )
   5666 {
   5667   HB_UShort           n;
   5668   HB_Error            error;
   5669   HB_UInt*           ftl;
   5670 
   5671   HB_ScriptList*     sl;
   5672   HB_ScriptRecord*   sr;
   5673   HB_ScriptTable*    s;
   5674   HB_LangSysRecord*  lsr;
   5675   HB_LangSys*        ls;
   5676   HB_UShort*          fi;
   5677 
   5678   HB_FeatureList*    fl;
   5679   HB_FeatureRecord*  fr;
   5680 
   5681 
   5682   if ( !gpos || !feature_tag_list )
   5683     return ERR(HB_Err_Invalid_Argument);
   5684 
   5685   sl = &gpos->ScriptList;
   5686   sr = sl->ScriptRecord;
   5687 
   5688   fl = &gpos->FeatureList;
   5689   fr = fl->FeatureRecord;
   5690 
   5691   if ( script_index >= sl->ScriptCount )
   5692     return ERR(HB_Err_Invalid_Argument);
   5693 
   5694   s   = &sr[script_index].Script;
   5695   lsr = s->LangSysRecord;
   5696 
   5697   if ( language_index == 0xFFFF )
   5698     ls = &s->DefaultLangSys;
   5699   else
   5700   {
   5701     if ( language_index >= s->LangSysCount )
   5702       return ERR(HB_Err_Invalid_Argument);
   5703 
   5704     ls = &lsr[language_index].LangSys;
   5705   }
   5706 
   5707   fi = ls->FeatureIndex;
   5708 
   5709   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
   5710     return error;
   5711 
   5712   for ( n = 0; n < ls->FeatureCount; n++ )
   5713   {
   5714     if ( fi[n] >= fl->FeatureCount )
   5715     {
   5716       FREE( ftl );
   5717       return ERR(HB_Err_Invalid_SubTable_Format);
   5718     }
   5719     ftl[n] = fr[fi[n]].FeatureTag;
   5720   }
   5721   ftl[n] = 0;
   5722 
   5723   *feature_tag_list = ftl;
   5724 
   5725   return HB_Err_Ok;
   5726 }
   5727 
   5728 
   5729 /* Do an individual subtable lookup.  Returns HB_Err_Ok if positioning
   5730    has been done, or HB_Err_Not_Covered if not.                        */
   5731 static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
   5732 				       HB_UShort         lookup_index,
   5733 				       HB_Buffer        buffer,
   5734 				       HB_UShort         context_length,
   5735 				       int               nesting_level )
   5736 {
   5737   HB_Error             error = HB_Err_Not_Covered;
   5738   HB_UShort            i, flags, lookup_count;
   5739   HB_GPOSHeader*       gpos = gpi->gpos;
   5740   HB_Lookup*           lo;
   5741   int		       lookup_type;
   5742 
   5743 
   5744   nesting_level++;
   5745 
   5746   if ( nesting_level > HB_MAX_NESTING_LEVEL )
   5747     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
   5748 
   5749   lookup_count = gpos->LookupList.LookupCount;
   5750   if (lookup_index >= lookup_count)
   5751     return error;
   5752 
   5753   lo    = &gpos->LookupList.Lookup[lookup_index];
   5754   flags = lo->LookupFlag;
   5755   lookup_type = lo->LookupType;
   5756 
   5757   for ( i = 0; i < lo->SubTableCount; i++ )
   5758   {
   5759     HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
   5760 
   5761     switch (lookup_type) {
   5762       case HB_GPOS_LOOKUP_SINGLE:
   5763         error = Lookup_SinglePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5764       case HB_GPOS_LOOKUP_PAIR:
   5765 	error = Lookup_PairPos		( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5766       case HB_GPOS_LOOKUP_CURSIVE:
   5767 	error = Lookup_CursivePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5768       case HB_GPOS_LOOKUP_MARKBASE:
   5769 	error = Lookup_MarkBasePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5770       case HB_GPOS_LOOKUP_MARKLIG:
   5771 	error = Lookup_MarkLigPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5772       case HB_GPOS_LOOKUP_MARKMARK:
   5773 	error = Lookup_MarkMarkPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5774       case HB_GPOS_LOOKUP_CONTEXT:
   5775 	error = Lookup_ContextPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5776       case HB_GPOS_LOOKUP_CHAIN:
   5777 	error = Lookup_ChainContextPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5778     /*case HB_GPOS_LOOKUP_EXTENSION:
   5779 	error = Lookup_ExtensionPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
   5780       default:
   5781 	error = HB_Err_Not_Covered;
   5782     }
   5783 
   5784     /* Check whether we have a successful positioning or an error other
   5785        than HB_Err_Not_Covered                                         */
   5786     if ( error != HB_Err_Not_Covered )
   5787       return error;
   5788   }
   5789 
   5790   return HB_Err_Not_Covered;
   5791 }
   5792 
   5793 
   5794 HB_INTERNAL HB_Error
   5795 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
   5796 			HB_Stream         stream,
   5797 			HB_UShort         lookup_type )
   5798 {
   5799   switch ( lookup_type ) {
   5800     case HB_GPOS_LOOKUP_SINGLE:		return Load_SinglePos		( st, stream );
   5801     case HB_GPOS_LOOKUP_PAIR:		return Load_PairPos		( st, stream );
   5802     case HB_GPOS_LOOKUP_CURSIVE:	return Load_CursivePos		( st, stream );
   5803     case HB_GPOS_LOOKUP_MARKBASE:	return Load_MarkBasePos		( st, stream );
   5804     case HB_GPOS_LOOKUP_MARKLIG:	return Load_MarkLigPos		( st, stream );
   5805     case HB_GPOS_LOOKUP_MARKMARK:	return Load_MarkMarkPos		( st, stream );
   5806     case HB_GPOS_LOOKUP_CONTEXT:	return Load_ContextPos		( st, stream );
   5807     case HB_GPOS_LOOKUP_CHAIN:		return Load_ChainContextPos	( st, stream );
   5808   /*case HB_GPOS_LOOKUP_EXTENSION:	return Load_ExtensionPos	( st, stream );*/
   5809     default:				return ERR(HB_Err_Invalid_SubTable_Format);
   5810   }
   5811 }
   5812 
   5813 
   5814 HB_INTERNAL void
   5815 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
   5816 			HB_UShort         lookup_type )
   5817 {
   5818   switch ( lookup_type ) {
   5819     case HB_GPOS_LOOKUP_SINGLE:		Free_SinglePos		( st ); return;
   5820     case HB_GPOS_LOOKUP_PAIR:		Free_PairPos		( st ); return;
   5821     case HB_GPOS_LOOKUP_CURSIVE:	Free_CursivePos		( st ); return;
   5822     case HB_GPOS_LOOKUP_MARKBASE:	Free_MarkBasePos	( st ); return;
   5823     case HB_GPOS_LOOKUP_MARKLIG:	Free_MarkLigPos		( st ); return;
   5824     case HB_GPOS_LOOKUP_MARKMARK:	Free_MarkMarkPos	( st ); return;
   5825     case HB_GPOS_LOOKUP_CONTEXT:	Free_ContextPos		( st ); return;
   5826     case HB_GPOS_LOOKUP_CHAIN:		Free_ChainContextPos	( st ); return;
   5827   /*case HB_GPOS_LOOKUP_EXTENSION:	Free_ExtensionPos	( st ); return;*/
   5828     default:									return;
   5829   }
   5830 }
   5831 
   5832 
   5833 /* apply one lookup to the input string object */
   5834 
   5835 static HB_Error  GPOS_Do_String_Lookup( GPOS_Instance*    gpi,
   5836 				   HB_UShort         lookup_index,
   5837 				   HB_Buffer        buffer )
   5838 {
   5839   HB_Error         error, retError = HB_Err_Not_Covered;
   5840   HB_GPOSHeader*  gpos = gpi->gpos;
   5841 
   5842   HB_UInt*  properties = gpos->LookupList.Properties;
   5843 
   5844   const int       nesting_level = 0;
   5845   /* 0xFFFF indicates that we don't have a context length yet */
   5846   const HB_UShort context_length = 0xFFFF;
   5847 
   5848 
   5849   gpi->last  = 0xFFFF;     /* no last valid glyph for cursive pos. */
   5850 
   5851   buffer->in_pos = 0;
   5852   while ( buffer->in_pos < buffer->in_length )
   5853   {
   5854     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
   5855     {
   5856       /* Note that the connection between mark and base glyphs hold
   5857 	 exactly one (string) lookup.  For example, it would be possible
   5858 	 that in the first lookup, mark glyph X is attached to base
   5859 	 glyph A, and in the next lookup it is attached to base glyph B.
   5860 	 It is up to the font designer to provide meaningful lookups and
   5861 	 lookup order.                                                   */
   5862 
   5863       error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
   5864       if ( error && error != HB_Err_Not_Covered )
   5865 	return error;
   5866     }
   5867     else
   5868     {
   5869       /* Contrary to properties defined in GDEF, user-defined properties
   5870 	 will always stop a possible cursive positioning.                */
   5871       gpi->last = 0xFFFF;
   5872 
   5873       error = HB_Err_Not_Covered;
   5874     }
   5875 
   5876     if ( error == HB_Err_Not_Covered )
   5877       (buffer->in_pos)++;
   5878     else
   5879       retError = error;
   5880   }
   5881 
   5882   return retError;
   5883 }
   5884 
   5885 
   5886 static HB_Error  Position_CursiveChain ( HB_Buffer     buffer )
   5887 {
   5888   HB_UInt   i, j;
   5889   HB_Position positions = buffer->positions;
   5890 
   5891   /* First handle all left-to-right connections */
   5892   for (j = 0; j < buffer->in_length; j++)
   5893   {
   5894     if (positions[j].cursive_chain > 0)
   5895       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
   5896   }
   5897 
   5898   /* Then handle all right-to-left connections */
   5899   for (i = buffer->in_length; i > 0; i--)
   5900   {
   5901     j = i - 1;
   5902 
   5903     if (positions[j].cursive_chain < 0)
   5904       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
   5905   }
   5906 
   5907   return HB_Err_Ok;
   5908 }
   5909 
   5910 
   5911 HB_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
   5912 			       HB_UShort        feature_index,
   5913 			       HB_UInt          property )
   5914 {
   5915   HB_UShort    i;
   5916 
   5917   HB_Feature  feature;
   5918   HB_UInt*     properties;
   5919   HB_UShort*   index;
   5920   HB_UShort    lookup_count;
   5921 
   5922   /* Each feature can only be added once */
   5923 
   5924   if ( !gpos ||
   5925        feature_index >= gpos->FeatureList.FeatureCount ||
   5926        gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
   5927     return ERR(HB_Err_Invalid_Argument);
   5928 
   5929   gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
   5930 
   5931   properties = gpos->LookupList.Properties;
   5932 
   5933   feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
   5934   index   = feature.LookupListIndex;
   5935   lookup_count = gpos->LookupList.LookupCount;
   5936 
   5937   for ( i = 0; i < feature.LookupListCount; i++ )
   5938   {
   5939     HB_UShort lookup_index = index[i];
   5940     if (lookup_index < lookup_count)
   5941       properties[lookup_index] |= property;
   5942   }
   5943 
   5944   return HB_Err_Ok;
   5945 }
   5946 
   5947 
   5948 
   5949 HB_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos )
   5950 {
   5951   HB_UShort i;
   5952 
   5953   HB_UInt*  properties;
   5954 
   5955 
   5956   if ( !gpos )
   5957     return ERR(HB_Err_Invalid_Argument);
   5958 
   5959   gpos->FeatureList.ApplyCount = 0;
   5960 
   5961   properties = gpos->LookupList.Properties;
   5962 
   5963   for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
   5964     properties[i] = 0;
   5965 
   5966   return HB_Err_Ok;
   5967 }
   5968 
   5969 
   5970 
   5971 HB_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
   5972 					HB_MMFunction   mmfunc,
   5973 					void*            data )
   5974 {
   5975   if ( !gpos )
   5976     return ERR(HB_Err_Invalid_Argument);
   5977 
   5978   gpos->mmfunc = mmfunc;
   5979   gpos->data   = data;
   5980 
   5981   return HB_Err_Ok;
   5982 }
   5983 
   5984 /* If `dvi' is TRUE, glyph contour points for anchor points and device
   5985    tables are ignored -- you will get device independent values.         */
   5986 
   5987 
   5988 HB_Error  HB_GPOS_Apply_String( HB_Font            font,
   5989 				HB_GPOSHeader*    gpos,
   5990 				HB_UShort          load_flags,
   5991 				HB_Buffer         buffer,
   5992 				HB_Bool            dvi,
   5993 				HB_Bool            r2l )
   5994 {
   5995   HB_Error       error, retError = HB_Err_Not_Covered;
   5996   GPOS_Instance  gpi;
   5997   int            i, j, lookup_count, num_features;
   5998 
   5999   if ( !font || !gpos || !buffer )
   6000     return ERR(HB_Err_Invalid_Argument);
   6001 
   6002   if ( buffer->in_length == 0 )
   6003     return HB_Err_Not_Covered;
   6004 
   6005   gpi.font       = font;
   6006   gpi.gpos       = gpos;
   6007   gpi.load_flags = load_flags;
   6008   gpi.r2l        = r2l;
   6009   gpi.dvi        = dvi;
   6010 
   6011   lookup_count = gpos->LookupList.LookupCount;
   6012   num_features = gpos->FeatureList.ApplyCount;
   6013 
   6014   if ( num_features )
   6015     {
   6016       error = _hb_buffer_clear_positions( buffer );
   6017       if ( error )
   6018 	return error;
   6019     }
   6020 
   6021   for ( i = 0; i < num_features; i++ )
   6022   {
   6023     HB_UShort  feature_index = gpos->FeatureList.ApplyOrder[i];
   6024     HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
   6025 
   6026     for ( j = 0; j < feature.LookupListCount; j++ )
   6027     {
   6028       HB_UShort lookup_index = feature.LookupListIndex[j];
   6029 
   6030       /* Skip nonexistant lookups */
   6031       if (lookup_index >= lookup_count)
   6032        continue;
   6033 
   6034       error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
   6035       if ( error )
   6036       {
   6037 	if ( error != HB_Err_Not_Covered )
   6038 	  return error;
   6039       }
   6040       else
   6041 	retError = error;
   6042     }
   6043   }
   6044 
   6045   if ( num_features )
   6046     {
   6047   error = Position_CursiveChain ( buffer );
   6048   if ( error )
   6049     return error;
   6050     }
   6051 
   6052   return retError;
   6053 }
   6054 
   6055 /* END */
   6056