a21600579e5d4df316a3032f3167cd0807dba476
[profile/ivi/qtbase.git] / src / 3rdparty / harfbuzz / src / harfbuzz-gpos.c
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@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 */