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