e969a0130985fcf29e279a150813c7dca1e8365c
[platform/upstream/harfbuzz.git] / src / hb-old / 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   if ( i > buffer->in_pos )
3016     return HB_Err_Not_Covered;
3017
3018   error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3019                           &mark2_index );
3020   if ( error )
3021     return error;
3022
3023   ma1 = &mmp->Mark1Array;
3024
3025   if ( mark1_index >= ma1->MarkCount )
3026     return ERR(HB_Err_Invalid_SubTable);
3027
3028   class        = ma1->MarkRecord[mark1_index].Class;
3029   mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3030
3031   if ( class >= mmp->ClassCount )
3032     return ERR(HB_Err_Invalid_SubTable);
3033
3034   ma2 = &mmp->Mark2Array;
3035
3036   if ( mark2_index >= ma2->Mark2Count )
3037     return ERR(HB_Err_Invalid_SubTable);
3038
3039   m2r          = &ma2->Mark2Record[mark2_index];
3040   mark2_anchor = &m2r->Mark2Anchor[class];
3041
3042   error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3043                       &x_mark1_value, &y_mark1_value );
3044   if ( error )
3045     return error;
3046   error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3047                       &x_mark2_value, &y_mark2_value );
3048   if ( error )
3049     return error;
3050
3051   /* anchor points are not cumulative */
3052
3053   o = POSITION( buffer->in_pos );
3054
3055   o->x_pos     = x_mark2_value - x_mark1_value;
3056   o->y_pos     = y_mark2_value - y_mark1_value;
3057   o->x_advance = 0;
3058   o->y_advance = 0;
3059   o->back      = 1;
3060
3061   (buffer->in_pos)++;
3062
3063   return HB_Err_Ok;
3064 }
3065
3066
3067 /* Do the actual positioning for a context positioning (either format
3068    7 or 8).  This is only called after we've determined that the stream
3069    matches the subrule.                                                 */
3070
3071 static HB_Error  Do_ContextPos( GPOS_Instance*        gpi,
3072                                 HB_UShort             GlyphCount,
3073                                 HB_UShort             PosCount,
3074                                 HB_PosLookupRecord*  pos,
3075                                 HB_Buffer            buffer,
3076                                 int                   nesting_level )
3077 {
3078   HB_Error  error;
3079   HB_UInt   i, old_pos;
3080
3081
3082   i = 0;
3083
3084   while ( i < GlyphCount )
3085   {
3086     if ( PosCount && i == pos->SequenceIndex )
3087     {
3088       old_pos = buffer->in_pos;
3089
3090       /* Do a positioning */
3091
3092       error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3093                                     GlyphCount, nesting_level );
3094
3095       if ( error )
3096         return error;
3097
3098       pos++;
3099       PosCount--;
3100       i += buffer->in_pos - old_pos;
3101     }
3102     else
3103     {
3104       i++;
3105       (buffer->in_pos)++;
3106     }
3107   }
3108
3109   return HB_Err_Ok;
3110 }
3111
3112
3113 /* LookupType 7 */
3114
3115 /* PosRule */
3116
3117 static HB_Error  Load_PosRule( HB_PosRule*  pr,
3118                                HB_Stream     stream )
3119 {
3120   HB_Error  error;
3121
3122   HB_UShort             n, count;
3123   HB_UShort*            i;
3124
3125   HB_PosLookupRecord*  plr;
3126
3127
3128   if ( ACCESS_Frame( 4L ) )
3129     return error;
3130
3131   pr->GlyphCount = GET_UShort();
3132   pr->PosCount   = GET_UShort();
3133
3134   FORGET_Frame();
3135
3136   pr->Input = NULL;
3137
3138   count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
3139
3140   if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3141     return error;
3142
3143   i = pr->Input;
3144
3145   if ( ACCESS_Frame( count * 2L ) )
3146     goto Fail2;
3147
3148   for ( n = 0; n < count; n++ )
3149     i[n] = GET_UShort();
3150
3151   FORGET_Frame();
3152
3153   pr->PosLookupRecord = NULL;
3154
3155   count = pr->PosCount;
3156
3157   if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3158     goto Fail2;
3159
3160   plr = pr->PosLookupRecord;
3161
3162   if ( ACCESS_Frame( count * 4L ) )
3163     goto Fail1;
3164
3165   for ( n = 0; n < count; n++ )
3166   {
3167     plr[n].SequenceIndex   = GET_UShort();
3168     plr[n].LookupListIndex = GET_UShort();
3169   }
3170
3171   FORGET_Frame();
3172
3173   return HB_Err_Ok;
3174
3175 Fail1:
3176   FREE( plr );
3177
3178 Fail2:
3179   FREE( i );
3180   return error;
3181 }
3182
3183
3184 static void  Free_PosRule( HB_PosRule*  pr )
3185 {
3186   FREE( pr->PosLookupRecord );
3187   FREE( pr->Input );
3188 }
3189
3190
3191 /* PosRuleSet */
3192
3193 static HB_Error  Load_PosRuleSet( HB_PosRuleSet*  prs,
3194                                   HB_Stream        stream )
3195 {
3196   HB_Error  error;
3197
3198   HB_UShort     n, m, count;
3199   HB_UInt      cur_offset, new_offset, base_offset;
3200
3201   HB_PosRule*  pr;
3202
3203
3204   base_offset = FILE_Pos();
3205
3206   if ( ACCESS_Frame( 2L ) )
3207     return error;
3208
3209   count = prs->PosRuleCount = GET_UShort();
3210
3211   FORGET_Frame();
3212
3213   prs->PosRule = NULL;
3214
3215   if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3216     return error;
3217
3218   pr = prs->PosRule;
3219
3220   for ( n = 0; n < count; n++ )
3221   {
3222     if ( ACCESS_Frame( 2L ) )
3223       goto Fail;
3224
3225     new_offset = GET_UShort() + base_offset;
3226
3227     FORGET_Frame();
3228
3229     cur_offset = FILE_Pos();
3230     if ( FILE_Seek( new_offset ) ||
3231          ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3232       goto Fail;
3233     (void)FILE_Seek( cur_offset );
3234   }
3235
3236   return HB_Err_Ok;
3237
3238 Fail:
3239   for ( m = 0; m < n; m++ )
3240     Free_PosRule( &pr[m] );
3241
3242   FREE( pr );
3243   return error;
3244 }
3245
3246
3247 static void  Free_PosRuleSet( HB_PosRuleSet*  prs )
3248 {
3249   HB_UShort     n, count;
3250
3251   HB_PosRule*  pr;
3252
3253
3254   if ( prs->PosRule )
3255   {
3256     count = prs->PosRuleCount;
3257     pr    = prs->PosRule;
3258
3259     for ( n = 0; n < count; n++ )
3260       Free_PosRule( &pr[n] );
3261
3262     FREE( pr );
3263   }
3264 }
3265
3266
3267 /* ContextPosFormat1 */
3268
3269 static HB_Error  Load_ContextPos1( HB_ContextPosFormat1*  cpf1,
3270                                    HB_Stream               stream )
3271 {
3272   HB_Error  error;
3273
3274   HB_UShort        n, m, count;
3275   HB_UInt         cur_offset, new_offset, base_offset;
3276
3277   HB_PosRuleSet*  prs;
3278
3279
3280   base_offset = FILE_Pos() - 2L;
3281
3282   if ( ACCESS_Frame( 2L ) )
3283     return error;
3284
3285   new_offset = GET_UShort() + base_offset;
3286
3287   FORGET_Frame();
3288
3289   cur_offset = FILE_Pos();
3290   if ( FILE_Seek( new_offset ) ||
3291        ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3292     return error;
3293   (void)FILE_Seek( cur_offset );
3294
3295   if ( ACCESS_Frame( 2L ) )
3296     goto Fail2;
3297
3298   count = cpf1->PosRuleSetCount = GET_UShort();
3299
3300   FORGET_Frame();
3301
3302   cpf1->PosRuleSet = NULL;
3303
3304   if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3305     goto Fail2;
3306
3307   prs = cpf1->PosRuleSet;
3308
3309   for ( n = 0; n < count; n++ )
3310   {
3311     if ( ACCESS_Frame( 2L ) )
3312       goto Fail1;
3313
3314     new_offset = GET_UShort() + base_offset;
3315
3316     FORGET_Frame();
3317
3318     cur_offset = FILE_Pos();
3319     if ( FILE_Seek( new_offset ) ||
3320          ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3321       goto Fail1;
3322     (void)FILE_Seek( cur_offset );
3323   }
3324
3325   return HB_Err_Ok;
3326
3327 Fail1:
3328   for ( m = 0; m < n; m++ )
3329     Free_PosRuleSet( &prs[m] );
3330
3331   FREE( prs );
3332
3333 Fail2:
3334   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3335   return error;
3336 }
3337
3338
3339 static void  Free_ContextPos1( HB_ContextPosFormat1*  cpf1 )
3340 {
3341   HB_UShort        n, count;
3342
3343   HB_PosRuleSet*  prs;
3344
3345
3346   if ( cpf1->PosRuleSet )
3347   {
3348     count = cpf1->PosRuleSetCount;
3349     prs   = cpf1->PosRuleSet;
3350
3351     for ( n = 0; n < count; n++ )
3352       Free_PosRuleSet( &prs[n] );
3353
3354     FREE( prs );
3355   }
3356
3357   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3358 }
3359
3360
3361 /* PosClassRule */
3362
3363 static HB_Error  Load_PosClassRule( HB_ContextPosFormat2*  cpf2,
3364                                     HB_PosClassRule*       pcr,
3365                                     HB_Stream               stream )
3366 {
3367   HB_Error  error;
3368
3369   HB_UShort             n, count;
3370
3371   HB_UShort*            c;
3372   HB_PosLookupRecord*  plr;
3373
3374
3375   if ( ACCESS_Frame( 4L ) )
3376     return error;
3377
3378   pcr->GlyphCount = GET_UShort();
3379   pcr->PosCount   = GET_UShort();
3380
3381   FORGET_Frame();
3382
3383   if ( pcr->GlyphCount > cpf2->MaxContextLength )
3384     cpf2->MaxContextLength = pcr->GlyphCount;
3385
3386   pcr->Class = NULL;
3387
3388   count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
3389
3390   if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3391     return error;
3392
3393   c = pcr->Class;
3394
3395   if ( ACCESS_Frame( count * 2L ) )
3396     goto Fail2;
3397
3398   for ( n = 0; n < count; n++ )
3399     c[n] = GET_UShort();
3400
3401   FORGET_Frame();
3402
3403   pcr->PosLookupRecord = NULL;
3404
3405   count = pcr->PosCount;
3406
3407   if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3408     goto Fail2;
3409
3410   plr = pcr->PosLookupRecord;
3411
3412   if ( ACCESS_Frame( count * 4L ) )
3413     goto Fail1;
3414
3415   for ( n = 0; n < count; n++ )
3416   {
3417     plr[n].SequenceIndex   = GET_UShort();
3418     plr[n].LookupListIndex = GET_UShort();
3419   }
3420
3421   FORGET_Frame();
3422
3423   return HB_Err_Ok;
3424
3425 Fail1:
3426   FREE( plr );
3427
3428 Fail2:
3429   FREE( c );
3430   return error;
3431 }
3432
3433
3434 static void  Free_PosClassRule( HB_PosClassRule*  pcr )
3435 {
3436   FREE( pcr->PosLookupRecord );
3437   FREE( pcr->Class );
3438 }
3439
3440
3441 /* PosClassSet */
3442
3443 static HB_Error  Load_PosClassSet( HB_ContextPosFormat2*  cpf2,
3444                                    HB_PosClassSet*        pcs,
3445                                    HB_Stream               stream )
3446 {
3447   HB_Error  error;
3448
3449   HB_UShort          n, m, count;
3450   HB_UInt           cur_offset, new_offset, base_offset;
3451
3452   HB_PosClassRule*  pcr;
3453
3454
3455   base_offset = FILE_Pos();
3456
3457   if ( ACCESS_Frame( 2L ) )
3458     return error;
3459
3460   count = pcs->PosClassRuleCount = GET_UShort();
3461
3462   FORGET_Frame();
3463
3464   pcs->PosClassRule = NULL;
3465
3466   if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3467     return error;
3468
3469   pcr = pcs->PosClassRule;
3470
3471   for ( n = 0; n < count; n++ )
3472   {
3473     if ( ACCESS_Frame( 2L ) )
3474       goto Fail;
3475
3476     new_offset = GET_UShort() + base_offset;
3477
3478     FORGET_Frame();
3479
3480     cur_offset = FILE_Pos();
3481     if ( FILE_Seek( new_offset ) ||
3482          ( error = Load_PosClassRule( cpf2, &pcr[n],
3483                                       stream ) ) != HB_Err_Ok )
3484       goto Fail;
3485     (void)FILE_Seek( cur_offset );
3486   }
3487
3488   return HB_Err_Ok;
3489
3490 Fail:
3491   for ( m = 0; m < n; m++ )
3492     Free_PosClassRule( &pcr[m] );
3493
3494   FREE( pcr );
3495   return error;
3496 }
3497
3498
3499 static void  Free_PosClassSet( HB_PosClassSet*  pcs )
3500 {
3501   HB_UShort          n, count;
3502
3503   HB_PosClassRule*  pcr;
3504
3505
3506   if ( pcs->PosClassRule )
3507   {
3508     count = pcs->PosClassRuleCount;
3509     pcr   = pcs->PosClassRule;
3510
3511     for ( n = 0; n < count; n++ )
3512       Free_PosClassRule( &pcr[n] );
3513
3514     FREE( pcr );
3515   }
3516 }
3517
3518
3519 /* ContextPosFormat2 */
3520
3521 static HB_Error  Load_ContextPos2( HB_ContextPosFormat2*  cpf2,
3522                                    HB_Stream               stream )
3523 {
3524   HB_Error  error;
3525
3526   HB_UShort         n, m, count;
3527   HB_UInt          cur_offset, new_offset, base_offset;
3528
3529   HB_PosClassSet*  pcs;
3530
3531
3532   base_offset = FILE_Pos() - 2;
3533
3534   if ( ACCESS_Frame( 2L ) )
3535     return error;
3536
3537   new_offset = GET_UShort() + base_offset;
3538
3539   FORGET_Frame();
3540
3541   cur_offset = FILE_Pos();
3542   if ( FILE_Seek( new_offset ) ||
3543        ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3544     return error;
3545   (void)FILE_Seek( cur_offset );
3546
3547   if ( ACCESS_Frame( 4L ) )
3548     goto Fail3;
3549
3550   new_offset = GET_UShort() + base_offset;
3551
3552   /* `PosClassSetCount' is the upper limit for class values, thus we
3553      read it now to make an additional safety check.                 */
3554
3555   count = cpf2->PosClassSetCount = GET_UShort();
3556
3557   FORGET_Frame();
3558
3559   cur_offset = FILE_Pos();
3560   if ( FILE_Seek( new_offset ) ||
3561        ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3562                                        stream ) ) != HB_Err_Ok )
3563     goto Fail3;
3564   (void)FILE_Seek( cur_offset );
3565
3566   cpf2->PosClassSet      = NULL;
3567   cpf2->MaxContextLength = 0;
3568
3569   if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3570     goto Fail2;
3571
3572   pcs = cpf2->PosClassSet;
3573
3574   for ( n = 0; n < count; n++ )
3575   {
3576     if ( ACCESS_Frame( 2L ) )
3577       goto Fail1;
3578
3579     new_offset = GET_UShort() + base_offset;
3580
3581     FORGET_Frame();
3582
3583     if ( new_offset != base_offset )      /* not a NULL offset */
3584     {
3585       cur_offset = FILE_Pos();
3586       if ( FILE_Seek( new_offset ) ||
3587            ( error = Load_PosClassSet( cpf2, &pcs[n],
3588                                        stream ) ) != HB_Err_Ok )
3589         goto Fail1;
3590       (void)FILE_Seek( cur_offset );
3591     }
3592     else
3593     {
3594       /* we create a PosClassSet table with no entries */
3595
3596       cpf2->PosClassSet[n].PosClassRuleCount = 0;
3597       cpf2->PosClassSet[n].PosClassRule      = NULL;
3598     }
3599   }
3600
3601   return HB_Err_Ok;
3602
3603 Fail1:
3604   for ( m = 0; m < n; n++ )
3605     Free_PosClassSet( &pcs[m] );
3606
3607   FREE( pcs );
3608
3609 Fail2:
3610   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3611
3612 Fail3:
3613   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3614   return error;
3615 }
3616
3617
3618 static void  Free_ContextPos2( HB_ContextPosFormat2*  cpf2 )
3619 {
3620   HB_UShort         n, count;
3621
3622   HB_PosClassSet*  pcs;
3623
3624
3625   if ( cpf2->PosClassSet )
3626   {
3627     count = cpf2->PosClassSetCount;
3628     pcs   = cpf2->PosClassSet;
3629
3630     for ( n = 0; n < count; n++ )
3631       Free_PosClassSet( &pcs[n] );
3632
3633     FREE( pcs );
3634   }
3635
3636   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3637   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3638 }
3639
3640
3641 /* ContextPosFormat3 */
3642
3643 static HB_Error  Load_ContextPos3( HB_ContextPosFormat3*  cpf3,
3644                                    HB_Stream               stream )
3645 {
3646   HB_Error  error;
3647
3648   HB_UShort             n, count;
3649   HB_UInt              cur_offset, new_offset, base_offset;
3650
3651   HB_Coverage*         c;
3652   HB_PosLookupRecord*  plr;
3653
3654
3655   base_offset = FILE_Pos() - 2L;
3656
3657   if ( ACCESS_Frame( 4L ) )
3658     return error;
3659
3660   cpf3->GlyphCount = GET_UShort();
3661   cpf3->PosCount   = GET_UShort();
3662
3663   FORGET_Frame();
3664
3665   cpf3->Coverage = NULL;
3666
3667   count = cpf3->GlyphCount;
3668
3669   if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3670     return error;
3671
3672   c = cpf3->Coverage;
3673
3674   for ( n = 0; n < count; n++ )
3675   {
3676     if ( ACCESS_Frame( 2L ) )
3677       goto Fail2;
3678
3679     new_offset = GET_UShort() + base_offset;
3680
3681     FORGET_Frame();
3682
3683     cur_offset = FILE_Pos();
3684     if ( FILE_Seek( new_offset ) ||
3685          ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3686       goto Fail2;
3687     (void)FILE_Seek( cur_offset );
3688   }
3689
3690   cpf3->PosLookupRecord = NULL;
3691
3692   count = cpf3->PosCount;
3693
3694   if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3695     goto Fail2;
3696
3697   plr = cpf3->PosLookupRecord;
3698
3699   if ( ACCESS_Frame( count * 4L ) )
3700     goto Fail1;
3701
3702   for ( n = 0; n < count; n++ )
3703   {
3704     plr[n].SequenceIndex   = GET_UShort();
3705     plr[n].LookupListIndex = GET_UShort();
3706   }
3707
3708   FORGET_Frame();
3709
3710   return HB_Err_Ok;
3711
3712 Fail1:
3713   FREE( plr );
3714
3715 Fail2:
3716   for ( n = 0; n < count; n++ )
3717     _HB_OPEN_Free_Coverage( &c[n] );
3718
3719   FREE( c );
3720   return error;
3721 }
3722
3723
3724 static void  Free_ContextPos3( HB_ContextPosFormat3*  cpf3 )
3725 {
3726   HB_UShort      n, count;
3727
3728   HB_Coverage*  c;
3729
3730
3731   FREE( cpf3->PosLookupRecord );
3732
3733   if ( cpf3->Coverage )
3734   {
3735     count = cpf3->GlyphCount;
3736     c     = cpf3->Coverage;
3737
3738     for ( n = 0; n < count; n++ )
3739       _HB_OPEN_Free_Coverage( &c[n] );
3740
3741     FREE( c );
3742   }
3743 }
3744
3745
3746 /* ContextPos */
3747
3748 static HB_Error  Load_ContextPos( HB_GPOS_SubTable* st,
3749                                   HB_Stream        stream )
3750 {
3751   HB_Error  error;
3752   HB_ContextPos*   cp = &st->context;
3753
3754
3755   if ( ACCESS_Frame( 2L ) )
3756     return error;
3757
3758   cp->PosFormat = GET_UShort();
3759
3760   FORGET_Frame();
3761
3762   switch ( cp->PosFormat )
3763   {
3764   case 1:
3765     return Load_ContextPos1( &cp->cpf.cpf1, stream );
3766
3767   case 2:
3768     return Load_ContextPos2( &cp->cpf.cpf2, stream );
3769
3770   case 3:
3771     return Load_ContextPos3( &cp->cpf.cpf3, stream );
3772
3773   default:
3774     return ERR(HB_Err_Invalid_SubTable_Format);
3775   }
3776
3777   return HB_Err_Ok;               /* never reached */
3778 }
3779
3780
3781 static void  Free_ContextPos( HB_GPOS_SubTable* st )
3782 {
3783   HB_ContextPos*   cp = &st->context;
3784
3785   switch ( cp->PosFormat )
3786   {
3787   case 1:  Free_ContextPos1( &cp->cpf.cpf1 ); break;
3788   case 2:  Free_ContextPos2( &cp->cpf.cpf2 ); break;
3789   case 3:  Free_ContextPos3( &cp->cpf.cpf3 ); break;
3790   default:                                            break;
3791   }
3792 }
3793
3794
3795 static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
3796                                      HB_ContextPosFormat1*  cpf1,
3797                                      HB_Buffer              buffer,
3798                                      HB_UShort               flags,
3799                                      HB_UShort               context_length,
3800                                      int                     nesting_level )
3801 {
3802   HB_UShort        index, property;
3803   HB_UShort        i, j, k, numpr;
3804   HB_Error         error;
3805   HB_GPOSHeader*  gpos = gpi->gpos;
3806
3807   HB_PosRule*     pr;
3808   HB_GDEFHeader*  gdef;
3809
3810
3811   gdef = gpos->gdef;
3812
3813   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3814     return error;
3815
3816   error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3817   if ( error )
3818     return error;
3819
3820   pr    = cpf1->PosRuleSet[index].PosRule;
3821   numpr = cpf1->PosRuleSet[index].PosRuleCount;
3822
3823   for ( k = 0; k < numpr; k++ )
3824   {
3825     if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3826       goto next_posrule;
3827
3828     if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3829       goto next_posrule;                       /* context is too long */
3830
3831     for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3832     {
3833       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3834       {
3835         if ( error && error != HB_Err_Not_Covered )
3836           return error;
3837
3838         if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3839           goto next_posrule;
3840         j++;
3841       }
3842
3843       if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3844         goto next_posrule;
3845     }
3846
3847     return Do_ContextPos( gpi, pr[k].GlyphCount,
3848                           pr[k].PosCount, pr[k].PosLookupRecord,
3849                           buffer,
3850                           nesting_level );
3851
3852     next_posrule:
3853       ;
3854   }
3855
3856   return HB_Err_Not_Covered;
3857 }
3858
3859
3860 static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
3861                                      HB_ContextPosFormat2*  cpf2,
3862                                      HB_Buffer              buffer,
3863                                      HB_UShort               flags,
3864                                      HB_UShort               context_length,
3865                                      int                     nesting_level )
3866 {
3867   HB_UShort          index, property;
3868   HB_Error           error;
3869   HB_UShort          i, j, k, known_classes;
3870
3871   HB_UShort*         classes;
3872   HB_UShort*         cl;
3873   HB_GPOSHeader*    gpos = gpi->gpos;
3874
3875   HB_PosClassSet*   pcs;
3876   HB_PosClassRule*  pr;
3877   HB_GDEFHeader*    gdef;
3878
3879
3880   gdef = gpos->gdef;
3881
3882   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3883     return error;
3884
3885   /* Note: The coverage table in format 2 doesn't give an index into
3886            anything.  It just lets us know whether or not we need to
3887            do any lookup at all.                                     */
3888
3889   error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3890   if ( error )
3891     return error;
3892
3893   if (cpf2->MaxContextLength < 1)
3894     return HB_Err_Not_Covered;
3895
3896   if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3897     return error;
3898
3899   error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3900                      &classes[0], NULL );
3901   if ( error && error != HB_Err_Not_Covered )
3902     goto End;
3903   known_classes = 0;
3904
3905   pcs = &cpf2->PosClassSet[classes[0]];
3906   if ( !pcs )
3907   {
3908     error = ERR(HB_Err_Invalid_SubTable);
3909     goto End;
3910   }
3911
3912   for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3913   {
3914     pr = &pcs->PosClassRule[k];
3915
3916     if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
3917       goto next_posclassrule;
3918
3919     if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
3920       goto next_posclassrule;                /* context is too long */
3921
3922     cl   = pr->Class;
3923
3924     /* Start at 1 because [0] is implied */
3925
3926     for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
3927     {
3928       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3929       {
3930         if ( error && error != HB_Err_Not_Covered )
3931           goto End;
3932
3933         if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3934           goto next_posclassrule;
3935         j++;
3936       }
3937
3938       if ( i > known_classes )
3939       {
3940         /* Keeps us from having to do this for each rule */
3941
3942         error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
3943         if ( error && error != HB_Err_Not_Covered )
3944           goto End;
3945         known_classes = i;
3946       }
3947
3948       if ( cl[i - 1] != classes[i] )
3949         goto next_posclassrule;
3950     }
3951
3952     error = Do_ContextPos( gpi, pr->GlyphCount,
3953                            pr->PosCount, pr->PosLookupRecord,
3954                            buffer,
3955                            nesting_level );
3956     goto End;
3957
3958   next_posclassrule:
3959     ;
3960   }
3961
3962   error = HB_Err_Not_Covered;
3963
3964 End:
3965   FREE( classes );
3966   return error;
3967 }
3968
3969
3970 static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
3971                                      HB_ContextPosFormat3*  cpf3,
3972                                      HB_Buffer              buffer,
3973                                      HB_UShort               flags,
3974                                      HB_UShort               context_length,
3975                                      int                     nesting_level )
3976 {
3977   HB_Error         error;
3978   HB_UShort        index, i, j, property;
3979   HB_GPOSHeader*  gpos = gpi->gpos;
3980
3981   HB_Coverage*    c;
3982   HB_GDEFHeader*  gdef;
3983
3984
3985   gdef = gpos->gdef;
3986
3987   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3988     return error;
3989
3990   if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
3991     return HB_Err_Not_Covered;
3992
3993   if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
3994     return HB_Err_Not_Covered;         /* context is too long */
3995
3996   c    = cpf3->Coverage;
3997
3998   for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
3999   {
4000     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
4001     {
4002       if ( error && error != HB_Err_Not_Covered )
4003         return error;
4004
4005       if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
4006         return HB_Err_Not_Covered;
4007       j++;
4008     }
4009
4010     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4011     if ( error )
4012       return error;
4013   }
4014
4015   return Do_ContextPos( gpi, cpf3->GlyphCount,
4016                         cpf3->PosCount, cpf3->PosLookupRecord,
4017                         buffer,
4018                         nesting_level );
4019 }
4020
4021
4022 static HB_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
4023                                     HB_GPOS_SubTable* st,
4024                                     HB_Buffer        buffer,
4025                                     HB_UShort         flags,
4026                                     HB_UShort         context_length,
4027                                     int               nesting_level )
4028 {
4029   HB_ContextPos*   cp = &st->context;
4030
4031   switch ( cp->PosFormat )
4032   {
4033   case 1:
4034     return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4035                                flags, context_length, nesting_level );
4036
4037   case 2:
4038     return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4039                                flags, context_length, nesting_level );
4040
4041   case 3:
4042     return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4043                                flags, context_length, nesting_level );
4044
4045   default:
4046     return ERR(HB_Err_Invalid_SubTable_Format);
4047   }
4048
4049   return HB_Err_Ok;               /* never reached */
4050 }
4051
4052
4053 /* LookupType 8 */
4054
4055 /* ChainPosRule */
4056
4057 static HB_Error  Load_ChainPosRule( HB_ChainPosRule*  cpr,
4058                                     HB_Stream          stream )
4059 {
4060   HB_Error  error;
4061
4062   HB_UShort             n, count;
4063   HB_UShort*            b;
4064   HB_UShort*            i;
4065   HB_UShort*            l;
4066
4067   HB_PosLookupRecord*  plr;
4068
4069
4070   if ( ACCESS_Frame( 2L ) )
4071     return error;
4072
4073   cpr->BacktrackGlyphCount = GET_UShort();
4074
4075   FORGET_Frame();
4076
4077   cpr->Backtrack = NULL;
4078
4079   count = cpr->BacktrackGlyphCount;
4080
4081   if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4082     return error;
4083
4084   b = cpr->Backtrack;
4085
4086   if ( ACCESS_Frame( count * 2L ) )
4087     goto Fail4;
4088
4089   for ( n = 0; n < count; n++ )
4090     b[n] = GET_UShort();
4091
4092   FORGET_Frame();
4093
4094   if ( ACCESS_Frame( 2L ) )
4095     goto Fail4;
4096
4097   cpr->InputGlyphCount = GET_UShort();
4098
4099   FORGET_Frame();
4100
4101   cpr->Input = NULL;
4102
4103   count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
4104
4105   if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4106     goto Fail4;
4107
4108   i = cpr->Input;
4109
4110   if ( ACCESS_Frame( count * 2L ) )
4111     goto Fail3;
4112
4113   for ( n = 0; n < count; n++ )
4114     i[n] = GET_UShort();
4115
4116   FORGET_Frame();
4117
4118   if ( ACCESS_Frame( 2L ) )
4119     goto Fail3;
4120
4121   cpr->LookaheadGlyphCount = GET_UShort();
4122
4123   FORGET_Frame();
4124
4125   cpr->Lookahead = NULL;
4126
4127   count = cpr->LookaheadGlyphCount;
4128
4129   if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4130     goto Fail3;
4131
4132   l = cpr->Lookahead;
4133
4134   if ( ACCESS_Frame( count * 2L ) )
4135     goto Fail2;
4136
4137   for ( n = 0; n < count; n++ )
4138     l[n] = GET_UShort();
4139
4140   FORGET_Frame();
4141
4142   if ( ACCESS_Frame( 2L ) )
4143     goto Fail2;
4144
4145   cpr->PosCount = GET_UShort();
4146
4147   FORGET_Frame();
4148
4149   cpr->PosLookupRecord = NULL;
4150
4151   count = cpr->PosCount;
4152
4153   if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4154     goto Fail2;
4155
4156   plr = cpr->PosLookupRecord;
4157
4158   if ( ACCESS_Frame( count * 4L ) )
4159     goto Fail1;
4160
4161   for ( n = 0; n < count; n++ )
4162   {
4163     plr[n].SequenceIndex   = GET_UShort();
4164     plr[n].LookupListIndex = GET_UShort();
4165   }
4166
4167   FORGET_Frame();
4168
4169   return HB_Err_Ok;
4170
4171 Fail1:
4172   FREE( plr );
4173
4174 Fail2:
4175   FREE( l );
4176
4177 Fail3:
4178   FREE( i );
4179
4180 Fail4:
4181   FREE( b );
4182   return error;
4183 }
4184
4185
4186 static void  Free_ChainPosRule( HB_ChainPosRule*  cpr )
4187 {
4188   FREE( cpr->PosLookupRecord );
4189   FREE( cpr->Lookahead );
4190   FREE( cpr->Input );
4191   FREE( cpr->Backtrack );
4192 }
4193
4194
4195 /* ChainPosRuleSet */
4196
4197 static HB_Error  Load_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
4198                                        HB_Stream             stream )
4199 {
4200   HB_Error  error;
4201
4202   HB_UShort          n, m, count;
4203   HB_UInt           cur_offset, new_offset, base_offset;
4204
4205   HB_ChainPosRule*  cpr;
4206
4207
4208   base_offset = FILE_Pos();
4209
4210   if ( ACCESS_Frame( 2L ) )
4211     return error;
4212
4213   count = cprs->ChainPosRuleCount = GET_UShort();
4214
4215   FORGET_Frame();
4216
4217   cprs->ChainPosRule = NULL;
4218
4219   if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4220     return error;
4221
4222   cpr = cprs->ChainPosRule;
4223
4224   for ( n = 0; n < count; n++ )
4225   {
4226     if ( ACCESS_Frame( 2L ) )
4227       goto Fail;
4228
4229     new_offset = GET_UShort() + base_offset;
4230
4231     FORGET_Frame();
4232
4233     cur_offset = FILE_Pos();
4234     if ( FILE_Seek( new_offset ) ||
4235          ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4236       goto Fail;
4237     (void)FILE_Seek( cur_offset );
4238   }
4239
4240   return HB_Err_Ok;
4241
4242 Fail:
4243   for ( m = 0; m < n; m++ )
4244     Free_ChainPosRule( &cpr[m] );
4245
4246   FREE( cpr );
4247   return error;
4248 }
4249
4250
4251 static void  Free_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs )
4252 {
4253   HB_UShort          n, count;
4254
4255   HB_ChainPosRule*  cpr;
4256
4257
4258   if ( cprs->ChainPosRule )
4259   {
4260     count = cprs->ChainPosRuleCount;
4261     cpr   = cprs->ChainPosRule;
4262
4263     for ( n = 0; n < count; n++ )
4264       Free_ChainPosRule( &cpr[n] );
4265
4266     FREE( cpr );
4267   }
4268 }
4269
4270
4271 /* ChainContextPosFormat1 */
4272
4273 static HB_Error  Load_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
4274                                         HB_Stream                    stream )
4275 {
4276   HB_Error  error;
4277
4278   HB_UShort             n, m, count;
4279   HB_UInt              cur_offset, new_offset, base_offset;
4280
4281   HB_ChainPosRuleSet*  cprs;
4282
4283
4284   base_offset = FILE_Pos() - 2L;
4285
4286   if ( ACCESS_Frame( 2L ) )
4287     return error;
4288
4289   new_offset = GET_UShort() + base_offset;
4290
4291   FORGET_Frame();
4292
4293   cur_offset = FILE_Pos();
4294   if ( FILE_Seek( new_offset ) ||
4295        ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4296     return error;
4297   (void)FILE_Seek( cur_offset );
4298
4299   if ( ACCESS_Frame( 2L ) )
4300     goto Fail2;
4301
4302   count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4303
4304   FORGET_Frame();
4305
4306   ccpf1->ChainPosRuleSet = NULL;
4307
4308   if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4309     goto Fail2;
4310
4311   cprs = ccpf1->ChainPosRuleSet;
4312
4313   for ( n = 0; n < count; n++ )
4314   {
4315     if ( ACCESS_Frame( 2L ) )
4316       goto Fail1;
4317
4318     new_offset = GET_UShort() + base_offset;
4319
4320     FORGET_Frame();
4321
4322     cur_offset = FILE_Pos();
4323     if ( FILE_Seek( new_offset ) ||
4324          ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4325       goto Fail1;
4326     (void)FILE_Seek( cur_offset );
4327   }
4328
4329   return HB_Err_Ok;
4330
4331 Fail1:
4332   for ( m = 0; m < n; m++ )
4333     Free_ChainPosRuleSet( &cprs[m] );
4334
4335   FREE( cprs );
4336
4337 Fail2:
4338   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4339   return error;
4340 }
4341
4342
4343 static void  Free_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1 )
4344 {
4345   HB_UShort             n, count;
4346
4347   HB_ChainPosRuleSet*  cprs;
4348
4349
4350   if ( ccpf1->ChainPosRuleSet )
4351   {
4352     count = ccpf1->ChainPosRuleSetCount;
4353     cprs  = ccpf1->ChainPosRuleSet;
4354
4355     for ( n = 0; n < count; n++ )
4356       Free_ChainPosRuleSet( &cprs[n] );
4357
4358     FREE( cprs );
4359   }
4360
4361   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4362 }
4363
4364
4365 /* ChainPosClassRule */
4366
4367 static HB_Error  Load_ChainPosClassRule(
4368                    HB_ChainContextPosFormat2*  ccpf2,
4369                    HB_ChainPosClassRule*       cpcr,
4370                    HB_Stream                    stream )
4371 {
4372   HB_Error  error;
4373
4374   HB_UShort             n, count;
4375
4376   HB_UShort*            b;
4377   HB_UShort*            i;
4378   HB_UShort*            l;
4379   HB_PosLookupRecord*  plr;
4380
4381
4382   if ( ACCESS_Frame( 2L ) )
4383     return error;
4384
4385   cpcr->BacktrackGlyphCount = GET_UShort();
4386
4387   FORGET_Frame();
4388
4389   if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4390     ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4391
4392   cpcr->Backtrack = NULL;
4393
4394   count = cpcr->BacktrackGlyphCount;
4395
4396   if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
4397     return error;
4398
4399   b = cpcr->Backtrack;
4400
4401   if ( ACCESS_Frame( count * 2L ) )
4402     goto Fail4;
4403
4404   for ( n = 0; n < count; n++ )
4405     b[n] = GET_UShort();
4406
4407   FORGET_Frame();
4408
4409   if ( ACCESS_Frame( 2L ) )
4410     goto Fail4;
4411
4412   cpcr->InputGlyphCount = GET_UShort();
4413
4414   if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4415     ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4416
4417   FORGET_Frame();
4418
4419   cpcr->Input = NULL;
4420
4421   count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4422
4423   if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4424     goto Fail4;
4425
4426   i = cpcr->Input;
4427
4428   if ( ACCESS_Frame( count * 2L ) )
4429     goto Fail3;
4430
4431   for ( n = 0; n < count; n++ )
4432     i[n] = GET_UShort();
4433
4434   FORGET_Frame();
4435
4436   if ( ACCESS_Frame( 2L ) )
4437     goto Fail3;
4438
4439   cpcr->LookaheadGlyphCount = GET_UShort();
4440
4441   FORGET_Frame();
4442
4443   if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4444     ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4445
4446   cpcr->Lookahead = NULL;
4447
4448   count = cpcr->LookaheadGlyphCount;
4449
4450   if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
4451     goto Fail3;
4452
4453   l = cpcr->Lookahead;
4454
4455   if ( ACCESS_Frame( count * 2L ) )
4456     goto Fail2;
4457
4458   for ( n = 0; n < count; n++ )
4459     l[n] = GET_UShort();
4460
4461   FORGET_Frame();
4462
4463   if ( ACCESS_Frame( 2L ) )
4464     goto Fail2;
4465
4466   cpcr->PosCount = GET_UShort();
4467
4468   FORGET_Frame();
4469
4470   cpcr->PosLookupRecord = NULL;
4471
4472   count = cpcr->PosCount;
4473
4474   if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4475     goto Fail2;
4476
4477   plr = cpcr->PosLookupRecord;
4478
4479   if ( ACCESS_Frame( count * 4L ) )
4480     goto Fail1;
4481
4482   for ( n = 0; n < count; n++ )
4483   {
4484     plr[n].SequenceIndex   = GET_UShort();
4485     plr[n].LookupListIndex = GET_UShort();
4486   }
4487
4488   FORGET_Frame();
4489
4490   return HB_Err_Ok;
4491
4492 Fail1:
4493   FREE( plr );
4494
4495 Fail2:
4496   FREE( l );
4497
4498 Fail3:
4499   FREE( i );
4500
4501 Fail4:
4502   FREE( b );
4503   return error;
4504 }
4505
4506
4507 static void  Free_ChainPosClassRule( HB_ChainPosClassRule*  cpcr )
4508 {
4509   FREE( cpcr->PosLookupRecord );
4510   FREE( cpcr->Lookahead );
4511   FREE( cpcr->Input );
4512   FREE( cpcr->Backtrack );
4513 }
4514
4515
4516 /* PosClassSet */
4517
4518 static HB_Error  Load_ChainPosClassSet(
4519                    HB_ChainContextPosFormat2*  ccpf2,
4520                    HB_ChainPosClassSet*        cpcs,
4521                    HB_Stream                    stream )
4522 {
4523   HB_Error  error;
4524
4525   HB_UShort               n, m, count;
4526   HB_UInt                cur_offset, new_offset, base_offset;
4527
4528   HB_ChainPosClassRule*  cpcr;
4529
4530
4531   base_offset = FILE_Pos();
4532
4533   if ( ACCESS_Frame( 2L ) )
4534     return error;
4535
4536   count = cpcs->ChainPosClassRuleCount = GET_UShort();
4537
4538   FORGET_Frame();
4539
4540   cpcs->ChainPosClassRule = NULL;
4541
4542   if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4543                     HB_ChainPosClassRule ) )
4544     return error;
4545
4546   cpcr = cpcs->ChainPosClassRule;
4547
4548   for ( n = 0; n < count; n++ )
4549   {
4550     if ( ACCESS_Frame( 2L ) )
4551       goto Fail;
4552
4553     new_offset = GET_UShort() + base_offset;
4554
4555     FORGET_Frame();
4556
4557     cur_offset = FILE_Pos();
4558     if ( FILE_Seek( new_offset ) ||
4559          ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4560                                            stream ) ) != HB_Err_Ok )
4561       goto Fail;
4562     (void)FILE_Seek( cur_offset );
4563   }
4564
4565   return HB_Err_Ok;
4566
4567 Fail:
4568   for ( m = 0; m < n; m++ )
4569     Free_ChainPosClassRule( &cpcr[m] );
4570
4571   FREE( cpcr );
4572   return error;
4573 }
4574
4575
4576 static void  Free_ChainPosClassSet( HB_ChainPosClassSet*  cpcs )
4577 {
4578   HB_UShort               n, count;
4579
4580   HB_ChainPosClassRule*  cpcr;
4581
4582
4583   if ( cpcs->ChainPosClassRule )
4584   {
4585     count = cpcs->ChainPosClassRuleCount;
4586     cpcr  = cpcs->ChainPosClassRule;
4587
4588     for ( n = 0; n < count; n++ )
4589       Free_ChainPosClassRule( &cpcr[n] );
4590
4591     FREE( cpcr );
4592   }
4593 }
4594
4595
4596 /* ChainContextPosFormat2 */
4597
4598 static HB_Error  Load_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
4599                                         HB_Stream                    stream )
4600 {
4601   HB_Error  error;
4602
4603   HB_UShort              n, m, count;
4604   HB_UInt               cur_offset, new_offset, base_offset;
4605   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
4606
4607   HB_ChainPosClassSet*  cpcs;
4608
4609
4610   base_offset = FILE_Pos() - 2;
4611
4612   if ( ACCESS_Frame( 2L ) )
4613     return error;
4614
4615   new_offset = GET_UShort() + base_offset;
4616
4617   FORGET_Frame();
4618
4619   cur_offset = FILE_Pos();
4620   if ( FILE_Seek( new_offset ) ||
4621        ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4622     return error;
4623   (void)FILE_Seek( cur_offset );
4624
4625   if ( ACCESS_Frame( 8L ) )
4626     goto Fail5;
4627
4628   backtrack_offset = GET_UShort();
4629   input_offset     = GET_UShort();
4630   lookahead_offset = GET_UShort();
4631
4632   /* `ChainPosClassSetCount' is the upper limit for input class values,
4633      thus we read it now to make an additional safety check. No limit
4634      is known or needed for the other two class definitions          */
4635
4636   count = ccpf2->ChainPosClassSetCount = GET_UShort();
4637
4638   FORGET_Frame();
4639
4640   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4641                                                        backtrack_offset, base_offset,
4642                                                        stream ) ) != HB_Err_Ok )
4643     goto Fail5;
4644   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4645                                                        input_offset, base_offset,
4646                                                        stream ) ) != HB_Err_Ok )
4647     goto Fail4;
4648   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4649                                                        lookahead_offset, base_offset,
4650                                                        stream ) ) != HB_Err_Ok )
4651     goto Fail3;
4652
4653   ccpf2->ChainPosClassSet   = NULL;
4654   ccpf2->MaxBacktrackLength = 0;
4655   ccpf2->MaxInputLength     = 0;
4656   ccpf2->MaxLookaheadLength = 0;
4657
4658   if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4659     goto Fail2;
4660
4661   cpcs = ccpf2->ChainPosClassSet;
4662
4663   for ( n = 0; n < count; n++ )
4664   {
4665     if ( ACCESS_Frame( 2L ) )
4666       goto Fail1;
4667
4668     new_offset = GET_UShort() + base_offset;
4669
4670     FORGET_Frame();
4671
4672     if ( new_offset != base_offset )      /* not a NULL offset */
4673     {
4674       cur_offset = FILE_Pos();
4675       if ( FILE_Seek( new_offset ) ||
4676            ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4677                                             stream ) ) != HB_Err_Ok )
4678         goto Fail1;
4679       (void)FILE_Seek( cur_offset );
4680     }
4681     else
4682     {
4683       /* we create a ChainPosClassSet table with no entries */
4684
4685       ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4686       ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
4687     }
4688   }
4689
4690   return HB_Err_Ok;
4691
4692 Fail1:
4693   for ( m = 0; m < n; m++ )
4694     Free_ChainPosClassSet( &cpcs[m] );
4695
4696   FREE( cpcs );
4697
4698 Fail2:
4699   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4700
4701 Fail3:
4702   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4703
4704 Fail4:
4705   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4706
4707 Fail5:
4708   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4709   return error;
4710 }
4711
4712
4713 static void  Free_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2 )
4714 {
4715   HB_UShort              n, count;
4716
4717   HB_ChainPosClassSet*  cpcs;
4718
4719
4720   if ( ccpf2->ChainPosClassSet )
4721   {
4722     count = ccpf2->ChainPosClassSetCount;
4723     cpcs  = ccpf2->ChainPosClassSet;
4724
4725     for ( n = 0; n < count; n++ )
4726       Free_ChainPosClassSet( &cpcs[n] );
4727
4728     FREE( cpcs );
4729   }
4730
4731   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4732   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4733   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4734
4735   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4736 }
4737
4738
4739 /* ChainContextPosFormat3 */
4740
4741 static HB_Error  Load_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
4742                                         HB_Stream                    stream )
4743 {
4744   HB_Error  error;
4745
4746   HB_UShort             n, nb, ni, nl, m, count;
4747   HB_UShort             backtrack_count, input_count, lookahead_count;
4748   HB_UInt              cur_offset, new_offset, base_offset;
4749
4750   HB_Coverage*         b;
4751   HB_Coverage*         i;
4752   HB_Coverage*         l;
4753   HB_PosLookupRecord*  plr;
4754
4755
4756   base_offset = FILE_Pos() - 2L;
4757
4758   if ( ACCESS_Frame( 2L ) )
4759     return error;
4760
4761   ccpf3->BacktrackGlyphCount = GET_UShort();
4762
4763   FORGET_Frame();
4764
4765   ccpf3->BacktrackCoverage = NULL;
4766
4767   backtrack_count = ccpf3->BacktrackGlyphCount;
4768
4769   if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4770                     HB_Coverage ) )
4771     return error;
4772
4773   b = ccpf3->BacktrackCoverage;
4774
4775   for ( nb = 0; nb < backtrack_count; nb++ )
4776   {
4777     if ( ACCESS_Frame( 2L ) )
4778       goto Fail4;
4779
4780     new_offset = GET_UShort() + base_offset;
4781
4782     FORGET_Frame();
4783
4784     cur_offset = FILE_Pos();
4785     if ( FILE_Seek( new_offset ) ||
4786          ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4787       goto Fail4;
4788     (void)FILE_Seek( cur_offset );
4789   }
4790
4791   if ( ACCESS_Frame( 2L ) )
4792     goto Fail4;
4793
4794   ccpf3->InputGlyphCount = GET_UShort();
4795
4796   FORGET_Frame();
4797
4798   ccpf3->InputCoverage = NULL;
4799
4800   input_count = ccpf3->InputGlyphCount;
4801
4802   if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4803     goto Fail4;
4804
4805   i = ccpf3->InputCoverage;
4806
4807   for ( ni = 0; ni < input_count; ni++ )
4808   {
4809     if ( ACCESS_Frame( 2L ) )
4810       goto Fail3;
4811
4812     new_offset = GET_UShort() + base_offset;
4813
4814     FORGET_Frame();
4815
4816     cur_offset = FILE_Pos();
4817     if ( FILE_Seek( new_offset ) ||
4818          ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4819       goto Fail3;
4820     (void)FILE_Seek( cur_offset );
4821   }
4822
4823   if ( ACCESS_Frame( 2L ) )
4824     goto Fail3;
4825
4826   ccpf3->LookaheadGlyphCount = GET_UShort();
4827
4828   FORGET_Frame();
4829
4830   ccpf3->LookaheadCoverage = NULL;
4831
4832   lookahead_count = ccpf3->LookaheadGlyphCount;
4833
4834   if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4835                     HB_Coverage ) )
4836     goto Fail3;
4837
4838   l = ccpf3->LookaheadCoverage;
4839
4840   for ( nl = 0; nl < lookahead_count; nl++ )
4841   {
4842     if ( ACCESS_Frame( 2L ) )
4843       goto Fail2;
4844
4845     new_offset = GET_UShort() + base_offset;
4846
4847     FORGET_Frame();
4848
4849     cur_offset = FILE_Pos();
4850     if ( FILE_Seek( new_offset ) ||
4851          ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4852       goto Fail2;
4853     (void)FILE_Seek( cur_offset );
4854   }
4855
4856   if ( ACCESS_Frame( 2L ) )
4857     goto Fail2;
4858
4859   ccpf3->PosCount = GET_UShort();
4860
4861   FORGET_Frame();
4862
4863   ccpf3->PosLookupRecord = NULL;
4864
4865   count = ccpf3->PosCount;
4866
4867   if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4868     goto Fail2;
4869
4870   plr = ccpf3->PosLookupRecord;
4871
4872   if ( ACCESS_Frame( count * 4L ) )
4873     goto Fail1;
4874
4875   for ( n = 0; n < count; n++ )
4876   {
4877     plr[n].SequenceIndex   = GET_UShort();
4878     plr[n].LookupListIndex = GET_UShort();
4879   }
4880
4881   FORGET_Frame();
4882
4883   return HB_Err_Ok;
4884
4885 Fail1:
4886   FREE( plr );
4887
4888 Fail2:
4889   for ( m = 0; m < nl; m++ )
4890     _HB_OPEN_Free_Coverage( &l[m] );
4891
4892   FREE( l );
4893
4894 Fail3:
4895   for ( m = 0; m < ni; m++ )
4896     _HB_OPEN_Free_Coverage( &i[m] );
4897
4898   FREE( i );
4899
4900 Fail4:
4901   for ( m = 0; m < nb; m++ )
4902     _HB_OPEN_Free_Coverage( &b[m] );
4903
4904   FREE( b );
4905   return error;
4906 }
4907
4908
4909 static void  Free_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3 )
4910 {
4911   HB_UShort      n, count;
4912
4913   HB_Coverage*  c;
4914
4915
4916   FREE( ccpf3->PosLookupRecord );
4917
4918   if ( ccpf3->LookaheadCoverage )
4919   {
4920     count = ccpf3->LookaheadGlyphCount;
4921     c     = ccpf3->LookaheadCoverage;
4922
4923     for ( n = 0; n < count; n++ )
4924       _HB_OPEN_Free_Coverage( &c[n] );
4925
4926     FREE( c );
4927   }
4928
4929   if ( ccpf3->InputCoverage )
4930   {
4931     count = ccpf3->InputGlyphCount;
4932     c     = ccpf3->InputCoverage;
4933
4934     for ( n = 0; n < count; n++ )
4935       _HB_OPEN_Free_Coverage( &c[n] );
4936
4937     FREE( c );
4938   }
4939
4940   if ( ccpf3->BacktrackCoverage )
4941   {
4942     count = ccpf3->BacktrackGlyphCount;
4943     c     = ccpf3->BacktrackCoverage;
4944
4945     for ( n = 0; n < count; n++ )
4946       _HB_OPEN_Free_Coverage( &c[n] );
4947
4948     FREE( c );
4949   }
4950 }
4951
4952
4953 /* ChainContextPos */
4954
4955 static HB_Error  Load_ChainContextPos( HB_GPOS_SubTable* st,
4956                                        HB_Stream             stream )
4957 {
4958   HB_Error  error;
4959   HB_ChainContextPos*  ccp = &st->chain;
4960
4961
4962   if ( ACCESS_Frame( 2L ) )
4963     return error;
4964
4965   ccp->PosFormat = GET_UShort();
4966
4967   FORGET_Frame();
4968
4969   switch ( ccp->PosFormat )
4970   {
4971   case 1:
4972     return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
4973
4974   case 2:
4975     return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
4976
4977   case 3:
4978     return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
4979
4980   default:
4981     return ERR(HB_Err_Invalid_SubTable_Format);
4982   }
4983
4984   return HB_Err_Ok;               /* never reached */
4985 }
4986
4987
4988 static void  Free_ChainContextPos( HB_GPOS_SubTable* st )
4989 {
4990   HB_ChainContextPos*  ccp = &st->chain;
4991
4992   switch ( ccp->PosFormat )
4993   {
4994   case 1:  Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
4995   case 2:  Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
4996   case 3:  Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
4997   default:                                                    break;
4998   }
4999 }
5000
5001
5002 static HB_Error  Lookup_ChainContextPos1(
5003                    GPOS_Instance*               gpi,
5004                    HB_ChainContextPosFormat1*  ccpf1,
5005                    HB_Buffer                   buffer,
5006                    HB_UShort                    flags,
5007                    HB_UShort                    context_length,
5008                    int                          nesting_level )
5009 {
5010   HB_UShort          index, property;
5011   HB_UShort          i, j, k, num_cpr;
5012   HB_UShort          bgc, igc, lgc;
5013   HB_Error           error;
5014   HB_GPOSHeader*    gpos = gpi->gpos;
5015
5016   HB_ChainPosRule*  cpr;
5017   HB_ChainPosRule   curr_cpr;
5018   HB_GDEFHeader*    gdef;
5019
5020
5021   gdef = gpos->gdef;
5022
5023   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5024     return error;
5025
5026   error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5027   if ( error )
5028     return error;
5029
5030   cpr     = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5031   num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5032
5033   for ( k = 0; k < num_cpr; k++ )
5034   {
5035     curr_cpr = cpr[k];
5036     bgc      = curr_cpr.BacktrackGlyphCount;
5037     igc      = curr_cpr.InputGlyphCount;
5038     lgc      = curr_cpr.LookaheadGlyphCount;
5039
5040     if ( context_length != 0xFFFF && context_length < igc )
5041       goto next_chainposrule;
5042
5043     /* check whether context is too long; it is a first guess only */
5044
5045     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5046       goto next_chainposrule;
5047
5048     if ( bgc )
5049     {
5050       /* Since we don't know in advance the number of glyphs to inspect,
5051          we search backwards for matches in the backtrack glyph array    */
5052
5053       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5054       {
5055         while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5056         {
5057           if ( error && error != HB_Err_Not_Covered )
5058             return error;
5059
5060           if ( j + 1 == bgc - i )
5061             goto next_chainposrule;
5062           j--;
5063         }
5064
5065         /* In OpenType 1.3, it is undefined whether the offsets of
5066            backtrack glyphs is in logical order or not.  Version 1.4
5067            will clarify this:
5068
5069              Logical order -      a  b  c  d  e  f  g  h  i  j
5070                                               i
5071              Input offsets -                  0  1
5072              Backtrack offsets -  3  2  1  0
5073              Lookahead offsets -                    0  1  2  3           */
5074
5075         if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5076           goto next_chainposrule;
5077       }
5078     }
5079
5080     /* Start at 1 because [0] is implied */
5081
5082     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5083     {
5084       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5085       {
5086         if ( error && error != HB_Err_Not_Covered )
5087           return error;
5088
5089         if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5090           goto next_chainposrule;
5091         j++;
5092       }
5093
5094       if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5095         goto next_chainposrule;
5096     }
5097
5098     /* we are starting to check for lookahead glyphs right after the
5099        last context glyph                                            */
5100
5101     for ( i = 0; i < lgc; i++, j++ )
5102     {
5103       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5104       {
5105         if ( error && error != HB_Err_Not_Covered )
5106           return error;
5107
5108         if ( j + lgc - i == (HB_Int)buffer->in_length )
5109           goto next_chainposrule;
5110         j++;
5111       }
5112
5113       if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5114         goto next_chainposrule;
5115     }
5116
5117     return Do_ContextPos( gpi, igc,
5118                           curr_cpr.PosCount,
5119                           curr_cpr.PosLookupRecord,
5120                           buffer,
5121                           nesting_level );
5122
5123   next_chainposrule:
5124     ;
5125   }
5126
5127   return HB_Err_Not_Covered;
5128 }
5129
5130
5131 static HB_Error  Lookup_ChainContextPos2(
5132                    GPOS_Instance*               gpi,
5133                    HB_ChainContextPosFormat2*  ccpf2,
5134                    HB_Buffer                   buffer,
5135                    HB_UShort                    flags,
5136                    HB_UShort                    context_length,
5137                    int                          nesting_level )
5138 {
5139   HB_UShort              index, property;
5140   HB_Error               error;
5141   HB_UShort              i, j, k;
5142   HB_UShort              bgc, igc, lgc;
5143   HB_UShort              known_backtrack_classes,
5144                          known_input_classes,
5145                          known_lookahead_classes;
5146
5147   HB_UShort*             backtrack_classes;
5148   HB_UShort*             input_classes;
5149   HB_UShort*             lookahead_classes;
5150
5151   HB_UShort*             bc;
5152   HB_UShort*             ic;
5153   HB_UShort*             lc;
5154   HB_GPOSHeader*        gpos = gpi->gpos;
5155
5156   HB_ChainPosClassSet*  cpcs;
5157   HB_ChainPosClassRule  cpcr;
5158   HB_GDEFHeader*        gdef;
5159
5160
5161   gdef = gpos->gdef;
5162
5163   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5164     return error;
5165
5166   /* Note: The coverage table in format 2 doesn't give an index into
5167            anything.  It just lets us know whether or not we need to
5168            do any lookup at all.                                     */
5169
5170   error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5171   if ( error )
5172     return error;
5173
5174   if (ccpf2->MaxInputLength < 1)
5175     return HB_Err_Not_Covered;
5176
5177   if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5178     return error;
5179   known_backtrack_classes = 0;
5180
5181   if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5182     goto End3;
5183   known_input_classes = 1;
5184
5185   if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5186     goto End2;
5187   known_lookahead_classes = 0;
5188
5189   error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5190                      &input_classes[0], NULL );
5191   if ( error && error != HB_Err_Not_Covered )
5192     goto End1;
5193
5194   cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5195   if ( !cpcs )
5196   {
5197     error = ERR(HB_Err_Invalid_SubTable);
5198     goto End1;
5199   }
5200
5201   for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5202   {
5203     cpcr = cpcs->ChainPosClassRule[k];
5204     bgc  = cpcr.BacktrackGlyphCount;
5205     igc  = cpcr.InputGlyphCount;
5206     lgc  = cpcr.LookaheadGlyphCount;
5207
5208     if ( context_length != 0xFFFF && context_length < igc )
5209       goto next_chainposclassrule;
5210
5211     /* check whether context is too long; it is a first guess only */
5212
5213     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5214       goto next_chainposclassrule;
5215
5216     if ( bgc )
5217     {
5218       /* Since we don't know in advance the number of glyphs to inspect,
5219          we search backwards for matches in the backtrack glyph array.
5220          Note that `known_backtrack_classes' starts at index 0.         */
5221
5222       bc       = cpcr.Backtrack;
5223
5224       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5225       {
5226         while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5227         {
5228           if ( error && error != HB_Err_Not_Covered )
5229             goto End1;
5230
5231           if ( j + 1 == bgc - i )
5232             goto next_chainposclassrule;
5233           j++;
5234         }
5235
5236         if ( i >= known_backtrack_classes )
5237         {
5238           /* Keeps us from having to do this for each rule */
5239
5240           error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5241                              &backtrack_classes[i], NULL );
5242           if ( error && error != HB_Err_Not_Covered )
5243             goto End1;
5244           known_backtrack_classes = i;
5245         }
5246
5247         if ( bc[i] != backtrack_classes[i] )
5248           goto next_chainposclassrule;
5249       }
5250     }
5251
5252     ic       = cpcr.Input;
5253
5254     /* Start at 1 because [0] is implied */
5255
5256     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5257     {
5258       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5259       {
5260         if ( error && error != HB_Err_Not_Covered )
5261           goto End1;
5262
5263         if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5264           goto next_chainposclassrule;
5265         j++;
5266       }
5267
5268       if ( i >= known_input_classes )
5269       {
5270         error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5271                            &input_classes[i], NULL );
5272         if ( error && error != HB_Err_Not_Covered )
5273           goto End1;
5274         known_input_classes = i;
5275       }
5276
5277       if ( ic[i - 1] != input_classes[i] )
5278         goto next_chainposclassrule;
5279     }
5280
5281     /* we are starting to check for lookahead glyphs right after the
5282        last context glyph                                            */
5283
5284     lc       = cpcr.Lookahead;
5285
5286     for ( i = 0; i < lgc; i++, j++ )
5287     {
5288       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5289       {
5290         if ( error && error != HB_Err_Not_Covered )
5291           goto End1;
5292
5293         if ( j + lgc - i == (HB_Int)buffer->in_length )
5294           goto next_chainposclassrule;
5295         j++;
5296       }
5297
5298       if ( i >= known_lookahead_classes )
5299       {
5300         error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5301                            &lookahead_classes[i], NULL );
5302         if ( error && error != HB_Err_Not_Covered )
5303           goto End1;
5304         known_lookahead_classes = i;
5305       }
5306
5307       if ( lc[i] != lookahead_classes[i] )
5308         goto next_chainposclassrule;
5309     }
5310
5311     error = Do_ContextPos( gpi, igc,
5312                            cpcr.PosCount,
5313                            cpcr.PosLookupRecord,
5314                            buffer,
5315                            nesting_level );
5316     goto End1;
5317
5318   next_chainposclassrule:
5319     ;
5320   }
5321
5322   error = HB_Err_Not_Covered;
5323
5324 End1:
5325   FREE( lookahead_classes );
5326
5327 End2:
5328   FREE( input_classes );
5329
5330 End3:
5331   FREE( backtrack_classes );
5332   return error;
5333 }
5334
5335
5336 static HB_Error  Lookup_ChainContextPos3(
5337                    GPOS_Instance*               gpi,
5338                    HB_ChainContextPosFormat3*  ccpf3,
5339                    HB_Buffer                   buffer,
5340                    HB_UShort                    flags,
5341                    HB_UShort                    context_length,
5342                    int                          nesting_level )
5343 {
5344   HB_UShort        index, i, j, property;
5345   HB_UShort        bgc, igc, lgc;
5346   HB_Error         error;
5347   HB_GPOSHeader*  gpos = gpi->gpos;
5348
5349   HB_Coverage*    bc;
5350   HB_Coverage*    ic;
5351   HB_Coverage*    lc;
5352   HB_GDEFHeader*  gdef;
5353
5354
5355   gdef = gpos->gdef;
5356
5357   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5358     return error;
5359
5360   bgc = ccpf3->BacktrackGlyphCount;
5361   igc = ccpf3->InputGlyphCount;
5362   lgc = ccpf3->LookaheadGlyphCount;
5363
5364   if ( context_length != 0xFFFF && context_length < igc )
5365     return HB_Err_Not_Covered;
5366
5367   /* check whether context is too long; it is a first guess only */
5368
5369   if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5370     return HB_Err_Not_Covered;
5371
5372   if ( bgc )
5373   {
5374     /* Since we don't know in advance the number of glyphs to inspect,
5375        we search backwards for matches in the backtrack glyph array    */
5376
5377     bc       = ccpf3->BacktrackCoverage;
5378
5379     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5380     {
5381       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5382       {
5383         if ( error && error != HB_Err_Not_Covered )
5384           return error;
5385
5386         if ( j + 1 == bgc - i )
5387           return HB_Err_Not_Covered;
5388         j--;
5389       }
5390
5391       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5392       if ( error )
5393         return error;
5394     }
5395   }
5396
5397   ic       = ccpf3->InputCoverage;
5398
5399   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5400   {
5401     /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5402     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5403     {
5404       if ( error && error != HB_Err_Not_Covered )
5405         return error;
5406
5407       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5408         return HB_Err_Not_Covered;
5409       j++;
5410     }
5411
5412     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5413     if ( error )
5414       return error;
5415   }
5416
5417   /* we are starting to check for lookahead glyphs right after the
5418      last context glyph                                            */
5419
5420   lc       = ccpf3->LookaheadCoverage;
5421
5422   for ( i = 0; i < lgc; i++, j++ )
5423   {
5424     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5425     {
5426       if ( error && error != HB_Err_Not_Covered )
5427         return error;
5428
5429       if ( j + lgc - i == (HB_Int)buffer->in_length )
5430         return HB_Err_Not_Covered;
5431       j++;
5432     }
5433
5434     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5435     if ( error )
5436       return error;
5437   }
5438
5439   return Do_ContextPos( gpi, igc,
5440                         ccpf3->PosCount,
5441                         ccpf3->PosLookupRecord,
5442                         buffer,
5443                         nesting_level );
5444 }
5445
5446
5447 static HB_Error  Lookup_ChainContextPos(
5448                    GPOS_Instance*        gpi,
5449                    HB_GPOS_SubTable* st,
5450                    HB_Buffer            buffer,
5451                    HB_UShort             flags,
5452                    HB_UShort             context_length,
5453                    int                   nesting_level )
5454 {
5455   HB_ChainContextPos*  ccp = &st->chain;
5456
5457   switch ( ccp->PosFormat )
5458   {
5459   case 1:
5460     return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5461                                     flags, context_length,
5462                                     nesting_level );
5463
5464   case 2:
5465     return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5466                                     flags, context_length,
5467                                     nesting_level );
5468
5469   case 3:
5470     return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5471                                     flags, context_length,
5472                                     nesting_level );
5473
5474   default:
5475     return ERR(HB_Err_Invalid_SubTable_Format);
5476   }
5477
5478   return HB_Err_Ok;               /* never reached */
5479 }
5480
5481
5482
5483 /***********
5484  * GPOS API
5485  ***********/
5486
5487
5488
5489 HB_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
5490                                  HB_UInt         script_tag,
5491                                  HB_UShort*       script_index )
5492 {
5493   HB_UShort          n;
5494
5495   HB_ScriptList*    sl;
5496   HB_ScriptRecord*  sr;
5497
5498
5499   if ( !gpos || !script_index )
5500     return ERR(HB_Err_Invalid_Argument);
5501
5502   sl = &gpos->ScriptList;
5503   sr = sl->ScriptRecord;
5504
5505   for ( n = 0; n < sl->ScriptCount; n++ )
5506     if ( script_tag == sr[n].ScriptTag )
5507     {
5508       *script_index = n;
5509
5510       return HB_Err_Ok;
5511     }
5512
5513   return HB_Err_Not_Covered;
5514 }
5515
5516
5517
5518 HB_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
5519                                    HB_UInt         language_tag,
5520                                    HB_UShort        script_index,
5521                                    HB_UShort*       language_index,
5522                                    HB_UShort*       req_feature_index )
5523 {
5524   HB_UShort           n;
5525
5526   HB_ScriptList*     sl;
5527   HB_ScriptRecord*   sr;
5528   HB_ScriptTable*         s;
5529   HB_LangSysRecord*  lsr;
5530
5531
5532   if ( !gpos || !language_index || !req_feature_index )
5533     return ERR(HB_Err_Invalid_Argument);
5534
5535   sl = &gpos->ScriptList;
5536   sr = sl->ScriptRecord;
5537
5538   if ( script_index >= sl->ScriptCount )
5539     return ERR(HB_Err_Invalid_Argument);
5540
5541   s   = &sr[script_index].Script;
5542   lsr = s->LangSysRecord;
5543
5544   for ( n = 0; n < s->LangSysCount; n++ )
5545     if ( language_tag == lsr[n].LangSysTag )
5546     {
5547       *language_index = n;
5548       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5549
5550       return HB_Err_Ok;
5551     }
5552
5553   return HB_Err_Not_Covered;
5554 }
5555
5556
5557 /* selecting 0xFFFF for language_index asks for the values of the
5558    default language (DefaultLangSys)                              */
5559
5560
5561 HB_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
5562                                   HB_UInt         feature_tag,
5563                                   HB_UShort        script_index,
5564                                   HB_UShort        language_index,
5565                                   HB_UShort*       feature_index )
5566 {
5567   HB_UShort           n;
5568
5569   HB_ScriptList*     sl;
5570   HB_ScriptRecord*   sr;
5571   HB_ScriptTable*         s;
5572   HB_LangSysRecord*  lsr;
5573   HB_LangSys*        ls;
5574   HB_UShort*          fi;
5575
5576   HB_FeatureList*    fl;
5577   HB_FeatureRecord*  fr;
5578
5579
5580   if ( !gpos || !feature_index )
5581     return ERR(HB_Err_Invalid_Argument);
5582
5583   sl = &gpos->ScriptList;
5584   sr = sl->ScriptRecord;
5585
5586   fl = &gpos->FeatureList;
5587   fr = fl->FeatureRecord;
5588
5589   if ( script_index >= sl->ScriptCount )
5590     return ERR(HB_Err_Invalid_Argument);
5591
5592   s   = &sr[script_index].Script;
5593   lsr = s->LangSysRecord;
5594
5595   if ( language_index == 0xFFFF )
5596     ls = &s->DefaultLangSys;
5597   else
5598   {
5599     if ( language_index >= s->LangSysCount )
5600       return ERR(HB_Err_Invalid_Argument);
5601
5602     ls = &lsr[language_index].LangSys;
5603   }
5604
5605   fi = ls->FeatureIndex;
5606
5607   for ( n = 0; n < ls->FeatureCount; n++ )
5608   {
5609     if ( fi[n] >= fl->FeatureCount )
5610       return ERR(HB_Err_Invalid_SubTable_Format);
5611
5612     if ( feature_tag == fr[fi[n]].FeatureTag )
5613     {
5614       *feature_index = fi[n];
5615
5616       return HB_Err_Ok;
5617     }
5618   }
5619
5620   return HB_Err_Not_Covered;
5621 }
5622
5623
5624 /* The next three functions return a null-terminated list */
5625
5626
5627 HB_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
5628                                  HB_UInt**       script_tag_list )
5629 {
5630   HB_Error           error;
5631   HB_UShort          n;
5632   HB_UInt*          stl;
5633
5634   HB_ScriptList*    sl;
5635   HB_ScriptRecord*  sr;
5636
5637
5638   if ( !gpos || !script_tag_list )
5639     return ERR(HB_Err_Invalid_Argument);
5640
5641   sl = &gpos->ScriptList;
5642   sr = sl->ScriptRecord;
5643
5644   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
5645     return error;
5646
5647   for ( n = 0; n < sl->ScriptCount; n++ )
5648     stl[n] = sr[n].ScriptTag;
5649   stl[n] = 0;
5650
5651   *script_tag_list = stl;
5652
5653   return HB_Err_Ok;
5654 }
5655
5656
5657
5658 HB_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
5659                                    HB_UShort        script_index,
5660                                    HB_UInt**       language_tag_list )
5661 {
5662   HB_Error            error;
5663   HB_UShort           n;
5664   HB_UInt*           ltl;
5665
5666   HB_ScriptList*     sl;
5667   HB_ScriptRecord*   sr;
5668   HB_ScriptTable*    s;
5669   HB_LangSysRecord*  lsr;
5670
5671
5672   if ( !gpos || !language_tag_list )
5673     return ERR(HB_Err_Invalid_Argument);
5674
5675   sl = &gpos->ScriptList;
5676   sr = sl->ScriptRecord;
5677
5678   if ( script_index >= sl->ScriptCount )
5679     return ERR(HB_Err_Invalid_Argument);
5680
5681   s   = &sr[script_index].Script;
5682   lsr = s->LangSysRecord;
5683
5684   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
5685     return error;
5686
5687   for ( n = 0; n < s->LangSysCount; n++ )
5688     ltl[n] = lsr[n].LangSysTag;
5689   ltl[n] = 0;
5690
5691   *language_tag_list = ltl;
5692
5693   return HB_Err_Ok;
5694 }
5695
5696
5697 /* selecting 0xFFFF for language_index asks for the values of the
5698    default language (DefaultLangSys)                              */
5699
5700
5701 HB_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
5702                                   HB_UShort        script_index,
5703                                   HB_UShort        language_index,
5704                                   HB_UInt**       feature_tag_list )
5705 {
5706   HB_UShort           n;
5707   HB_Error            error;
5708   HB_UInt*           ftl;
5709
5710   HB_ScriptList*     sl;
5711   HB_ScriptRecord*   sr;
5712   HB_ScriptTable*    s;
5713   HB_LangSysRecord*  lsr;
5714   HB_LangSys*        ls;
5715   HB_UShort*          fi;
5716
5717   HB_FeatureList*    fl;
5718   HB_FeatureRecord*  fr;
5719
5720
5721   if ( !gpos || !feature_tag_list )
5722     return ERR(HB_Err_Invalid_Argument);
5723
5724   sl = &gpos->ScriptList;
5725   sr = sl->ScriptRecord;
5726
5727   fl = &gpos->FeatureList;
5728   fr = fl->FeatureRecord;
5729
5730   if ( script_index >= sl->ScriptCount )
5731     return ERR(HB_Err_Invalid_Argument);
5732
5733   s   = &sr[script_index].Script;
5734   lsr = s->LangSysRecord;
5735
5736   if ( language_index == 0xFFFF )
5737     ls = &s->DefaultLangSys;
5738   else
5739   {
5740     if ( language_index >= s->LangSysCount )
5741       return ERR(HB_Err_Invalid_Argument);
5742
5743     ls = &lsr[language_index].LangSys;
5744   }
5745
5746   fi = ls->FeatureIndex;
5747
5748   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
5749     return error;
5750
5751   for ( n = 0; n < ls->FeatureCount; n++ )
5752   {
5753     if ( fi[n] >= fl->FeatureCount )
5754     {
5755       FREE( ftl );
5756       return ERR(HB_Err_Invalid_SubTable_Format);
5757     }
5758     ftl[n] = fr[fi[n]].FeatureTag;
5759   }
5760   ftl[n] = 0;
5761
5762   *feature_tag_list = ftl;
5763
5764   return HB_Err_Ok;
5765 }
5766
5767
5768 /* Do an individual subtable lookup.  Returns HB_Err_Ok if positioning
5769    has been done, or HB_Err_Not_Covered if not.                        */
5770 static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
5771                                        HB_UShort         lookup_index,
5772                                        HB_Buffer        buffer,
5773                                        HB_UShort         context_length,
5774                                        int               nesting_level )
5775 {
5776   HB_Error             error = HB_Err_Not_Covered;
5777   HB_UShort            i, flags, lookup_count;
5778   HB_GPOSHeader*       gpos = gpi->gpos;
5779   HB_Lookup*           lo;
5780   int                  lookup_type;
5781
5782
5783   nesting_level++;
5784
5785   if ( nesting_level > HB_MAX_NESTING_LEVEL )
5786     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
5787
5788   lookup_count = gpos->LookupList.LookupCount;
5789   if (lookup_index >= lookup_count)
5790     return error;
5791
5792   lo    = &gpos->LookupList.Lookup[lookup_index];
5793   flags = lo->LookupFlag;
5794   lookup_type = lo->LookupType;
5795
5796   for ( i = 0; i < lo->SubTableCount; i++ )
5797   {
5798     HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
5799
5800     switch (lookup_type) {
5801       case HB_GPOS_LOOKUP_SINGLE:
5802         error = Lookup_SinglePos        ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5803       case HB_GPOS_LOOKUP_PAIR:
5804         error = Lookup_PairPos          ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5805       case HB_GPOS_LOOKUP_CURSIVE:
5806         error = Lookup_CursivePos       ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5807       case HB_GPOS_LOOKUP_MARKBASE:
5808         error = Lookup_MarkBasePos      ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5809       case HB_GPOS_LOOKUP_MARKLIG:
5810         error = Lookup_MarkLigPos       ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5811       case HB_GPOS_LOOKUP_MARKMARK:
5812         error = Lookup_MarkMarkPos      ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5813       case HB_GPOS_LOOKUP_CONTEXT:
5814         error = Lookup_ContextPos       ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5815       case HB_GPOS_LOOKUP_CHAIN:
5816         error = Lookup_ChainContextPos  ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5817     /*case HB_GPOS_LOOKUP_EXTENSION:
5818         error = Lookup_ExtensionPos     ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5819       default:
5820         error = HB_Err_Not_Covered;
5821     }
5822
5823     /* Check whether we have a successful positioning or an error other
5824        than HB_Err_Not_Covered                                         */
5825     if ( error != HB_Err_Not_Covered )
5826       return error;
5827   }
5828
5829   return HB_Err_Not_Covered;
5830 }
5831
5832
5833 HB_INTERNAL HB_Error
5834 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5835                         HB_Stream         stream,
5836                         HB_UShort         lookup_type )
5837 {
5838   switch ( lookup_type ) {
5839     case HB_GPOS_LOOKUP_SINGLE:         return Load_SinglePos           ( st, stream );
5840     case HB_GPOS_LOOKUP_PAIR:           return Load_PairPos             ( st, stream );
5841     case HB_GPOS_LOOKUP_CURSIVE:        return Load_CursivePos          ( st, stream );
5842     case HB_GPOS_LOOKUP_MARKBASE:       return Load_MarkBasePos         ( st, stream );
5843     case HB_GPOS_LOOKUP_MARKLIG:        return Load_MarkLigPos          ( st, stream );
5844     case HB_GPOS_LOOKUP_MARKMARK:       return Load_MarkMarkPos         ( st, stream );
5845     case HB_GPOS_LOOKUP_CONTEXT:        return Load_ContextPos          ( st, stream );
5846     case HB_GPOS_LOOKUP_CHAIN:          return Load_ChainContextPos     ( st, stream );
5847   /*case HB_GPOS_LOOKUP_EXTENSION:      return Load_ExtensionPos        ( st, stream );*/
5848     default:                            return ERR(HB_Err_Invalid_SubTable_Format);
5849   }
5850 }
5851
5852
5853 HB_INTERNAL void
5854 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
5855                         HB_UShort         lookup_type )
5856 {
5857   switch ( lookup_type ) {
5858     case HB_GPOS_LOOKUP_SINGLE:         Free_SinglePos          ( st ); return;
5859     case HB_GPOS_LOOKUP_PAIR:           Free_PairPos            ( st ); return;
5860     case HB_GPOS_LOOKUP_CURSIVE:        Free_CursivePos         ( st ); return;
5861     case HB_GPOS_LOOKUP_MARKBASE:       Free_MarkBasePos        ( st ); return;
5862     case HB_GPOS_LOOKUP_MARKLIG:        Free_MarkLigPos         ( st ); return;
5863     case HB_GPOS_LOOKUP_MARKMARK:       Free_MarkMarkPos        ( st ); return;
5864     case HB_GPOS_LOOKUP_CONTEXT:        Free_ContextPos         ( st ); return;
5865     case HB_GPOS_LOOKUP_CHAIN:          Free_ChainContextPos    ( st ); return;
5866   /*case HB_GPOS_LOOKUP_EXTENSION:      Free_ExtensionPos       ( st ); return;*/
5867     default:                                                                    return;
5868   }
5869 }
5870
5871
5872 /* apply one lookup to the input string object */
5873
5874 static HB_Error  GPOS_Do_String_Lookup( GPOS_Instance*    gpi,
5875                                    HB_UShort         lookup_index,
5876                                    HB_Buffer        buffer )
5877 {
5878   HB_Error         error, retError = HB_Err_Not_Covered;
5879   HB_GPOSHeader*  gpos = gpi->gpos;
5880
5881   HB_UInt*  properties = gpos->LookupList.Properties;
5882
5883   const int       nesting_level = 0;
5884   /* 0xFFFF indicates that we don't have a context length yet */
5885   const HB_UShort context_length = 0xFFFF;
5886
5887
5888   gpi->last  = 0xFFFF;     /* no last valid glyph for cursive pos. */
5889
5890   buffer->in_pos = 0;
5891   while ( buffer->in_pos < buffer->in_length )
5892   {
5893     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
5894     {
5895       /* Note that the connection between mark and base glyphs hold
5896          exactly one (string) lookup.  For example, it would be possible
5897          that in the first lookup, mark glyph X is attached to base
5898          glyph A, and in the next lookup it is attached to base glyph B.
5899          It is up to the font designer to provide meaningful lookups and
5900          lookup order.                                                   */
5901
5902       error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5903       if ( error && error != HB_Err_Not_Covered )
5904         return error;
5905     }
5906     else
5907     {
5908       /* Contrary to properties defined in GDEF, user-defined properties
5909          will always stop a possible cursive positioning.                */
5910       gpi->last = 0xFFFF;
5911
5912       error = HB_Err_Not_Covered;
5913     }
5914
5915     if ( error == HB_Err_Not_Covered )
5916       (buffer->in_pos)++;
5917     else
5918       retError = error;
5919   }
5920
5921   return retError;
5922 }
5923
5924
5925 static HB_Error  Position_CursiveChain ( HB_Buffer     buffer )
5926 {
5927   HB_UInt   i, j;
5928   HB_Position positions = buffer->positions;
5929
5930   /* First handle all left-to-right connections */
5931   for (j = 0; j < buffer->in_length; j++)
5932   {
5933     if (positions[j].cursive_chain > 0)
5934       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5935   }
5936
5937   /* Then handle all right-to-left connections */
5938   for (i = buffer->in_length; i > 0; i--)
5939   {
5940     j = i - 1;
5941
5942     if (positions[j].cursive_chain < 0)
5943       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5944   }
5945
5946   return HB_Err_Ok;
5947 }
5948
5949
5950 HB_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
5951                                HB_UShort        feature_index,
5952                                HB_UInt          property )
5953 {
5954   HB_UShort    i;
5955
5956   HB_Feature  feature;
5957   HB_UInt*     properties;
5958   HB_UShort*   index;
5959   HB_UShort    lookup_count;
5960
5961   /* Each feature can only be added once */
5962
5963   if ( !gpos ||
5964        feature_index >= gpos->FeatureList.FeatureCount ||
5965        gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
5966     return ERR(HB_Err_Invalid_Argument);
5967
5968   gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
5969
5970   properties = gpos->LookupList.Properties;
5971
5972   feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
5973   index   = feature.LookupListIndex;
5974   lookup_count = gpos->LookupList.LookupCount;
5975
5976   for ( i = 0; i < feature.LookupListCount; i++ )
5977   {
5978     HB_UShort lookup_index = index[i];
5979     if (lookup_index < lookup_count)
5980       properties[lookup_index] |= property;
5981   }
5982
5983   return HB_Err_Ok;
5984 }
5985
5986
5987
5988 HB_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos )
5989 {
5990   HB_UShort i;
5991
5992   HB_UInt*  properties;
5993
5994
5995   if ( !gpos )
5996     return ERR(HB_Err_Invalid_Argument);
5997
5998   gpos->FeatureList.ApplyCount = 0;
5999
6000   properties = gpos->LookupList.Properties;
6001
6002   for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
6003     properties[i] = 0;
6004
6005   return HB_Err_Ok;
6006 }
6007
6008 #ifdef HB_SUPPORT_MULTIPLE_MASTER
6009 HB_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
6010                                         HB_MMFunction   mmfunc,
6011                                         void*            data )
6012 {
6013   if ( !gpos )
6014     return ERR(HB_Err_Invalid_Argument);
6015
6016   gpos->mmfunc = mmfunc;
6017   gpos->data   = data;
6018
6019   return HB_Err_Ok;
6020 }
6021 #endif
6022
6023 /* If `dvi' is TRUE, glyph contour points for anchor points and device
6024    tables are ignored -- you will get device independent values.         */
6025
6026
6027 HB_Error  HB_GPOS_Apply_String( HB_Font            font,
6028                                 HB_GPOSHeader*    gpos,
6029                                 HB_UShort          load_flags,
6030                                 HB_Buffer         buffer,
6031                                 HB_Bool            dvi,
6032                                 HB_Bool            r2l )
6033 {
6034   HB_Error       error, retError = HB_Err_Not_Covered;
6035   GPOS_Instance  gpi;
6036   int            i, j, lookup_count, num_features;
6037
6038   if ( !font || !gpos || !buffer )
6039     return ERR(HB_Err_Invalid_Argument);
6040
6041   if ( buffer->in_length == 0 )
6042     return HB_Err_Not_Covered;
6043
6044   gpi.font       = font;
6045   gpi.gpos       = gpos;
6046   gpi.load_flags = load_flags;
6047   gpi.r2l        = r2l;
6048   gpi.dvi        = dvi;
6049
6050   lookup_count = gpos->LookupList.LookupCount;
6051   num_features = gpos->FeatureList.ApplyCount;
6052
6053   if ( num_features )
6054     {
6055       error = _hb_buffer_clear_positions( buffer );
6056       if ( error )
6057         return error;
6058     }
6059
6060   for ( i = 0; i < num_features; i++ )
6061   {
6062     HB_UShort  feature_index = gpos->FeatureList.ApplyOrder[i];
6063     HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6064
6065     for ( j = 0; j < feature.LookupListCount; j++ )
6066     {
6067       HB_UShort lookup_index = feature.LookupListIndex[j];
6068
6069       /* Skip nonexistant lookups */
6070       if (lookup_index >= lookup_count)
6071        continue;
6072
6073       error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6074       if ( error )
6075       {
6076         if ( error != HB_Err_Not_Covered )
6077           return error;
6078       }
6079       else
6080         retError = error;
6081     }
6082   }
6083
6084   if ( num_features )
6085     {
6086   error = Position_CursiveChain ( buffer );
6087   if ( error )
6088     return error;
6089     }
6090
6091   return retError;
6092 }
6093
6094 /* END */