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