• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   pvr = ppf1->PairSet[index].PairValueRecord;
1511   if ( !pvr )
1512     return ERR(HB_Err_Invalid_SubTable);
1513 
1514   glyph2 = IN_CURGLYPH();
1515 
1516   for ( numpvr = ppf1->PairSet[index].PairValueCount;
1517 	numpvr;
1518 	numpvr--, pvr++ )
1519   {
1520     if ( glyph2 == pvr->SecondGlyph )
1521     {
1522       error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1523 			       POSITION( first_pos ) );
1524       if ( error )
1525 	return error;
1526       return Get_ValueRecord( gpi, &pvr->Value2, format2,
1527 			      POSITION( buffer->in_pos ) );
1528     }
1529   }
1530 
1531   return HB_Err_Not_Covered;
1532 }
1533 
1534 
Lookup_PairPos2(GPOS_Instance * gpi,HB_PairPosFormat2 * ppf2,HB_Buffer buffer,HB_UInt first_pos,HB_UShort format1,HB_UShort format2)1535 static HB_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
1536 				  HB_PairPosFormat2*  ppf2,
1537 				  HB_Buffer           buffer,
1538 				  HB_UInt              first_pos,
1539 				  HB_UShort            format1,
1540 				  HB_UShort            format2 )
1541 {
1542   HB_Error           error;
1543   HB_UShort          cl1 = 0, cl2 = 0; /* shut compiler up */
1544 
1545   HB_Class1Record*  c1r;
1546   HB_Class2Record*  c2r;
1547 
1548 
1549   error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
1550 		     &cl1, NULL );
1551   if ( error && error != HB_Err_Not_Covered )
1552     return error;
1553   error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1554 		     &cl2, NULL );
1555   if ( error && error != HB_Err_Not_Covered )
1556     return error;
1557 
1558   c1r = &ppf2->Class1Record[cl1];
1559   if ( !c1r )
1560     return ERR(HB_Err_Invalid_SubTable);
1561   c2r = &c1r->Class2Record[cl2];
1562 
1563   error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1564   if ( error )
1565     return error;
1566   return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
1567 }
1568 
1569 
Lookup_PairPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1570 static HB_Error  Lookup_PairPos( GPOS_Instance*    gpi,
1571 				 HB_GPOS_SubTable* st,
1572 				 HB_Buffer        buffer,
1573 				 HB_UShort         flags,
1574 				 HB_UShort         context_length,
1575 				 int               nesting_level )
1576 {
1577   HB_Error         error;
1578   HB_UShort        index, property;
1579   HB_UInt          first_pos;
1580   HB_GPOSHeader*  gpos = gpi->gpos;
1581   HB_PairPos*     pp = &st->pair;
1582 
1583   HB_UNUSED(nesting_level);
1584 
1585   if ( buffer->in_pos >= buffer->in_length - 1 )
1586     return HB_Err_Not_Covered;           /* Not enough glyphs in stream */
1587 
1588   if ( context_length != 0xFFFF && context_length < 2 )
1589     return HB_Err_Not_Covered;
1590 
1591   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1592     return error;
1593 
1594   error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1595   if ( error )
1596     return error;
1597 
1598   /* second glyph */
1599 
1600   first_pos = buffer->in_pos;
1601   (buffer->in_pos)++;
1602 
1603   while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
1604 			  flags, &property ) )
1605   {
1606     if ( error && error != HB_Err_Not_Covered )
1607       return error;
1608 
1609     if ( buffer->in_pos == buffer->in_length )
1610       {
1611 	buffer->in_pos = first_pos;
1612         return HB_Err_Not_Covered;
1613       }
1614     (buffer->in_pos)++;
1615 
1616   }
1617 
1618   switch ( pp->PosFormat )
1619   {
1620   case 1:
1621     error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1622 			     first_pos, index,
1623 			     pp->ValueFormat1, pp->ValueFormat2 );
1624     break;
1625 
1626   case 2:
1627     error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1628 			     pp->ValueFormat1, pp->ValueFormat2 );
1629     break;
1630 
1631   default:
1632     return ERR(HB_Err_Invalid_SubTable_Format);
1633   }
1634 
1635   /* if we don't have coverage for the second glyph don't skip it for
1636      further lookups but reset in_pos back to the first_glyph and let
1637      the caller in Do_String_Lookup increment in_pos */
1638   if ( error == HB_Err_Not_Covered )
1639       buffer->in_pos = first_pos;
1640 
1641   /* adjusting the `next' glyph */
1642 
1643   if ( pp->ValueFormat2 )
1644     (buffer->in_pos)++;
1645 
1646   return error;
1647 }
1648 
1649 
1650 /* LookupType 3 */
1651 
1652 /* CursivePosFormat1 */
1653 
Load_CursivePos(HB_GPOS_SubTable * st,HB_Stream stream)1654 static HB_Error  Load_CursivePos( HB_GPOS_SubTable* st,
1655 				  HB_Stream        stream )
1656 {
1657   HB_Error  error;
1658   HB_CursivePos*  cp = &st->cursive;
1659 
1660   HB_UShort             n, m, count;
1661   HB_UInt              cur_offset, new_offset, base_offset;
1662 
1663   HB_EntryExitRecord*  eer;
1664 
1665 
1666   base_offset = FILE_Pos();
1667 
1668   if ( ACCESS_Frame( 4L ) )
1669     return error;
1670 
1671   cp->PosFormat = GET_UShort();
1672   new_offset    = GET_UShort() + base_offset;
1673 
1674   FORGET_Frame();
1675 
1676   cur_offset = FILE_Pos();
1677   if ( FILE_Seek( new_offset ) ||
1678        ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
1679     return error;
1680   (void)FILE_Seek( cur_offset );
1681 
1682   if ( ACCESS_Frame( 2L ) )
1683     goto Fail2;
1684 
1685   count = cp->EntryExitCount = GET_UShort();
1686 
1687   FORGET_Frame();
1688 
1689   cp->EntryExitRecord = NULL;
1690 
1691   if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1692     goto Fail2;
1693 
1694   eer = cp->EntryExitRecord;
1695 
1696   for ( n = 0; n < count; n++ )
1697   {
1698     HB_UInt entry_offset;
1699 
1700     if ( ACCESS_Frame( 2L ) )
1701       return error;
1702 
1703     entry_offset = new_offset = GET_UShort();
1704 
1705     FORGET_Frame();
1706 
1707     if ( new_offset )
1708     {
1709       new_offset += base_offset;
1710 
1711       cur_offset = FILE_Pos();
1712       if ( FILE_Seek( new_offset ) ||
1713 	   ( error = Load_Anchor( &eer[n].EntryAnchor,
1714 				  stream ) ) != HB_Err_Ok )
1715 	goto Fail1;
1716       (void)FILE_Seek( cur_offset );
1717     }
1718     else
1719       eer[n].EntryAnchor.PosFormat   = 0;
1720 
1721     if ( ACCESS_Frame( 2L ) )
1722       return error;
1723 
1724     new_offset = GET_UShort();
1725 
1726     FORGET_Frame();
1727 
1728     if ( new_offset )
1729     {
1730       new_offset += base_offset;
1731 
1732       cur_offset = FILE_Pos();
1733       if ( FILE_Seek( new_offset ) ||
1734 	   ( error = Load_Anchor( &eer[n].ExitAnchor,
1735 				  stream ) ) != HB_Err_Ok )
1736       {
1737 	if ( entry_offset )
1738 	  Free_Anchor( &eer[n].EntryAnchor );
1739 	goto Fail1;
1740       }
1741       (void)FILE_Seek( cur_offset );
1742     }
1743     else
1744       eer[n].ExitAnchor.PosFormat   = 0;
1745   }
1746 
1747   return HB_Err_Ok;
1748 
1749 Fail1:
1750   for ( m = 0; m < n; m++ )
1751   {
1752     Free_Anchor( &eer[m].EntryAnchor );
1753     Free_Anchor( &eer[m].ExitAnchor );
1754   }
1755 
1756   FREE( eer );
1757 
1758 Fail2:
1759   _HB_OPEN_Free_Coverage( &cp->Coverage );
1760   return error;
1761 }
1762 
1763 
Free_CursivePos(HB_GPOS_SubTable * st)1764 static void  Free_CursivePos( HB_GPOS_SubTable* st )
1765 {
1766   HB_UShort             n, count;
1767   HB_CursivePos*  cp = &st->cursive;
1768 
1769   HB_EntryExitRecord*  eer;
1770 
1771 
1772   if ( cp->EntryExitRecord )
1773   {
1774     count = cp->EntryExitCount;
1775     eer   = cp->EntryExitRecord;
1776 
1777     for ( n = 0; n < count; n++ )
1778     {
1779       Free_Anchor( &eer[n].EntryAnchor );
1780       Free_Anchor( &eer[n].ExitAnchor );
1781     }
1782 
1783     FREE( eer );
1784   }
1785 
1786   _HB_OPEN_Free_Coverage( &cp->Coverage );
1787 }
1788 
1789 
Lookup_CursivePos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1790 static HB_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
1791 				    HB_GPOS_SubTable* st,
1792 				    HB_Buffer        buffer,
1793 				    HB_UShort         flags,
1794 				    HB_UShort         context_length,
1795 				    int               nesting_level )
1796 {
1797   HB_UShort        index, property;
1798   HB_Error         error;
1799   HB_GPOSHeader*  gpos = gpi->gpos;
1800   HB_CursivePos*  cp = &st->cursive;
1801 
1802   HB_EntryExitRecord*  eer;
1803   HB_Fixed                entry_x, entry_y;
1804   HB_Fixed                exit_x, exit_y;
1805 
1806   HB_UNUSED(nesting_level);
1807 
1808   if ( context_length != 0xFFFF && context_length < 1 )
1809   {
1810     gpi->last = 0xFFFF;
1811     return HB_Err_Not_Covered;
1812   }
1813 
1814   /* Glyphs not having the right GDEF properties will be ignored, i.e.,
1815      gpi->last won't be reset (contrary to user defined properties). */
1816 
1817   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1818     return error;
1819 
1820   /* We don't handle mark glyphs here.  According to Andrei, this isn't
1821      possible, but who knows...                                         */
1822 
1823   if ( property == HB_GDEF_MARK )
1824   {
1825     gpi->last = 0xFFFF;
1826     return HB_Err_Not_Covered;
1827   }
1828 
1829   error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1830   if ( error )
1831   {
1832     gpi->last = 0xFFFF;
1833     return error;
1834   }
1835 
1836   if ( index >= cp->EntryExitCount )
1837     return ERR(HB_Err_Invalid_SubTable);
1838 
1839   eer = &cp->EntryExitRecord[index];
1840 
1841   /* Now comes the messiest part of the whole OpenType
1842      specification.  At first glance, cursive connections seem easy
1843      to understand, but there are pitfalls!  The reason is that
1844      the specs don't mention how to compute the advance values
1845      resp. glyph offsets.  I was told it would be an omission, to
1846      be fixed in the next OpenType version...  Again many thanks to
1847      Andrei Burago <andreib@microsoft.com> for clarifications.
1848 
1849      Consider the following example:
1850 
1851 		      |  xadv1    |
1852 		       +---------+
1853 		       |         |
1854 		 +-----+--+ 1    |
1855 		 |     | .|      |
1856 		 |    0+--+------+
1857 		 |   2    |
1858 		 |        |
1859 		0+--------+
1860 		|  xadv2   |
1861 
1862        glyph1: advance width = 12
1863 	       anchor point = (3,1)
1864 
1865        glyph2: advance width = 11
1866 	       anchor point = (9,4)
1867 
1868        LSB is 1 for both glyphs (so the boxes drawn above are glyph
1869        bboxes).  Writing direction is R2L; `0' denotes the glyph's
1870        coordinate origin.
1871 
1872      Now the surprising part: The advance width of the *left* glyph
1873      (resp. of the *bottom* glyph) will be modified, no matter
1874      whether the writing direction is L2R or R2L (resp. T2B or
1875      B2T)!  This assymetry is caused by the fact that the glyph's
1876      coordinate origin is always the lower left corner for all
1877      writing directions.
1878 
1879      Continuing the above example, we can compute the new
1880      (horizontal) advance width of glyph2 as
1881 
1882        9 - 3 = 6  ,
1883 
1884      and the new vertical offset of glyph2 as
1885 
1886        1 - 4 = -3  .
1887 
1888 
1889      Vertical writing direction is far more complicated:
1890 
1891      a) Assuming that we recompute the advance height of the lower glyph:
1892 
1893 				  --
1894 		       +---------+
1895 	      --       |         |
1896 		 +-----+--+ 1    | yadv1
1897 		 |     | .|      |
1898 	   yadv2 |    0+--+------+        -- BSB1  --
1899 		 |   2    |       --      --        y_offset
1900 		 |        |
1901    BSB2 --      0+--------+                        --
1902 	--    --
1903 
1904        glyph1: advance height = 6
1905 	       anchor point = (3,1)
1906 
1907        glyph2: advance height = 7
1908 	       anchor point = (9,4)
1909 
1910        TSB is 1 for both glyphs; writing direction is T2B.
1911 
1912 
1913 	 BSB1     = yadv1 - (TSB1 + ymax1)
1914 	 BSB2     = yadv2 - (TSB2 + ymax2)
1915 	 y_offset = y2 - y1
1916 
1917        vertical advance width of glyph2
1918 	 = y_offset + BSB2 - BSB1
1919 	 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1920 	 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1921 	 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1922 
1923 
1924      b) Assuming that we recompute the advance height of the upper glyph:
1925 
1926 				  --      --
1927 		       +---------+        -- TSB1
1928 	--    --       |         |
1929    TSB2 --       +-----+--+ 1    | yadv1   ymax1
1930 		 |     | .|      |
1931 	   yadv2 |    0+--+------+        --       --
1932     ymax2        |   2    |       --                y_offset
1933 		 |        |
1934 	--      0+--------+                        --
1935 	      --
1936 
1937        glyph1: advance height = 6
1938 	       anchor point = (3,1)
1939 
1940        glyph2: advance height = 7
1941 	       anchor point = (9,4)
1942 
1943        TSB is 1 for both glyphs; writing direction is T2B.
1944 
1945        y_offset = y2 - y1
1946 
1947        vertical advance width of glyph2
1948 	 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1949 	 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1950 
1951 
1952      Comparing a) with b) shows that b) is easier to compute.  I'll wait
1953      for a reply from Andrei to see what should really be implemented...
1954 
1955      Since horizontal advance widths or vertical advance heights
1956      can be used alone but not together, no ambiguity occurs.        */
1957 
1958   if ( gpi->last == 0xFFFF )
1959     goto end;
1960 
1961   /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1962      table.                                                         */
1963 
1964   error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1965 		      &entry_x, &entry_y );
1966   if ( error == HB_Err_Not_Covered )
1967     goto end;
1968   if ( error )
1969     return error;
1970 
1971   if ( gpi->r2l )
1972   {
1973     POSITION( buffer->in_pos )->x_advance   = entry_x - gpi->anchor_x;
1974     POSITION( buffer->in_pos )->new_advance = TRUE;
1975   }
1976   else
1977   {
1978     POSITION( gpi->last )->x_advance   = gpi->anchor_x - entry_x;
1979     POSITION( gpi->last )->new_advance = TRUE;
1980   }
1981 
1982   if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
1983   {
1984     POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
1985     POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
1986   }
1987   else
1988   {
1989     POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
1990     POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
1991   }
1992 
1993 end:
1994   error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
1995 		      &exit_x, &exit_y );
1996   if ( error == HB_Err_Not_Covered )
1997     gpi->last = 0xFFFF;
1998   else
1999   {
2000     gpi->last     = buffer->in_pos;
2001     gpi->anchor_x = exit_x;
2002     gpi->anchor_y = exit_y;
2003   }
2004   if ( error )
2005     return error;
2006 
2007   (buffer->in_pos)++;
2008 
2009   return HB_Err_Ok;
2010 }
2011 
2012 
2013 /* LookupType 4 */
2014 
2015 /* BaseArray */
2016 
Load_BaseArray(HB_BaseArray * ba,HB_UShort num_classes,HB_Stream stream)2017 static HB_Error  Load_BaseArray( HB_BaseArray*  ba,
2018 				 HB_UShort       num_classes,
2019 				 HB_Stream       stream )
2020 {
2021   HB_Error  error;
2022 
2023   HB_UShort       m, n, count;
2024   HB_UInt         cur_offset, new_offset, base_offset;
2025 
2026   HB_BaseRecord  *br;
2027   HB_Anchor      *ban, *bans;
2028 
2029 
2030   base_offset = FILE_Pos();
2031 
2032   if ( ACCESS_Frame( 2L ) )
2033     return error;
2034 
2035   count = ba->BaseCount = GET_UShort();
2036 
2037   FORGET_Frame();
2038 
2039   ba->BaseRecord = NULL;
2040 
2041   if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2042     return error;
2043 
2044   br = ba->BaseRecord;
2045 
2046   bans = NULL;
2047 
2048   if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
2049     goto Fail;
2050 
2051   for ( m = 0; m < count; m++ )
2052   {
2053     br[m].BaseAnchor = NULL;
2054 
2055     ban = br[m].BaseAnchor = bans + m * num_classes;
2056 
2057     for ( n = 0; n < num_classes; n++ )
2058     {
2059       if ( ACCESS_Frame( 2L ) )
2060 	goto Fail;
2061 
2062       new_offset = GET_UShort() + base_offset;
2063 
2064       FORGET_Frame();
2065 
2066       if (new_offset == base_offset) {
2067 	/* XXX
2068 	 * Doulos SIL Regular is buggy and has zero offsets here.
2069 	 * Skip it
2070 	 */
2071 	ban[n].PosFormat = 0;
2072 	continue;
2073       }
2074 
2075       cur_offset = FILE_Pos();
2076       if ( FILE_Seek( new_offset ) ||
2077 	   ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
2078 	goto Fail;
2079       (void)FILE_Seek( cur_offset );
2080     }
2081   }
2082 
2083   return HB_Err_Ok;
2084 
2085 Fail:
2086   FREE( bans );
2087   FREE( br );
2088   return error;
2089 }
2090 
2091 
Free_BaseArray(HB_BaseArray * ba,HB_UShort num_classes)2092 static void  Free_BaseArray( HB_BaseArray*  ba,
2093 			     HB_UShort       num_classes )
2094 {
2095   HB_BaseRecord  *br;
2096   HB_Anchor      *bans;
2097 
2098   if ( ba->BaseRecord )
2099   {
2100     br    = ba->BaseRecord;
2101 
2102     if ( ba->BaseCount )
2103     {
2104       HB_UShort i, count;
2105       count = num_classes * ba->BaseCount;
2106       bans = br[0].BaseAnchor;
2107       for (i = 0; i < count; i++)
2108         Free_Anchor (&bans[i]);
2109       FREE( bans );
2110     }
2111 
2112     FREE( br );
2113   }
2114 }
2115 
2116 
2117 /* MarkBasePosFormat1 */
2118 
Load_MarkBasePos(HB_GPOS_SubTable * st,HB_Stream stream)2119 static HB_Error  Load_MarkBasePos( HB_GPOS_SubTable* st,
2120 				   HB_Stream         stream )
2121 {
2122   HB_Error  error;
2123   HB_MarkBasePos* mbp = &st->markbase;
2124 
2125   HB_UInt  cur_offset, new_offset, base_offset;
2126 
2127 
2128   base_offset = FILE_Pos();
2129 
2130   if ( ACCESS_Frame( 4L ) )
2131     return error;
2132 
2133   mbp->PosFormat = GET_UShort();
2134   new_offset     = GET_UShort() + base_offset;
2135 
2136   FORGET_Frame();
2137 
2138   if (mbp->PosFormat != 1)
2139     return ERR(HB_Err_Invalid_SubTable_Format);
2140 
2141   cur_offset = FILE_Pos();
2142   if ( FILE_Seek( new_offset ) ||
2143        ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
2144     return error;
2145   (void)FILE_Seek( cur_offset );
2146 
2147   if ( ACCESS_Frame( 2L ) )
2148     goto Fail3;
2149 
2150   new_offset = GET_UShort() + base_offset;
2151 
2152   FORGET_Frame();
2153 
2154   cur_offset = FILE_Pos();
2155   if ( FILE_Seek( new_offset ) ||
2156        ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
2157     goto Fail3;
2158   (void)FILE_Seek( cur_offset );
2159 
2160   if ( ACCESS_Frame( 4L ) )
2161     goto Fail2;
2162 
2163   mbp->ClassCount = GET_UShort();
2164   new_offset      = GET_UShort() + base_offset;
2165 
2166   FORGET_Frame();
2167 
2168   cur_offset = FILE_Pos();
2169   if ( FILE_Seek( new_offset ) ||
2170        ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
2171     goto Fail2;
2172   (void)FILE_Seek( cur_offset );
2173 
2174   if ( ACCESS_Frame( 2L ) )
2175     goto Fail1;
2176 
2177   new_offset = GET_UShort() + base_offset;
2178 
2179   FORGET_Frame();
2180 
2181   cur_offset = FILE_Pos();
2182   if ( FILE_Seek( new_offset ) ||
2183        ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2184 				 stream ) ) != HB_Err_Ok )
2185     goto Fail1;
2186 
2187   return HB_Err_Ok;
2188 
2189 Fail1:
2190   Free_MarkArray( &mbp->MarkArray );
2191 
2192 Fail2:
2193   _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2194 
2195 Fail3:
2196   _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2197   return error;
2198 }
2199 
2200 
Free_MarkBasePos(HB_GPOS_SubTable * st)2201 static void  Free_MarkBasePos( HB_GPOS_SubTable* st )
2202 {
2203   HB_MarkBasePos* mbp = &st->markbase;
2204 
2205   Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
2206   Free_MarkArray( &mbp->MarkArray );
2207   _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2208   _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2209 }
2210 
2211 
Lookup_MarkBasePos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2212 static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
2213 				     HB_GPOS_SubTable* st,
2214 				     HB_Buffer        buffer,
2215 				     HB_UShort         flags,
2216 				     HB_UShort         context_length,
2217 				     int               nesting_level )
2218 {
2219   HB_UShort        i, j, mark_index, base_index, property, class;
2220   HB_Fixed           x_mark_value, y_mark_value, x_base_value, y_base_value;
2221   HB_Error         error;
2222   HB_GPOSHeader*  gpos = gpi->gpos;
2223   HB_MarkBasePos* mbp = &st->markbase;
2224 
2225   HB_MarkArray*   ma;
2226   HB_BaseArray*   ba;
2227   HB_BaseRecord*  br;
2228   HB_Anchor*      mark_anchor;
2229   HB_Anchor*      base_anchor;
2230 
2231   HB_Position     o;
2232 
2233   HB_UNUSED(nesting_level);
2234 
2235   if ( context_length != 0xFFFF && context_length < 1 )
2236     return HB_Err_Not_Covered;
2237 
2238   if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
2239     return HB_Err_Not_Covered;
2240 
2241   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2242 		       flags, &property ) )
2243     return error;
2244 
2245   error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2246 			  &mark_index );
2247   if ( error )
2248     return error;
2249 
2250   /* now we search backwards for a non-mark glyph */
2251 
2252   i = 1;
2253   j = buffer->in_pos - 1;
2254 
2255   while ( i <= buffer->in_pos )
2256   {
2257     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2258 					&property );
2259     if ( error )
2260       return error;
2261 
2262     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2263       break;
2264 
2265     i++;
2266     j--;
2267   }
2268 
2269   /* The following assertion is too strong -- at least for mangal.ttf. */
2270 #if 0
2271   if ( property != HB_GDEF_BASE_GLYPH )
2272     return HB_Err_Not_Covered;
2273 #endif
2274 
2275   if ( i > buffer->in_pos )
2276     return HB_Err_Not_Covered;
2277 
2278   error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2279 			  &base_index );
2280   if ( error )
2281     return error;
2282 
2283   ma = &mbp->MarkArray;
2284 
2285   if ( mark_index >= ma->MarkCount )
2286     return ERR(HB_Err_Invalid_SubTable);
2287 
2288   class       = ma->MarkRecord[mark_index].Class;
2289   mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2290 
2291   if ( class >= mbp->ClassCount )
2292     return ERR(HB_Err_Invalid_SubTable);
2293 
2294   ba = &mbp->BaseArray;
2295 
2296   if ( base_index >= ba->BaseCount )
2297     return ERR(HB_Err_Invalid_SubTable);
2298 
2299   br          = &ba->BaseRecord[base_index];
2300   base_anchor = &br->BaseAnchor[class];
2301 
2302   error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2303 		      &x_mark_value, &y_mark_value );
2304   if ( error )
2305     return error;
2306 
2307   error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2308 		      &x_base_value, &y_base_value );
2309   if ( error )
2310     return error;
2311 
2312   /* anchor points are not cumulative */
2313 
2314   o = POSITION( buffer->in_pos );
2315 
2316   o->x_pos     = x_base_value - x_mark_value;
2317   o->y_pos     = y_base_value - y_mark_value;
2318   o->x_advance = 0;
2319   o->y_advance = 0;
2320   o->back      = i;
2321 
2322   (buffer->in_pos)++;
2323 
2324   return HB_Err_Ok;
2325 }
2326 
2327 
2328 /* LookupType 5 */
2329 
2330 /* LigatureAttach */
2331 
Load_LigatureAttach(HB_LigatureAttach * lat,HB_UShort num_classes,HB_Stream stream)2332 static HB_Error  Load_LigatureAttach( HB_LigatureAttach*  lat,
2333 				      HB_UShort            num_classes,
2334 				      HB_Stream            stream )
2335 {
2336   HB_Error  error;
2337 
2338   HB_UShort             m, n, k, count;
2339   HB_UInt              cur_offset, new_offset, base_offset;
2340 
2341   HB_ComponentRecord*  cr;
2342   HB_Anchor*           lan;
2343 
2344 
2345   base_offset = FILE_Pos();
2346 
2347   if ( ACCESS_Frame( 2L ) )
2348     return error;
2349 
2350   count = lat->ComponentCount = GET_UShort();
2351 
2352   FORGET_Frame();
2353 
2354   lat->ComponentRecord = NULL;
2355 
2356   if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2357     return error;
2358 
2359   cr = lat->ComponentRecord;
2360 
2361   for ( m = 0; m < count; m++ )
2362   {
2363     cr[m].LigatureAnchor = NULL;
2364 
2365     if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
2366       goto Fail;
2367 
2368     lan = cr[m].LigatureAnchor;
2369 
2370     for ( n = 0; n < num_classes; n++ )
2371     {
2372       if ( ACCESS_Frame( 2L ) )
2373 	goto Fail0;
2374 
2375       new_offset = GET_UShort();
2376 
2377       FORGET_Frame();
2378 
2379       if ( new_offset )
2380       {
2381 	new_offset += base_offset;
2382 
2383 	cur_offset = FILE_Pos();
2384 	if ( FILE_Seek( new_offset ) ||
2385 	     ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
2386 	  goto Fail0;
2387 	(void)FILE_Seek( cur_offset );
2388       }
2389       else
2390 	lan[n].PosFormat = 0;
2391     }
2392 
2393     continue;
2394   Fail0:
2395     for ( k = 0; k < n; k++ )
2396       Free_Anchor( &lan[k] );
2397     goto Fail;
2398   }
2399 
2400   return HB_Err_Ok;
2401 
2402 Fail:
2403   for ( k = 0; k < m; k++ )
2404   {
2405     lan = cr[k].LigatureAnchor;
2406 
2407     for ( n = 0; n < num_classes; n++ )
2408       Free_Anchor( &lan[n] );
2409 
2410     FREE( lan );
2411   }
2412 
2413   FREE( cr );
2414   return error;
2415 }
2416 
2417 
Free_LigatureAttach(HB_LigatureAttach * lat,HB_UShort num_classes)2418 static void  Free_LigatureAttach( HB_LigatureAttach*  lat,
2419 				  HB_UShort            num_classes )
2420 {
2421   HB_UShort        m, n, count;
2422 
2423   HB_ComponentRecord*  cr;
2424   HB_Anchor*           lan;
2425 
2426 
2427   if ( lat->ComponentRecord )
2428   {
2429     count = lat->ComponentCount;
2430     cr    = lat->ComponentRecord;
2431 
2432     for ( m = 0; m < count; m++ )
2433     {
2434       lan = cr[m].LigatureAnchor;
2435 
2436       for ( n = 0; n < num_classes; n++ )
2437 	Free_Anchor( &lan[n] );
2438 
2439       FREE( lan );
2440     }
2441 
2442     FREE( cr );
2443   }
2444 }
2445 
2446 
2447 /* LigatureArray */
2448 
Load_LigatureArray(HB_LigatureArray * la,HB_UShort num_classes,HB_Stream stream)2449 static HB_Error  Load_LigatureArray( HB_LigatureArray*  la,
2450 				     HB_UShort           num_classes,
2451 				     HB_Stream           stream )
2452 {
2453   HB_Error  error;
2454 
2455   HB_UShort            n, m, count;
2456   HB_UInt             cur_offset, new_offset, base_offset;
2457 
2458   HB_LigatureAttach*  lat;
2459 
2460 
2461   base_offset = FILE_Pos();
2462 
2463   if ( ACCESS_Frame( 2L ) )
2464     return error;
2465 
2466   count = la->LigatureCount = GET_UShort();
2467 
2468   FORGET_Frame();
2469 
2470   la->LigatureAttach = NULL;
2471 
2472   if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2473     return error;
2474 
2475   lat = la->LigatureAttach;
2476 
2477   for ( n = 0; n < count; n++ )
2478   {
2479     if ( ACCESS_Frame( 2L ) )
2480       goto Fail;
2481 
2482     new_offset = GET_UShort() + base_offset;
2483 
2484     FORGET_Frame();
2485 
2486     cur_offset = FILE_Pos();
2487     if ( FILE_Seek( new_offset ) ||
2488 	 ( error = Load_LigatureAttach( &lat[n], num_classes,
2489 					stream ) ) != HB_Err_Ok )
2490       goto Fail;
2491     (void)FILE_Seek( cur_offset );
2492   }
2493 
2494   return HB_Err_Ok;
2495 
2496 Fail:
2497   for ( m = 0; m < n; m++ )
2498     Free_LigatureAttach( &lat[m], num_classes );
2499 
2500   FREE( lat );
2501   return error;
2502 }
2503 
2504 
Free_LigatureArray(HB_LigatureArray * la,HB_UShort num_classes)2505 static void  Free_LigatureArray( HB_LigatureArray*  la,
2506 				 HB_UShort           num_classes )
2507 {
2508   HB_UShort            n, count;
2509 
2510   HB_LigatureAttach*  lat;
2511 
2512 
2513   if ( la->LigatureAttach )
2514   {
2515     count = la->LigatureCount;
2516     lat   = la->LigatureAttach;
2517 
2518     for ( n = 0; n < count; n++ )
2519       Free_LigatureAttach( &lat[n], num_classes );
2520 
2521     FREE( lat );
2522   }
2523 }
2524 
2525 
2526 /* MarkLigPosFormat1 */
2527 
Load_MarkLigPos(HB_GPOS_SubTable * st,HB_Stream stream)2528 static HB_Error  Load_MarkLigPos( HB_GPOS_SubTable* st,
2529 				  HB_Stream        stream )
2530 {
2531   HB_Error  error;
2532   HB_MarkLigPos*  mlp = &st->marklig;
2533 
2534   HB_UInt  cur_offset, new_offset, base_offset;
2535 
2536 
2537   base_offset = FILE_Pos();
2538 
2539   if ( ACCESS_Frame( 4L ) )
2540     return error;
2541 
2542   mlp->PosFormat = GET_UShort();
2543   new_offset     = GET_UShort() + base_offset;
2544 
2545   FORGET_Frame();
2546 
2547   cur_offset = FILE_Pos();
2548   if ( FILE_Seek( new_offset ) ||
2549        ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
2550     return error;
2551   (void)FILE_Seek( cur_offset );
2552 
2553   if ( ACCESS_Frame( 2L ) )
2554     goto Fail3;
2555 
2556   new_offset = GET_UShort() + base_offset;
2557 
2558   FORGET_Frame();
2559 
2560   cur_offset = FILE_Pos();
2561   if ( FILE_Seek( new_offset ) ||
2562        ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2563 				stream ) ) != HB_Err_Ok )
2564     goto Fail3;
2565   (void)FILE_Seek( cur_offset );
2566 
2567   if ( ACCESS_Frame( 4L ) )
2568     goto Fail2;
2569 
2570   mlp->ClassCount = GET_UShort();
2571   new_offset      = GET_UShort() + base_offset;
2572 
2573   FORGET_Frame();
2574 
2575   cur_offset = FILE_Pos();
2576   if ( FILE_Seek( new_offset ) ||
2577        ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
2578     goto Fail2;
2579   (void)FILE_Seek( cur_offset );
2580 
2581   if ( ACCESS_Frame( 2L ) )
2582     goto Fail1;
2583 
2584   new_offset = GET_UShort() + base_offset;
2585 
2586   FORGET_Frame();
2587 
2588   cur_offset = FILE_Pos();
2589   if ( FILE_Seek( new_offset ) ||
2590        ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2591 				     stream ) ) != HB_Err_Ok )
2592     goto Fail1;
2593 
2594   return HB_Err_Ok;
2595 
2596 Fail1:
2597   Free_MarkArray( &mlp->MarkArray );
2598 
2599 Fail2:
2600   _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2601 
2602 Fail3:
2603   _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2604   return error;
2605 }
2606 
2607 
Free_MarkLigPos(HB_GPOS_SubTable * st)2608 static void  Free_MarkLigPos( HB_GPOS_SubTable* st)
2609 {
2610   HB_MarkLigPos*  mlp = &st->marklig;
2611 
2612   Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
2613   Free_MarkArray( &mlp->MarkArray );
2614   _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2615   _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2616 }
2617 
2618 
Lookup_MarkLigPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2619 static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
2620 				    HB_GPOS_SubTable* st,
2621 				    HB_Buffer        buffer,
2622 				    HB_UShort         flags,
2623 				    HB_UShort         context_length,
2624 				    int               nesting_level )
2625 {
2626   HB_UShort        i, j, mark_index, lig_index, property, class;
2627   HB_UShort        mark_glyph;
2628   HB_Fixed           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2629   HB_Error         error;
2630   HB_GPOSHeader*  gpos = gpi->gpos;
2631   HB_MarkLigPos*  mlp = &st->marklig;
2632 
2633   HB_MarkArray*        ma;
2634   HB_LigatureArray*    la;
2635   HB_LigatureAttach*   lat;
2636   HB_ComponentRecord*  cr;
2637   HB_UShort             comp_index;
2638   HB_Anchor*           mark_anchor;
2639   HB_Anchor*           lig_anchor;
2640 
2641   HB_Position    o;
2642 
2643   HB_UNUSED(nesting_level);
2644 
2645   if ( context_length != 0xFFFF && context_length < 1 )
2646     return HB_Err_Not_Covered;
2647 
2648   if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
2649     return HB_Err_Not_Covered;
2650 
2651   mark_glyph = IN_CURGLYPH();
2652 
2653   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
2654     return error;
2655 
2656   error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2657   if ( error )
2658     return error;
2659 
2660   /* now we search backwards for a non-mark glyph */
2661 
2662   i = 1;
2663   j = buffer->in_pos - 1;
2664 
2665   while ( i <= buffer->in_pos )
2666   {
2667     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2668 					&property );
2669     if ( error )
2670       return error;
2671 
2672     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2673       break;
2674 
2675     i++;
2676     j--;
2677   }
2678 
2679   /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2680      too strong, thus it is commented out.                             */
2681 #if 0
2682   if ( property != HB_GDEF_LIGATURE )
2683     return HB_Err_Not_Covered;
2684 #endif
2685 
2686   if ( i > buffer->in_pos )
2687     return HB_Err_Not_Covered;
2688 
2689   error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2690 			  &lig_index );
2691   if ( error )
2692     return error;
2693 
2694   ma = &mlp->MarkArray;
2695 
2696   if ( mark_index >= ma->MarkCount )
2697     return ERR(HB_Err_Invalid_SubTable);
2698 
2699   class       = ma->MarkRecord[mark_index].Class;
2700   mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2701 
2702   if ( class >= mlp->ClassCount )
2703     return ERR(HB_Err_Invalid_SubTable);
2704 
2705   la = &mlp->LigatureArray;
2706 
2707   if ( lig_index >= la->LigatureCount )
2708     return ERR(HB_Err_Invalid_SubTable);
2709 
2710   lat = &la->LigatureAttach[lig_index];
2711 
2712   /* We must now check whether the ligature ID of the current mark glyph
2713      is identical to the ligature ID of the found ligature.  If yes, we
2714      can directly use the component index.  If not, we attach the mark
2715      glyph to the last component of the ligature.                        */
2716 
2717   if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
2718   {
2719     comp_index = IN_COMPONENT( buffer->in_pos );
2720     if ( comp_index >= lat->ComponentCount )
2721       return HB_Err_Not_Covered;
2722   }
2723   else
2724     comp_index = lat->ComponentCount - 1;
2725 
2726   cr         = &lat->ComponentRecord[comp_index];
2727   lig_anchor = &cr->LigatureAnchor[class];
2728 
2729   error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2730 		      &x_mark_value, &y_mark_value );
2731   if ( error )
2732     return error;
2733   error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2734 		      &x_lig_value, &y_lig_value );
2735   if ( error )
2736     return error;
2737 
2738   /* anchor points are not cumulative */
2739 
2740   o = POSITION( buffer->in_pos );
2741 
2742   o->x_pos     = x_lig_value - x_mark_value;
2743   o->y_pos     = y_lig_value - y_mark_value;
2744   o->x_advance = 0;
2745   o->y_advance = 0;
2746   o->back      = i;
2747 
2748   (buffer->in_pos)++;
2749 
2750   return HB_Err_Ok;
2751 }
2752 
2753 
2754 /* LookupType 6 */
2755 
2756 /* Mark2Array */
2757 
Load_Mark2Array(HB_Mark2Array * m2a,HB_UShort num_classes,HB_Stream stream)2758 static HB_Error  Load_Mark2Array( HB_Mark2Array*  m2a,
2759 				  HB_UShort        num_classes,
2760 				  HB_Stream        stream )
2761 {
2762   HB_Error  error;
2763 
2764   HB_UShort        m, n, count;
2765   HB_UInt          cur_offset, new_offset, base_offset;
2766 
2767   HB_Mark2Record  *m2r;
2768   HB_Anchor       *m2an, *m2ans;
2769 
2770 
2771   base_offset = FILE_Pos();
2772 
2773   if ( ACCESS_Frame( 2L ) )
2774     return error;
2775 
2776   count = m2a->Mark2Count = GET_UShort();
2777 
2778   FORGET_Frame();
2779 
2780   m2a->Mark2Record = NULL;
2781 
2782   if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2783     return error;
2784 
2785   m2r = m2a->Mark2Record;
2786 
2787   m2ans = NULL;
2788 
2789   if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
2790     goto Fail;
2791 
2792   for ( m = 0; m < count; m++ )
2793   {
2794     m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
2795 
2796     for ( n = 0; n < num_classes; n++ )
2797     {
2798       if ( ACCESS_Frame( 2L ) )
2799 	goto Fail;
2800 
2801       new_offset = GET_UShort() + base_offset;
2802 
2803       FORGET_Frame();
2804 
2805       if (new_offset == base_offset) {
2806         /* Anchor table not provided.  Skip loading.
2807 	 * Some versions of FreeSans hit this. */
2808         m2an[n].PosFormat = 0;
2809 	continue;
2810       }
2811 
2812       cur_offset = FILE_Pos();
2813       if ( FILE_Seek( new_offset ) ||
2814 	   ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
2815 	goto Fail;
2816       (void)FILE_Seek( cur_offset );
2817     }
2818   }
2819 
2820   return HB_Err_Ok;
2821 
2822 Fail:
2823   FREE( m2ans );
2824   FREE( m2r );
2825   return error;
2826 }
2827 
2828 
Free_Mark2Array(HB_Mark2Array * m2a,HB_UShort num_classes)2829 static void  Free_Mark2Array( HB_Mark2Array*  m2a,
2830 			      HB_UShort        num_classes )
2831 {
2832   HB_Mark2Record  *m2r;
2833   HB_Anchor       *m2ans;
2834 
2835   HB_UNUSED(num_classes);
2836 
2837   if ( m2a->Mark2Record )
2838   {
2839     m2r   = m2a->Mark2Record;
2840 
2841     if ( m2a->Mark2Count )
2842     {
2843       m2ans = m2r[0].Mark2Anchor;
2844       FREE( m2ans );
2845     }
2846 
2847     FREE( m2r );
2848   }
2849 }
2850 
2851 
2852 /* MarkMarkPosFormat1 */
2853 
Load_MarkMarkPos(HB_GPOS_SubTable * st,HB_Stream stream)2854 static HB_Error  Load_MarkMarkPos( HB_GPOS_SubTable* st,
2855 				   HB_Stream         stream )
2856 {
2857   HB_Error  error;
2858   HB_MarkMarkPos* mmp = &st->markmark;
2859 
2860   HB_UInt  cur_offset, new_offset, base_offset;
2861 
2862 
2863   base_offset = FILE_Pos();
2864 
2865   if ( ACCESS_Frame( 4L ) )
2866     return error;
2867 
2868   mmp->PosFormat = GET_UShort();
2869   new_offset     = GET_UShort() + base_offset;
2870 
2871   FORGET_Frame();
2872 
2873   cur_offset = FILE_Pos();
2874   if ( FILE_Seek( new_offset ) ||
2875        ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2876 				stream ) ) != HB_Err_Ok )
2877     return error;
2878   (void)FILE_Seek( cur_offset );
2879 
2880   if ( ACCESS_Frame( 2L ) )
2881     goto Fail3;
2882 
2883   new_offset = GET_UShort() + base_offset;
2884 
2885   FORGET_Frame();
2886 
2887   cur_offset = FILE_Pos();
2888   if ( FILE_Seek( new_offset ) ||
2889        ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2890 				stream ) ) != HB_Err_Ok )
2891     goto Fail3;
2892   (void)FILE_Seek( cur_offset );
2893 
2894   if ( ACCESS_Frame( 4L ) )
2895     goto Fail2;
2896 
2897   mmp->ClassCount = GET_UShort();
2898   new_offset      = GET_UShort() + base_offset;
2899 
2900   FORGET_Frame();
2901 
2902   cur_offset = FILE_Pos();
2903   if ( FILE_Seek( new_offset ) ||
2904        ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
2905     goto Fail2;
2906   (void)FILE_Seek( cur_offset );
2907 
2908   if ( ACCESS_Frame( 2L ) )
2909     goto Fail1;
2910 
2911   new_offset = GET_UShort() + base_offset;
2912 
2913   FORGET_Frame();
2914 
2915   cur_offset = FILE_Pos();
2916   if ( FILE_Seek( new_offset ) ||
2917        ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2918 				  stream ) ) != HB_Err_Ok )
2919     goto Fail1;
2920 
2921   return HB_Err_Ok;
2922 
2923 Fail1:
2924   Free_MarkArray( &mmp->Mark1Array );
2925 
2926 Fail2:
2927   _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2928 
2929 Fail3:
2930   _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2931   return error;
2932 }
2933 
2934 
Free_MarkMarkPos(HB_GPOS_SubTable * st)2935 static void  Free_MarkMarkPos( HB_GPOS_SubTable* st)
2936 {
2937   HB_MarkMarkPos* mmp = &st->markmark;
2938 
2939   Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2940   Free_MarkArray( &mmp->Mark1Array );
2941   _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2942   _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2943 }
2944 
2945 
Lookup_MarkMarkPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2946 static HB_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
2947 				     HB_GPOS_SubTable* st,
2948 				     HB_Buffer        buffer,
2949 				     HB_UShort         flags,
2950 				     HB_UShort         context_length,
2951 				     int               nesting_level )
2952 {
2953   HB_UShort        i, j, mark1_index, mark2_index, property, class;
2954   HB_Fixed           x_mark1_value, y_mark1_value,
2955 		   x_mark2_value, y_mark2_value;
2956   HB_Error         error;
2957   HB_GPOSHeader*  gpos = gpi->gpos;
2958   HB_MarkMarkPos* mmp = &st->markmark;
2959 
2960   HB_MarkArray*    ma1;
2961   HB_Mark2Array*   ma2;
2962   HB_Mark2Record*  m2r;
2963   HB_Anchor*       mark1_anchor;
2964   HB_Anchor*       mark2_anchor;
2965 
2966   HB_Position    o;
2967 
2968   HB_UNUSED(nesting_level);
2969 
2970   if ( context_length != 0xFFFF && context_length < 1 )
2971     return HB_Err_Not_Covered;
2972 
2973   if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
2974     return HB_Err_Not_Covered;
2975 
2976   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2977 		       flags, &property ) )
2978     return error;
2979 
2980   error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
2981 			  &mark1_index );
2982   if ( error )
2983     return error;
2984 
2985   /* now we search backwards for a suitable mark glyph until a non-mark
2986      glyph                                                */
2987 
2988   if ( buffer->in_pos == 0 )
2989     return HB_Err_Not_Covered;
2990 
2991   i = 1;
2992   j = buffer->in_pos - 1;
2993   while ( i <= buffer->in_pos )
2994   {
2995     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2996 					&property );
2997     if ( error )
2998       return error;
2999 
3000     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
3001       return HB_Err_Not_Covered;
3002 
3003     if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
3004     {
3005       if ( property == (flags & 0xFF00) )
3006         break;
3007     }
3008     else
3009       break;
3010 
3011     i++;
3012     j--;
3013   }
3014 
3015   error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3016 			  &mark2_index );
3017   if ( error )
3018     return error;
3019 
3020   ma1 = &mmp->Mark1Array;
3021 
3022   if ( mark1_index >= ma1->MarkCount )
3023     return ERR(HB_Err_Invalid_SubTable);
3024 
3025   class        = ma1->MarkRecord[mark1_index].Class;
3026   mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3027 
3028   if ( class >= mmp->ClassCount )
3029     return ERR(HB_Err_Invalid_SubTable);
3030 
3031   ma2 = &mmp->Mark2Array;
3032 
3033   if ( mark2_index >= ma2->Mark2Count )
3034     return ERR(HB_Err_Invalid_SubTable);
3035 
3036   m2r          = &ma2->Mark2Record[mark2_index];
3037   mark2_anchor = &m2r->Mark2Anchor[class];
3038 
3039   error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3040 		      &x_mark1_value, &y_mark1_value );
3041   if ( error )
3042     return error;
3043   error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3044 		      &x_mark2_value, &y_mark2_value );
3045   if ( error )
3046     return error;
3047 
3048   /* anchor points are not cumulative */
3049 
3050   o = POSITION( buffer->in_pos );
3051 
3052   o->x_pos     = x_mark2_value - x_mark1_value;
3053   o->y_pos     = y_mark2_value - y_mark1_value;
3054   o->x_advance = 0;
3055   o->y_advance = 0;
3056   o->back      = 1;
3057 
3058   (buffer->in_pos)++;
3059 
3060   return HB_Err_Ok;
3061 }
3062 
3063 
3064 /* Do the actual positioning for a context positioning (either format
3065    7 or 8).  This is only called after we've determined that the stream
3066    matches the subrule.                                                 */
3067 
Do_ContextPos(GPOS_Instance * gpi,HB_UShort GlyphCount,HB_UShort PosCount,HB_PosLookupRecord * pos,HB_Buffer buffer,int nesting_level)3068 static HB_Error  Do_ContextPos( GPOS_Instance*        gpi,
3069 				HB_UShort             GlyphCount,
3070 				HB_UShort             PosCount,
3071 				HB_PosLookupRecord*  pos,
3072 				HB_Buffer            buffer,
3073 				int                   nesting_level )
3074 {
3075   HB_Error  error;
3076   HB_UInt   i, old_pos;
3077 
3078 
3079   i = 0;
3080 
3081   while ( i < GlyphCount )
3082   {
3083     if ( PosCount && i == pos->SequenceIndex )
3084     {
3085       old_pos = buffer->in_pos;
3086 
3087       /* Do a positioning */
3088 
3089       error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3090 				    GlyphCount, nesting_level );
3091 
3092       if ( error )
3093 	return error;
3094 
3095       pos++;
3096       PosCount--;
3097       i += buffer->in_pos - old_pos;
3098     }
3099     else
3100     {
3101       i++;
3102       (buffer->in_pos)++;
3103     }
3104   }
3105 
3106   return HB_Err_Ok;
3107 }
3108 
3109 
3110 /* LookupType 7 */
3111 
3112 /* PosRule */
3113 
Load_PosRule(HB_PosRule * pr,HB_Stream stream)3114 static HB_Error  Load_PosRule( HB_PosRule*  pr,
3115 			       HB_Stream     stream )
3116 {
3117   HB_Error  error;
3118 
3119   HB_UShort             n, count;
3120   HB_UShort*            i;
3121 
3122   HB_PosLookupRecord*  plr;
3123 
3124 
3125   if ( ACCESS_Frame( 4L ) )
3126     return error;
3127 
3128   pr->GlyphCount = GET_UShort();
3129   pr->PosCount   = GET_UShort();
3130 
3131   FORGET_Frame();
3132 
3133   pr->Input = NULL;
3134 
3135   count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
3136 
3137   if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3138     return error;
3139 
3140   i = pr->Input;
3141 
3142   if ( ACCESS_Frame( count * 2L ) )
3143     goto Fail2;
3144 
3145   for ( n = 0; n < count; n++ )
3146     i[n] = GET_UShort();
3147 
3148   FORGET_Frame();
3149 
3150   pr->PosLookupRecord = NULL;
3151 
3152   count = pr->PosCount;
3153 
3154   if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3155     goto Fail2;
3156 
3157   plr = pr->PosLookupRecord;
3158 
3159   if ( ACCESS_Frame( count * 4L ) )
3160     goto Fail1;
3161 
3162   for ( n = 0; n < count; n++ )
3163   {
3164     plr[n].SequenceIndex   = GET_UShort();
3165     plr[n].LookupListIndex = GET_UShort();
3166   }
3167 
3168   FORGET_Frame();
3169 
3170   return HB_Err_Ok;
3171 
3172 Fail1:
3173   FREE( plr );
3174 
3175 Fail2:
3176   FREE( i );
3177   return error;
3178 }
3179 
3180 
Free_PosRule(HB_PosRule * pr)3181 static void  Free_PosRule( HB_PosRule*  pr )
3182 {
3183   FREE( pr->PosLookupRecord );
3184   FREE( pr->Input );
3185 }
3186 
3187 
3188 /* PosRuleSet */
3189 
Load_PosRuleSet(HB_PosRuleSet * prs,HB_Stream stream)3190 static HB_Error  Load_PosRuleSet( HB_PosRuleSet*  prs,
3191 				  HB_Stream        stream )
3192 {
3193   HB_Error  error;
3194 
3195   HB_UShort     n, m, count;
3196   HB_UInt      cur_offset, new_offset, base_offset;
3197 
3198   HB_PosRule*  pr;
3199 
3200 
3201   base_offset = FILE_Pos();
3202 
3203   if ( ACCESS_Frame( 2L ) )
3204     return error;
3205 
3206   count = prs->PosRuleCount = GET_UShort();
3207 
3208   FORGET_Frame();
3209 
3210   prs->PosRule = NULL;
3211 
3212   if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3213     return error;
3214 
3215   pr = prs->PosRule;
3216 
3217   for ( n = 0; n < count; n++ )
3218   {
3219     if ( ACCESS_Frame( 2L ) )
3220       goto Fail;
3221 
3222     new_offset = GET_UShort() + base_offset;
3223 
3224     FORGET_Frame();
3225 
3226     cur_offset = FILE_Pos();
3227     if ( FILE_Seek( new_offset ) ||
3228 	 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3229       goto Fail;
3230     (void)FILE_Seek( cur_offset );
3231   }
3232 
3233   return HB_Err_Ok;
3234 
3235 Fail:
3236   for ( m = 0; m < n; m++ )
3237     Free_PosRule( &pr[m] );
3238 
3239   FREE( pr );
3240   return error;
3241 }
3242 
3243 
Free_PosRuleSet(HB_PosRuleSet * prs)3244 static void  Free_PosRuleSet( HB_PosRuleSet*  prs )
3245 {
3246   HB_UShort     n, count;
3247 
3248   HB_PosRule*  pr;
3249 
3250 
3251   if ( prs->PosRule )
3252   {
3253     count = prs->PosRuleCount;
3254     pr    = prs->PosRule;
3255 
3256     for ( n = 0; n < count; n++ )
3257       Free_PosRule( &pr[n] );
3258 
3259     FREE( pr );
3260   }
3261 }
3262 
3263 
3264 /* ContextPosFormat1 */
3265 
Load_ContextPos1(HB_ContextPosFormat1 * cpf1,HB_Stream stream)3266 static HB_Error  Load_ContextPos1( HB_ContextPosFormat1*  cpf1,
3267 				   HB_Stream               stream )
3268 {
3269   HB_Error  error;
3270 
3271   HB_UShort        n, m, count;
3272   HB_UInt         cur_offset, new_offset, base_offset;
3273 
3274   HB_PosRuleSet*  prs;
3275 
3276 
3277   base_offset = FILE_Pos() - 2L;
3278 
3279   if ( ACCESS_Frame( 2L ) )
3280     return error;
3281 
3282   new_offset = GET_UShort() + base_offset;
3283 
3284   FORGET_Frame();
3285 
3286   cur_offset = FILE_Pos();
3287   if ( FILE_Seek( new_offset ) ||
3288        ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3289     return error;
3290   (void)FILE_Seek( cur_offset );
3291 
3292   if ( ACCESS_Frame( 2L ) )
3293     goto Fail2;
3294 
3295   count = cpf1->PosRuleSetCount = GET_UShort();
3296 
3297   FORGET_Frame();
3298 
3299   cpf1->PosRuleSet = NULL;
3300 
3301   if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3302     goto Fail2;
3303 
3304   prs = cpf1->PosRuleSet;
3305 
3306   for ( n = 0; n < count; n++ )
3307   {
3308     if ( ACCESS_Frame( 2L ) )
3309       goto Fail1;
3310 
3311     new_offset = GET_UShort() + base_offset;
3312 
3313     FORGET_Frame();
3314 
3315     cur_offset = FILE_Pos();
3316     if ( FILE_Seek( new_offset ) ||
3317 	 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3318       goto Fail1;
3319     (void)FILE_Seek( cur_offset );
3320   }
3321 
3322   return HB_Err_Ok;
3323 
3324 Fail1:
3325   for ( m = 0; m < n; m++ )
3326     Free_PosRuleSet( &prs[m] );
3327 
3328   FREE( prs );
3329 
3330 Fail2:
3331   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3332   return error;
3333 }
3334 
3335 
Free_ContextPos1(HB_ContextPosFormat1 * cpf1)3336 static void  Free_ContextPos1( HB_ContextPosFormat1*  cpf1 )
3337 {
3338   HB_UShort        n, count;
3339 
3340   HB_PosRuleSet*  prs;
3341 
3342 
3343   if ( cpf1->PosRuleSet )
3344   {
3345     count = cpf1->PosRuleSetCount;
3346     prs   = cpf1->PosRuleSet;
3347 
3348     for ( n = 0; n < count; n++ )
3349       Free_PosRuleSet( &prs[n] );
3350 
3351     FREE( prs );
3352   }
3353 
3354   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3355 }
3356 
3357 
3358 /* PosClassRule */
3359 
Load_PosClassRule(HB_ContextPosFormat2 * cpf2,HB_PosClassRule * pcr,HB_Stream stream)3360 static HB_Error  Load_PosClassRule( HB_ContextPosFormat2*  cpf2,
3361 				    HB_PosClassRule*       pcr,
3362 				    HB_Stream               stream )
3363 {
3364   HB_Error  error;
3365 
3366   HB_UShort             n, count;
3367 
3368   HB_UShort*            c;
3369   HB_PosLookupRecord*  plr;
3370 
3371 
3372   if ( ACCESS_Frame( 4L ) )
3373     return error;
3374 
3375   pcr->GlyphCount = GET_UShort();
3376   pcr->PosCount   = GET_UShort();
3377 
3378   FORGET_Frame();
3379 
3380   if ( pcr->GlyphCount > cpf2->MaxContextLength )
3381     cpf2->MaxContextLength = pcr->GlyphCount;
3382 
3383   pcr->Class = NULL;
3384 
3385   count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
3386 
3387   if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3388     return error;
3389 
3390   c = pcr->Class;
3391 
3392   if ( ACCESS_Frame( count * 2L ) )
3393     goto Fail2;
3394 
3395   for ( n = 0; n < count; n++ )
3396     c[n] = GET_UShort();
3397 
3398   FORGET_Frame();
3399 
3400   pcr->PosLookupRecord = NULL;
3401 
3402   count = pcr->PosCount;
3403 
3404   if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3405     goto Fail2;
3406 
3407   plr = pcr->PosLookupRecord;
3408 
3409   if ( ACCESS_Frame( count * 4L ) )
3410     goto Fail1;
3411 
3412   for ( n = 0; n < count; n++ )
3413   {
3414     plr[n].SequenceIndex   = GET_UShort();
3415     plr[n].LookupListIndex = GET_UShort();
3416   }
3417 
3418   FORGET_Frame();
3419 
3420   return HB_Err_Ok;
3421 
3422 Fail1:
3423   FREE( plr );
3424 
3425 Fail2:
3426   FREE( c );
3427   return error;
3428 }
3429 
3430 
Free_PosClassRule(HB_PosClassRule * pcr)3431 static void  Free_PosClassRule( HB_PosClassRule*  pcr )
3432 {
3433   FREE( pcr->PosLookupRecord );
3434   FREE( pcr->Class );
3435 }
3436 
3437 
3438 /* PosClassSet */
3439 
Load_PosClassSet(HB_ContextPosFormat2 * cpf2,HB_PosClassSet * pcs,HB_Stream stream)3440 static HB_Error  Load_PosClassSet( HB_ContextPosFormat2*  cpf2,
3441 				   HB_PosClassSet*        pcs,
3442 				   HB_Stream               stream )
3443 {
3444   HB_Error  error;
3445 
3446   HB_UShort          n, m, count;
3447   HB_UInt           cur_offset, new_offset, base_offset;
3448 
3449   HB_PosClassRule*  pcr;
3450 
3451 
3452   base_offset = FILE_Pos();
3453 
3454   if ( ACCESS_Frame( 2L ) )
3455     return error;
3456 
3457   count = pcs->PosClassRuleCount = GET_UShort();
3458 
3459   FORGET_Frame();
3460 
3461   pcs->PosClassRule = NULL;
3462 
3463   if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3464     return error;
3465 
3466   pcr = pcs->PosClassRule;
3467 
3468   for ( n = 0; n < count; n++ )
3469   {
3470     if ( ACCESS_Frame( 2L ) )
3471       goto Fail;
3472 
3473     new_offset = GET_UShort() + base_offset;
3474 
3475     FORGET_Frame();
3476 
3477     cur_offset = FILE_Pos();
3478     if ( FILE_Seek( new_offset ) ||
3479 	 ( error = Load_PosClassRule( cpf2, &pcr[n],
3480 				      stream ) ) != HB_Err_Ok )
3481       goto Fail;
3482     (void)FILE_Seek( cur_offset );
3483   }
3484 
3485   return HB_Err_Ok;
3486 
3487 Fail:
3488   for ( m = 0; m < n; m++ )
3489     Free_PosClassRule( &pcr[m] );
3490 
3491   FREE( pcr );
3492   return error;
3493 }
3494 
3495 
Free_PosClassSet(HB_PosClassSet * pcs)3496 static void  Free_PosClassSet( HB_PosClassSet*  pcs )
3497 {
3498   HB_UShort          n, count;
3499 
3500   HB_PosClassRule*  pcr;
3501 
3502 
3503   if ( pcs->PosClassRule )
3504   {
3505     count = pcs->PosClassRuleCount;
3506     pcr   = pcs->PosClassRule;
3507 
3508     for ( n = 0; n < count; n++ )
3509       Free_PosClassRule( &pcr[n] );
3510 
3511     FREE( pcr );
3512   }
3513 }
3514 
3515 
3516 /* ContextPosFormat2 */
3517 
Load_ContextPos2(HB_ContextPosFormat2 * cpf2,HB_Stream stream)3518 static HB_Error  Load_ContextPos2( HB_ContextPosFormat2*  cpf2,
3519 				   HB_Stream               stream )
3520 {
3521   HB_Error  error;
3522 
3523   HB_UShort         n, m, count;
3524   HB_UInt          cur_offset, new_offset, base_offset;
3525 
3526   HB_PosClassSet*  pcs;
3527 
3528 
3529   base_offset = FILE_Pos() - 2;
3530 
3531   if ( ACCESS_Frame( 2L ) )
3532     return error;
3533 
3534   new_offset = GET_UShort() + base_offset;
3535 
3536   FORGET_Frame();
3537 
3538   cur_offset = FILE_Pos();
3539   if ( FILE_Seek( new_offset ) ||
3540        ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3541     return error;
3542   (void)FILE_Seek( cur_offset );
3543 
3544   if ( ACCESS_Frame( 4L ) )
3545     goto Fail3;
3546 
3547   new_offset = GET_UShort() + base_offset;
3548 
3549   /* `PosClassSetCount' is the upper limit for class values, thus we
3550      read it now to make an additional safety check.                 */
3551 
3552   count = cpf2->PosClassSetCount = GET_UShort();
3553 
3554   FORGET_Frame();
3555 
3556   cur_offset = FILE_Pos();
3557   if ( FILE_Seek( new_offset ) ||
3558        ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3559 				       stream ) ) != HB_Err_Ok )
3560     goto Fail3;
3561   (void)FILE_Seek( cur_offset );
3562 
3563   cpf2->PosClassSet      = NULL;
3564   cpf2->MaxContextLength = 0;
3565 
3566   if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3567     goto Fail2;
3568 
3569   pcs = cpf2->PosClassSet;
3570 
3571   for ( n = 0; n < count; n++ )
3572   {
3573     if ( ACCESS_Frame( 2L ) )
3574       goto Fail1;
3575 
3576     new_offset = GET_UShort() + base_offset;
3577 
3578     FORGET_Frame();
3579 
3580     if ( new_offset != base_offset )      /* not a NULL offset */
3581     {
3582       cur_offset = FILE_Pos();
3583       if ( FILE_Seek( new_offset ) ||
3584 	   ( error = Load_PosClassSet( cpf2, &pcs[n],
3585 				       stream ) ) != HB_Err_Ok )
3586 	goto Fail1;
3587       (void)FILE_Seek( cur_offset );
3588     }
3589     else
3590     {
3591       /* we create a PosClassSet table with no entries */
3592 
3593       cpf2->PosClassSet[n].PosClassRuleCount = 0;
3594       cpf2->PosClassSet[n].PosClassRule      = NULL;
3595     }
3596   }
3597 
3598   return HB_Err_Ok;
3599 
3600 Fail1:
3601   for ( m = 0; m < n; n++ )
3602     Free_PosClassSet( &pcs[m] );
3603 
3604   FREE( pcs );
3605 
3606 Fail2:
3607   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3608 
3609 Fail3:
3610   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3611   return error;
3612 }
3613 
3614 
Free_ContextPos2(HB_ContextPosFormat2 * cpf2)3615 static void  Free_ContextPos2( HB_ContextPosFormat2*  cpf2 )
3616 {
3617   HB_UShort         n, count;
3618 
3619   HB_PosClassSet*  pcs;
3620 
3621 
3622   if ( cpf2->PosClassSet )
3623   {
3624     count = cpf2->PosClassSetCount;
3625     pcs   = cpf2->PosClassSet;
3626 
3627     for ( n = 0; n < count; n++ )
3628       Free_PosClassSet( &pcs[n] );
3629 
3630     FREE( pcs );
3631   }
3632 
3633   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3634   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3635 }
3636 
3637 
3638 /* ContextPosFormat3 */
3639 
Load_ContextPos3(HB_ContextPosFormat3 * cpf3,HB_Stream stream)3640 static HB_Error  Load_ContextPos3( HB_ContextPosFormat3*  cpf3,
3641 				   HB_Stream               stream )
3642 {
3643   HB_Error  error;
3644 
3645   HB_UShort             n, count;
3646   HB_UInt              cur_offset, new_offset, base_offset;
3647 
3648   HB_Coverage*         c;
3649   HB_PosLookupRecord*  plr;
3650 
3651 
3652   base_offset = FILE_Pos() - 2L;
3653 
3654   if ( ACCESS_Frame( 4L ) )
3655     return error;
3656 
3657   cpf3->GlyphCount = GET_UShort();
3658   cpf3->PosCount   = GET_UShort();
3659 
3660   FORGET_Frame();
3661 
3662   cpf3->Coverage = NULL;
3663 
3664   count = cpf3->GlyphCount;
3665 
3666   if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3667     return error;
3668 
3669   c = cpf3->Coverage;
3670 
3671   for ( n = 0; n < count; n++ )
3672   {
3673     if ( ACCESS_Frame( 2L ) )
3674       goto Fail2;
3675 
3676     new_offset = GET_UShort() + base_offset;
3677 
3678     FORGET_Frame();
3679 
3680     cur_offset = FILE_Pos();
3681     if ( FILE_Seek( new_offset ) ||
3682 	 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3683       goto Fail2;
3684     (void)FILE_Seek( cur_offset );
3685   }
3686 
3687   cpf3->PosLookupRecord = NULL;
3688 
3689   count = cpf3->PosCount;
3690 
3691   if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3692     goto Fail2;
3693 
3694   plr = cpf3->PosLookupRecord;
3695 
3696   if ( ACCESS_Frame( count * 4L ) )
3697     goto Fail1;
3698 
3699   for ( n = 0; n < count; n++ )
3700   {
3701     plr[n].SequenceIndex   = GET_UShort();
3702     plr[n].LookupListIndex = GET_UShort();
3703   }
3704 
3705   FORGET_Frame();
3706 
3707   return HB_Err_Ok;
3708 
3709 Fail1:
3710   FREE( plr );
3711 
3712 Fail2:
3713   for ( n = 0; n < count; n++ )
3714     _HB_OPEN_Free_Coverage( &c[n] );
3715 
3716   FREE( c );
3717   return error;
3718 }
3719 
3720 
Free_ContextPos3(HB_ContextPosFormat3 * cpf3)3721 static void  Free_ContextPos3( HB_ContextPosFormat3*  cpf3 )
3722 {
3723   HB_UShort      n, count;
3724 
3725   HB_Coverage*  c;
3726 
3727 
3728   FREE( cpf3->PosLookupRecord );
3729 
3730   if ( cpf3->Coverage )
3731   {
3732     count = cpf3->GlyphCount;
3733     c     = cpf3->Coverage;
3734 
3735     for ( n = 0; n < count; n++ )
3736       _HB_OPEN_Free_Coverage( &c[n] );
3737 
3738     FREE( c );
3739   }
3740 }
3741 
3742 
3743 /* ContextPos */
3744 
Load_ContextPos(HB_GPOS_SubTable * st,HB_Stream stream)3745 static HB_Error  Load_ContextPos( HB_GPOS_SubTable* st,
3746 				  HB_Stream        stream )
3747 {
3748   HB_Error  error;
3749   HB_ContextPos*   cp = &st->context;
3750 
3751 
3752   if ( ACCESS_Frame( 2L ) )
3753     return error;
3754 
3755   cp->PosFormat = GET_UShort();
3756 
3757   FORGET_Frame();
3758 
3759   switch ( cp->PosFormat )
3760   {
3761   case 1:
3762     return Load_ContextPos1( &cp->cpf.cpf1, stream );
3763 
3764   case 2:
3765     return Load_ContextPos2( &cp->cpf.cpf2, stream );
3766 
3767   case 3:
3768     return Load_ContextPos3( &cp->cpf.cpf3, stream );
3769 
3770   default:
3771     return ERR(HB_Err_Invalid_SubTable_Format);
3772   }
3773 
3774   return HB_Err_Ok;               /* never reached */
3775 }
3776 
3777 
Free_ContextPos(HB_GPOS_SubTable * st)3778 static void  Free_ContextPos( HB_GPOS_SubTable* st )
3779 {
3780   HB_ContextPos*   cp = &st->context;
3781 
3782   switch ( cp->PosFormat )
3783   {
3784   case 1:  Free_ContextPos1( &cp->cpf.cpf1 ); break;
3785   case 2:  Free_ContextPos2( &cp->cpf.cpf2 ); break;
3786   case 3:  Free_ContextPos3( &cp->cpf.cpf3 ); break;
3787   default:					      break;
3788   }
3789 }
3790 
3791 
Lookup_ContextPos1(GPOS_Instance * gpi,HB_ContextPosFormat1 * cpf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3792 static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
3793 				     HB_ContextPosFormat1*  cpf1,
3794 				     HB_Buffer              buffer,
3795 				     HB_UShort               flags,
3796 				     HB_UShort               context_length,
3797 				     int                     nesting_level )
3798 {
3799   HB_UShort        index, property;
3800   HB_UShort        i, j, k, numpr;
3801   HB_Error         error;
3802   HB_GPOSHeader*  gpos = gpi->gpos;
3803 
3804   HB_PosRule*     pr;
3805   HB_GDEFHeader*  gdef;
3806 
3807 
3808   gdef = gpos->gdef;
3809 
3810   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3811     return error;
3812 
3813   error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3814   if ( error )
3815     return error;
3816 
3817   pr    = cpf1->PosRuleSet[index].PosRule;
3818   numpr = cpf1->PosRuleSet[index].PosRuleCount;
3819 
3820   for ( k = 0; k < numpr; k++ )
3821   {
3822     if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3823       goto next_posrule;
3824 
3825     if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3826       goto next_posrule;                       /* context is too long */
3827 
3828     for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3829     {
3830       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3831       {
3832 	if ( error && error != HB_Err_Not_Covered )
3833 	  return error;
3834 
3835 	if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3836 	  goto next_posrule;
3837 	j++;
3838       }
3839 
3840       if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3841 	goto next_posrule;
3842     }
3843 
3844     return Do_ContextPos( gpi, pr[k].GlyphCount,
3845 			  pr[k].PosCount, pr[k].PosLookupRecord,
3846 			  buffer,
3847 			  nesting_level );
3848 
3849     next_posrule:
3850       ;
3851   }
3852 
3853   return HB_Err_Not_Covered;
3854 }
3855 
3856 
Lookup_ContextPos2(GPOS_Instance * gpi,HB_ContextPosFormat2 * cpf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3857 static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
3858 				     HB_ContextPosFormat2*  cpf2,
3859 				     HB_Buffer              buffer,
3860 				     HB_UShort               flags,
3861 				     HB_UShort               context_length,
3862 				     int                     nesting_level )
3863 {
3864   HB_UShort          index, property;
3865   HB_Error           error;
3866   HB_UShort          i, j, k, known_classes;
3867 
3868   HB_UShort*         classes;
3869   HB_UShort*         cl;
3870   HB_GPOSHeader*    gpos = gpi->gpos;
3871 
3872   HB_PosClassSet*   pcs;
3873   HB_PosClassRule*  pr;
3874   HB_GDEFHeader*    gdef;
3875 
3876 
3877   gdef = gpos->gdef;
3878 
3879   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3880     return error;
3881 
3882   /* Note: The coverage table in format 2 doesn't give an index into
3883 	   anything.  It just lets us know whether or not we need to
3884 	   do any lookup at all.                                     */
3885 
3886   error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3887   if ( error )
3888     return error;
3889 
3890   if (cpf2->MaxContextLength < 1)
3891     return HB_Err_Not_Covered;
3892 
3893   if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3894     return error;
3895 
3896   error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3897 		     &classes[0], NULL );
3898   if ( error && error != HB_Err_Not_Covered )
3899     goto End;
3900   known_classes = 0;
3901 
3902   pcs = &cpf2->PosClassSet[classes[0]];
3903   if ( !pcs )
3904   {
3905     error = ERR(HB_Err_Invalid_SubTable);
3906     goto End;
3907   }
3908 
3909   for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3910   {
3911     pr = &pcs->PosClassRule[k];
3912 
3913     if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
3914       goto next_posclassrule;
3915 
3916     if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
3917       goto next_posclassrule;                /* context is too long */
3918 
3919     cl   = pr->Class;
3920 
3921     /* Start at 1 because [0] is implied */
3922 
3923     for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
3924     {
3925       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3926       {
3927 	if ( error && error != HB_Err_Not_Covered )
3928 	  goto End;
3929 
3930 	if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3931 	  goto next_posclassrule;
3932 	j++;
3933       }
3934 
3935       if ( i > known_classes )
3936       {
3937 	/* Keeps us from having to do this for each rule */
3938 
3939 	error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
3940 	if ( error && error != HB_Err_Not_Covered )
3941 	  goto End;
3942 	known_classes = i;
3943       }
3944 
3945       if ( cl[i - 1] != classes[i] )
3946 	goto next_posclassrule;
3947     }
3948 
3949     error = Do_ContextPos( gpi, pr->GlyphCount,
3950 			   pr->PosCount, pr->PosLookupRecord,
3951 			   buffer,
3952 			   nesting_level );
3953     goto End;
3954 
3955   next_posclassrule:
3956     ;
3957   }
3958 
3959   error = HB_Err_Not_Covered;
3960 
3961 End:
3962   FREE( classes );
3963   return error;
3964 }
3965 
3966 
Lookup_ContextPos3(GPOS_Instance * gpi,HB_ContextPosFormat3 * cpf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3967 static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
3968 				     HB_ContextPosFormat3*  cpf3,
3969 				     HB_Buffer              buffer,
3970 				     HB_UShort               flags,
3971 				     HB_UShort               context_length,
3972 				     int                     nesting_level )
3973 {
3974   HB_Error         error;
3975   HB_UShort        index, i, j, property;
3976   HB_GPOSHeader*  gpos = gpi->gpos;
3977 
3978   HB_Coverage*    c;
3979   HB_GDEFHeader*  gdef;
3980 
3981 
3982   gdef = gpos->gdef;
3983 
3984   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3985     return error;
3986 
3987   if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
3988     return HB_Err_Not_Covered;
3989 
3990   if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
3991     return HB_Err_Not_Covered;         /* context is too long */
3992 
3993   c    = cpf3->Coverage;
3994 
3995   for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
3996   {
3997     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3998     {
3999       if ( error && error != HB_Err_Not_Covered )
4000 	return error;
4001 
4002       if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
4003 	return HB_Err_Not_Covered;
4004       j++;
4005     }
4006 
4007     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4008     if ( error )
4009       return error;
4010   }
4011 
4012   return Do_ContextPos( gpi, cpf3->GlyphCount,
4013 			cpf3->PosCount, cpf3->PosLookupRecord,
4014 			buffer,
4015 			nesting_level );
4016 }
4017 
4018 
Lookup_ContextPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)4019 static HB_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
4020 				    HB_GPOS_SubTable* st,
4021 				    HB_Buffer        buffer,
4022 				    HB_UShort         flags,
4023 				    HB_UShort         context_length,
4024 				    int               nesting_level )
4025 {
4026   HB_ContextPos*   cp = &st->context;
4027 
4028   switch ( cp->PosFormat )
4029   {
4030   case 1:
4031     return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4032 			       flags, context_length, nesting_level );
4033 
4034   case 2:
4035     return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4036 			       flags, context_length, nesting_level );
4037 
4038   case 3:
4039     return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4040 			       flags, context_length, nesting_level );
4041 
4042   default:
4043     return ERR(HB_Err_Invalid_SubTable_Format);
4044   }
4045 
4046   return HB_Err_Ok;               /* never reached */
4047 }
4048 
4049 
4050 /* LookupType 8 */
4051 
4052 /* ChainPosRule */
4053 
Load_ChainPosRule(HB_ChainPosRule * cpr,HB_Stream stream)4054 static HB_Error  Load_ChainPosRule( HB_ChainPosRule*  cpr,
4055 				    HB_Stream          stream )
4056 {
4057   HB_Error  error;
4058 
4059   HB_UShort             n, count;
4060   HB_UShort*            b;
4061   HB_UShort*            i;
4062   HB_UShort*            l;
4063 
4064   HB_PosLookupRecord*  plr;
4065 
4066 
4067   if ( ACCESS_Frame( 2L ) )
4068     return error;
4069 
4070   cpr->BacktrackGlyphCount = GET_UShort();
4071 
4072   FORGET_Frame();
4073 
4074   cpr->Backtrack = NULL;
4075 
4076   count = cpr->BacktrackGlyphCount;
4077 
4078   if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4079     return error;
4080 
4081   b = cpr->Backtrack;
4082 
4083   if ( ACCESS_Frame( count * 2L ) )
4084     goto Fail4;
4085 
4086   for ( n = 0; n < count; n++ )
4087     b[n] = GET_UShort();
4088 
4089   FORGET_Frame();
4090 
4091   if ( ACCESS_Frame( 2L ) )
4092     goto Fail4;
4093 
4094   cpr->InputGlyphCount = GET_UShort();
4095 
4096   FORGET_Frame();
4097 
4098   cpr->Input = NULL;
4099 
4100   count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
4101 
4102   if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4103     goto Fail4;
4104 
4105   i = cpr->Input;
4106 
4107   if ( ACCESS_Frame( count * 2L ) )
4108     goto Fail3;
4109 
4110   for ( n = 0; n < count; n++ )
4111     i[n] = GET_UShort();
4112 
4113   FORGET_Frame();
4114 
4115   if ( ACCESS_Frame( 2L ) )
4116     goto Fail3;
4117 
4118   cpr->LookaheadGlyphCount = GET_UShort();
4119 
4120   FORGET_Frame();
4121 
4122   cpr->Lookahead = NULL;
4123 
4124   count = cpr->LookaheadGlyphCount;
4125 
4126   if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4127     goto Fail3;
4128 
4129   l = cpr->Lookahead;
4130 
4131   if ( ACCESS_Frame( count * 2L ) )
4132     goto Fail2;
4133 
4134   for ( n = 0; n < count; n++ )
4135     l[n] = GET_UShort();
4136 
4137   FORGET_Frame();
4138 
4139   if ( ACCESS_Frame( 2L ) )
4140     goto Fail2;
4141 
4142   cpr->PosCount = GET_UShort();
4143 
4144   FORGET_Frame();
4145 
4146   cpr->PosLookupRecord = NULL;
4147 
4148   count = cpr->PosCount;
4149 
4150   if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4151     goto Fail2;
4152 
4153   plr = cpr->PosLookupRecord;
4154 
4155   if ( ACCESS_Frame( count * 4L ) )
4156     goto Fail1;
4157 
4158   for ( n = 0; n < count; n++ )
4159   {
4160     plr[n].SequenceIndex   = GET_UShort();
4161     plr[n].LookupListIndex = GET_UShort();
4162   }
4163 
4164   FORGET_Frame();
4165 
4166   return HB_Err_Ok;
4167 
4168 Fail1:
4169   FREE( plr );
4170 
4171 Fail2:
4172   FREE( l );
4173 
4174 Fail3:
4175   FREE( i );
4176 
4177 Fail4:
4178   FREE( b );
4179   return error;
4180 }
4181 
4182 
Free_ChainPosRule(HB_ChainPosRule * cpr)4183 static void  Free_ChainPosRule( HB_ChainPosRule*  cpr )
4184 {
4185   FREE( cpr->PosLookupRecord );
4186   FREE( cpr->Lookahead );
4187   FREE( cpr->Input );
4188   FREE( cpr->Backtrack );
4189 }
4190 
4191 
4192 /* ChainPosRuleSet */
4193 
Load_ChainPosRuleSet(HB_ChainPosRuleSet * cprs,HB_Stream stream)4194 static HB_Error  Load_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
4195 				       HB_Stream             stream )
4196 {
4197   HB_Error  error;
4198 
4199   HB_UShort          n, m, count;
4200   HB_UInt           cur_offset, new_offset, base_offset;
4201 
4202   HB_ChainPosRule*  cpr;
4203 
4204 
4205   base_offset = FILE_Pos();
4206 
4207   if ( ACCESS_Frame( 2L ) )
4208     return error;
4209 
4210   count = cprs->ChainPosRuleCount = GET_UShort();
4211 
4212   FORGET_Frame();
4213 
4214   cprs->ChainPosRule = NULL;
4215 
4216   if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4217     return error;
4218 
4219   cpr = cprs->ChainPosRule;
4220 
4221   for ( n = 0; n < count; n++ )
4222   {
4223     if ( ACCESS_Frame( 2L ) )
4224       goto Fail;
4225 
4226     new_offset = GET_UShort() + base_offset;
4227 
4228     FORGET_Frame();
4229 
4230     cur_offset = FILE_Pos();
4231     if ( FILE_Seek( new_offset ) ||
4232 	 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4233       goto Fail;
4234     (void)FILE_Seek( cur_offset );
4235   }
4236 
4237   return HB_Err_Ok;
4238 
4239 Fail:
4240   for ( m = 0; m < n; m++ )
4241     Free_ChainPosRule( &cpr[m] );
4242 
4243   FREE( cpr );
4244   return error;
4245 }
4246 
4247 
Free_ChainPosRuleSet(HB_ChainPosRuleSet * cprs)4248 static void  Free_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs )
4249 {
4250   HB_UShort          n, count;
4251 
4252   HB_ChainPosRule*  cpr;
4253 
4254 
4255   if ( cprs->ChainPosRule )
4256   {
4257     count = cprs->ChainPosRuleCount;
4258     cpr   = cprs->ChainPosRule;
4259 
4260     for ( n = 0; n < count; n++ )
4261       Free_ChainPosRule( &cpr[n] );
4262 
4263     FREE( cpr );
4264   }
4265 }
4266 
4267 
4268 /* ChainContextPosFormat1 */
4269 
Load_ChainContextPos1(HB_ChainContextPosFormat1 * ccpf1,HB_Stream stream)4270 static HB_Error  Load_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
4271 					HB_Stream                    stream )
4272 {
4273   HB_Error  error;
4274 
4275   HB_UShort             n, m, count;
4276   HB_UInt              cur_offset, new_offset, base_offset;
4277 
4278   HB_ChainPosRuleSet*  cprs;
4279 
4280 
4281   base_offset = FILE_Pos() - 2L;
4282 
4283   if ( ACCESS_Frame( 2L ) )
4284     return error;
4285 
4286   new_offset = GET_UShort() + base_offset;
4287 
4288   FORGET_Frame();
4289 
4290   cur_offset = FILE_Pos();
4291   if ( FILE_Seek( new_offset ) ||
4292        ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4293     return error;
4294   (void)FILE_Seek( cur_offset );
4295 
4296   if ( ACCESS_Frame( 2L ) )
4297     goto Fail2;
4298 
4299   count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4300 
4301   FORGET_Frame();
4302 
4303   ccpf1->ChainPosRuleSet = NULL;
4304 
4305   if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4306     goto Fail2;
4307 
4308   cprs = ccpf1->ChainPosRuleSet;
4309 
4310   for ( n = 0; n < count; n++ )
4311   {
4312     if ( ACCESS_Frame( 2L ) )
4313       goto Fail1;
4314 
4315     new_offset = GET_UShort() + base_offset;
4316 
4317     FORGET_Frame();
4318 
4319     cur_offset = FILE_Pos();
4320     if ( FILE_Seek( new_offset ) ||
4321 	 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4322       goto Fail1;
4323     (void)FILE_Seek( cur_offset );
4324   }
4325 
4326   return HB_Err_Ok;
4327 
4328 Fail1:
4329   for ( m = 0; m < n; m++ )
4330     Free_ChainPosRuleSet( &cprs[m] );
4331 
4332   FREE( cprs );
4333 
4334 Fail2:
4335   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4336   return error;
4337 }
4338 
4339 
Free_ChainContextPos1(HB_ChainContextPosFormat1 * ccpf1)4340 static void  Free_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1 )
4341 {
4342   HB_UShort             n, count;
4343 
4344   HB_ChainPosRuleSet*  cprs;
4345 
4346 
4347   if ( ccpf1->ChainPosRuleSet )
4348   {
4349     count = ccpf1->ChainPosRuleSetCount;
4350     cprs  = ccpf1->ChainPosRuleSet;
4351 
4352     for ( n = 0; n < count; n++ )
4353       Free_ChainPosRuleSet( &cprs[n] );
4354 
4355     FREE( cprs );
4356   }
4357 
4358   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4359 }
4360 
4361 
4362 /* ChainPosClassRule */
4363 
Load_ChainPosClassRule(HB_ChainContextPosFormat2 * ccpf2,HB_ChainPosClassRule * cpcr,HB_Stream stream)4364 static HB_Error  Load_ChainPosClassRule(
4365 		   HB_ChainContextPosFormat2*  ccpf2,
4366 		   HB_ChainPosClassRule*       cpcr,
4367 		   HB_Stream                    stream )
4368 {
4369   HB_Error  error;
4370 
4371   HB_UShort             n, count;
4372 
4373   HB_UShort*            b;
4374   HB_UShort*            i;
4375   HB_UShort*            l;
4376   HB_PosLookupRecord*  plr;
4377 
4378 
4379   if ( ACCESS_Frame( 2L ) )
4380     return error;
4381 
4382   cpcr->BacktrackGlyphCount = GET_UShort();
4383 
4384   FORGET_Frame();
4385 
4386   if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4387     ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4388 
4389   cpcr->Backtrack = NULL;
4390 
4391   count = cpcr->BacktrackGlyphCount;
4392 
4393   if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
4394     return error;
4395 
4396   b = cpcr->Backtrack;
4397 
4398   if ( ACCESS_Frame( count * 2L ) )
4399     goto Fail4;
4400 
4401   for ( n = 0; n < count; n++ )
4402     b[n] = GET_UShort();
4403 
4404   FORGET_Frame();
4405 
4406   if ( ACCESS_Frame( 2L ) )
4407     goto Fail4;
4408 
4409   cpcr->InputGlyphCount = GET_UShort();
4410 
4411   if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4412     ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4413 
4414   FORGET_Frame();
4415 
4416   cpcr->Input = NULL;
4417 
4418   count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4419 
4420   if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4421     goto Fail4;
4422 
4423   i = cpcr->Input;
4424 
4425   if ( ACCESS_Frame( count * 2L ) )
4426     goto Fail3;
4427 
4428   for ( n = 0; n < count; n++ )
4429     i[n] = GET_UShort();
4430 
4431   FORGET_Frame();
4432 
4433   if ( ACCESS_Frame( 2L ) )
4434     goto Fail3;
4435 
4436   cpcr->LookaheadGlyphCount = GET_UShort();
4437 
4438   FORGET_Frame();
4439 
4440   if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4441     ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4442 
4443   cpcr->Lookahead = NULL;
4444 
4445   count = cpcr->LookaheadGlyphCount;
4446 
4447   if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
4448     goto Fail3;
4449 
4450   l = cpcr->Lookahead;
4451 
4452   if ( ACCESS_Frame( count * 2L ) )
4453     goto Fail2;
4454 
4455   for ( n = 0; n < count; n++ )
4456     l[n] = GET_UShort();
4457 
4458   FORGET_Frame();
4459 
4460   if ( ACCESS_Frame( 2L ) )
4461     goto Fail2;
4462 
4463   cpcr->PosCount = GET_UShort();
4464 
4465   FORGET_Frame();
4466 
4467   cpcr->PosLookupRecord = NULL;
4468 
4469   count = cpcr->PosCount;
4470 
4471   if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4472     goto Fail2;
4473 
4474   plr = cpcr->PosLookupRecord;
4475 
4476   if ( ACCESS_Frame( count * 4L ) )
4477     goto Fail1;
4478 
4479   for ( n = 0; n < count; n++ )
4480   {
4481     plr[n].SequenceIndex   = GET_UShort();
4482     plr[n].LookupListIndex = GET_UShort();
4483   }
4484 
4485   FORGET_Frame();
4486 
4487   return HB_Err_Ok;
4488 
4489 Fail1:
4490   FREE( plr );
4491 
4492 Fail2:
4493   FREE( l );
4494 
4495 Fail3:
4496   FREE( i );
4497 
4498 Fail4:
4499   FREE( b );
4500   return error;
4501 }
4502 
4503 
Free_ChainPosClassRule(HB_ChainPosClassRule * cpcr)4504 static void  Free_ChainPosClassRule( HB_ChainPosClassRule*  cpcr )
4505 {
4506   FREE( cpcr->PosLookupRecord );
4507   FREE( cpcr->Lookahead );
4508   FREE( cpcr->Input );
4509   FREE( cpcr->Backtrack );
4510 }
4511 
4512 
4513 /* PosClassSet */
4514 
Load_ChainPosClassSet(HB_ChainContextPosFormat2 * ccpf2,HB_ChainPosClassSet * cpcs,HB_Stream stream)4515 static HB_Error  Load_ChainPosClassSet(
4516 		   HB_ChainContextPosFormat2*  ccpf2,
4517 		   HB_ChainPosClassSet*        cpcs,
4518 		   HB_Stream                    stream )
4519 {
4520   HB_Error  error;
4521 
4522   HB_UShort               n, m, count;
4523   HB_UInt                cur_offset, new_offset, base_offset;
4524 
4525   HB_ChainPosClassRule*  cpcr;
4526 
4527 
4528   base_offset = FILE_Pos();
4529 
4530   if ( ACCESS_Frame( 2L ) )
4531     return error;
4532 
4533   count = cpcs->ChainPosClassRuleCount = GET_UShort();
4534 
4535   FORGET_Frame();
4536 
4537   cpcs->ChainPosClassRule = NULL;
4538 
4539   if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4540 		    HB_ChainPosClassRule ) )
4541     return error;
4542 
4543   cpcr = cpcs->ChainPosClassRule;
4544 
4545   for ( n = 0; n < count; n++ )
4546   {
4547     if ( ACCESS_Frame( 2L ) )
4548       goto Fail;
4549 
4550     new_offset = GET_UShort() + base_offset;
4551 
4552     FORGET_Frame();
4553 
4554     cur_offset = FILE_Pos();
4555     if ( FILE_Seek( new_offset ) ||
4556 	 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4557 					   stream ) ) != HB_Err_Ok )
4558       goto Fail;
4559     (void)FILE_Seek( cur_offset );
4560   }
4561 
4562   return HB_Err_Ok;
4563 
4564 Fail:
4565   for ( m = 0; m < n; m++ )
4566     Free_ChainPosClassRule( &cpcr[m] );
4567 
4568   FREE( cpcr );
4569   return error;
4570 }
4571 
4572 
Free_ChainPosClassSet(HB_ChainPosClassSet * cpcs)4573 static void  Free_ChainPosClassSet( HB_ChainPosClassSet*  cpcs )
4574 {
4575   HB_UShort               n, count;
4576 
4577   HB_ChainPosClassRule*  cpcr;
4578 
4579 
4580   if ( cpcs->ChainPosClassRule )
4581   {
4582     count = cpcs->ChainPosClassRuleCount;
4583     cpcr  = cpcs->ChainPosClassRule;
4584 
4585     for ( n = 0; n < count; n++ )
4586       Free_ChainPosClassRule( &cpcr[n] );
4587 
4588     FREE( cpcr );
4589   }
4590 }
4591 
4592 
4593 /* ChainContextPosFormat2 */
4594 
Load_ChainContextPos2(HB_ChainContextPosFormat2 * ccpf2,HB_Stream stream)4595 static HB_Error  Load_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
4596 					HB_Stream                    stream )
4597 {
4598   HB_Error  error;
4599 
4600   HB_UShort              n, m, count;
4601   HB_UInt               cur_offset, new_offset, base_offset;
4602   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
4603 
4604   HB_ChainPosClassSet*  cpcs;
4605 
4606 
4607   base_offset = FILE_Pos() - 2;
4608 
4609   if ( ACCESS_Frame( 2L ) )
4610     return error;
4611 
4612   new_offset = GET_UShort() + base_offset;
4613 
4614   FORGET_Frame();
4615 
4616   cur_offset = FILE_Pos();
4617   if ( FILE_Seek( new_offset ) ||
4618        ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4619     return error;
4620   (void)FILE_Seek( cur_offset );
4621 
4622   if ( ACCESS_Frame( 8L ) )
4623     goto Fail5;
4624 
4625   backtrack_offset = GET_UShort();
4626   input_offset     = GET_UShort();
4627   lookahead_offset = GET_UShort();
4628 
4629   /* `ChainPosClassSetCount' is the upper limit for input class values,
4630      thus we read it now to make an additional safety check. No limit
4631      is known or needed for the other two class definitions          */
4632 
4633   count = ccpf2->ChainPosClassSetCount = GET_UShort();
4634 
4635   FORGET_Frame();
4636 
4637   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4638 						       backtrack_offset, base_offset,
4639 						       stream ) ) != HB_Err_Ok )
4640     goto Fail5;
4641   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4642 						       input_offset, base_offset,
4643 						       stream ) ) != HB_Err_Ok )
4644     goto Fail4;
4645   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4646 						       lookahead_offset, base_offset,
4647 						       stream ) ) != HB_Err_Ok )
4648     goto Fail3;
4649 
4650   ccpf2->ChainPosClassSet   = NULL;
4651   ccpf2->MaxBacktrackLength = 0;
4652   ccpf2->MaxInputLength     = 0;
4653   ccpf2->MaxLookaheadLength = 0;
4654 
4655   if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4656     goto Fail2;
4657 
4658   cpcs = ccpf2->ChainPosClassSet;
4659 
4660   for ( n = 0; n < count; n++ )
4661   {
4662     if ( ACCESS_Frame( 2L ) )
4663       goto Fail1;
4664 
4665     new_offset = GET_UShort() + base_offset;
4666 
4667     FORGET_Frame();
4668 
4669     if ( new_offset != base_offset )      /* not a NULL offset */
4670     {
4671       cur_offset = FILE_Pos();
4672       if ( FILE_Seek( new_offset ) ||
4673 	   ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4674 					    stream ) ) != HB_Err_Ok )
4675 	goto Fail1;
4676       (void)FILE_Seek( cur_offset );
4677     }
4678     else
4679     {
4680       /* we create a ChainPosClassSet table with no entries */
4681 
4682       ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4683       ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
4684     }
4685   }
4686 
4687   return HB_Err_Ok;
4688 
4689 Fail1:
4690   for ( m = 0; m < n; m++ )
4691     Free_ChainPosClassSet( &cpcs[m] );
4692 
4693   FREE( cpcs );
4694 
4695 Fail2:
4696   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4697 
4698 Fail3:
4699   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4700 
4701 Fail4:
4702   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4703 
4704 Fail5:
4705   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4706   return error;
4707 }
4708 
4709 
Free_ChainContextPos2(HB_ChainContextPosFormat2 * ccpf2)4710 static void  Free_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2 )
4711 {
4712   HB_UShort              n, count;
4713 
4714   HB_ChainPosClassSet*  cpcs;
4715 
4716 
4717   if ( ccpf2->ChainPosClassSet )
4718   {
4719     count = ccpf2->ChainPosClassSetCount;
4720     cpcs  = ccpf2->ChainPosClassSet;
4721 
4722     for ( n = 0; n < count; n++ )
4723       Free_ChainPosClassSet( &cpcs[n] );
4724 
4725     FREE( cpcs );
4726   }
4727 
4728   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4729   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4730   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4731 
4732   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4733 }
4734 
4735 
4736 /* ChainContextPosFormat3 */
4737 
Load_ChainContextPos3(HB_ChainContextPosFormat3 * ccpf3,HB_Stream stream)4738 static HB_Error  Load_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
4739 					HB_Stream                    stream )
4740 {
4741   HB_Error  error;
4742 
4743   HB_UShort             n, nb, ni, nl, m, count;
4744   HB_UShort             backtrack_count, input_count, lookahead_count;
4745   HB_UInt              cur_offset, new_offset, base_offset;
4746 
4747   HB_Coverage*         b;
4748   HB_Coverage*         i;
4749   HB_Coverage*         l;
4750   HB_PosLookupRecord*  plr;
4751 
4752 
4753   base_offset = FILE_Pos() - 2L;
4754 
4755   if ( ACCESS_Frame( 2L ) )
4756     return error;
4757 
4758   ccpf3->BacktrackGlyphCount = GET_UShort();
4759 
4760   FORGET_Frame();
4761 
4762   ccpf3->BacktrackCoverage = NULL;
4763 
4764   backtrack_count = ccpf3->BacktrackGlyphCount;
4765 
4766   if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4767 		    HB_Coverage ) )
4768     return error;
4769 
4770   b = ccpf3->BacktrackCoverage;
4771 
4772   for ( nb = 0; nb < backtrack_count; nb++ )
4773   {
4774     if ( ACCESS_Frame( 2L ) )
4775       goto Fail4;
4776 
4777     new_offset = GET_UShort() + base_offset;
4778 
4779     FORGET_Frame();
4780 
4781     cur_offset = FILE_Pos();
4782     if ( FILE_Seek( new_offset ) ||
4783 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4784       goto Fail4;
4785     (void)FILE_Seek( cur_offset );
4786   }
4787 
4788   if ( ACCESS_Frame( 2L ) )
4789     goto Fail4;
4790 
4791   ccpf3->InputGlyphCount = GET_UShort();
4792 
4793   FORGET_Frame();
4794 
4795   ccpf3->InputCoverage = NULL;
4796 
4797   input_count = ccpf3->InputGlyphCount;
4798 
4799   if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4800     goto Fail4;
4801 
4802   i = ccpf3->InputCoverage;
4803 
4804   for ( ni = 0; ni < input_count; ni++ )
4805   {
4806     if ( ACCESS_Frame( 2L ) )
4807       goto Fail3;
4808 
4809     new_offset = GET_UShort() + base_offset;
4810 
4811     FORGET_Frame();
4812 
4813     cur_offset = FILE_Pos();
4814     if ( FILE_Seek( new_offset ) ||
4815 	 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4816       goto Fail3;
4817     (void)FILE_Seek( cur_offset );
4818   }
4819 
4820   if ( ACCESS_Frame( 2L ) )
4821     goto Fail3;
4822 
4823   ccpf3->LookaheadGlyphCount = GET_UShort();
4824 
4825   FORGET_Frame();
4826 
4827   ccpf3->LookaheadCoverage = NULL;
4828 
4829   lookahead_count = ccpf3->LookaheadGlyphCount;
4830 
4831   if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4832 		    HB_Coverage ) )
4833     goto Fail3;
4834 
4835   l = ccpf3->LookaheadCoverage;
4836 
4837   for ( nl = 0; nl < lookahead_count; nl++ )
4838   {
4839     if ( ACCESS_Frame( 2L ) )
4840       goto Fail2;
4841 
4842     new_offset = GET_UShort() + base_offset;
4843 
4844     FORGET_Frame();
4845 
4846     cur_offset = FILE_Pos();
4847     if ( FILE_Seek( new_offset ) ||
4848 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4849       goto Fail2;
4850     (void)FILE_Seek( cur_offset );
4851   }
4852 
4853   if ( ACCESS_Frame( 2L ) )
4854     goto Fail2;
4855 
4856   ccpf3->PosCount = GET_UShort();
4857 
4858   FORGET_Frame();
4859 
4860   ccpf3->PosLookupRecord = NULL;
4861 
4862   count = ccpf3->PosCount;
4863 
4864   if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4865     goto Fail2;
4866 
4867   plr = ccpf3->PosLookupRecord;
4868 
4869   if ( ACCESS_Frame( count * 4L ) )
4870     goto Fail1;
4871 
4872   for ( n = 0; n < count; n++ )
4873   {
4874     plr[n].SequenceIndex   = GET_UShort();
4875     plr[n].LookupListIndex = GET_UShort();
4876   }
4877 
4878   FORGET_Frame();
4879 
4880   return HB_Err_Ok;
4881 
4882 Fail1:
4883   FREE( plr );
4884 
4885 Fail2:
4886   for ( m = 0; m < nl; m++ )
4887     _HB_OPEN_Free_Coverage( &l[m] );
4888 
4889   FREE( l );
4890 
4891 Fail3:
4892   for ( m = 0; m < ni; m++ )
4893     _HB_OPEN_Free_Coverage( &i[m] );
4894 
4895   FREE( i );
4896 
4897 Fail4:
4898   for ( m = 0; m < nb; m++ )
4899     _HB_OPEN_Free_Coverage( &b[m] );
4900 
4901   FREE( b );
4902   return error;
4903 }
4904 
4905 
Free_ChainContextPos3(HB_ChainContextPosFormat3 * ccpf3)4906 static void  Free_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3 )
4907 {
4908   HB_UShort      n, count;
4909 
4910   HB_Coverage*  c;
4911 
4912 
4913   FREE( ccpf3->PosLookupRecord );
4914 
4915   if ( ccpf3->LookaheadCoverage )
4916   {
4917     count = ccpf3->LookaheadGlyphCount;
4918     c     = ccpf3->LookaheadCoverage;
4919 
4920     for ( n = 0; n < count; n++ )
4921       _HB_OPEN_Free_Coverage( &c[n] );
4922 
4923     FREE( c );
4924   }
4925 
4926   if ( ccpf3->InputCoverage )
4927   {
4928     count = ccpf3->InputGlyphCount;
4929     c     = ccpf3->InputCoverage;
4930 
4931     for ( n = 0; n < count; n++ )
4932       _HB_OPEN_Free_Coverage( &c[n] );
4933 
4934     FREE( c );
4935   }
4936 
4937   if ( ccpf3->BacktrackCoverage )
4938   {
4939     count = ccpf3->BacktrackGlyphCount;
4940     c     = ccpf3->BacktrackCoverage;
4941 
4942     for ( n = 0; n < count; n++ )
4943       _HB_OPEN_Free_Coverage( &c[n] );
4944 
4945     FREE( c );
4946   }
4947 }
4948 
4949 
4950 /* ChainContextPos */
4951 
Load_ChainContextPos(HB_GPOS_SubTable * st,HB_Stream stream)4952 static HB_Error  Load_ChainContextPos( HB_GPOS_SubTable* st,
4953 				       HB_Stream             stream )
4954 {
4955   HB_Error  error;
4956   HB_ChainContextPos*  ccp = &st->chain;
4957 
4958 
4959   if ( ACCESS_Frame( 2L ) )
4960     return error;
4961 
4962   ccp->PosFormat = GET_UShort();
4963 
4964   FORGET_Frame();
4965 
4966   switch ( ccp->PosFormat )
4967   {
4968   case 1:
4969     return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
4970 
4971   case 2:
4972     return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
4973 
4974   case 3:
4975     return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
4976 
4977   default:
4978     return ERR(HB_Err_Invalid_SubTable_Format);
4979   }
4980 
4981   return HB_Err_Ok;               /* never reached */
4982 }
4983 
4984 
Free_ChainContextPos(HB_GPOS_SubTable * st)4985 static void  Free_ChainContextPos( HB_GPOS_SubTable* st )
4986 {
4987   HB_ChainContextPos*  ccp = &st->chain;
4988 
4989   switch ( ccp->PosFormat )
4990   {
4991   case 1:  Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
4992   case 2:  Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
4993   case 3:  Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
4994   default:						      break;
4995   }
4996 }
4997 
4998 
Lookup_ChainContextPos1(GPOS_Instance * gpi,HB_ChainContextPosFormat1 * ccpf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)4999 static HB_Error  Lookup_ChainContextPos1(
5000 		   GPOS_Instance*               gpi,
5001 		   HB_ChainContextPosFormat1*  ccpf1,
5002 		   HB_Buffer                   buffer,
5003 		   HB_UShort                    flags,
5004 		   HB_UShort                    context_length,
5005 		   int                          nesting_level )
5006 {
5007   HB_UShort          index, property;
5008   HB_UShort          i, j, k, num_cpr;
5009   HB_UShort          bgc, igc, lgc;
5010   HB_Error           error;
5011   HB_GPOSHeader*    gpos = gpi->gpos;
5012 
5013   HB_ChainPosRule*  cpr;
5014   HB_ChainPosRule   curr_cpr;
5015   HB_GDEFHeader*    gdef;
5016 
5017 
5018   gdef = gpos->gdef;
5019 
5020   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5021     return error;
5022 
5023   error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5024   if ( error )
5025     return error;
5026 
5027   cpr     = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5028   num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5029 
5030   for ( k = 0; k < num_cpr; k++ )
5031   {
5032     curr_cpr = cpr[k];
5033     bgc      = curr_cpr.BacktrackGlyphCount;
5034     igc      = curr_cpr.InputGlyphCount;
5035     lgc      = curr_cpr.LookaheadGlyphCount;
5036 
5037     if ( context_length != 0xFFFF && context_length < igc )
5038       goto next_chainposrule;
5039 
5040     /* check whether context is too long; it is a first guess only */
5041 
5042     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5043       goto next_chainposrule;
5044 
5045     if ( bgc )
5046     {
5047       /* Since we don't know in advance the number of glyphs to inspect,
5048 	 we search backwards for matches in the backtrack glyph array    */
5049 
5050       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5051       {
5052 	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5053 	{
5054 	  if ( error && error != HB_Err_Not_Covered )
5055 	    return error;
5056 
5057 	  if ( j + 1 == bgc - i )
5058 	    goto next_chainposrule;
5059 	  j--;
5060 	}
5061 
5062 	/* In OpenType 1.3, it is undefined whether the offsets of
5063 	   backtrack glyphs is in logical order or not.  Version 1.4
5064 	   will clarify this:
5065 
5066 	     Logical order -      a  b  c  d  e  f  g  h  i  j
5067 					      i
5068 	     Input offsets -                  0  1
5069 	     Backtrack offsets -  3  2  1  0
5070 	     Lookahead offsets -                    0  1  2  3           */
5071 
5072 	if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5073 	  goto next_chainposrule;
5074       }
5075     }
5076 
5077     /* Start at 1 because [0] is implied */
5078 
5079     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5080     {
5081       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5082       {
5083 	if ( error && error != HB_Err_Not_Covered )
5084 	  return error;
5085 
5086 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5087 	  goto next_chainposrule;
5088 	j++;
5089       }
5090 
5091       if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5092 	goto next_chainposrule;
5093     }
5094 
5095     /* we are starting to check for lookahead glyphs right after the
5096        last context glyph                                            */
5097 
5098     for ( i = 0; i < lgc; i++, j++ )
5099     {
5100       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5101       {
5102 	if ( error && error != HB_Err_Not_Covered )
5103 	  return error;
5104 
5105 	if ( j + lgc - i == (HB_Int)buffer->in_length )
5106 	  goto next_chainposrule;
5107 	j++;
5108       }
5109 
5110       if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5111 	goto next_chainposrule;
5112     }
5113 
5114     return Do_ContextPos( gpi, igc,
5115 			  curr_cpr.PosCount,
5116 			  curr_cpr.PosLookupRecord,
5117 			  buffer,
5118 			  nesting_level );
5119 
5120   next_chainposrule:
5121     ;
5122   }
5123 
5124   return HB_Err_Not_Covered;
5125 }
5126 
5127 
Lookup_ChainContextPos2(GPOS_Instance * gpi,HB_ChainContextPosFormat2 * ccpf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5128 static HB_Error  Lookup_ChainContextPos2(
5129 		   GPOS_Instance*               gpi,
5130 		   HB_ChainContextPosFormat2*  ccpf2,
5131 		   HB_Buffer                   buffer,
5132 		   HB_UShort                    flags,
5133 		   HB_UShort                    context_length,
5134 		   int                          nesting_level )
5135 {
5136   HB_UShort              index, property;
5137   HB_Error               error;
5138   HB_UShort              i, j, k;
5139   HB_UShort              bgc, igc, lgc;
5140   HB_UShort              known_backtrack_classes,
5141 			 known_input_classes,
5142 			 known_lookahead_classes;
5143 
5144   HB_UShort*             backtrack_classes;
5145   HB_UShort*             input_classes;
5146   HB_UShort*             lookahead_classes;
5147 
5148   HB_UShort*             bc;
5149   HB_UShort*             ic;
5150   HB_UShort*             lc;
5151   HB_GPOSHeader*        gpos = gpi->gpos;
5152 
5153   HB_ChainPosClassSet*  cpcs;
5154   HB_ChainPosClassRule  cpcr;
5155   HB_GDEFHeader*        gdef;
5156 
5157 
5158   gdef = gpos->gdef;
5159 
5160   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5161     return error;
5162 
5163   /* Note: The coverage table in format 2 doesn't give an index into
5164 	   anything.  It just lets us know whether or not we need to
5165 	   do any lookup at all.                                     */
5166 
5167   error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5168   if ( error )
5169     return error;
5170 
5171   if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5172     return error;
5173   known_backtrack_classes = 0;
5174 
5175   if (ccpf2->MaxInputLength < 1)
5176     return HB_Err_Not_Covered;
5177 
5178   if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5179     goto End3;
5180   known_input_classes = 1;
5181 
5182   if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5183     goto End2;
5184   known_lookahead_classes = 0;
5185 
5186   error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5187 		     &input_classes[0], NULL );
5188   if ( error && error != HB_Err_Not_Covered )
5189     goto End1;
5190 
5191   cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5192   if ( !cpcs )
5193   {
5194     error = ERR(HB_Err_Invalid_SubTable);
5195     goto End1;
5196   }
5197 
5198   for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5199   {
5200     cpcr = cpcs->ChainPosClassRule[k];
5201     bgc  = cpcr.BacktrackGlyphCount;
5202     igc  = cpcr.InputGlyphCount;
5203     lgc  = cpcr.LookaheadGlyphCount;
5204 
5205     if ( context_length != 0xFFFF && context_length < igc )
5206       goto next_chainposclassrule;
5207 
5208     /* check whether context is too long; it is a first guess only */
5209 
5210     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5211       goto next_chainposclassrule;
5212 
5213     if ( bgc )
5214     {
5215       /* Since we don't know in advance the number of glyphs to inspect,
5216 	 we search backwards for matches in the backtrack glyph array.
5217 	 Note that `known_backtrack_classes' starts at index 0.         */
5218 
5219       bc       = cpcr.Backtrack;
5220 
5221       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5222       {
5223 	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5224 	{
5225 	  if ( error && error != HB_Err_Not_Covered )
5226 	    goto End1;
5227 
5228 	  if ( j + 1 == bgc - i )
5229 	    goto next_chainposclassrule;
5230 	  j++;
5231 	}
5232 
5233 	if ( i >= known_backtrack_classes )
5234 	{
5235 	  /* Keeps us from having to do this for each rule */
5236 
5237 	  error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5238 			     &backtrack_classes[i], NULL );
5239 	  if ( error && error != HB_Err_Not_Covered )
5240 	    goto End1;
5241 	  known_backtrack_classes = i;
5242 	}
5243 
5244 	if ( bc[i] != backtrack_classes[i] )
5245 	  goto next_chainposclassrule;
5246       }
5247     }
5248 
5249     ic       = cpcr.Input;
5250 
5251     /* Start at 1 because [0] is implied */
5252 
5253     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5254     {
5255       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5256       {
5257 	if ( error && error != HB_Err_Not_Covered )
5258 	  goto End1;
5259 
5260 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5261 	  goto next_chainposclassrule;
5262 	j++;
5263       }
5264 
5265       if ( i >= known_input_classes )
5266       {
5267 	error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5268 			   &input_classes[i], NULL );
5269 	if ( error && error != HB_Err_Not_Covered )
5270 	  goto End1;
5271 	known_input_classes = i;
5272       }
5273 
5274       if ( ic[i - 1] != input_classes[i] )
5275 	goto next_chainposclassrule;
5276     }
5277 
5278     /* we are starting to check for lookahead glyphs right after the
5279        last context glyph                                            */
5280 
5281     lc       = cpcr.Lookahead;
5282 
5283     for ( i = 0; i < lgc; i++, j++ )
5284     {
5285       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5286       {
5287 	if ( error && error != HB_Err_Not_Covered )
5288 	  goto End1;
5289 
5290 	if ( j + lgc - i == (HB_Int)buffer->in_length )
5291 	  goto next_chainposclassrule;
5292 	j++;
5293       }
5294 
5295       if ( i >= known_lookahead_classes )
5296       {
5297 	error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5298 			   &lookahead_classes[i], NULL );
5299 	if ( error && error != HB_Err_Not_Covered )
5300 	  goto End1;
5301 	known_lookahead_classes = i;
5302       }
5303 
5304       if ( lc[i] != lookahead_classes[i] )
5305 	goto next_chainposclassrule;
5306     }
5307 
5308     error = Do_ContextPos( gpi, igc,
5309 			   cpcr.PosCount,
5310 			   cpcr.PosLookupRecord,
5311 			   buffer,
5312 			   nesting_level );
5313     goto End1;
5314 
5315   next_chainposclassrule:
5316     ;
5317   }
5318 
5319   error = HB_Err_Not_Covered;
5320 
5321 End1:
5322   FREE( lookahead_classes );
5323 
5324 End2:
5325   FREE( input_classes );
5326 
5327 End3:
5328   FREE( backtrack_classes );
5329   return error;
5330 }
5331 
5332 
Lookup_ChainContextPos3(GPOS_Instance * gpi,HB_ChainContextPosFormat3 * ccpf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5333 static HB_Error  Lookup_ChainContextPos3(
5334 		   GPOS_Instance*               gpi,
5335 		   HB_ChainContextPosFormat3*  ccpf3,
5336 		   HB_Buffer                   buffer,
5337 		   HB_UShort                    flags,
5338 		   HB_UShort                    context_length,
5339 		   int                          nesting_level )
5340 {
5341   HB_UShort        index, i, j, property;
5342   HB_UShort        bgc, igc, lgc;
5343   HB_Error         error;
5344   HB_GPOSHeader*  gpos = gpi->gpos;
5345 
5346   HB_Coverage*    bc;
5347   HB_Coverage*    ic;
5348   HB_Coverage*    lc;
5349   HB_GDEFHeader*  gdef;
5350 
5351 
5352   gdef = gpos->gdef;
5353 
5354   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5355     return error;
5356 
5357   bgc = ccpf3->BacktrackGlyphCount;
5358   igc = ccpf3->InputGlyphCount;
5359   lgc = ccpf3->LookaheadGlyphCount;
5360 
5361   if ( context_length != 0xFFFF && context_length < igc )
5362     return HB_Err_Not_Covered;
5363 
5364   /* check whether context is too long; it is a first guess only */
5365 
5366   if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5367     return HB_Err_Not_Covered;
5368 
5369   if ( bgc )
5370   {
5371     /* Since we don't know in advance the number of glyphs to inspect,
5372        we search backwards for matches in the backtrack glyph array    */
5373 
5374     bc       = ccpf3->BacktrackCoverage;
5375 
5376     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5377     {
5378       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5379       {
5380 	if ( error && error != HB_Err_Not_Covered )
5381 	  return error;
5382 
5383 	if ( j + 1 == bgc - i )
5384 	  return HB_Err_Not_Covered;
5385 	j--;
5386       }
5387 
5388       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5389       if ( error )
5390 	return error;
5391     }
5392   }
5393 
5394   ic       = ccpf3->InputCoverage;
5395 
5396   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5397   {
5398     /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5399     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5400     {
5401       if ( error && error != HB_Err_Not_Covered )
5402 	return error;
5403 
5404       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5405 	return HB_Err_Not_Covered;
5406       j++;
5407     }
5408 
5409     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5410     if ( error )
5411       return error;
5412   }
5413 
5414   /* we are starting to check for lookahead glyphs right after the
5415      last context glyph                                            */
5416 
5417   lc       = ccpf3->LookaheadCoverage;
5418 
5419   for ( i = 0; i < lgc; i++, j++ )
5420   {
5421     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5422     {
5423       if ( error && error != HB_Err_Not_Covered )
5424 	return error;
5425 
5426       if ( j + lgc - i == (HB_Int)buffer->in_length )
5427 	return HB_Err_Not_Covered;
5428       j++;
5429     }
5430 
5431     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5432     if ( error )
5433       return error;
5434   }
5435 
5436   return Do_ContextPos( gpi, igc,
5437 			ccpf3->PosCount,
5438 			ccpf3->PosLookupRecord,
5439 			buffer,
5440 			nesting_level );
5441 }
5442 
5443 
Lookup_ChainContextPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5444 static HB_Error  Lookup_ChainContextPos(
5445 		   GPOS_Instance*        gpi,
5446 		   HB_GPOS_SubTable* st,
5447 		   HB_Buffer            buffer,
5448 		   HB_UShort             flags,
5449 		   HB_UShort             context_length,
5450 		   int                   nesting_level )
5451 {
5452   HB_ChainContextPos*  ccp = &st->chain;
5453 
5454   switch ( ccp->PosFormat )
5455   {
5456   case 1:
5457     return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5458 				    flags, context_length,
5459 				    nesting_level );
5460 
5461   case 2:
5462     return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5463 				    flags, context_length,
5464 				    nesting_level );
5465 
5466   case 3:
5467     return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5468 				    flags, context_length,
5469 				    nesting_level );
5470 
5471   default:
5472     return ERR(HB_Err_Invalid_SubTable_Format);
5473   }
5474 
5475   return HB_Err_Ok;               /* never reached */
5476 }
5477 
5478 
5479 
5480 /***********
5481  * GPOS API
5482  ***********/
5483 
5484 
5485 
HB_GPOS_Select_Script(HB_GPOSHeader * gpos,HB_UInt script_tag,HB_UShort * script_index)5486 HB_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
5487 				 HB_UInt         script_tag,
5488 				 HB_UShort*       script_index )
5489 {
5490   HB_UShort          n;
5491 
5492   HB_ScriptList*    sl;
5493   HB_ScriptRecord*  sr;
5494 
5495 
5496   if ( !gpos || !script_index )
5497     return ERR(HB_Err_Invalid_Argument);
5498 
5499   sl = &gpos->ScriptList;
5500   sr = sl->ScriptRecord;
5501 
5502   for ( n = 0; n < sl->ScriptCount; n++ )
5503     if ( script_tag == sr[n].ScriptTag )
5504     {
5505       *script_index = n;
5506 
5507       return HB_Err_Ok;
5508     }
5509 
5510   return HB_Err_Not_Covered;
5511 }
5512 
5513 
5514 
HB_GPOS_Select_Language(HB_GPOSHeader * gpos,HB_UInt language_tag,HB_UShort script_index,HB_UShort * language_index,HB_UShort * req_feature_index)5515 HB_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
5516 				   HB_UInt         language_tag,
5517 				   HB_UShort        script_index,
5518 				   HB_UShort*       language_index,
5519 				   HB_UShort*       req_feature_index )
5520 {
5521   HB_UShort           n;
5522 
5523   HB_ScriptList*     sl;
5524   HB_ScriptRecord*   sr;
5525   HB_ScriptTable*         s;
5526   HB_LangSysRecord*  lsr;
5527 
5528 
5529   if ( !gpos || !language_index || !req_feature_index )
5530     return ERR(HB_Err_Invalid_Argument);
5531 
5532   sl = &gpos->ScriptList;
5533   sr = sl->ScriptRecord;
5534 
5535   if ( script_index >= sl->ScriptCount )
5536     return ERR(HB_Err_Invalid_Argument);
5537 
5538   s   = &sr[script_index].Script;
5539   lsr = s->LangSysRecord;
5540 
5541   for ( n = 0; n < s->LangSysCount; n++ )
5542     if ( language_tag == lsr[n].LangSysTag )
5543     {
5544       *language_index = n;
5545       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5546 
5547       return HB_Err_Ok;
5548     }
5549 
5550   return HB_Err_Not_Covered;
5551 }
5552 
5553 
5554 /* selecting 0xFFFF for language_index asks for the values of the
5555    default language (DefaultLangSys)                              */
5556 
5557 
HB_GPOS_Select_Feature(HB_GPOSHeader * gpos,HB_UInt feature_tag,HB_UShort script_index,HB_UShort language_index,HB_UShort * feature_index)5558 HB_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
5559 				  HB_UInt         feature_tag,
5560 				  HB_UShort        script_index,
5561 				  HB_UShort        language_index,
5562 				  HB_UShort*       feature_index )
5563 {
5564   HB_UShort           n;
5565 
5566   HB_ScriptList*     sl;
5567   HB_ScriptRecord*   sr;
5568   HB_ScriptTable*         s;
5569   HB_LangSysRecord*  lsr;
5570   HB_LangSys*        ls;
5571   HB_UShort*          fi;
5572 
5573   HB_FeatureList*    fl;
5574   HB_FeatureRecord*  fr;
5575 
5576 
5577   if ( !gpos || !feature_index )
5578     return ERR(HB_Err_Invalid_Argument);
5579 
5580   sl = &gpos->ScriptList;
5581   sr = sl->ScriptRecord;
5582 
5583   fl = &gpos->FeatureList;
5584   fr = fl->FeatureRecord;
5585 
5586   if ( script_index >= sl->ScriptCount )
5587     return ERR(HB_Err_Invalid_Argument);
5588 
5589   s   = &sr[script_index].Script;
5590   lsr = s->LangSysRecord;
5591 
5592   if ( language_index == 0xFFFF )
5593     ls = &s->DefaultLangSys;
5594   else
5595   {
5596     if ( language_index >= s->LangSysCount )
5597       return ERR(HB_Err_Invalid_Argument);
5598 
5599     ls = &lsr[language_index].LangSys;
5600   }
5601 
5602   fi = ls->FeatureIndex;
5603 
5604   for ( n = 0; n < ls->FeatureCount; n++ )
5605   {
5606     if ( fi[n] >= fl->FeatureCount )
5607       return ERR(HB_Err_Invalid_SubTable_Format);
5608 
5609     if ( feature_tag == fr[fi[n]].FeatureTag )
5610     {
5611       *feature_index = fi[n];
5612 
5613       return HB_Err_Ok;
5614     }
5615   }
5616 
5617   return HB_Err_Not_Covered;
5618 }
5619 
5620 
5621 /* The next three functions return a null-terminated list */
5622 
5623 
HB_GPOS_Query_Scripts(HB_GPOSHeader * gpos,HB_UInt ** script_tag_list)5624 HB_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
5625 				 HB_UInt**       script_tag_list )
5626 {
5627   HB_Error           error;
5628   HB_UShort          n;
5629   HB_UInt*          stl;
5630 
5631   HB_ScriptList*    sl;
5632   HB_ScriptRecord*  sr;
5633 
5634 
5635   if ( !gpos || !script_tag_list )
5636     return ERR(HB_Err_Invalid_Argument);
5637 
5638   sl = &gpos->ScriptList;
5639   sr = sl->ScriptRecord;
5640 
5641   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
5642     return error;
5643 
5644   for ( n = 0; n < sl->ScriptCount; n++ )
5645     stl[n] = sr[n].ScriptTag;
5646   stl[n] = 0;
5647 
5648   *script_tag_list = stl;
5649 
5650   return HB_Err_Ok;
5651 }
5652 
5653 
5654 
HB_GPOS_Query_Languages(HB_GPOSHeader * gpos,HB_UShort script_index,HB_UInt ** language_tag_list)5655 HB_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
5656 				   HB_UShort        script_index,
5657 				   HB_UInt**       language_tag_list )
5658 {
5659   HB_Error            error;
5660   HB_UShort           n;
5661   HB_UInt*           ltl;
5662 
5663   HB_ScriptList*     sl;
5664   HB_ScriptRecord*   sr;
5665   HB_ScriptTable*    s;
5666   HB_LangSysRecord*  lsr;
5667 
5668 
5669   if ( !gpos || !language_tag_list )
5670     return ERR(HB_Err_Invalid_Argument);
5671 
5672   sl = &gpos->ScriptList;
5673   sr = sl->ScriptRecord;
5674 
5675   if ( script_index >= sl->ScriptCount )
5676     return ERR(HB_Err_Invalid_Argument);
5677 
5678   s   = &sr[script_index].Script;
5679   lsr = s->LangSysRecord;
5680 
5681   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
5682     return error;
5683 
5684   for ( n = 0; n < s->LangSysCount; n++ )
5685     ltl[n] = lsr[n].LangSysTag;
5686   ltl[n] = 0;
5687 
5688   *language_tag_list = ltl;
5689 
5690   return HB_Err_Ok;
5691 }
5692 
5693 
5694 /* selecting 0xFFFF for language_index asks for the values of the
5695    default language (DefaultLangSys)                              */
5696 
5697 
HB_GPOS_Query_Features(HB_GPOSHeader * gpos,HB_UShort script_index,HB_UShort language_index,HB_UInt ** feature_tag_list)5698 HB_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
5699 				  HB_UShort        script_index,
5700 				  HB_UShort        language_index,
5701 				  HB_UInt**       feature_tag_list )
5702 {
5703   HB_UShort           n;
5704   HB_Error            error;
5705   HB_UInt*           ftl;
5706 
5707   HB_ScriptList*     sl;
5708   HB_ScriptRecord*   sr;
5709   HB_ScriptTable*    s;
5710   HB_LangSysRecord*  lsr;
5711   HB_LangSys*        ls;
5712   HB_UShort*          fi;
5713 
5714   HB_FeatureList*    fl;
5715   HB_FeatureRecord*  fr;
5716 
5717 
5718   if ( !gpos || !feature_tag_list )
5719     return ERR(HB_Err_Invalid_Argument);
5720 
5721   sl = &gpos->ScriptList;
5722   sr = sl->ScriptRecord;
5723 
5724   fl = &gpos->FeatureList;
5725   fr = fl->FeatureRecord;
5726 
5727   if ( script_index >= sl->ScriptCount )
5728     return ERR(HB_Err_Invalid_Argument);
5729 
5730   s   = &sr[script_index].Script;
5731   lsr = s->LangSysRecord;
5732 
5733   if ( language_index == 0xFFFF )
5734     ls = &s->DefaultLangSys;
5735   else
5736   {
5737     if ( language_index >= s->LangSysCount )
5738       return ERR(HB_Err_Invalid_Argument);
5739 
5740     ls = &lsr[language_index].LangSys;
5741   }
5742 
5743   fi = ls->FeatureIndex;
5744 
5745   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
5746     return error;
5747 
5748   for ( n = 0; n < ls->FeatureCount; n++ )
5749   {
5750     if ( fi[n] >= fl->FeatureCount )
5751     {
5752       FREE( ftl );
5753       return ERR(HB_Err_Invalid_SubTable_Format);
5754     }
5755     ftl[n] = fr[fi[n]].FeatureTag;
5756   }
5757   ftl[n] = 0;
5758 
5759   *feature_tag_list = ftl;
5760 
5761   return HB_Err_Ok;
5762 }
5763 
5764 
5765 /* Do an individual subtable lookup.  Returns HB_Err_Ok if positioning
5766    has been done, or HB_Err_Not_Covered if not.                        */
GPOS_Do_Glyph_Lookup(GPOS_Instance * gpi,HB_UShort lookup_index,HB_Buffer buffer,HB_UShort context_length,int nesting_level)5767 static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
5768 				       HB_UShort         lookup_index,
5769 				       HB_Buffer        buffer,
5770 				       HB_UShort         context_length,
5771 				       int               nesting_level )
5772 {
5773   HB_Error             error = HB_Err_Not_Covered;
5774   HB_UShort            i, flags, lookup_count;
5775   HB_GPOSHeader*       gpos = gpi->gpos;
5776   HB_Lookup*           lo;
5777   int		       lookup_type;
5778 
5779 
5780   nesting_level++;
5781 
5782   if ( nesting_level > HB_MAX_NESTING_LEVEL )
5783     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
5784 
5785   lookup_count = gpos->LookupList.LookupCount;
5786   if (lookup_index >= lookup_count)
5787     return error;
5788 
5789   lo    = &gpos->LookupList.Lookup[lookup_index];
5790   flags = lo->LookupFlag;
5791   lookup_type = lo->LookupType;
5792 
5793   for ( i = 0; i < lo->SubTableCount; i++ )
5794   {
5795     HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
5796 
5797     switch (lookup_type) {
5798       case HB_GPOS_LOOKUP_SINGLE:
5799         error = Lookup_SinglePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5800       case HB_GPOS_LOOKUP_PAIR:
5801 	error = Lookup_PairPos		( gpi, st, buffer, flags, context_length, nesting_level ); break;
5802       case HB_GPOS_LOOKUP_CURSIVE:
5803 	error = Lookup_CursivePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5804       case HB_GPOS_LOOKUP_MARKBASE:
5805 	error = Lookup_MarkBasePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5806       case HB_GPOS_LOOKUP_MARKLIG:
5807 	error = Lookup_MarkLigPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5808       case HB_GPOS_LOOKUP_MARKMARK:
5809 	error = Lookup_MarkMarkPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5810       case HB_GPOS_LOOKUP_CONTEXT:
5811 	error = Lookup_ContextPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5812       case HB_GPOS_LOOKUP_CHAIN:
5813 	error = Lookup_ChainContextPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
5814     /*case HB_GPOS_LOOKUP_EXTENSION:
5815 	error = Lookup_ExtensionPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5816       default:
5817 	error = HB_Err_Not_Covered;
5818     }
5819 
5820     /* Check whether we have a successful positioning or an error other
5821        than HB_Err_Not_Covered                                         */
5822     if ( error != HB_Err_Not_Covered )
5823       return error;
5824   }
5825 
5826   return HB_Err_Not_Covered;
5827 }
5828 
5829 
5830 HB_INTERNAL HB_Error
_HB_GPOS_Load_SubTable(HB_GPOS_SubTable * st,HB_Stream stream,HB_UShort lookup_type)5831 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5832 			HB_Stream         stream,
5833 			HB_UShort         lookup_type )
5834 {
5835   switch ( lookup_type ) {
5836     case HB_GPOS_LOOKUP_SINGLE:		return Load_SinglePos		( st, stream );
5837     case HB_GPOS_LOOKUP_PAIR:		return Load_PairPos		( st, stream );
5838     case HB_GPOS_LOOKUP_CURSIVE:	return Load_CursivePos		( st, stream );
5839     case HB_GPOS_LOOKUP_MARKBASE:	return Load_MarkBasePos		( st, stream );
5840     case HB_GPOS_LOOKUP_MARKLIG:	return Load_MarkLigPos		( st, stream );
5841     case HB_GPOS_LOOKUP_MARKMARK:	return Load_MarkMarkPos		( st, stream );
5842     case HB_GPOS_LOOKUP_CONTEXT:	return Load_ContextPos		( st, stream );
5843     case HB_GPOS_LOOKUP_CHAIN:		return Load_ChainContextPos	( st, stream );
5844   /*case HB_GPOS_LOOKUP_EXTENSION:	return Load_ExtensionPos	( st, stream );*/
5845     default:				return ERR(HB_Err_Invalid_SubTable_Format);
5846   }
5847 }
5848 
5849 
5850 HB_INTERNAL void
_HB_GPOS_Free_SubTable(HB_GPOS_SubTable * st,HB_UShort lookup_type)5851 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
5852 			HB_UShort         lookup_type )
5853 {
5854   switch ( lookup_type ) {
5855     case HB_GPOS_LOOKUP_SINGLE:		Free_SinglePos		( st ); return;
5856     case HB_GPOS_LOOKUP_PAIR:		Free_PairPos		( st ); return;
5857     case HB_GPOS_LOOKUP_CURSIVE:	Free_CursivePos		( st ); return;
5858     case HB_GPOS_LOOKUP_MARKBASE:	Free_MarkBasePos	( st ); return;
5859     case HB_GPOS_LOOKUP_MARKLIG:	Free_MarkLigPos		( st ); return;
5860     case HB_GPOS_LOOKUP_MARKMARK:	Free_MarkMarkPos	( st ); return;
5861     case HB_GPOS_LOOKUP_CONTEXT:	Free_ContextPos		( st ); return;
5862     case HB_GPOS_LOOKUP_CHAIN:		Free_ChainContextPos	( st ); return;
5863   /*case HB_GPOS_LOOKUP_EXTENSION:	Free_ExtensionPos	( st ); return;*/
5864     default:									return;
5865   }
5866 }
5867 
5868 
5869 /* apply one lookup to the input string object */
5870 
GPOS_Do_String_Lookup(GPOS_Instance * gpi,HB_UShort lookup_index,HB_Buffer buffer)5871 static HB_Error  GPOS_Do_String_Lookup( GPOS_Instance*    gpi,
5872 				   HB_UShort         lookup_index,
5873 				   HB_Buffer        buffer )
5874 {
5875   HB_Error         error, retError = HB_Err_Not_Covered;
5876   HB_GPOSHeader*  gpos = gpi->gpos;
5877 
5878   HB_UInt*  properties = gpos->LookupList.Properties;
5879 
5880   const int       nesting_level = 0;
5881   /* 0xFFFF indicates that we don't have a context length yet */
5882   const HB_UShort context_length = 0xFFFF;
5883 
5884 
5885   gpi->last  = 0xFFFF;     /* no last valid glyph for cursive pos. */
5886 
5887   buffer->in_pos = 0;
5888   while ( buffer->in_pos < buffer->in_length )
5889   {
5890     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
5891     {
5892       /* Note that the connection between mark and base glyphs hold
5893 	 exactly one (string) lookup.  For example, it would be possible
5894 	 that in the first lookup, mark glyph X is attached to base
5895 	 glyph A, and in the next lookup it is attached to base glyph B.
5896 	 It is up to the font designer to provide meaningful lookups and
5897 	 lookup order.                                                   */
5898 
5899       error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5900       if ( error && error != HB_Err_Not_Covered )
5901 	return error;
5902     }
5903     else
5904     {
5905       /* Contrary to properties defined in GDEF, user-defined properties
5906 	 will always stop a possible cursive positioning.                */
5907       gpi->last = 0xFFFF;
5908 
5909       error = HB_Err_Not_Covered;
5910     }
5911 
5912     if ( error == HB_Err_Not_Covered )
5913       (buffer->in_pos)++;
5914     else
5915       retError = error;
5916   }
5917 
5918   return retError;
5919 }
5920 
5921 
Position_CursiveChain(HB_Buffer buffer)5922 static HB_Error  Position_CursiveChain ( HB_Buffer     buffer )
5923 {
5924   HB_UInt   i, j;
5925   HB_Position positions = buffer->positions;
5926 
5927   /* First handle all left-to-right connections */
5928   for (j = 0; j < buffer->in_length; j++)
5929   {
5930     if (positions[j].cursive_chain > 0)
5931       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5932   }
5933 
5934   /* Then handle all right-to-left connections */
5935   for (i = buffer->in_length; i > 0; i--)
5936   {
5937     j = i - 1;
5938 
5939     if (positions[j].cursive_chain < 0)
5940       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5941   }
5942 
5943   return HB_Err_Ok;
5944 }
5945 
5946 
HB_GPOS_Add_Feature(HB_GPOSHeader * gpos,HB_UShort feature_index,HB_UInt property)5947 HB_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
5948 			       HB_UShort        feature_index,
5949 			       HB_UInt          property )
5950 {
5951   HB_UShort    i;
5952 
5953   HB_Feature  feature;
5954   HB_UInt*     properties;
5955   HB_UShort*   index;
5956   HB_UShort    lookup_count;
5957 
5958   /* Each feature can only be added once */
5959 
5960   if ( !gpos ||
5961        feature_index >= gpos->FeatureList.FeatureCount ||
5962        gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
5963     return ERR(HB_Err_Invalid_Argument);
5964 
5965   gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
5966 
5967   properties = gpos->LookupList.Properties;
5968 
5969   feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
5970   index   = feature.LookupListIndex;
5971   lookup_count = gpos->LookupList.LookupCount;
5972 
5973   for ( i = 0; i < feature.LookupListCount; i++ )
5974   {
5975     HB_UShort lookup_index = index[i];
5976     if (lookup_index < lookup_count)
5977       properties[lookup_index] |= property;
5978   }
5979 
5980   return HB_Err_Ok;
5981 }
5982 
5983 
5984 
HB_GPOS_Clear_Features(HB_GPOSHeader * gpos)5985 HB_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos )
5986 {
5987   HB_UShort i;
5988 
5989   HB_UInt*  properties;
5990 
5991 
5992   if ( !gpos )
5993     return ERR(HB_Err_Invalid_Argument);
5994 
5995   gpos->FeatureList.ApplyCount = 0;
5996 
5997   properties = gpos->LookupList.Properties;
5998 
5999   for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
6000     properties[i] = 0;
6001 
6002   return HB_Err_Ok;
6003 }
6004 
6005 #ifdef HB_SUPPORT_MULTIPLE_MASTER
HB_GPOS_Register_MM_Function(HB_GPOSHeader * gpos,HB_MMFunction mmfunc,void * data)6006 HB_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
6007 					HB_MMFunction   mmfunc,
6008 					void*            data )
6009 {
6010   if ( !gpos )
6011     return ERR(HB_Err_Invalid_Argument);
6012 
6013   gpos->mmfunc = mmfunc;
6014   gpos->data   = data;
6015 
6016   return HB_Err_Ok;
6017 }
6018 #endif
6019 
6020 /* If `dvi' is TRUE, glyph contour points for anchor points and device
6021    tables are ignored -- you will get device independent values.         */
6022 
6023 
HB_GPOS_Apply_String(HB_Font font,HB_GPOSHeader * gpos,HB_UShort load_flags,HB_Buffer buffer,HB_Bool dvi,HB_Bool r2l)6024 HB_Error  HB_GPOS_Apply_String( HB_Font            font,
6025 				HB_GPOSHeader*    gpos,
6026 				HB_UShort          load_flags,
6027 				HB_Buffer         buffer,
6028 				HB_Bool            dvi,
6029 				HB_Bool            r2l )
6030 {
6031   HB_Error       error, retError = HB_Err_Not_Covered;
6032   GPOS_Instance  gpi;
6033   int            i, j, lookup_count, num_features;
6034 
6035   if ( !font || !gpos || !buffer )
6036     return ERR(HB_Err_Invalid_Argument);
6037 
6038   if ( buffer->in_length == 0 )
6039     return HB_Err_Not_Covered;
6040 
6041   gpi.font       = font;
6042   gpi.gpos       = gpos;
6043   gpi.load_flags = load_flags;
6044   gpi.r2l        = r2l;
6045   gpi.dvi        = dvi;
6046 
6047   lookup_count = gpos->LookupList.LookupCount;
6048   num_features = gpos->FeatureList.ApplyCount;
6049 
6050   if ( num_features )
6051     {
6052       error = _hb_buffer_clear_positions( buffer );
6053       if ( error )
6054 	return error;
6055     }
6056 
6057   for ( i = 0; i < num_features; i++ )
6058   {
6059     HB_UShort  feature_index = gpos->FeatureList.ApplyOrder[i];
6060     HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6061 
6062     for ( j = 0; j < feature.LookupListCount; j++ )
6063     {
6064       HB_UShort lookup_index = feature.LookupListIndex[j];
6065 
6066       /* Skip nonexistant lookups */
6067       if (lookup_index >= lookup_count)
6068        continue;
6069 
6070       error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6071       if ( error )
6072       {
6073 	if ( error != HB_Err_Not_Covered )
6074 	  return error;
6075       }
6076       else
6077 	retError = error;
6078     }
6079   }
6080 
6081   if ( num_features )
6082     {
6083   error = Position_CursiveChain ( buffer );
6084   if ( error )
6085     return error;
6086     }
6087 
6088   return retError;
6089 }
6090 
6091 /* END */
6092