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