2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
4 * Copyright (C) 2007 Red Hat, Inc.
6 * This is part of HarfBuzz, an OpenType Layout engine library.
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.
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
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.
26 * Red Hat Author(s): Behdad Esfahbod
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"
40 HB_UShort load_flags; /* how the glyph should be loaded */
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 */
49 typedef struct GPOS_Instance_ GPOS_Instance;
52 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
53 HB_UShort lookup_index,
55 HB_UShort context_length,
60 #ifdef HB_SUPPORT_MULTIPLE_MASTER
61 /* the client application must replace this with something more
62 meaningful if multiple master fonts are to be supported. */
64 static HB_Error default_mmfunc( HB_Font font,
66 HB_Fixed* metric_value,
71 HB_UNUSED(metric_value);
73 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
79 HB_Error HB_Load_GPOS_Table( HB_Stream stream,
80 HB_GPOSHeader** retptr,
82 HB_Stream gdefStream )
84 HB_UInt cur_offset, new_offset, base_offset;
92 return ERR(HB_Err_Invalid_Argument);
94 if ( GOTO_Table( TTAG_GPOS ) )
97 base_offset = FILE_Pos();
99 if ( ALLOC ( gpos, sizeof( *gpos ) ) )
102 #ifdef HB_SUPPORT_MULTIPLE_MASTER
103 gpos->mmfunc = default_mmfunc;
108 if ( FILE_Seek( base_offset + 4L ) ||
112 new_offset = GET_UShort() + base_offset;
116 cur_offset = FILE_Pos();
117 if ( FILE_Seek( new_offset ) ||
118 ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
119 stream ) ) != HB_Err_Ok )
121 (void)FILE_Seek( cur_offset );
123 if ( ACCESS_Frame( 2L ) )
126 new_offset = GET_UShort() + base_offset;
130 cur_offset = FILE_Pos();
131 if ( FILE_Seek( new_offset ) ||
132 ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
133 stream ) ) != HB_Err_Ok )
135 (void)FILE_Seek( cur_offset );
137 if ( ACCESS_Frame( 2L ) )
140 new_offset = GET_UShort() + base_offset;
144 cur_offset = FILE_Pos();
145 if ( FILE_Seek( new_offset ) ||
146 ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
147 stream, HB_Type_GPOS ) ) != HB_Err_Ok )
150 gpos->gdef = gdef; /* can be NULL */
152 if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
153 gpos->LookupList.Lookup,
154 gpos->LookupList.LookupCount ) ) )
162 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
165 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
168 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
177 HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
179 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
180 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
181 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
189 /*****************************
190 * SubTable related functions
191 *****************************/
197 /* There is a subtle difference in the specs between a `table' and a
198 `record' -- offsets for device tables in ValueRecords are taken from
199 the parent table and not the parent record. */
201 static HB_Error Load_ValueRecord( HB_ValueRecord* vr,
208 HB_UInt cur_offset, new_offset;
211 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
213 if ( ACCESS_Frame( 2L ) )
216 vr->XPlacement = GET_Short();
223 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
225 if ( ACCESS_Frame( 2L ) )
228 vr->YPlacement = GET_Short();
235 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
237 if ( ACCESS_Frame( 2L ) )
240 vr->XAdvance = GET_Short();
247 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
249 if ( ACCESS_Frame( 2L ) )
252 vr->YAdvance = GET_Short();
259 if ( format & HB_GPOS_FORMAT_HAVE_DEVICE_TABLES )
261 if ( ALLOC_ARRAY( vr->DeviceTables, 4, HB_Device ) )
263 vr->DeviceTables[VR_X_ADVANCE_DEVICE] = 0;
264 vr->DeviceTables[VR_Y_ADVANCE_DEVICE] = 0;
265 vr->DeviceTables[VR_X_PLACEMENT_DEVICE] = 0;
266 vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] = 0;
270 vr->DeviceTables = 0;
273 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
275 if ( ACCESS_Frame( 2L ) )
278 new_offset = GET_UShort();
284 new_offset += base_offset;
286 cur_offset = FILE_Pos();
287 if ( FILE_Seek( new_offset ) ||
288 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_X_PLACEMENT_DEVICE],
289 stream ) ) != HB_Err_Ok )
291 (void)FILE_Seek( cur_offset );
295 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
297 if ( ACCESS_Frame( 2L ) )
300 new_offset = GET_UShort();
306 new_offset += base_offset;
308 cur_offset = FILE_Pos();
309 if ( FILE_Seek( new_offset ) ||
310 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_Y_PLACEMENT_DEVICE],
311 stream ) ) != HB_Err_Ok )
313 (void)FILE_Seek( cur_offset );
317 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
319 if ( ACCESS_Frame( 2L ) )
322 new_offset = GET_UShort();
328 new_offset += base_offset;
330 cur_offset = FILE_Pos();
331 if ( FILE_Seek( new_offset ) ||
332 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_X_ADVANCE_DEVICE],
333 stream ) ) != HB_Err_Ok )
335 (void)FILE_Seek( cur_offset );
339 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
341 if ( ACCESS_Frame( 2L ) )
344 new_offset = GET_UShort();
350 new_offset += base_offset;
352 cur_offset = FILE_Pos();
353 if ( FILE_Seek( new_offset ) ||
354 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_Y_ADVANCE_DEVICE],
355 stream ) ) != HB_Err_Ok )
357 (void)FILE_Seek( cur_offset );
361 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
363 if ( ACCESS_Frame( 2L ) )
366 #ifdef HB_SUPPORT_MULTIPLE_MASTER
367 vr->XIdPlacement = GET_UShort();
374 #ifdef HB_SUPPORT_MULTIPLE_MASTER
376 vr->XIdPlacement = 0;
379 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
381 if ( ACCESS_Frame( 2L ) )
384 #ifdef HB_SUPPORT_MULTIPLE_MASTER
385 vr->YIdPlacement = GET_UShort();
392 #ifdef HB_SUPPORT_MULTIPLE_MASTER
394 vr->YIdPlacement = 0;
397 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
399 if ( ACCESS_Frame( 2L ) )
402 #ifdef HB_SUPPORT_MULTIPLE_MASTER
403 vr->XIdAdvance = GET_UShort();
410 #ifdef HB_SUPPORT_MULTIPLE_MASTER
415 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
417 if ( ACCESS_Frame( 2L ) )
420 #ifdef HB_SUPPORT_MULTIPLE_MASTER
421 vr->YIdAdvance = GET_UShort();
428 #ifdef HB_SUPPORT_MULTIPLE_MASTER
436 if ( vr->DeviceTables )
437 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] );
440 if ( vr->DeviceTables )
441 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] );
444 if ( vr->DeviceTables )
445 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] );
448 FREE( vr->DeviceTables );
453 static void Free_ValueRecord( HB_ValueRecord* vr,
456 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
457 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] );
458 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
459 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] );
460 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
461 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] );
462 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
463 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_PLACEMENT_DEVICE] );
464 FREE( vr->DeviceTables );
468 static HB_Error Get_ValueRecord( GPOS_Instance* gpi,
473 HB_Short pixel_value;
474 HB_Error error = HB_Err_Ok;
475 #ifdef HB_SUPPORT_MULTIPLE_MASTER
476 HB_GPOSHeader* gpos = gpi->gpos;
480 HB_UShort x_ppem, y_ppem;
481 HB_16Dot16 x_scale, y_scale;
487 x_ppem = gpi->font->x_ppem;
488 y_ppem = gpi->font->y_ppem;
489 x_scale = gpi->font->x_scale;
490 y_scale = gpi->font->y_scale;
492 /* design units -> fractional pixel */
494 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
495 gd->x_pos += x_scale * vr->XPlacement / 0x10000;
496 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
497 gd->y_pos += y_scale * vr->YPlacement / 0x10000;
498 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
499 gd->x_advance += x_scale * vr->XAdvance / 0x10000;
500 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
501 gd->y_advance += y_scale * vr->YAdvance / 0x10000;
505 /* pixel -> fractional pixel */
507 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
509 _HB_OPEN_Get_Device( vr->DeviceTables[VR_X_PLACEMENT_DEVICE], x_ppem, &pixel_value );
510 gd->x_pos += pixel_value << 6;
512 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
514 _HB_OPEN_Get_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE], y_ppem, &pixel_value );
515 gd->y_pos += pixel_value << 6;
517 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
519 _HB_OPEN_Get_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE], x_ppem, &pixel_value );
520 gd->x_advance += pixel_value << 6;
522 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
524 _HB_OPEN_Get_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE], y_ppem, &pixel_value );
525 gd->y_advance += pixel_value << 6;
529 #ifdef HB_SUPPORT_MULTIPLE_MASTER
530 /* values returned from mmfunc() are already in fractional pixels */
532 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
534 error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
535 &value, gpos->data );
540 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
542 error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
543 &value, gpos->data );
548 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
550 error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
551 &value, gpos->data );
554 gd->x_advance += value;
556 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
558 error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
559 &value, gpos->data );
562 gd->y_advance += value;
575 static HB_Error Load_Anchor( HB_Anchor* an,
580 HB_UInt cur_offset, new_offset, base_offset;
583 base_offset = FILE_Pos();
585 if ( ACCESS_Frame( 2L ) )
588 an->PosFormat = GET_UShort();
592 switch ( an->PosFormat )
595 if ( ACCESS_Frame( 4L ) )
598 an->af.af1.XCoordinate = GET_Short();
599 an->af.af1.YCoordinate = GET_Short();
605 if ( ACCESS_Frame( 6L ) )
608 an->af.af2.XCoordinate = GET_Short();
609 an->af.af2.YCoordinate = GET_Short();
610 an->af.af2.AnchorPoint = GET_UShort();
616 if ( ACCESS_Frame( 6L ) )
619 an->af.af3.XCoordinate = GET_Short();
620 an->af.af3.YCoordinate = GET_Short();
622 new_offset = GET_UShort();
628 if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) )
631 an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] = 0;
632 an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] = 0;
634 new_offset += base_offset;
636 cur_offset = FILE_Pos();
637 if ( FILE_Seek( new_offset ) ||
638 ( error = _HB_OPEN_Load_Device( &an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE],
639 stream ) ) != HB_Err_Ok )
641 (void)FILE_Seek( cur_offset );
644 if ( ACCESS_Frame( 2L ) )
647 new_offset = GET_UShort();
653 if ( !an->af.af3.DeviceTables )
655 if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) )
658 an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] = 0;
659 an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] = 0;
662 new_offset += base_offset;
664 cur_offset = FILE_Pos();
665 if ( FILE_Seek( new_offset ) ||
666 ( error = _HB_OPEN_Load_Device( &an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE],
667 stream ) ) != HB_Err_Ok )
669 (void)FILE_Seek( cur_offset );
674 if ( ACCESS_Frame( 4L ) )
677 #ifdef HB_SUPPORT_MULTIPLE_MASTER
678 an->af.af4.XIdAnchor = GET_UShort();
679 an->af.af4.YIdAnchor = GET_UShort();
689 return ERR(HB_Err_Invalid_SubTable_Format);
695 if ( an->af.af3.DeviceTables )
696 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] );
699 FREE( an->af.af3.DeviceTables );
704 static void Free_Anchor( HB_Anchor* an)
706 if ( an->PosFormat == 3 && an->af.af3.DeviceTables )
708 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] );
709 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] );
710 FREE( an->af.af3.DeviceTables );
715 static HB_Error Get_Anchor( GPOS_Instance* gpi,
717 HB_UShort glyph_index,
721 HB_Error error = HB_Err_Ok;
723 #ifdef HB_SUPPORT_MULTIPLE_MASTER
724 HB_GPOSHeader* gpos = gpi->gpos;
728 HB_Short pixel_value;
730 HB_UShort x_ppem, y_ppem;
731 HB_16Dot16 x_scale, y_scale;
734 x_ppem = gpi->font->x_ppem;
735 y_ppem = gpi->font->y_ppem;
736 x_scale = gpi->font->x_scale;
737 y_scale = gpi->font->y_scale;
739 switch ( an->PosFormat )
742 /* The special case of an empty AnchorTable */
745 return HB_Err_Not_Covered;
748 *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
749 *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
755 hb_uint32 n_points = 0;
756 ap = an->af.af2.AnchorPoint;
757 if (!gpi->font->klass->getPointInOutline)
758 goto no_contour_point;
759 error = gpi->font->klass->getPointInOutline(gpi->font, glyph_index, gpi->load_flags, ap, x_value, y_value, &n_points);
762 /* if n_points is set to zero, we use the design coordinate value pair.
763 * This can happen e.g. for sbit glyphs. */
765 goto no_contour_point;
770 *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
771 *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
778 _HB_OPEN_Get_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE], x_ppem, &pixel_value );
779 *x_value = pixel_value << 6;
780 _HB_OPEN_Get_Device( an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE], y_ppem, &pixel_value );
781 *y_value = pixel_value << 6;
784 *x_value = *y_value = 0;
786 *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
787 *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
791 #ifdef HB_SUPPORT_MULTIPLE_MASTER
792 error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
793 x_value, gpos->data );
797 error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
798 y_value, gpos->data );
803 return ERR(HB_Err_Not_Covered);
813 static HB_Error Load_MarkArray ( HB_MarkArray* ma,
818 HB_UShort n, m, count;
819 HB_UInt cur_offset, new_offset, base_offset;
824 base_offset = FILE_Pos();
826 if ( ACCESS_Frame( 2L ) )
829 count = ma->MarkCount = GET_UShort();
833 ma->MarkRecord = NULL;
835 if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
840 for ( n = 0; n < count; n++ )
842 if ( ACCESS_Frame( 4L ) )
845 mr[n].Class = GET_UShort();
846 new_offset = GET_UShort() + base_offset;
850 cur_offset = FILE_Pos();
851 if ( FILE_Seek( new_offset ) ||
852 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
854 (void)FILE_Seek( cur_offset );
860 for ( m = 0; m < n; m++ )
861 Free_Anchor( &mr[m].MarkAnchor );
868 static void Free_MarkArray( HB_MarkArray* ma )
875 if ( ma->MarkRecord )
877 count = ma->MarkCount;
880 for ( n = 0; n < count; n++ )
881 Free_Anchor( &mr[n].MarkAnchor );
890 /* SinglePosFormat1 */
891 /* SinglePosFormat2 */
893 static HB_Error Load_SinglePos( HB_GPOS_SubTable* st,
897 HB_SinglePos* sp = &st->single;
899 HB_UShort n, m, count, format;
900 HB_UInt cur_offset, new_offset, base_offset;
905 base_offset = FILE_Pos();
907 if ( ACCESS_Frame( 6L ) )
910 sp->PosFormat = GET_UShort();
911 new_offset = GET_UShort() + base_offset;
913 format = sp->ValueFormat = GET_UShort();
918 return ERR(HB_Err_Invalid_SubTable);
920 cur_offset = FILE_Pos();
921 if ( FILE_Seek( new_offset ) ||
922 ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
924 (void)FILE_Seek( cur_offset );
926 switch ( sp->PosFormat )
929 error = Load_ValueRecord( &sp->spf.spf1.Value, format,
930 base_offset, stream );
936 if ( ACCESS_Frame( 2L ) )
939 count = sp->spf.spf2.ValueCount = GET_UShort();
943 sp->spf.spf2.Value = NULL;
945 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
948 vr = sp->spf.spf2.Value;
950 for ( n = 0; n < count; n++ )
952 error = Load_ValueRecord( &vr[n], format, base_offset, stream );
959 return ERR(HB_Err_Invalid_SubTable_Format);
965 for ( m = 0; m < n; m++ )
966 Free_ValueRecord( &vr[m], format );
971 _HB_OPEN_Free_Coverage( &sp->Coverage );
976 static void Free_SinglePos( HB_GPOS_SubTable* st )
978 HB_UShort n, count, format;
979 HB_SinglePos* sp = &st->single;
984 format = sp->ValueFormat;
986 switch ( sp->PosFormat )
989 Free_ValueRecord( &sp->spf.spf1.Value, format );
993 if ( sp->spf.spf2.Value )
995 count = sp->spf.spf2.ValueCount;
996 v = sp->spf.spf2.Value;
998 for ( n = 0; n < count; n++ )
999 Free_ValueRecord( &v[n], format );
1008 _HB_OPEN_Free_Coverage( &sp->Coverage );
1011 static HB_Error Lookup_SinglePos( GPOS_Instance* gpi,
1012 HB_GPOS_SubTable* st,
1015 HB_UShort context_length,
1018 HB_UShort index, property;
1020 HB_GPOSHeader* gpos = gpi->gpos;
1021 HB_SinglePos* sp = &st->single;
1023 HB_UNUSED(nesting_level);
1025 if ( context_length != 0xFFFF && context_length < 1 )
1026 return HB_Err_Not_Covered;
1028 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1031 error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
1035 switch ( sp->PosFormat )
1038 error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
1039 sp->ValueFormat, POSITION( buffer->in_pos ) );
1045 if ( index >= sp->spf.spf2.ValueCount )
1046 return ERR(HB_Err_Invalid_SubTable);
1047 error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
1048 sp->ValueFormat, POSITION( buffer->in_pos ) );
1054 return ERR(HB_Err_Invalid_SubTable);
1067 static HB_Error Load_PairSet ( HB_PairSet* ps,
1074 HB_UShort n, m, count;
1075 HB_UInt base_offset;
1077 HB_PairValueRecord* pvr;
1080 base_offset = FILE_Pos();
1082 if ( ACCESS_Frame( 2L ) )
1085 count = ps->PairValueCount = GET_UShort();
1089 ps->PairValueRecord = NULL;
1091 if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
1094 pvr = ps->PairValueRecord;
1096 for ( n = 0; n < count; n++ )
1098 if ( ACCESS_Frame( 2L ) )
1101 pvr[n].SecondGlyph = GET_UShort();
1107 error = Load_ValueRecord( &pvr[n].Value1, format1,
1108 base_offset, stream );
1114 error = Load_ValueRecord( &pvr[n].Value2, format2,
1115 base_offset, stream );
1119 Free_ValueRecord( &pvr[n].Value1, format1 );
1128 for ( m = 0; m < n; m++ )
1131 Free_ValueRecord( &pvr[m].Value1, format1 );
1133 Free_ValueRecord( &pvr[m].Value2, format2 );
1141 static void Free_PairSet( HB_PairSet* ps,
1147 HB_PairValueRecord* pvr;
1150 if ( ps->PairValueRecord )
1152 count = ps->PairValueCount;
1153 pvr = ps->PairValueRecord;
1155 for ( n = 0; n < count; n++ )
1158 Free_ValueRecord( &pvr[n].Value1, format1 );
1160 Free_ValueRecord( &pvr[n].Value2, format2 );
1168 /* PairPosFormat1 */
1170 static HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
1177 HB_UShort n, m, count;
1178 HB_UInt cur_offset, new_offset, base_offset;
1183 base_offset = FILE_Pos() - 8L;
1185 if ( ACCESS_Frame( 2L ) )
1188 count = ppf1->PairSetCount = GET_UShort();
1192 ppf1->PairSet = NULL;
1194 if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
1199 for ( n = 0; n < count; n++ )
1201 if ( ACCESS_Frame( 2L ) )
1204 new_offset = GET_UShort() + base_offset;
1208 cur_offset = FILE_Pos();
1209 if ( FILE_Seek( new_offset ) ||
1210 ( error = Load_PairSet( &ps[n], format1,
1211 format2, stream ) ) != HB_Err_Ok )
1213 (void)FILE_Seek( cur_offset );
1219 for ( m = 0; m < n; m++ )
1220 Free_PairSet( &ps[m], format1, format2 );
1227 static void Free_PairPos1( HB_PairPosFormat1* ppf1,
1236 if ( ppf1->PairSet )
1238 count = ppf1->PairSetCount;
1241 for ( n = 0; n < count; n++ )
1242 Free_PairSet( &ps[n], format1, format2 );
1249 /* PairPosFormat2 */
1251 static HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
1258 HB_UShort m, n, k, count1, count2;
1259 HB_UInt cur_offset, new_offset1, new_offset2, base_offset;
1261 HB_Class1Record* c1r;
1262 HB_Class2Record* c2r;
1265 base_offset = FILE_Pos() - 8L;
1267 if ( ACCESS_Frame( 8L ) )
1270 new_offset1 = GET_UShort() + base_offset;
1271 new_offset2 = GET_UShort() + base_offset;
1273 /* `Class1Count' and `Class2Count' are the upper limits for class
1274 values, thus we read it now to make additional safety checks. */
1276 count1 = ppf2->Class1Count = GET_UShort();
1277 count2 = ppf2->Class2Count = GET_UShort();
1281 cur_offset = FILE_Pos();
1282 if ( FILE_Seek( new_offset1 ) ||
1283 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
1284 stream ) ) != HB_Err_Ok )
1286 if ( FILE_Seek( new_offset2 ) ||
1287 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
1288 stream ) ) != HB_Err_Ok )
1290 (void)FILE_Seek( cur_offset );
1292 ppf2->Class1Record = NULL;
1294 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
1297 c1r = ppf2->Class1Record;
1299 for ( m = 0; m < count1; m++ )
1301 c1r[m].Class2Record = NULL;
1303 if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
1306 c2r = c1r[m].Class2Record;
1308 for ( n = 0; n < count2; n++ )
1312 error = Load_ValueRecord( &c2r[n].Value1, format1,
1313 base_offset, stream );
1319 error = Load_ValueRecord( &c2r[n].Value2, format2,
1320 base_offset, stream );
1324 Free_ValueRecord( &c2r[n].Value1, format1 );
1333 for ( k = 0; k < n; k++ )
1336 Free_ValueRecord( &c2r[k].Value1, format1 );
1338 Free_ValueRecord( &c2r[k].Value2, format2 );
1346 for ( k = 0; k < m; k++ )
1348 c2r = c1r[k].Class2Record;
1350 for ( n = 0; n < count2; n++ )
1353 Free_ValueRecord( &c2r[n].Value1, format1 );
1355 Free_ValueRecord( &c2r[n].Value2, format2 );
1364 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1367 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1372 static void Free_PairPos2( HB_PairPosFormat2* ppf2,
1376 HB_UShort m, n, count1, count2;
1378 HB_Class1Record* c1r;
1379 HB_Class2Record* c2r;
1382 if ( ppf2->Class1Record )
1384 c1r = ppf2->Class1Record;
1385 count1 = ppf2->Class1Count;
1386 count2 = ppf2->Class2Count;
1388 for ( m = 0; m < count1; m++ )
1390 c2r = c1r[m].Class2Record;
1392 for ( n = 0; n < count2; n++ )
1395 Free_ValueRecord( &c2r[n].Value1, format1 );
1397 Free_ValueRecord( &c2r[n].Value2, format2 );
1405 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1406 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1411 static HB_Error Load_PairPos( HB_GPOS_SubTable* st,
1415 HB_PairPos* pp = &st->pair;
1417 HB_UShort format1, format2;
1418 HB_UInt cur_offset, new_offset, base_offset;
1421 base_offset = FILE_Pos();
1423 if ( ACCESS_Frame( 8L ) )
1426 pp->PosFormat = GET_UShort();
1427 new_offset = GET_UShort() + base_offset;
1429 format1 = pp->ValueFormat1 = GET_UShort();
1430 format2 = pp->ValueFormat2 = GET_UShort();
1434 cur_offset = FILE_Pos();
1435 if ( FILE_Seek( new_offset ) ||
1436 ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
1438 (void)FILE_Seek( cur_offset );
1440 switch ( pp->PosFormat )
1443 error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
1449 error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
1455 return ERR(HB_Err_Invalid_SubTable_Format);
1461 _HB_OPEN_Free_Coverage( &pp->Coverage );
1466 static void Free_PairPos( HB_GPOS_SubTable* st )
1468 HB_UShort format1, format2;
1469 HB_PairPos* pp = &st->pair;
1472 format1 = pp->ValueFormat1;
1473 format2 = pp->ValueFormat2;
1475 switch ( pp->PosFormat )
1478 Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
1482 Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
1489 _HB_OPEN_Free_Coverage( &pp->Coverage );
1493 static HB_Error Lookup_PairPos1( GPOS_Instance* gpi,
1494 HB_PairPosFormat1* ppf1,
1502 HB_UShort numpvr, glyph2;
1504 HB_PairValueRecord* pvr;
1507 if ( index >= ppf1->PairSetCount )
1508 return ERR(HB_Err_Invalid_SubTable);
1510 pvr = ppf1->PairSet[index].PairValueRecord;
1512 return ERR(HB_Err_Invalid_SubTable);
1514 glyph2 = IN_CURGLYPH();
1516 for ( numpvr = ppf1->PairSet[index].PairValueCount;
1520 if ( glyph2 == pvr->SecondGlyph )
1522 error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1523 POSITION( first_pos ) );
1526 return Get_ValueRecord( gpi, &pvr->Value2, format2,
1527 POSITION( buffer->in_pos ) );
1531 return HB_Err_Not_Covered;
1535 static HB_Error Lookup_PairPos2( GPOS_Instance* gpi,
1536 HB_PairPosFormat2* ppf2,
1543 HB_UShort cl1 = 0, cl2 = 0; /* shut compiler up */
1545 HB_Class1Record* c1r;
1546 HB_Class2Record* c2r;
1549 error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
1551 if ( error && error != HB_Err_Not_Covered )
1553 error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1555 if ( error && error != HB_Err_Not_Covered )
1558 c1r = &ppf2->Class1Record[cl1];
1560 return ERR(HB_Err_Invalid_SubTable);
1561 c2r = &c1r->Class2Record[cl2];
1563 error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1566 return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
1570 static HB_Error Lookup_PairPos( GPOS_Instance* gpi,
1571 HB_GPOS_SubTable* st,
1574 HB_UShort context_length,
1578 HB_UShort index, property;
1580 HB_GPOSHeader* gpos = gpi->gpos;
1581 HB_PairPos* pp = &st->pair;
1583 HB_UNUSED(nesting_level);
1585 if ( buffer->in_pos >= buffer->in_length - 1 )
1586 return HB_Err_Not_Covered; /* Not enough glyphs in stream */
1588 if ( context_length != 0xFFFF && context_length < 2 )
1589 return HB_Err_Not_Covered;
1591 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1594 error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1600 first_pos = buffer->in_pos;
1603 while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
1604 flags, &property ) )
1606 if ( error && error != HB_Err_Not_Covered )
1609 if ( buffer->in_pos == buffer->in_length )
1611 buffer->in_pos = first_pos;
1612 return HB_Err_Not_Covered;
1618 switch ( pp->PosFormat )
1621 error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1623 pp->ValueFormat1, pp->ValueFormat2 );
1627 error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1628 pp->ValueFormat1, pp->ValueFormat2 );
1632 return ERR(HB_Err_Invalid_SubTable_Format);
1635 /* if we don't have coverage for the second glyph don't skip it for
1636 further lookups but reset in_pos back to the first_glyph and let
1637 the caller in Do_String_Lookup increment in_pos */
1638 if ( error == HB_Err_Not_Covered )
1639 buffer->in_pos = first_pos;
1641 /* adjusting the `next' glyph */
1643 if ( pp->ValueFormat2 )
1652 /* CursivePosFormat1 */
1654 static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
1658 HB_CursivePos* cp = &st->cursive;
1660 HB_UShort n, m, count;
1661 HB_UInt cur_offset, new_offset, base_offset;
1663 HB_EntryExitRecord* eer;
1666 base_offset = FILE_Pos();
1668 if ( ACCESS_Frame( 4L ) )
1671 cp->PosFormat = GET_UShort();
1672 new_offset = GET_UShort() + base_offset;
1676 cur_offset = FILE_Pos();
1677 if ( FILE_Seek( new_offset ) ||
1678 ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
1680 (void)FILE_Seek( cur_offset );
1682 if ( ACCESS_Frame( 2L ) )
1685 count = cp->EntryExitCount = GET_UShort();
1689 cp->EntryExitRecord = NULL;
1691 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1694 eer = cp->EntryExitRecord;
1696 for ( n = 0; n < count; n++ )
1698 HB_UInt entry_offset;
1700 if ( ACCESS_Frame( 2L ) )
1703 entry_offset = new_offset = GET_UShort();
1709 new_offset += base_offset;
1711 cur_offset = FILE_Pos();
1712 if ( FILE_Seek( new_offset ) ||
1713 ( error = Load_Anchor( &eer[n].EntryAnchor,
1714 stream ) ) != HB_Err_Ok )
1716 (void)FILE_Seek( cur_offset );
1719 eer[n].EntryAnchor.PosFormat = 0;
1721 if ( ACCESS_Frame( 2L ) )
1724 new_offset = GET_UShort();
1730 new_offset += base_offset;
1732 cur_offset = FILE_Pos();
1733 if ( FILE_Seek( new_offset ) ||
1734 ( error = Load_Anchor( &eer[n].ExitAnchor,
1735 stream ) ) != HB_Err_Ok )
1738 Free_Anchor( &eer[n].EntryAnchor );
1741 (void)FILE_Seek( cur_offset );
1744 eer[n].ExitAnchor.PosFormat = 0;
1750 for ( m = 0; m < n; m++ )
1752 Free_Anchor( &eer[m].EntryAnchor );
1753 Free_Anchor( &eer[m].ExitAnchor );
1759 _HB_OPEN_Free_Coverage( &cp->Coverage );
1764 static void Free_CursivePos( HB_GPOS_SubTable* st )
1767 HB_CursivePos* cp = &st->cursive;
1769 HB_EntryExitRecord* eer;
1772 if ( cp->EntryExitRecord )
1774 count = cp->EntryExitCount;
1775 eer = cp->EntryExitRecord;
1777 for ( n = 0; n < count; n++ )
1779 Free_Anchor( &eer[n].EntryAnchor );
1780 Free_Anchor( &eer[n].ExitAnchor );
1786 _HB_OPEN_Free_Coverage( &cp->Coverage );
1790 static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
1791 HB_GPOS_SubTable* st,
1794 HB_UShort context_length,
1797 HB_UShort index, property;
1799 HB_GPOSHeader* gpos = gpi->gpos;
1800 HB_CursivePos* cp = &st->cursive;
1802 HB_EntryExitRecord* eer;
1803 HB_Fixed entry_x, entry_y;
1804 HB_Fixed exit_x, exit_y;
1806 HB_UNUSED(nesting_level);
1808 if ( context_length != 0xFFFF && context_length < 1 )
1811 return HB_Err_Not_Covered;
1814 /* Glyphs not having the right GDEF properties will be ignored, i.e.,
1815 gpi->last won't be reset (contrary to user defined properties). */
1817 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1820 /* We don't handle mark glyphs here. According to Andrei, this isn't
1821 possible, but who knows... */
1823 if ( property == HB_GDEF_MARK )
1826 return HB_Err_Not_Covered;
1829 error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1836 if ( index >= cp->EntryExitCount )
1837 return ERR(HB_Err_Invalid_SubTable);
1839 eer = &cp->EntryExitRecord[index];
1841 /* Now comes the messiest part of the whole OpenType
1842 specification. At first glance, cursive connections seem easy
1843 to understand, but there are pitfalls! The reason is that
1844 the specs don't mention how to compute the advance values
1845 resp. glyph offsets. I was told it would be an omission, to
1846 be fixed in the next OpenType version... Again many thanks to
1847 Andrei Burago <andreib@microsoft.com> for clarifications.
1849 Consider the following example:
1862 glyph1: advance width = 12
1863 anchor point = (3,1)
1865 glyph2: advance width = 11
1866 anchor point = (9,4)
1868 LSB is 1 for both glyphs (so the boxes drawn above are glyph
1869 bboxes). Writing direction is R2L; `0' denotes the glyph's
1872 Now the surprising part: The advance width of the *left* glyph
1873 (resp. of the *bottom* glyph) will be modified, no matter
1874 whether the writing direction is L2R or R2L (resp. T2B or
1875 B2T)! This assymetry is caused by the fact that the glyph's
1876 coordinate origin is always the lower left corner for all
1879 Continuing the above example, we can compute the new
1880 (horizontal) advance width of glyph2 as
1884 and the new vertical offset of glyph2 as
1889 Vertical writing direction is far more complicated:
1891 a) Assuming that we recompute the advance height of the lower glyph:
1896 +-----+--+ 1 | yadv1
1898 yadv2 | 0+--+------+ -- BSB1 --
1899 | 2 | -- -- y_offset
1901 BSB2 -- 0+--------+ --
1904 glyph1: advance height = 6
1905 anchor point = (3,1)
1907 glyph2: advance height = 7
1908 anchor point = (9,4)
1910 TSB is 1 for both glyphs; writing direction is T2B.
1913 BSB1 = yadv1 - (TSB1 + ymax1)
1914 BSB2 = yadv2 - (TSB2 + ymax2)
1917 vertical advance width of glyph2
1918 = y_offset + BSB2 - BSB1
1919 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1920 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1921 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1924 b) Assuming that we recompute the advance height of the upper glyph:
1929 TSB2 -- +-----+--+ 1 | yadv1 ymax1
1931 yadv2 | 0+--+------+ -- --
1932 ymax2 | 2 | -- y_offset
1937 glyph1: advance height = 6
1938 anchor point = (3,1)
1940 glyph2: advance height = 7
1941 anchor point = (9,4)
1943 TSB is 1 for both glyphs; writing direction is T2B.
1947 vertical advance width of glyph2
1948 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1949 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1952 Comparing a) with b) shows that b) is easier to compute. I'll wait
1953 for a reply from Andrei to see what should really be implemented...
1955 Since horizontal advance widths or vertical advance heights
1956 can be used alone but not together, no ambiguity occurs. */
1958 if ( gpi->last == 0xFFFF )
1961 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1964 error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1965 &entry_x, &entry_y );
1966 if ( error == HB_Err_Not_Covered )
1973 POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
1974 POSITION( buffer->in_pos )->new_advance = TRUE;
1978 POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
1979 POSITION( gpi->last )->new_advance = TRUE;
1982 if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
1984 POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
1985 POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
1989 POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
1990 POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
1994 error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
1996 if ( error == HB_Err_Not_Covered )
2000 gpi->last = buffer->in_pos;
2001 gpi->anchor_x = exit_x;
2002 gpi->anchor_y = exit_y;
2017 static HB_Error Load_BaseArray( HB_BaseArray* ba,
2018 HB_UShort num_classes,
2023 HB_UShort m, n, count;
2024 HB_UInt cur_offset, new_offset, base_offset;
2027 HB_Anchor *ban, *bans;
2030 base_offset = FILE_Pos();
2032 if ( ACCESS_Frame( 2L ) )
2035 count = ba->BaseCount = GET_UShort();
2039 ba->BaseRecord = NULL;
2041 if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2044 br = ba->BaseRecord;
2048 if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
2051 for ( m = 0; m < count; m++ )
2053 br[m].BaseAnchor = NULL;
2055 ban = br[m].BaseAnchor = bans + m * num_classes;
2057 for ( n = 0; n < num_classes; n++ )
2059 if ( ACCESS_Frame( 2L ) )
2062 new_offset = GET_UShort() + base_offset;
2066 if (new_offset == base_offset) {
2068 * Doulos SIL Regular is buggy and has zero offsets here.
2071 ban[n].PosFormat = 0;
2075 cur_offset = FILE_Pos();
2076 if ( FILE_Seek( new_offset ) ||
2077 ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
2079 (void)FILE_Seek( cur_offset );
2092 static void Free_BaseArray( HB_BaseArray* ba,
2093 HB_UShort num_classes )
2098 if ( ba->BaseRecord )
2100 br = ba->BaseRecord;
2102 if ( ba->BaseCount )
2105 count = num_classes * ba->BaseCount;
2106 bans = br[0].BaseAnchor;
2107 for (i = 0; i < count; i++)
2108 Free_Anchor (&bans[i]);
2117 /* MarkBasePosFormat1 */
2119 static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
2123 HB_MarkBasePos* mbp = &st->markbase;
2125 HB_UInt cur_offset, new_offset, base_offset;
2128 base_offset = FILE_Pos();
2130 if ( ACCESS_Frame( 4L ) )
2133 mbp->PosFormat = GET_UShort();
2134 new_offset = GET_UShort() + base_offset;
2138 if (mbp->PosFormat != 1)
2139 return ERR(HB_Err_Invalid_SubTable_Format);
2141 cur_offset = FILE_Pos();
2142 if ( FILE_Seek( new_offset ) ||
2143 ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
2145 (void)FILE_Seek( cur_offset );
2147 if ( ACCESS_Frame( 2L ) )
2150 new_offset = GET_UShort() + base_offset;
2154 cur_offset = FILE_Pos();
2155 if ( FILE_Seek( new_offset ) ||
2156 ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
2158 (void)FILE_Seek( cur_offset );
2160 if ( ACCESS_Frame( 4L ) )
2163 mbp->ClassCount = GET_UShort();
2164 new_offset = GET_UShort() + base_offset;
2168 cur_offset = FILE_Pos();
2169 if ( FILE_Seek( new_offset ) ||
2170 ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
2172 (void)FILE_Seek( cur_offset );
2174 if ( ACCESS_Frame( 2L ) )
2177 new_offset = GET_UShort() + base_offset;
2181 cur_offset = FILE_Pos();
2182 if ( FILE_Seek( new_offset ) ||
2183 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2184 stream ) ) != HB_Err_Ok )
2190 Free_MarkArray( &mbp->MarkArray );
2193 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2196 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2201 static void Free_MarkBasePos( HB_GPOS_SubTable* st )
2203 HB_MarkBasePos* mbp = &st->markbase;
2205 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
2206 Free_MarkArray( &mbp->MarkArray );
2207 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2208 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2212 static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
2213 HB_GPOS_SubTable* st,
2216 HB_UShort context_length,
2219 HB_UShort i, j, mark_index, base_index, property, class;
2220 HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value;
2222 HB_GPOSHeader* gpos = gpi->gpos;
2223 HB_MarkBasePos* mbp = &st->markbase;
2228 HB_Anchor* mark_anchor;
2229 HB_Anchor* base_anchor;
2233 HB_UNUSED(nesting_level);
2235 if ( context_length != 0xFFFF && context_length < 1 )
2236 return HB_Err_Not_Covered;
2238 if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
2239 return HB_Err_Not_Covered;
2241 if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2242 flags, &property ) )
2245 error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2250 /* now we search backwards for a non-mark glyph */
2253 j = buffer->in_pos - 1;
2255 while ( i <= buffer->in_pos )
2257 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2262 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2269 /* The following assertion is too strong -- at least for mangal.ttf. */
2271 if ( property != HB_GDEF_BASE_GLYPH )
2272 return HB_Err_Not_Covered;
2275 if ( i > buffer->in_pos )
2276 return HB_Err_Not_Covered;
2278 error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2283 ma = &mbp->MarkArray;
2285 if ( mark_index >= ma->MarkCount )
2286 return ERR(HB_Err_Invalid_SubTable);
2288 class = ma->MarkRecord[mark_index].Class;
2289 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2291 if ( class >= mbp->ClassCount )
2292 return ERR(HB_Err_Invalid_SubTable);
2294 ba = &mbp->BaseArray;
2296 if ( base_index >= ba->BaseCount )
2297 return ERR(HB_Err_Invalid_SubTable);
2299 br = &ba->BaseRecord[base_index];
2300 base_anchor = &br->BaseAnchor[class];
2302 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2303 &x_mark_value, &y_mark_value );
2307 error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2308 &x_base_value, &y_base_value );
2312 /* anchor points are not cumulative */
2314 o = POSITION( buffer->in_pos );
2316 o->x_pos = x_base_value - x_mark_value;
2317 o->y_pos = y_base_value - y_mark_value;
2330 /* LigatureAttach */
2332 static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
2333 HB_UShort num_classes,
2338 HB_UShort m, n, k, count;
2339 HB_UInt cur_offset, new_offset, base_offset;
2341 HB_ComponentRecord* cr;
2345 base_offset = FILE_Pos();
2347 if ( ACCESS_Frame( 2L ) )
2350 count = lat->ComponentCount = GET_UShort();
2354 lat->ComponentRecord = NULL;
2356 if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2359 cr = lat->ComponentRecord;
2361 for ( m = 0; m < count; m++ )
2363 cr[m].LigatureAnchor = NULL;
2365 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
2368 lan = cr[m].LigatureAnchor;
2370 for ( n = 0; n < num_classes; n++ )
2372 if ( ACCESS_Frame( 2L ) )
2375 new_offset = GET_UShort();
2381 new_offset += base_offset;
2383 cur_offset = FILE_Pos();
2384 if ( FILE_Seek( new_offset ) ||
2385 ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
2387 (void)FILE_Seek( cur_offset );
2390 lan[n].PosFormat = 0;
2395 for ( k = 0; k < n; k++ )
2396 Free_Anchor( &lan[k] );
2403 for ( k = 0; k < m; k++ )
2405 lan = cr[k].LigatureAnchor;
2407 for ( n = 0; n < num_classes; n++ )
2408 Free_Anchor( &lan[n] );
2418 static void Free_LigatureAttach( HB_LigatureAttach* lat,
2419 HB_UShort num_classes )
2421 HB_UShort m, n, count;
2423 HB_ComponentRecord* cr;
2427 if ( lat->ComponentRecord )
2429 count = lat->ComponentCount;
2430 cr = lat->ComponentRecord;
2432 for ( m = 0; m < count; m++ )
2434 lan = cr[m].LigatureAnchor;
2436 for ( n = 0; n < num_classes; n++ )
2437 Free_Anchor( &lan[n] );
2449 static HB_Error Load_LigatureArray( HB_LigatureArray* la,
2450 HB_UShort num_classes,
2455 HB_UShort n, m, count;
2456 HB_UInt cur_offset, new_offset, base_offset;
2458 HB_LigatureAttach* lat;
2461 base_offset = FILE_Pos();
2463 if ( ACCESS_Frame( 2L ) )
2466 count = la->LigatureCount = GET_UShort();
2470 la->LigatureAttach = NULL;
2472 if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2475 lat = la->LigatureAttach;
2477 for ( n = 0; n < count; n++ )
2479 if ( ACCESS_Frame( 2L ) )
2482 new_offset = GET_UShort() + base_offset;
2486 cur_offset = FILE_Pos();
2487 if ( FILE_Seek( new_offset ) ||
2488 ( error = Load_LigatureAttach( &lat[n], num_classes,
2489 stream ) ) != HB_Err_Ok )
2491 (void)FILE_Seek( cur_offset );
2497 for ( m = 0; m < n; m++ )
2498 Free_LigatureAttach( &lat[m], num_classes );
2505 static void Free_LigatureArray( HB_LigatureArray* la,
2506 HB_UShort num_classes )
2510 HB_LigatureAttach* lat;
2513 if ( la->LigatureAttach )
2515 count = la->LigatureCount;
2516 lat = la->LigatureAttach;
2518 for ( n = 0; n < count; n++ )
2519 Free_LigatureAttach( &lat[n], num_classes );
2526 /* MarkLigPosFormat1 */
2528 static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
2532 HB_MarkLigPos* mlp = &st->marklig;
2534 HB_UInt cur_offset, new_offset, base_offset;
2537 base_offset = FILE_Pos();
2539 if ( ACCESS_Frame( 4L ) )
2542 mlp->PosFormat = GET_UShort();
2543 new_offset = GET_UShort() + base_offset;
2547 cur_offset = FILE_Pos();
2548 if ( FILE_Seek( new_offset ) ||
2549 ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
2551 (void)FILE_Seek( cur_offset );
2553 if ( ACCESS_Frame( 2L ) )
2556 new_offset = GET_UShort() + base_offset;
2560 cur_offset = FILE_Pos();
2561 if ( FILE_Seek( new_offset ) ||
2562 ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2563 stream ) ) != HB_Err_Ok )
2565 (void)FILE_Seek( cur_offset );
2567 if ( ACCESS_Frame( 4L ) )
2570 mlp->ClassCount = GET_UShort();
2571 new_offset = GET_UShort() + base_offset;
2575 cur_offset = FILE_Pos();
2576 if ( FILE_Seek( new_offset ) ||
2577 ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
2579 (void)FILE_Seek( cur_offset );
2581 if ( ACCESS_Frame( 2L ) )
2584 new_offset = GET_UShort() + base_offset;
2588 cur_offset = FILE_Pos();
2589 if ( FILE_Seek( new_offset ) ||
2590 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2591 stream ) ) != HB_Err_Ok )
2597 Free_MarkArray( &mlp->MarkArray );
2600 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2603 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2608 static void Free_MarkLigPos( HB_GPOS_SubTable* st)
2610 HB_MarkLigPos* mlp = &st->marklig;
2612 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
2613 Free_MarkArray( &mlp->MarkArray );
2614 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2615 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2619 static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
2620 HB_GPOS_SubTable* st,
2623 HB_UShort context_length,
2626 HB_UShort i, j, mark_index, lig_index, property, class;
2627 HB_UShort mark_glyph;
2628 HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2630 HB_GPOSHeader* gpos = gpi->gpos;
2631 HB_MarkLigPos* mlp = &st->marklig;
2634 HB_LigatureArray* la;
2635 HB_LigatureAttach* lat;
2636 HB_ComponentRecord* cr;
2637 HB_UShort comp_index;
2638 HB_Anchor* mark_anchor;
2639 HB_Anchor* lig_anchor;
2643 HB_UNUSED(nesting_level);
2645 if ( context_length != 0xFFFF && context_length < 1 )
2646 return HB_Err_Not_Covered;
2648 if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
2649 return HB_Err_Not_Covered;
2651 mark_glyph = IN_CURGLYPH();
2653 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
2656 error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2660 /* now we search backwards for a non-mark glyph */
2663 j = buffer->in_pos - 1;
2665 while ( i <= buffer->in_pos )
2667 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2672 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2679 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2680 too strong, thus it is commented out. */
2682 if ( property != HB_GDEF_LIGATURE )
2683 return HB_Err_Not_Covered;
2686 if ( i > buffer->in_pos )
2687 return HB_Err_Not_Covered;
2689 error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2694 ma = &mlp->MarkArray;
2696 if ( mark_index >= ma->MarkCount )
2697 return ERR(HB_Err_Invalid_SubTable);
2699 class = ma->MarkRecord[mark_index].Class;
2700 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2702 if ( class >= mlp->ClassCount )
2703 return ERR(HB_Err_Invalid_SubTable);
2705 la = &mlp->LigatureArray;
2707 if ( lig_index >= la->LigatureCount )
2708 return ERR(HB_Err_Invalid_SubTable);
2710 lat = &la->LigatureAttach[lig_index];
2712 /* We must now check whether the ligature ID of the current mark glyph
2713 is identical to the ligature ID of the found ligature. If yes, we
2714 can directly use the component index. If not, we attach the mark
2715 glyph to the last component of the ligature. */
2717 if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
2719 comp_index = IN_COMPONENT( buffer->in_pos );
2720 if ( comp_index >= lat->ComponentCount )
2721 return HB_Err_Not_Covered;
2724 comp_index = lat->ComponentCount - 1;
2726 cr = &lat->ComponentRecord[comp_index];
2727 lig_anchor = &cr->LigatureAnchor[class];
2729 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2730 &x_mark_value, &y_mark_value );
2733 error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2734 &x_lig_value, &y_lig_value );
2738 /* anchor points are not cumulative */
2740 o = POSITION( buffer->in_pos );
2742 o->x_pos = x_lig_value - x_mark_value;
2743 o->y_pos = y_lig_value - y_mark_value;
2758 static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
2759 HB_UShort num_classes,
2764 HB_UShort m, n, count;
2765 HB_UInt cur_offset, new_offset, base_offset;
2767 HB_Mark2Record *m2r;
2768 HB_Anchor *m2an, *m2ans;
2771 base_offset = FILE_Pos();
2773 if ( ACCESS_Frame( 2L ) )
2776 count = m2a->Mark2Count = GET_UShort();
2780 m2a->Mark2Record = NULL;
2782 if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2785 m2r = m2a->Mark2Record;
2789 if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
2792 for ( m = 0; m < count; m++ )
2794 m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
2796 for ( n = 0; n < num_classes; n++ )
2798 if ( ACCESS_Frame( 2L ) )
2801 new_offset = GET_UShort() + base_offset;
2805 if (new_offset == base_offset) {
2806 /* Anchor table not provided. Skip loading.
2807 * Some versions of FreeSans hit this. */
2808 m2an[n].PosFormat = 0;
2812 cur_offset = FILE_Pos();
2813 if ( FILE_Seek( new_offset ) ||
2814 ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
2816 (void)FILE_Seek( cur_offset );
2829 static void Free_Mark2Array( HB_Mark2Array* m2a,
2830 HB_UShort num_classes )
2832 HB_Mark2Record *m2r;
2835 HB_UNUSED(num_classes);
2837 if ( m2a->Mark2Record )
2839 m2r = m2a->Mark2Record;
2841 if ( m2a->Mark2Count )
2843 m2ans = m2r[0].Mark2Anchor;
2852 /* MarkMarkPosFormat1 */
2854 static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
2858 HB_MarkMarkPos* mmp = &st->markmark;
2860 HB_UInt cur_offset, new_offset, base_offset;
2863 base_offset = FILE_Pos();
2865 if ( ACCESS_Frame( 4L ) )
2868 mmp->PosFormat = GET_UShort();
2869 new_offset = GET_UShort() + base_offset;
2873 cur_offset = FILE_Pos();
2874 if ( FILE_Seek( new_offset ) ||
2875 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2876 stream ) ) != HB_Err_Ok )
2878 (void)FILE_Seek( cur_offset );
2880 if ( ACCESS_Frame( 2L ) )
2883 new_offset = GET_UShort() + base_offset;
2887 cur_offset = FILE_Pos();
2888 if ( FILE_Seek( new_offset ) ||
2889 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2890 stream ) ) != HB_Err_Ok )
2892 (void)FILE_Seek( cur_offset );
2894 if ( ACCESS_Frame( 4L ) )
2897 mmp->ClassCount = GET_UShort();
2898 new_offset = GET_UShort() + base_offset;
2902 cur_offset = FILE_Pos();
2903 if ( FILE_Seek( new_offset ) ||
2904 ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
2906 (void)FILE_Seek( cur_offset );
2908 if ( ACCESS_Frame( 2L ) )
2911 new_offset = GET_UShort() + base_offset;
2915 cur_offset = FILE_Pos();
2916 if ( FILE_Seek( new_offset ) ||
2917 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2918 stream ) ) != HB_Err_Ok )
2924 Free_MarkArray( &mmp->Mark1Array );
2927 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2930 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2935 static void Free_MarkMarkPos( HB_GPOS_SubTable* st)
2937 HB_MarkMarkPos* mmp = &st->markmark;
2939 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2940 Free_MarkArray( &mmp->Mark1Array );
2941 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2942 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2946 static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
2947 HB_GPOS_SubTable* st,
2950 HB_UShort context_length,
2953 HB_UShort i, j, mark1_index, mark2_index, property, class;
2954 HB_Fixed x_mark1_value, y_mark1_value,
2955 x_mark2_value, y_mark2_value;
2957 HB_GPOSHeader* gpos = gpi->gpos;
2958 HB_MarkMarkPos* mmp = &st->markmark;
2962 HB_Mark2Record* m2r;
2963 HB_Anchor* mark1_anchor;
2964 HB_Anchor* mark2_anchor;
2968 HB_UNUSED(nesting_level);
2970 if ( context_length != 0xFFFF && context_length < 1 )
2971 return HB_Err_Not_Covered;
2973 if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
2974 return HB_Err_Not_Covered;
2976 if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2977 flags, &property ) )
2980 error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
2985 /* now we search backwards for a suitable mark glyph until a non-mark
2988 if ( buffer->in_pos == 0 )
2989 return HB_Err_Not_Covered;
2992 j = buffer->in_pos - 1;
2993 while ( i <= buffer->in_pos )
2995 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
3000 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
3001 return HB_Err_Not_Covered;
3003 if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
3005 if ( property == (flags & 0xFF00) )
3015 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3020 ma1 = &mmp->Mark1Array;
3022 if ( mark1_index >= ma1->MarkCount )
3023 return ERR(HB_Err_Invalid_SubTable);
3025 class = ma1->MarkRecord[mark1_index].Class;
3026 mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3028 if ( class >= mmp->ClassCount )
3029 return ERR(HB_Err_Invalid_SubTable);
3031 ma2 = &mmp->Mark2Array;
3033 if ( mark2_index >= ma2->Mark2Count )
3034 return ERR(HB_Err_Invalid_SubTable);
3036 m2r = &ma2->Mark2Record[mark2_index];
3037 mark2_anchor = &m2r->Mark2Anchor[class];
3039 error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3040 &x_mark1_value, &y_mark1_value );
3043 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3044 &x_mark2_value, &y_mark2_value );
3048 /* anchor points are not cumulative */
3050 o = POSITION( buffer->in_pos );
3052 o->x_pos = x_mark2_value - x_mark1_value;
3053 o->y_pos = y_mark2_value - y_mark1_value;
3064 /* Do the actual positioning for a context positioning (either format
3065 7 or 8). This is only called after we've determined that the stream
3066 matches the subrule. */
3068 static HB_Error Do_ContextPos( GPOS_Instance* gpi,
3069 HB_UShort GlyphCount,
3071 HB_PosLookupRecord* pos,
3081 while ( i < GlyphCount )
3083 if ( PosCount && i == pos->SequenceIndex )
3085 old_pos = buffer->in_pos;
3087 /* Do a positioning */
3089 error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3090 GlyphCount, nesting_level );
3097 i += buffer->in_pos - old_pos;
3114 static HB_Error Load_PosRule( HB_PosRule* pr,
3122 HB_PosLookupRecord* plr;
3125 if ( ACCESS_Frame( 4L ) )
3128 pr->GlyphCount = GET_UShort();
3129 pr->PosCount = GET_UShort();
3135 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3137 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3142 if ( ACCESS_Frame( count * 2L ) )
3145 for ( n = 0; n < count; n++ )
3146 i[n] = GET_UShort();
3150 pr->PosLookupRecord = NULL;
3152 count = pr->PosCount;
3154 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3157 plr = pr->PosLookupRecord;
3159 if ( ACCESS_Frame( count * 4L ) )
3162 for ( n = 0; n < count; n++ )
3164 plr[n].SequenceIndex = GET_UShort();
3165 plr[n].LookupListIndex = GET_UShort();
3181 static void Free_PosRule( HB_PosRule* pr )
3183 FREE( pr->PosLookupRecord );
3190 static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
3195 HB_UShort n, m, count;
3196 HB_UInt cur_offset, new_offset, base_offset;
3201 base_offset = FILE_Pos();
3203 if ( ACCESS_Frame( 2L ) )
3206 count = prs->PosRuleCount = GET_UShort();
3210 prs->PosRule = NULL;
3212 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3217 for ( n = 0; n < count; n++ )
3219 if ( ACCESS_Frame( 2L ) )
3222 new_offset = GET_UShort() + base_offset;
3226 cur_offset = FILE_Pos();
3227 if ( FILE_Seek( new_offset ) ||
3228 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3230 (void)FILE_Seek( cur_offset );
3236 for ( m = 0; m < n; m++ )
3237 Free_PosRule( &pr[m] );
3244 static void Free_PosRuleSet( HB_PosRuleSet* prs )
3253 count = prs->PosRuleCount;
3256 for ( n = 0; n < count; n++ )
3257 Free_PosRule( &pr[n] );
3264 /* ContextPosFormat1 */
3266 static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
3271 HB_UShort n, m, count;
3272 HB_UInt cur_offset, new_offset, base_offset;
3277 base_offset = FILE_Pos() - 2L;
3279 if ( ACCESS_Frame( 2L ) )
3282 new_offset = GET_UShort() + base_offset;
3286 cur_offset = FILE_Pos();
3287 if ( FILE_Seek( new_offset ) ||
3288 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3290 (void)FILE_Seek( cur_offset );
3292 if ( ACCESS_Frame( 2L ) )
3295 count = cpf1->PosRuleSetCount = GET_UShort();
3299 cpf1->PosRuleSet = NULL;
3301 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3304 prs = cpf1->PosRuleSet;
3306 for ( n = 0; n < count; n++ )
3308 if ( ACCESS_Frame( 2L ) )
3311 new_offset = GET_UShort() + base_offset;
3315 cur_offset = FILE_Pos();
3316 if ( FILE_Seek( new_offset ) ||
3317 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3319 (void)FILE_Seek( cur_offset );
3325 for ( m = 0; m < n; m++ )
3326 Free_PosRuleSet( &prs[m] );
3331 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3336 static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
3343 if ( cpf1->PosRuleSet )
3345 count = cpf1->PosRuleSetCount;
3346 prs = cpf1->PosRuleSet;
3348 for ( n = 0; n < count; n++ )
3349 Free_PosRuleSet( &prs[n] );
3354 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3360 static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
3361 HB_PosClassRule* pcr,
3369 HB_PosLookupRecord* plr;
3372 if ( ACCESS_Frame( 4L ) )
3375 pcr->GlyphCount = GET_UShort();
3376 pcr->PosCount = GET_UShort();
3380 if ( pcr->GlyphCount > cpf2->MaxContextLength )
3381 cpf2->MaxContextLength = pcr->GlyphCount;
3385 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3387 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3392 if ( ACCESS_Frame( count * 2L ) )
3395 for ( n = 0; n < count; n++ )
3396 c[n] = GET_UShort();
3400 pcr->PosLookupRecord = NULL;
3402 count = pcr->PosCount;
3404 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3407 plr = pcr->PosLookupRecord;
3409 if ( ACCESS_Frame( count * 4L ) )
3412 for ( n = 0; n < count; n++ )
3414 plr[n].SequenceIndex = GET_UShort();
3415 plr[n].LookupListIndex = GET_UShort();
3431 static void Free_PosClassRule( HB_PosClassRule* pcr )
3433 FREE( pcr->PosLookupRecord );
3440 static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
3441 HB_PosClassSet* pcs,
3446 HB_UShort n, m, count;
3447 HB_UInt cur_offset, new_offset, base_offset;
3449 HB_PosClassRule* pcr;
3452 base_offset = FILE_Pos();
3454 if ( ACCESS_Frame( 2L ) )
3457 count = pcs->PosClassRuleCount = GET_UShort();
3461 pcs->PosClassRule = NULL;
3463 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3466 pcr = pcs->PosClassRule;
3468 for ( n = 0; n < count; n++ )
3470 if ( ACCESS_Frame( 2L ) )
3473 new_offset = GET_UShort() + base_offset;
3477 cur_offset = FILE_Pos();
3478 if ( FILE_Seek( new_offset ) ||
3479 ( error = Load_PosClassRule( cpf2, &pcr[n],
3480 stream ) ) != HB_Err_Ok )
3482 (void)FILE_Seek( cur_offset );
3488 for ( m = 0; m < n; m++ )
3489 Free_PosClassRule( &pcr[m] );
3496 static void Free_PosClassSet( HB_PosClassSet* pcs )
3500 HB_PosClassRule* pcr;
3503 if ( pcs->PosClassRule )
3505 count = pcs->PosClassRuleCount;
3506 pcr = pcs->PosClassRule;
3508 for ( n = 0; n < count; n++ )
3509 Free_PosClassRule( &pcr[n] );
3516 /* ContextPosFormat2 */
3518 static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
3523 HB_UShort n, m, count;
3524 HB_UInt cur_offset, new_offset, base_offset;
3526 HB_PosClassSet* pcs;
3529 base_offset = FILE_Pos() - 2;
3531 if ( ACCESS_Frame( 2L ) )
3534 new_offset = GET_UShort() + base_offset;
3538 cur_offset = FILE_Pos();
3539 if ( FILE_Seek( new_offset ) ||
3540 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3542 (void)FILE_Seek( cur_offset );
3544 if ( ACCESS_Frame( 4L ) )
3547 new_offset = GET_UShort() + base_offset;
3549 /* `PosClassSetCount' is the upper limit for class values, thus we
3550 read it now to make an additional safety check. */
3552 count = cpf2->PosClassSetCount = GET_UShort();
3556 cur_offset = FILE_Pos();
3557 if ( FILE_Seek( new_offset ) ||
3558 ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3559 stream ) ) != HB_Err_Ok )
3561 (void)FILE_Seek( cur_offset );
3563 cpf2->PosClassSet = NULL;
3564 cpf2->MaxContextLength = 0;
3566 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3569 pcs = cpf2->PosClassSet;
3571 for ( n = 0; n < count; n++ )
3573 if ( ACCESS_Frame( 2L ) )
3576 new_offset = GET_UShort() + base_offset;
3580 if ( new_offset != base_offset ) /* not a NULL offset */
3582 cur_offset = FILE_Pos();
3583 if ( FILE_Seek( new_offset ) ||
3584 ( error = Load_PosClassSet( cpf2, &pcs[n],
3585 stream ) ) != HB_Err_Ok )
3587 (void)FILE_Seek( cur_offset );
3591 /* we create a PosClassSet table with no entries */
3593 cpf2->PosClassSet[n].PosClassRuleCount = 0;
3594 cpf2->PosClassSet[n].PosClassRule = NULL;
3601 for ( m = 0; m < n; n++ )
3602 Free_PosClassSet( &pcs[m] );
3607 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3610 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3615 static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
3619 HB_PosClassSet* pcs;
3622 if ( cpf2->PosClassSet )
3624 count = cpf2->PosClassSetCount;
3625 pcs = cpf2->PosClassSet;
3627 for ( n = 0; n < count; n++ )
3628 Free_PosClassSet( &pcs[n] );
3633 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3634 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3638 /* ContextPosFormat3 */
3640 static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
3646 HB_UInt cur_offset, new_offset, base_offset;
3649 HB_PosLookupRecord* plr;
3652 base_offset = FILE_Pos() - 2L;
3654 if ( ACCESS_Frame( 4L ) )
3657 cpf3->GlyphCount = GET_UShort();
3658 cpf3->PosCount = GET_UShort();
3662 cpf3->Coverage = NULL;
3664 count = cpf3->GlyphCount;
3666 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3671 for ( n = 0; n < count; n++ )
3673 if ( ACCESS_Frame( 2L ) )
3676 new_offset = GET_UShort() + base_offset;
3680 cur_offset = FILE_Pos();
3681 if ( FILE_Seek( new_offset ) ||
3682 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3684 (void)FILE_Seek( cur_offset );
3687 cpf3->PosLookupRecord = NULL;
3689 count = cpf3->PosCount;
3691 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3694 plr = cpf3->PosLookupRecord;
3696 if ( ACCESS_Frame( count * 4L ) )
3699 for ( n = 0; n < count; n++ )
3701 plr[n].SequenceIndex = GET_UShort();
3702 plr[n].LookupListIndex = GET_UShort();
3713 for ( n = 0; n < count; n++ )
3714 _HB_OPEN_Free_Coverage( &c[n] );
3721 static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
3728 FREE( cpf3->PosLookupRecord );
3730 if ( cpf3->Coverage )
3732 count = cpf3->GlyphCount;
3735 for ( n = 0; n < count; n++ )
3736 _HB_OPEN_Free_Coverage( &c[n] );
3745 static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
3749 HB_ContextPos* cp = &st->context;
3752 if ( ACCESS_Frame( 2L ) )
3755 cp->PosFormat = GET_UShort();
3759 switch ( cp->PosFormat )
3762 return Load_ContextPos1( &cp->cpf.cpf1, stream );
3765 return Load_ContextPos2( &cp->cpf.cpf2, stream );
3768 return Load_ContextPos3( &cp->cpf.cpf3, stream );
3771 return ERR(HB_Err_Invalid_SubTable_Format);
3774 return HB_Err_Ok; /* never reached */
3778 static void Free_ContextPos( HB_GPOS_SubTable* st )
3780 HB_ContextPos* cp = &st->context;
3782 switch ( cp->PosFormat )
3784 case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break;
3785 case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break;
3786 case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break;
3792 static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3793 HB_ContextPosFormat1* cpf1,
3796 HB_UShort context_length,
3799 HB_UShort index, property;
3800 HB_UShort i, j, k, numpr;
3802 HB_GPOSHeader* gpos = gpi->gpos;
3805 HB_GDEFHeader* gdef;
3810 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3813 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3817 pr = cpf1->PosRuleSet[index].PosRule;
3818 numpr = cpf1->PosRuleSet[index].PosRuleCount;
3820 for ( k = 0; k < numpr; k++ )
3822 if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3825 if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3826 goto next_posrule; /* context is too long */
3828 for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3830 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3832 if ( error && error != HB_Err_Not_Covered )
3835 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3840 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3844 return Do_ContextPos( gpi, pr[k].GlyphCount,
3845 pr[k].PosCount, pr[k].PosLookupRecord,
3853 return HB_Err_Not_Covered;
3857 static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
3858 HB_ContextPosFormat2* cpf2,
3861 HB_UShort context_length,
3864 HB_UShort index, property;
3866 HB_UShort i, j, k, known_classes;
3870 HB_GPOSHeader* gpos = gpi->gpos;
3872 HB_PosClassSet* pcs;
3873 HB_PosClassRule* pr;
3874 HB_GDEFHeader* gdef;
3879 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3882 /* Note: The coverage table in format 2 doesn't give an index into
3883 anything. It just lets us know whether or not we need to
3884 do any lookup at all. */
3886 error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3890 if (cpf2->MaxContextLength < 1)
3891 return HB_Err_Not_Covered;
3893 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3896 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3897 &classes[0], NULL );
3898 if ( error && error != HB_Err_Not_Covered )
3902 pcs = &cpf2->PosClassSet[classes[0]];
3905 error = ERR(HB_Err_Invalid_SubTable);
3909 for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3911 pr = &pcs->PosClassRule[k];
3913 if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
3914 goto next_posclassrule;
3916 if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
3917 goto next_posclassrule; /* context is too long */
3921 /* Start at 1 because [0] is implied */
3923 for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
3925 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3927 if ( error && error != HB_Err_Not_Covered )
3930 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3931 goto next_posclassrule;
3935 if ( i > known_classes )
3937 /* Keeps us from having to do this for each rule */
3939 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
3940 if ( error && error != HB_Err_Not_Covered )
3945 if ( cl[i - 1] != classes[i] )
3946 goto next_posclassrule;
3949 error = Do_ContextPos( gpi, pr->GlyphCount,
3950 pr->PosCount, pr->PosLookupRecord,
3959 error = HB_Err_Not_Covered;
3967 static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
3968 HB_ContextPosFormat3* cpf3,
3971 HB_UShort context_length,
3975 HB_UShort index, i, j, property;
3976 HB_GPOSHeader* gpos = gpi->gpos;
3979 HB_GDEFHeader* gdef;
3984 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3987 if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
3988 return HB_Err_Not_Covered;
3990 if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
3991 return HB_Err_Not_Covered; /* context is too long */
3995 for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
3997 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3999 if ( error && error != HB_Err_Not_Covered )
4002 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
4003 return HB_Err_Not_Covered;
4007 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4012 return Do_ContextPos( gpi, cpf3->GlyphCount,
4013 cpf3->PosCount, cpf3->PosLookupRecord,
4019 static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
4020 HB_GPOS_SubTable* st,
4023 HB_UShort context_length,
4026 HB_ContextPos* cp = &st->context;
4028 switch ( cp->PosFormat )
4031 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4032 flags, context_length, nesting_level );
4035 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4036 flags, context_length, nesting_level );
4039 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4040 flags, context_length, nesting_level );
4043 return ERR(HB_Err_Invalid_SubTable_Format);
4046 return HB_Err_Ok; /* never reached */
4054 static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
4064 HB_PosLookupRecord* plr;
4067 if ( ACCESS_Frame( 2L ) )
4070 cpr->BacktrackGlyphCount = GET_UShort();
4074 cpr->Backtrack = NULL;
4076 count = cpr->BacktrackGlyphCount;
4078 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4083 if ( ACCESS_Frame( count * 2L ) )
4086 for ( n = 0; n < count; n++ )
4087 b[n] = GET_UShort();
4091 if ( ACCESS_Frame( 2L ) )
4094 cpr->InputGlyphCount = GET_UShort();
4100 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4102 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4107 if ( ACCESS_Frame( count * 2L ) )
4110 for ( n = 0; n < count; n++ )
4111 i[n] = GET_UShort();
4115 if ( ACCESS_Frame( 2L ) )
4118 cpr->LookaheadGlyphCount = GET_UShort();
4122 cpr->Lookahead = NULL;
4124 count = cpr->LookaheadGlyphCount;
4126 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4131 if ( ACCESS_Frame( count * 2L ) )
4134 for ( n = 0; n < count; n++ )
4135 l[n] = GET_UShort();
4139 if ( ACCESS_Frame( 2L ) )
4142 cpr->PosCount = GET_UShort();
4146 cpr->PosLookupRecord = NULL;
4148 count = cpr->PosCount;
4150 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4153 plr = cpr->PosLookupRecord;
4155 if ( ACCESS_Frame( count * 4L ) )
4158 for ( n = 0; n < count; n++ )
4160 plr[n].SequenceIndex = GET_UShort();
4161 plr[n].LookupListIndex = GET_UShort();
4183 static void Free_ChainPosRule( HB_ChainPosRule* cpr )
4185 FREE( cpr->PosLookupRecord );
4186 FREE( cpr->Lookahead );
4188 FREE( cpr->Backtrack );
4192 /* ChainPosRuleSet */
4194 static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4199 HB_UShort n, m, count;
4200 HB_UInt cur_offset, new_offset, base_offset;
4202 HB_ChainPosRule* cpr;
4205 base_offset = FILE_Pos();
4207 if ( ACCESS_Frame( 2L ) )
4210 count = cprs->ChainPosRuleCount = GET_UShort();
4214 cprs->ChainPosRule = NULL;
4216 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4219 cpr = cprs->ChainPosRule;
4221 for ( n = 0; n < count; n++ )
4223 if ( ACCESS_Frame( 2L ) )
4226 new_offset = GET_UShort() + base_offset;
4230 cur_offset = FILE_Pos();
4231 if ( FILE_Seek( new_offset ) ||
4232 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4234 (void)FILE_Seek( cur_offset );
4240 for ( m = 0; m < n; m++ )
4241 Free_ChainPosRule( &cpr[m] );
4248 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
4252 HB_ChainPosRule* cpr;
4255 if ( cprs->ChainPosRule )
4257 count = cprs->ChainPosRuleCount;
4258 cpr = cprs->ChainPosRule;
4260 for ( n = 0; n < count; n++ )
4261 Free_ChainPosRule( &cpr[n] );
4268 /* ChainContextPosFormat1 */
4270 static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4275 HB_UShort n, m, count;
4276 HB_UInt cur_offset, new_offset, base_offset;
4278 HB_ChainPosRuleSet* cprs;
4281 base_offset = FILE_Pos() - 2L;
4283 if ( ACCESS_Frame( 2L ) )
4286 new_offset = GET_UShort() + base_offset;
4290 cur_offset = FILE_Pos();
4291 if ( FILE_Seek( new_offset ) ||
4292 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4294 (void)FILE_Seek( cur_offset );
4296 if ( ACCESS_Frame( 2L ) )
4299 count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4303 ccpf1->ChainPosRuleSet = NULL;
4305 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4308 cprs = ccpf1->ChainPosRuleSet;
4310 for ( n = 0; n < count; n++ )
4312 if ( ACCESS_Frame( 2L ) )
4315 new_offset = GET_UShort() + base_offset;
4319 cur_offset = FILE_Pos();
4320 if ( FILE_Seek( new_offset ) ||
4321 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4323 (void)FILE_Seek( cur_offset );
4329 for ( m = 0; m < n; m++ )
4330 Free_ChainPosRuleSet( &cprs[m] );
4335 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4340 static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
4344 HB_ChainPosRuleSet* cprs;
4347 if ( ccpf1->ChainPosRuleSet )
4349 count = ccpf1->ChainPosRuleSetCount;
4350 cprs = ccpf1->ChainPosRuleSet;
4352 for ( n = 0; n < count; n++ )
4353 Free_ChainPosRuleSet( &cprs[n] );
4358 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4362 /* ChainPosClassRule */
4364 static HB_Error Load_ChainPosClassRule(
4365 HB_ChainContextPosFormat2* ccpf2,
4366 HB_ChainPosClassRule* cpcr,
4376 HB_PosLookupRecord* plr;
4379 if ( ACCESS_Frame( 2L ) )
4382 cpcr->BacktrackGlyphCount = GET_UShort();
4386 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4387 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4389 cpcr->Backtrack = NULL;
4391 count = cpcr->BacktrackGlyphCount;
4393 if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
4396 b = cpcr->Backtrack;
4398 if ( ACCESS_Frame( count * 2L ) )
4401 for ( n = 0; n < count; n++ )
4402 b[n] = GET_UShort();
4406 if ( ACCESS_Frame( 2L ) )
4409 cpcr->InputGlyphCount = GET_UShort();
4411 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4412 ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4418 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4420 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4425 if ( ACCESS_Frame( count * 2L ) )
4428 for ( n = 0; n < count; n++ )
4429 i[n] = GET_UShort();
4433 if ( ACCESS_Frame( 2L ) )
4436 cpcr->LookaheadGlyphCount = GET_UShort();
4440 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4441 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4443 cpcr->Lookahead = NULL;
4445 count = cpcr->LookaheadGlyphCount;
4447 if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
4450 l = cpcr->Lookahead;
4452 if ( ACCESS_Frame( count * 2L ) )
4455 for ( n = 0; n < count; n++ )
4456 l[n] = GET_UShort();
4460 if ( ACCESS_Frame( 2L ) )
4463 cpcr->PosCount = GET_UShort();
4467 cpcr->PosLookupRecord = NULL;
4469 count = cpcr->PosCount;
4471 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4474 plr = cpcr->PosLookupRecord;
4476 if ( ACCESS_Frame( count * 4L ) )
4479 for ( n = 0; n < count; n++ )
4481 plr[n].SequenceIndex = GET_UShort();
4482 plr[n].LookupListIndex = GET_UShort();
4504 static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
4506 FREE( cpcr->PosLookupRecord );
4507 FREE( cpcr->Lookahead );
4508 FREE( cpcr->Input );
4509 FREE( cpcr->Backtrack );
4515 static HB_Error Load_ChainPosClassSet(
4516 HB_ChainContextPosFormat2* ccpf2,
4517 HB_ChainPosClassSet* cpcs,
4522 HB_UShort n, m, count;
4523 HB_UInt cur_offset, new_offset, base_offset;
4525 HB_ChainPosClassRule* cpcr;
4528 base_offset = FILE_Pos();
4530 if ( ACCESS_Frame( 2L ) )
4533 count = cpcs->ChainPosClassRuleCount = GET_UShort();
4537 cpcs->ChainPosClassRule = NULL;
4539 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4540 HB_ChainPosClassRule ) )
4543 cpcr = cpcs->ChainPosClassRule;
4545 for ( n = 0; n < count; n++ )
4547 if ( ACCESS_Frame( 2L ) )
4550 new_offset = GET_UShort() + base_offset;
4554 cur_offset = FILE_Pos();
4555 if ( FILE_Seek( new_offset ) ||
4556 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4557 stream ) ) != HB_Err_Ok )
4559 (void)FILE_Seek( cur_offset );
4565 for ( m = 0; m < n; m++ )
4566 Free_ChainPosClassRule( &cpcr[m] );
4573 static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
4577 HB_ChainPosClassRule* cpcr;
4580 if ( cpcs->ChainPosClassRule )
4582 count = cpcs->ChainPosClassRuleCount;
4583 cpcr = cpcs->ChainPosClassRule;
4585 for ( n = 0; n < count; n++ )
4586 Free_ChainPosClassRule( &cpcr[n] );
4593 /* ChainContextPosFormat2 */
4595 static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4600 HB_UShort n, m, count;
4601 HB_UInt cur_offset, new_offset, base_offset;
4602 HB_UInt backtrack_offset, input_offset, lookahead_offset;
4604 HB_ChainPosClassSet* cpcs;
4607 base_offset = FILE_Pos() - 2;
4609 if ( ACCESS_Frame( 2L ) )
4612 new_offset = GET_UShort() + base_offset;
4616 cur_offset = FILE_Pos();
4617 if ( FILE_Seek( new_offset ) ||
4618 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4620 (void)FILE_Seek( cur_offset );
4622 if ( ACCESS_Frame( 8L ) )
4625 backtrack_offset = GET_UShort();
4626 input_offset = GET_UShort();
4627 lookahead_offset = GET_UShort();
4629 /* `ChainPosClassSetCount' is the upper limit for input class values,
4630 thus we read it now to make an additional safety check. No limit
4631 is known or needed for the other two class definitions */
4633 count = ccpf2->ChainPosClassSetCount = GET_UShort();
4637 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4638 backtrack_offset, base_offset,
4639 stream ) ) != HB_Err_Ok )
4641 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4642 input_offset, base_offset,
4643 stream ) ) != HB_Err_Ok )
4645 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4646 lookahead_offset, base_offset,
4647 stream ) ) != HB_Err_Ok )
4650 ccpf2->ChainPosClassSet = NULL;
4651 ccpf2->MaxBacktrackLength = 0;
4652 ccpf2->MaxInputLength = 0;
4653 ccpf2->MaxLookaheadLength = 0;
4655 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4658 cpcs = ccpf2->ChainPosClassSet;
4660 for ( n = 0; n < count; n++ )
4662 if ( ACCESS_Frame( 2L ) )
4665 new_offset = GET_UShort() + base_offset;
4669 if ( new_offset != base_offset ) /* not a NULL offset */
4671 cur_offset = FILE_Pos();
4672 if ( FILE_Seek( new_offset ) ||
4673 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4674 stream ) ) != HB_Err_Ok )
4676 (void)FILE_Seek( cur_offset );
4680 /* we create a ChainPosClassSet table with no entries */
4682 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4683 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4690 for ( m = 0; m < n; m++ )
4691 Free_ChainPosClassSet( &cpcs[m] );
4696 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4699 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4702 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4705 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4710 static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
4714 HB_ChainPosClassSet* cpcs;
4717 if ( ccpf2->ChainPosClassSet )
4719 count = ccpf2->ChainPosClassSetCount;
4720 cpcs = ccpf2->ChainPosClassSet;
4722 for ( n = 0; n < count; n++ )
4723 Free_ChainPosClassSet( &cpcs[n] );
4728 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4729 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4730 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4732 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4736 /* ChainContextPosFormat3 */
4738 static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
4743 HB_UShort n, nb, ni, nl, m, count;
4744 HB_UShort backtrack_count, input_count, lookahead_count;
4745 HB_UInt cur_offset, new_offset, base_offset;
4750 HB_PosLookupRecord* plr;
4753 base_offset = FILE_Pos() - 2L;
4755 if ( ACCESS_Frame( 2L ) )
4758 ccpf3->BacktrackGlyphCount = GET_UShort();
4762 ccpf3->BacktrackCoverage = NULL;
4764 backtrack_count = ccpf3->BacktrackGlyphCount;
4766 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4770 b = ccpf3->BacktrackCoverage;
4772 for ( nb = 0; nb < backtrack_count; nb++ )
4774 if ( ACCESS_Frame( 2L ) )
4777 new_offset = GET_UShort() + base_offset;
4781 cur_offset = FILE_Pos();
4782 if ( FILE_Seek( new_offset ) ||
4783 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4785 (void)FILE_Seek( cur_offset );
4788 if ( ACCESS_Frame( 2L ) )
4791 ccpf3->InputGlyphCount = GET_UShort();
4795 ccpf3->InputCoverage = NULL;
4797 input_count = ccpf3->InputGlyphCount;
4799 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4802 i = ccpf3->InputCoverage;
4804 for ( ni = 0; ni < input_count; ni++ )
4806 if ( ACCESS_Frame( 2L ) )
4809 new_offset = GET_UShort() + base_offset;
4813 cur_offset = FILE_Pos();
4814 if ( FILE_Seek( new_offset ) ||
4815 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4817 (void)FILE_Seek( cur_offset );
4820 if ( ACCESS_Frame( 2L ) )
4823 ccpf3->LookaheadGlyphCount = GET_UShort();
4827 ccpf3->LookaheadCoverage = NULL;
4829 lookahead_count = ccpf3->LookaheadGlyphCount;
4831 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4835 l = ccpf3->LookaheadCoverage;
4837 for ( nl = 0; nl < lookahead_count; nl++ )
4839 if ( ACCESS_Frame( 2L ) )
4842 new_offset = GET_UShort() + base_offset;
4846 cur_offset = FILE_Pos();
4847 if ( FILE_Seek( new_offset ) ||
4848 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4850 (void)FILE_Seek( cur_offset );
4853 if ( ACCESS_Frame( 2L ) )
4856 ccpf3->PosCount = GET_UShort();
4860 ccpf3->PosLookupRecord = NULL;
4862 count = ccpf3->PosCount;
4864 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4867 plr = ccpf3->PosLookupRecord;
4869 if ( ACCESS_Frame( count * 4L ) )
4872 for ( n = 0; n < count; n++ )
4874 plr[n].SequenceIndex = GET_UShort();
4875 plr[n].LookupListIndex = GET_UShort();
4886 for ( m = 0; m < nl; m++ )
4887 _HB_OPEN_Free_Coverage( &l[m] );
4892 for ( m = 0; m < ni; m++ )
4893 _HB_OPEN_Free_Coverage( &i[m] );
4898 for ( m = 0; m < nb; m++ )
4899 _HB_OPEN_Free_Coverage( &b[m] );
4906 static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
4913 FREE( ccpf3->PosLookupRecord );
4915 if ( ccpf3->LookaheadCoverage )
4917 count = ccpf3->LookaheadGlyphCount;
4918 c = ccpf3->LookaheadCoverage;
4920 for ( n = 0; n < count; n++ )
4921 _HB_OPEN_Free_Coverage( &c[n] );
4926 if ( ccpf3->InputCoverage )
4928 count = ccpf3->InputGlyphCount;
4929 c = ccpf3->InputCoverage;
4931 for ( n = 0; n < count; n++ )
4932 _HB_OPEN_Free_Coverage( &c[n] );
4937 if ( ccpf3->BacktrackCoverage )
4939 count = ccpf3->BacktrackGlyphCount;
4940 c = ccpf3->BacktrackCoverage;
4942 for ( n = 0; n < count; n++ )
4943 _HB_OPEN_Free_Coverage( &c[n] );
4950 /* ChainContextPos */
4952 static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
4956 HB_ChainContextPos* ccp = &st->chain;
4959 if ( ACCESS_Frame( 2L ) )
4962 ccp->PosFormat = GET_UShort();
4966 switch ( ccp->PosFormat )
4969 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
4972 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
4975 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
4978 return ERR(HB_Err_Invalid_SubTable_Format);
4981 return HB_Err_Ok; /* never reached */
4985 static void Free_ChainContextPos( HB_GPOS_SubTable* st )
4987 HB_ChainContextPos* ccp = &st->chain;
4989 switch ( ccp->PosFormat )
4991 case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
4992 case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
4993 case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
4999 static HB_Error Lookup_ChainContextPos1(
5001 HB_ChainContextPosFormat1* ccpf1,
5004 HB_UShort context_length,
5007 HB_UShort index, property;
5008 HB_UShort i, j, k, num_cpr;
5009 HB_UShort bgc, igc, lgc;
5011 HB_GPOSHeader* gpos = gpi->gpos;
5013 HB_ChainPosRule* cpr;
5014 HB_ChainPosRule curr_cpr;
5015 HB_GDEFHeader* gdef;
5020 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5023 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5027 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5028 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5030 for ( k = 0; k < num_cpr; k++ )
5033 bgc = curr_cpr.BacktrackGlyphCount;
5034 igc = curr_cpr.InputGlyphCount;
5035 lgc = curr_cpr.LookaheadGlyphCount;
5037 if ( context_length != 0xFFFF && context_length < igc )
5038 goto next_chainposrule;
5040 /* check whether context is too long; it is a first guess only */
5042 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5043 goto next_chainposrule;
5047 /* Since we don't know in advance the number of glyphs to inspect,
5048 we search backwards for matches in the backtrack glyph array */
5050 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5052 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5054 if ( error && error != HB_Err_Not_Covered )
5057 if ( j + 1 == bgc - i )
5058 goto next_chainposrule;
5062 /* In OpenType 1.3, it is undefined whether the offsets of
5063 backtrack glyphs is in logical order or not. Version 1.4
5066 Logical order - a b c d e f g h i j
5069 Backtrack offsets - 3 2 1 0
5070 Lookahead offsets - 0 1 2 3 */
5072 if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5073 goto next_chainposrule;
5077 /* Start at 1 because [0] is implied */
5079 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5081 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5083 if ( error && error != HB_Err_Not_Covered )
5086 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5087 goto next_chainposrule;
5091 if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5092 goto next_chainposrule;
5095 /* we are starting to check for lookahead glyphs right after the
5096 last context glyph */
5098 for ( i = 0; i < lgc; i++, j++ )
5100 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5102 if ( error && error != HB_Err_Not_Covered )
5105 if ( j + lgc - i == (HB_Int)buffer->in_length )
5106 goto next_chainposrule;
5110 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5111 goto next_chainposrule;
5114 return Do_ContextPos( gpi, igc,
5116 curr_cpr.PosLookupRecord,
5124 return HB_Err_Not_Covered;
5128 static HB_Error Lookup_ChainContextPos2(
5130 HB_ChainContextPosFormat2* ccpf2,
5133 HB_UShort context_length,
5136 HB_UShort index, property;
5139 HB_UShort bgc, igc, lgc;
5140 HB_UShort known_backtrack_classes,
5141 known_input_classes,
5142 known_lookahead_classes;
5144 HB_UShort* backtrack_classes;
5145 HB_UShort* input_classes;
5146 HB_UShort* lookahead_classes;
5151 HB_GPOSHeader* gpos = gpi->gpos;
5153 HB_ChainPosClassSet* cpcs;
5154 HB_ChainPosClassRule cpcr;
5155 HB_GDEFHeader* gdef;
5160 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5163 /* Note: The coverage table in format 2 doesn't give an index into
5164 anything. It just lets us know whether or not we need to
5165 do any lookup at all. */
5167 error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5171 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5173 known_backtrack_classes = 0;
5175 if (ccpf2->MaxInputLength < 1)
5176 return HB_Err_Not_Covered;
5178 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5180 known_input_classes = 1;
5182 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5184 known_lookahead_classes = 0;
5186 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5187 &input_classes[0], NULL );
5188 if ( error && error != HB_Err_Not_Covered )
5191 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5194 error = ERR(HB_Err_Invalid_SubTable);
5198 for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5200 cpcr = cpcs->ChainPosClassRule[k];
5201 bgc = cpcr.BacktrackGlyphCount;
5202 igc = cpcr.InputGlyphCount;
5203 lgc = cpcr.LookaheadGlyphCount;
5205 if ( context_length != 0xFFFF && context_length < igc )
5206 goto next_chainposclassrule;
5208 /* check whether context is too long; it is a first guess only */
5210 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5211 goto next_chainposclassrule;
5215 /* Since we don't know in advance the number of glyphs to inspect,
5216 we search backwards for matches in the backtrack glyph array.
5217 Note that `known_backtrack_classes' starts at index 0. */
5219 bc = cpcr.Backtrack;
5221 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5223 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5225 if ( error && error != HB_Err_Not_Covered )
5228 if ( j + 1 == bgc - i )
5229 goto next_chainposclassrule;
5233 if ( i >= known_backtrack_classes )
5235 /* Keeps us from having to do this for each rule */
5237 error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5238 &backtrack_classes[i], NULL );
5239 if ( error && error != HB_Err_Not_Covered )
5241 known_backtrack_classes = i;
5244 if ( bc[i] != backtrack_classes[i] )
5245 goto next_chainposclassrule;
5251 /* Start at 1 because [0] is implied */
5253 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5255 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5257 if ( error && error != HB_Err_Not_Covered )
5260 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5261 goto next_chainposclassrule;
5265 if ( i >= known_input_classes )
5267 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5268 &input_classes[i], NULL );
5269 if ( error && error != HB_Err_Not_Covered )
5271 known_input_classes = i;
5274 if ( ic[i - 1] != input_classes[i] )
5275 goto next_chainposclassrule;
5278 /* we are starting to check for lookahead glyphs right after the
5279 last context glyph */
5281 lc = cpcr.Lookahead;
5283 for ( i = 0; i < lgc; i++, j++ )
5285 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5287 if ( error && error != HB_Err_Not_Covered )
5290 if ( j + lgc - i == (HB_Int)buffer->in_length )
5291 goto next_chainposclassrule;
5295 if ( i >= known_lookahead_classes )
5297 error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5298 &lookahead_classes[i], NULL );
5299 if ( error && error != HB_Err_Not_Covered )
5301 known_lookahead_classes = i;
5304 if ( lc[i] != lookahead_classes[i] )
5305 goto next_chainposclassrule;
5308 error = Do_ContextPos( gpi, igc,
5310 cpcr.PosLookupRecord,
5315 next_chainposclassrule:
5319 error = HB_Err_Not_Covered;
5322 FREE( lookahead_classes );
5325 FREE( input_classes );
5328 FREE( backtrack_classes );
5333 static HB_Error Lookup_ChainContextPos3(
5335 HB_ChainContextPosFormat3* ccpf3,
5338 HB_UShort context_length,
5341 HB_UShort index, i, j, property;
5342 HB_UShort bgc, igc, lgc;
5344 HB_GPOSHeader* gpos = gpi->gpos;
5349 HB_GDEFHeader* gdef;
5354 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5357 bgc = ccpf3->BacktrackGlyphCount;
5358 igc = ccpf3->InputGlyphCount;
5359 lgc = ccpf3->LookaheadGlyphCount;
5361 if ( context_length != 0xFFFF && context_length < igc )
5362 return HB_Err_Not_Covered;
5364 /* check whether context is too long; it is a first guess only */
5366 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5367 return HB_Err_Not_Covered;
5371 /* Since we don't know in advance the number of glyphs to inspect,
5372 we search backwards for matches in the backtrack glyph array */
5374 bc = ccpf3->BacktrackCoverage;
5376 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5378 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5380 if ( error && error != HB_Err_Not_Covered )
5383 if ( j + 1 == bgc - i )
5384 return HB_Err_Not_Covered;
5388 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5394 ic = ccpf3->InputCoverage;
5396 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5398 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5399 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5401 if ( error && error != HB_Err_Not_Covered )
5404 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5405 return HB_Err_Not_Covered;
5409 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5414 /* we are starting to check for lookahead glyphs right after the
5415 last context glyph */
5417 lc = ccpf3->LookaheadCoverage;
5419 for ( i = 0; i < lgc; i++, j++ )
5421 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5423 if ( error && error != HB_Err_Not_Covered )
5426 if ( j + lgc - i == (HB_Int)buffer->in_length )
5427 return HB_Err_Not_Covered;
5431 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5436 return Do_ContextPos( gpi, igc,
5438 ccpf3->PosLookupRecord,
5444 static HB_Error Lookup_ChainContextPos(
5446 HB_GPOS_SubTable* st,
5449 HB_UShort context_length,
5452 HB_ChainContextPos* ccp = &st->chain;
5454 switch ( ccp->PosFormat )
5457 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5458 flags, context_length,
5462 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5463 flags, context_length,
5467 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5468 flags, context_length,
5472 return ERR(HB_Err_Invalid_SubTable_Format);
5475 return HB_Err_Ok; /* never reached */
5486 HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
5488 HB_UShort* script_index )
5493 HB_ScriptRecord* sr;
5496 if ( !gpos || !script_index )
5497 return ERR(HB_Err_Invalid_Argument);
5499 sl = &gpos->ScriptList;
5500 sr = sl->ScriptRecord;
5502 for ( n = 0; n < sl->ScriptCount; n++ )
5503 if ( script_tag == sr[n].ScriptTag )
5510 return HB_Err_Not_Covered;
5515 HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
5516 HB_UInt language_tag,
5517 HB_UShort script_index,
5518 HB_UShort* language_index,
5519 HB_UShort* req_feature_index )
5524 HB_ScriptRecord* sr;
5526 HB_LangSysRecord* lsr;
5529 if ( !gpos || !language_index || !req_feature_index )
5530 return ERR(HB_Err_Invalid_Argument);
5532 sl = &gpos->ScriptList;
5533 sr = sl->ScriptRecord;
5535 if ( script_index >= sl->ScriptCount )
5536 return ERR(HB_Err_Invalid_Argument);
5538 s = &sr[script_index].Script;
5539 lsr = s->LangSysRecord;
5541 for ( n = 0; n < s->LangSysCount; n++ )
5542 if ( language_tag == lsr[n].LangSysTag )
5544 *language_index = n;
5545 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5550 return HB_Err_Not_Covered;
5554 /* selecting 0xFFFF for language_index asks for the values of the
5555 default language (DefaultLangSys) */
5558 HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
5559 HB_UInt feature_tag,
5560 HB_UShort script_index,
5561 HB_UShort language_index,
5562 HB_UShort* feature_index )
5567 HB_ScriptRecord* sr;
5569 HB_LangSysRecord* lsr;
5574 HB_FeatureRecord* fr;
5577 if ( !gpos || !feature_index )
5578 return ERR(HB_Err_Invalid_Argument);
5580 sl = &gpos->ScriptList;
5581 sr = sl->ScriptRecord;
5583 fl = &gpos->FeatureList;
5584 fr = fl->FeatureRecord;
5586 if ( script_index >= sl->ScriptCount )
5587 return ERR(HB_Err_Invalid_Argument);
5589 s = &sr[script_index].Script;
5590 lsr = s->LangSysRecord;
5592 if ( language_index == 0xFFFF )
5593 ls = &s->DefaultLangSys;
5596 if ( language_index >= s->LangSysCount )
5597 return ERR(HB_Err_Invalid_Argument);
5599 ls = &lsr[language_index].LangSys;
5602 fi = ls->FeatureIndex;
5604 for ( n = 0; n < ls->FeatureCount; n++ )
5606 if ( fi[n] >= fl->FeatureCount )
5607 return ERR(HB_Err_Invalid_SubTable_Format);
5609 if ( feature_tag == fr[fi[n]].FeatureTag )
5611 *feature_index = fi[n];
5617 return HB_Err_Not_Covered;
5621 /* The next three functions return a null-terminated list */
5624 HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
5625 HB_UInt** script_tag_list )
5632 HB_ScriptRecord* sr;
5635 if ( !gpos || !script_tag_list )
5636 return ERR(HB_Err_Invalid_Argument);
5638 sl = &gpos->ScriptList;
5639 sr = sl->ScriptRecord;
5641 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
5644 for ( n = 0; n < sl->ScriptCount; n++ )
5645 stl[n] = sr[n].ScriptTag;
5648 *script_tag_list = stl;
5655 HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
5656 HB_UShort script_index,
5657 HB_UInt** language_tag_list )
5664 HB_ScriptRecord* sr;
5666 HB_LangSysRecord* lsr;
5669 if ( !gpos || !language_tag_list )
5670 return ERR(HB_Err_Invalid_Argument);
5672 sl = &gpos->ScriptList;
5673 sr = sl->ScriptRecord;
5675 if ( script_index >= sl->ScriptCount )
5676 return ERR(HB_Err_Invalid_Argument);
5678 s = &sr[script_index].Script;
5679 lsr = s->LangSysRecord;
5681 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
5684 for ( n = 0; n < s->LangSysCount; n++ )
5685 ltl[n] = lsr[n].LangSysTag;
5688 *language_tag_list = ltl;
5694 /* selecting 0xFFFF for language_index asks for the values of the
5695 default language (DefaultLangSys) */
5698 HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
5699 HB_UShort script_index,
5700 HB_UShort language_index,
5701 HB_UInt** feature_tag_list )
5708 HB_ScriptRecord* sr;
5710 HB_LangSysRecord* lsr;
5715 HB_FeatureRecord* fr;
5718 if ( !gpos || !feature_tag_list )
5719 return ERR(HB_Err_Invalid_Argument);
5721 sl = &gpos->ScriptList;
5722 sr = sl->ScriptRecord;
5724 fl = &gpos->FeatureList;
5725 fr = fl->FeatureRecord;
5727 if ( script_index >= sl->ScriptCount )
5728 return ERR(HB_Err_Invalid_Argument);
5730 s = &sr[script_index].Script;
5731 lsr = s->LangSysRecord;
5733 if ( language_index == 0xFFFF )
5734 ls = &s->DefaultLangSys;
5737 if ( language_index >= s->LangSysCount )
5738 return ERR(HB_Err_Invalid_Argument);
5740 ls = &lsr[language_index].LangSys;
5743 fi = ls->FeatureIndex;
5745 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
5748 for ( n = 0; n < ls->FeatureCount; n++ )
5750 if ( fi[n] >= fl->FeatureCount )
5753 return ERR(HB_Err_Invalid_SubTable_Format);
5755 ftl[n] = fr[fi[n]].FeatureTag;
5759 *feature_tag_list = ftl;
5765 /* Do an individual subtable lookup. Returns HB_Err_Ok if positioning
5766 has been done, or HB_Err_Not_Covered if not. */
5767 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
5768 HB_UShort lookup_index,
5770 HB_UShort context_length,
5773 HB_Error error = HB_Err_Not_Covered;
5774 HB_UShort i, flags, lookup_count;
5775 HB_GPOSHeader* gpos = gpi->gpos;
5782 if ( nesting_level > HB_MAX_NESTING_LEVEL )
5783 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
5785 lookup_count = gpos->LookupList.LookupCount;
5786 if (lookup_index >= lookup_count)
5789 lo = &gpos->LookupList.Lookup[lookup_index];
5790 flags = lo->LookupFlag;
5791 lookup_type = lo->LookupType;
5793 for ( i = 0; i < lo->SubTableCount; i++ )
5795 HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
5797 switch (lookup_type) {
5798 case HB_GPOS_LOOKUP_SINGLE:
5799 error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5800 case HB_GPOS_LOOKUP_PAIR:
5801 error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5802 case HB_GPOS_LOOKUP_CURSIVE:
5803 error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5804 case HB_GPOS_LOOKUP_MARKBASE:
5805 error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5806 case HB_GPOS_LOOKUP_MARKLIG:
5807 error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5808 case HB_GPOS_LOOKUP_MARKMARK:
5809 error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5810 case HB_GPOS_LOOKUP_CONTEXT:
5811 error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5812 case HB_GPOS_LOOKUP_CHAIN:
5813 error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5814 /*case HB_GPOS_LOOKUP_EXTENSION:
5815 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5817 error = HB_Err_Not_Covered;
5820 /* Check whether we have a successful positioning or an error other
5821 than HB_Err_Not_Covered */
5822 if ( error != HB_Err_Not_Covered )
5826 return HB_Err_Not_Covered;
5830 HB_INTERNAL HB_Error
5831 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5833 HB_UShort lookup_type )
5835 switch ( lookup_type ) {
5836 case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream );
5837 case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream );
5838 case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream );
5839 case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream );
5840 case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream );
5841 case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream );
5842 case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream );
5843 case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream );
5844 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/
5845 default: return ERR(HB_Err_Invalid_SubTable_Format);
5851 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
5852 HB_UShort lookup_type )
5854 switch ( lookup_type ) {
5855 case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return;
5856 case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return;
5857 case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return;
5858 case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return;
5859 case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return;
5860 case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return;
5861 case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return;
5862 case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return;
5863 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/
5869 /* apply one lookup to the input string object */
5871 static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
5872 HB_UShort lookup_index,
5875 HB_Error error, retError = HB_Err_Not_Covered;
5876 HB_GPOSHeader* gpos = gpi->gpos;
5878 HB_UInt* properties = gpos->LookupList.Properties;
5880 const int nesting_level = 0;
5881 /* 0xFFFF indicates that we don't have a context length yet */
5882 const HB_UShort context_length = 0xFFFF;
5885 gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
5888 while ( buffer->in_pos < buffer->in_length )
5890 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
5892 /* Note that the connection between mark and base glyphs hold
5893 exactly one (string) lookup. For example, it would be possible
5894 that in the first lookup, mark glyph X is attached to base
5895 glyph A, and in the next lookup it is attached to base glyph B.
5896 It is up to the font designer to provide meaningful lookups and
5899 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5900 if ( error && error != HB_Err_Not_Covered )
5905 /* Contrary to properties defined in GDEF, user-defined properties
5906 will always stop a possible cursive positioning. */
5909 error = HB_Err_Not_Covered;
5912 if ( error == HB_Err_Not_Covered )
5922 static HB_Error Position_CursiveChain ( HB_Buffer buffer )
5925 HB_Position positions = buffer->positions;
5927 /* First handle all left-to-right connections */
5928 for (j = 0; j < buffer->in_length; j++)
5930 if (positions[j].cursive_chain > 0)
5931 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5934 /* Then handle all right-to-left connections */
5935 for (i = buffer->in_length; i > 0; i--)
5939 if (positions[j].cursive_chain < 0)
5940 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5947 HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
5948 HB_UShort feature_index,
5954 HB_UInt* properties;
5956 HB_UShort lookup_count;
5958 /* Each feature can only be added once */
5961 feature_index >= gpos->FeatureList.FeatureCount ||
5962 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
5963 return ERR(HB_Err_Invalid_Argument);
5965 gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
5967 properties = gpos->LookupList.Properties;
5969 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
5970 index = feature.LookupListIndex;
5971 lookup_count = gpos->LookupList.LookupCount;
5973 for ( i = 0; i < feature.LookupListCount; i++ )
5975 HB_UShort lookup_index = index[i];
5976 if (lookup_index < lookup_count)
5977 properties[lookup_index] |= property;
5985 HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
5989 HB_UInt* properties;
5993 return ERR(HB_Err_Invalid_Argument);
5995 gpos->FeatureList.ApplyCount = 0;
5997 properties = gpos->LookupList.Properties;
5999 for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
6005 #ifdef HB_SUPPORT_MULTIPLE_MASTER
6006 HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
6007 HB_MMFunction mmfunc,
6011 return ERR(HB_Err_Invalid_Argument);
6013 gpos->mmfunc = mmfunc;
6020 /* If `dvi' is TRUE, glyph contour points for anchor points and device
6021 tables are ignored -- you will get device independent values. */
6024 HB_Error HB_GPOS_Apply_String( HB_Font font,
6025 HB_GPOSHeader* gpos,
6026 HB_UShort load_flags,
6031 HB_Error error, retError = HB_Err_Not_Covered;
6033 int i, j, lookup_count, num_features;
6035 if ( !font || !gpos || !buffer )
6036 return ERR(HB_Err_Invalid_Argument);
6038 if ( buffer->in_length == 0 )
6039 return HB_Err_Not_Covered;
6043 gpi.load_flags = load_flags;
6047 lookup_count = gpos->LookupList.LookupCount;
6048 num_features = gpos->FeatureList.ApplyCount;
6052 error = _hb_buffer_clear_positions( buffer );
6057 for ( i = 0; i < num_features; i++ )
6059 HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i];
6060 HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6062 for ( j = 0; j < feature.LookupListCount; j++ )
6064 HB_UShort lookup_index = feature.LookupListIndex[j];
6066 /* Skip nonexistant lookups */
6067 if (lookup_index >= lookup_count)
6070 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6073 if ( error != HB_Err_Not_Covered )
6083 error = Position_CursiveChain ( buffer );