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