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"
39 HB_UShort load_flags; /* how the glyph should be loaded */
42 HB_UShort last; /* the last valid glyph -- used
43 with cursive positioning */
44 HB_Fixed anchor_x; /* the coordinates of the anchor point */
45 HB_Fixed anchor_y; /* of the last valid glyph */
48 typedef struct GPOS_Instance_ GPOS_Instance;
51 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
52 HB_UShort lookup_index,
54 HB_UShort context_length,
59 /* the client application must replace this with something more
60 meaningful if multiple master fonts are to be supported. */
62 static HB_Error default_mmfunc( HB_Font font,
64 HB_Fixed* metric_value,
69 HB_UNUSED(metric_value);
71 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
76 HB_Error HB_Load_GPOS_Table( HB_Font font,
77 HB_GPOSHeader** retptr,
80 HB_UInt cur_offset, new_offset, base_offset;
84 HB_Stream stream = font->stream;
89 return ERR(HB_Err_Invalid_Argument);
91 if ( GOTO_Table( TTAG_GPOS ) )
94 base_offset = FILE_Pos();
96 if ( ALLOC ( gpos, sizeof( *gpos ) ) )
99 gpos->gfunc = FT_Load_Glyph;
100 gpos->mmfunc = default_mmfunc;
104 if ( FILE_Seek( base_offset + 4L ) ||
108 new_offset = GET_UShort() + base_offset;
112 cur_offset = FILE_Pos();
113 if ( FILE_Seek( new_offset ) ||
114 ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
115 stream ) ) != HB_Err_Ok )
117 (void)FILE_Seek( cur_offset );
119 if ( ACCESS_Frame( 2L ) )
122 new_offset = GET_UShort() + base_offset;
126 cur_offset = FILE_Pos();
127 if ( FILE_Seek( new_offset ) ||
128 ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
129 stream ) ) != HB_Err_Ok )
131 (void)FILE_Seek( cur_offset );
133 if ( ACCESS_Frame( 2L ) )
136 new_offset = GET_UShort() + base_offset;
140 cur_offset = FILE_Pos();
141 if ( FILE_Seek( new_offset ) ||
142 ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
143 stream, HB_Type_GPOS ) ) != HB_Err_Ok )
146 gpos->gdef = gdef; /* can be NULL */
148 if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
149 gpos->LookupList.Lookup,
150 gpos->LookupList.LookupCount ) ) )
158 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
161 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
164 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
173 HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
175 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
176 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
177 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
185 /*****************************
186 * SubTable related functions
187 *****************************/
193 /* There is a subtle difference in the specs between a `table' and a
194 `record' -- offsets for device tables in ValueRecords are taken from
195 the parent table and not the parent record. */
197 static HB_Error Load_ValueRecord( HB_ValueRecord* vr,
204 HB_UInt cur_offset, new_offset;
207 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
209 if ( ACCESS_Frame( 2L ) )
212 vr->XPlacement = GET_Short();
219 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
221 if ( ACCESS_Frame( 2L ) )
224 vr->YPlacement = GET_Short();
231 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
233 if ( ACCESS_Frame( 2L ) )
236 vr->XAdvance = GET_Short();
243 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
245 if ( ACCESS_Frame( 2L ) )
248 vr->YAdvance = GET_Short();
255 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
257 if ( ACCESS_Frame( 2L ) )
260 new_offset = GET_UShort();
266 new_offset += base_offset;
268 cur_offset = FILE_Pos();
269 if ( FILE_Seek( new_offset ) ||
270 ( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
271 stream ) ) != HB_Err_Ok )
273 (void)FILE_Seek( cur_offset );
281 vr->XPlacementDevice.StartSize = 0;
282 vr->XPlacementDevice.EndSize = 0;
283 vr->XPlacementDevice.DeltaValue = NULL;
286 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
288 if ( ACCESS_Frame( 2L ) )
291 new_offset = GET_UShort();
297 new_offset += base_offset;
299 cur_offset = FILE_Pos();
300 if ( FILE_Seek( new_offset ) ||
301 ( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
302 stream ) ) != HB_Err_Ok )
304 (void)FILE_Seek( cur_offset );
312 vr->YPlacementDevice.StartSize = 0;
313 vr->YPlacementDevice.EndSize = 0;
314 vr->YPlacementDevice.DeltaValue = NULL;
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->XAdvanceDevice,
333 stream ) ) != HB_Err_Ok )
335 (void)FILE_Seek( cur_offset );
343 vr->XAdvanceDevice.StartSize = 0;
344 vr->XAdvanceDevice.EndSize = 0;
345 vr->XAdvanceDevice.DeltaValue = NULL;
348 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
350 if ( ACCESS_Frame( 2L ) )
353 new_offset = GET_UShort();
359 new_offset += base_offset;
361 cur_offset = FILE_Pos();
362 if ( FILE_Seek( new_offset ) ||
363 ( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
364 stream ) ) != HB_Err_Ok )
366 (void)FILE_Seek( cur_offset );
374 vr->YAdvanceDevice.StartSize = 0;
375 vr->YAdvanceDevice.EndSize = 0;
376 vr->YAdvanceDevice.DeltaValue = NULL;
379 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
381 if ( ACCESS_Frame( 2L ) )
384 vr->XIdPlacement = GET_UShort();
389 vr->XIdPlacement = 0;
391 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
393 if ( ACCESS_Frame( 2L ) )
396 vr->YIdPlacement = GET_UShort();
401 vr->YIdPlacement = 0;
403 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
405 if ( ACCESS_Frame( 2L ) )
408 vr->XIdAdvance = GET_UShort();
415 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
417 if ( ACCESS_Frame( 2L ) )
420 vr->YIdAdvance = GET_UShort();
430 _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
433 _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
436 _HB_OPEN_Free_Device( &vr->YPlacementDevice );
441 static void Free_ValueRecord( HB_ValueRecord* vr,
444 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
445 _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
446 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
447 _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
448 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
449 _HB_OPEN_Free_Device( &vr->YPlacementDevice );
450 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
451 _HB_OPEN_Free_Device( &vr->XPlacementDevice );
455 static HB_Error Get_ValueRecord( GPOS_Instance* gpi,
461 HB_Short pixel_value;
462 HB_Error error = HB_Err_Ok;
463 HB_GPOSHeader* gpos = gpi->gpos;
465 HB_UShort x_ppem, y_ppem;
466 HB_16Dot16 x_scale, y_scale;
472 x_ppem = gpi->font->size->metrics.x_ppem;
473 y_ppem = gpi->font->size->metrics.y_ppem;
474 x_scale = gpi->font->size->metrics.x_scale;
475 y_scale = gpi->font->size->metrics.y_scale;
477 /* design units -> fractional pixel */
479 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
480 gd->x_pos += x_scale * vr->XPlacement / 0x10000;
481 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
482 gd->y_pos += y_scale * vr->YPlacement / 0x10000;
483 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
484 gd->x_advance += x_scale * vr->XAdvance / 0x10000;
485 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
486 gd->y_advance += y_scale * vr->YAdvance / 0x10000;
490 /* pixel -> fractional pixel */
492 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
494 _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
495 gd->x_pos += pixel_value << 6;
497 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
499 _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
500 gd->y_pos += pixel_value << 6;
502 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
504 _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
505 gd->x_advance += pixel_value << 6;
507 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
509 _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
510 gd->y_advance += pixel_value << 6;
514 /* values returned from mmfunc() are already in fractional pixels */
516 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
518 error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
519 &value, gpos->data );
524 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
526 error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
527 &value, gpos->data );
532 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
534 error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
535 &value, gpos->data );
538 gd->x_advance += value;
540 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
542 error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
543 &value, gpos->data );
546 gd->y_advance += value;
558 static HB_Error Load_Anchor( HB_Anchor* an,
563 HB_UInt cur_offset, new_offset, base_offset;
566 base_offset = FILE_Pos();
568 if ( ACCESS_Frame( 2L ) )
571 an->PosFormat = GET_UShort();
575 switch ( an->PosFormat )
578 if ( ACCESS_Frame( 4L ) )
581 an->af.af1.XCoordinate = GET_Short();
582 an->af.af1.YCoordinate = GET_Short();
588 if ( ACCESS_Frame( 6L ) )
591 an->af.af2.XCoordinate = GET_Short();
592 an->af.af2.YCoordinate = GET_Short();
593 an->af.af2.AnchorPoint = GET_UShort();
599 if ( ACCESS_Frame( 6L ) )
602 an->af.af3.XCoordinate = GET_Short();
603 an->af.af3.YCoordinate = GET_Short();
605 new_offset = GET_UShort();
611 new_offset += base_offset;
613 cur_offset = FILE_Pos();
614 if ( FILE_Seek( new_offset ) ||
615 ( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
616 stream ) ) != HB_Err_Ok )
618 (void)FILE_Seek( cur_offset );
622 an->af.af3.XDeviceTable.StartSize = 0;
623 an->af.af3.XDeviceTable.EndSize = 0;
624 an->af.af3.XDeviceTable.DeltaValue = NULL;
627 if ( ACCESS_Frame( 2L ) )
630 new_offset = GET_UShort();
636 new_offset += base_offset;
638 cur_offset = FILE_Pos();
639 if ( FILE_Seek( new_offset ) ||
640 ( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
641 stream ) ) != HB_Err_Ok )
643 (void)FILE_Seek( cur_offset );
647 an->af.af3.YDeviceTable.StartSize = 0;
648 an->af.af3.YDeviceTable.EndSize = 0;
649 an->af.af3.YDeviceTable.DeltaValue = NULL;
654 if ( ACCESS_Frame( 4L ) )
657 an->af.af4.XIdAnchor = GET_UShort();
658 an->af.af4.YIdAnchor = GET_UShort();
664 return ERR(HB_Err_Invalid_SubTable_Format);
670 _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
675 static void Free_Anchor( HB_Anchor* an )
677 if ( an->PosFormat == 3 )
679 _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable );
680 _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
685 static HB_Error Get_Anchor( GPOS_Instance* gpi,
687 HB_UShort glyph_index,
691 HB_Error error = HB_Err_Ok;
694 HB_GPOSHeader* gpos = gpi->gpos;
697 HB_Short pixel_value;
698 HB_UShort load_flags;
700 HB_UShort x_ppem, y_ppem;
701 HB_16Dot16 x_scale, y_scale;
704 x_ppem = gpi->font->size->metrics.x_ppem;
705 y_ppem = gpi->font->size->metrics.y_ppem;
706 x_scale = gpi->font->size->metrics.x_scale;
707 y_scale = gpi->font->size->metrics.y_scale;
709 switch ( an->PosFormat )
712 /* The special case of an empty AnchorTable */
715 return HB_Err_Not_Covered;
718 *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
719 *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
723 /* glyphs must be scaled */
725 load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE;
729 error = (gpos->gfunc)( gpi->font, glyph_index, load_flags );
733 if ( gpi->font->glyph->format != ft_glyph_format_outline )
734 return ERR(HB_Err_Invalid_SubTable);
736 ap = an->af.af2.AnchorPoint;
738 outline = gpi->font->glyph->outline;
740 /* if n_points is set to zero, we use the design coordinate value pair.
741 * This can happen e.g. for sbit glyphs. */
742 if ( !outline.n_points )
743 goto no_contour_point;
745 if ( ap >= outline.n_points )
746 return ERR(HB_Err_Invalid_SubTable);
748 *x_value = outline.points[ap].x;
749 *y_value = outline.points[ap].y;
754 *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
755 *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
762 _HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
763 *x_value = pixel_value << 6;
764 _HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
765 *y_value = pixel_value << 6;
768 *x_value = *y_value = 0;
770 *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
771 *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
775 error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
776 x_value, gpos->data );
780 error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
781 y_value, gpos->data );
793 static HB_Error Load_MarkArray ( HB_MarkArray* ma,
798 HB_UShort n, m, count;
799 HB_UInt cur_offset, new_offset, base_offset;
804 base_offset = FILE_Pos();
806 if ( ACCESS_Frame( 2L ) )
809 count = ma->MarkCount = GET_UShort();
813 ma->MarkRecord = NULL;
815 if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
820 for ( n = 0; n < count; n++ )
822 if ( ACCESS_Frame( 4L ) )
825 mr[n].Class = GET_UShort();
826 new_offset = GET_UShort() + base_offset;
830 cur_offset = FILE_Pos();
831 if ( FILE_Seek( new_offset ) ||
832 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
834 (void)FILE_Seek( cur_offset );
840 for ( m = 0; m < n; m++ )
841 Free_Anchor( &mr[m].MarkAnchor );
848 static void Free_MarkArray( HB_MarkArray* ma )
855 if ( ma->MarkRecord )
857 count = ma->MarkCount;
860 for ( n = 0; n < count; n++ )
861 Free_Anchor( &mr[n].MarkAnchor );
870 /* SinglePosFormat1 */
871 /* SinglePosFormat2 */
873 static HB_Error Load_SinglePos( HB_GPOS_SubTable* st,
877 HB_SinglePos* sp = &st->single;
879 HB_UShort n, m, count, format;
880 HB_UInt cur_offset, new_offset, base_offset;
885 base_offset = FILE_Pos();
887 if ( ACCESS_Frame( 6L ) )
890 sp->PosFormat = GET_UShort();
891 new_offset = GET_UShort() + base_offset;
893 format = sp->ValueFormat = GET_UShort();
898 return ERR(HB_Err_Invalid_SubTable);
900 cur_offset = FILE_Pos();
901 if ( FILE_Seek( new_offset ) ||
902 ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
904 (void)FILE_Seek( cur_offset );
906 switch ( sp->PosFormat )
909 error = Load_ValueRecord( &sp->spf.spf1.Value, format,
910 base_offset, stream );
916 if ( ACCESS_Frame( 2L ) )
919 count = sp->spf.spf2.ValueCount = GET_UShort();
923 sp->spf.spf2.Value = NULL;
925 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
928 vr = sp->spf.spf2.Value;
930 for ( n = 0; n < count; n++ )
932 error = Load_ValueRecord( &vr[n], format, base_offset, stream );
939 return ERR(HB_Err_Invalid_SubTable_Format);
945 for ( m = 0; m < n; m++ )
946 Free_ValueRecord( &vr[m], format );
951 _HB_OPEN_Free_Coverage( &sp->Coverage );
956 static void Free_SinglePos( HB_GPOS_SubTable* st )
958 HB_UShort n, count, format;
959 HB_SinglePos* sp = &st->single;
964 format = sp->ValueFormat;
966 switch ( sp->PosFormat )
969 Free_ValueRecord( &sp->spf.spf1.Value, format );
973 if ( sp->spf.spf2.Value )
975 count = sp->spf.spf2.ValueCount;
976 v = sp->spf.spf2.Value;
978 for ( n = 0; n < count; n++ )
979 Free_ValueRecord( &v[n], format );
988 _HB_OPEN_Free_Coverage( &sp->Coverage );
991 static HB_Error Lookup_SinglePos( GPOS_Instance* gpi,
992 HB_GPOS_SubTable* st,
995 HB_UShort context_length,
998 HB_UShort index, property;
1000 HB_GPOSHeader* gpos = gpi->gpos;
1001 HB_SinglePos* sp = &st->single;
1003 HB_UNUSED(nesting_level);
1005 if ( context_length != 0xFFFF && context_length < 1 )
1006 return HB_Err_Not_Covered;
1008 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1011 error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
1015 switch ( sp->PosFormat )
1018 error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
1019 sp->ValueFormat, POSITION( buffer->in_pos ) );
1025 if ( index >= sp->spf.spf2.ValueCount )
1026 return ERR(HB_Err_Invalid_SubTable);
1027 error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
1028 sp->ValueFormat, POSITION( buffer->in_pos ) );
1034 return ERR(HB_Err_Invalid_SubTable);
1047 static HB_Error Load_PairSet ( HB_PairSet* ps,
1054 HB_UShort n, m, count;
1055 HB_UInt base_offset;
1057 HB_PairValueRecord* pvr;
1060 base_offset = FILE_Pos();
1062 if ( ACCESS_Frame( 2L ) )
1065 count = ps->PairValueCount = GET_UShort();
1069 ps->PairValueRecord = NULL;
1071 if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
1074 pvr = ps->PairValueRecord;
1076 for ( n = 0; n < count; n++ )
1078 if ( ACCESS_Frame( 2L ) )
1081 pvr[n].SecondGlyph = GET_UShort();
1087 error = Load_ValueRecord( &pvr[n].Value1, format1,
1088 base_offset, stream );
1094 error = Load_ValueRecord( &pvr[n].Value2, format2,
1095 base_offset, stream );
1099 Free_ValueRecord( &pvr[n].Value1, format1 );
1108 for ( m = 0; m < n; m++ )
1111 Free_ValueRecord( &pvr[m].Value1, format1 );
1113 Free_ValueRecord( &pvr[m].Value2, format2 );
1121 static void Free_PairSet( HB_PairSet* ps,
1127 HB_PairValueRecord* pvr;
1130 if ( ps->PairValueRecord )
1132 count = ps->PairValueCount;
1133 pvr = ps->PairValueRecord;
1135 for ( n = 0; n < count; n++ )
1138 Free_ValueRecord( &pvr[n].Value1, format1 );
1140 Free_ValueRecord( &pvr[n].Value2, format2 );
1148 /* PairPosFormat1 */
1150 static HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
1157 HB_UShort n, m, count;
1158 HB_UInt cur_offset, new_offset, base_offset;
1163 base_offset = FILE_Pos() - 8L;
1165 if ( ACCESS_Frame( 2L ) )
1168 count = ppf1->PairSetCount = GET_UShort();
1172 ppf1->PairSet = NULL;
1174 if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
1179 for ( n = 0; n < count; n++ )
1181 if ( ACCESS_Frame( 2L ) )
1184 new_offset = GET_UShort() + base_offset;
1188 cur_offset = FILE_Pos();
1189 if ( FILE_Seek( new_offset ) ||
1190 ( error = Load_PairSet( &ps[n], format1,
1191 format2, stream ) ) != HB_Err_Ok )
1193 (void)FILE_Seek( cur_offset );
1199 for ( m = 0; m < n; m++ )
1200 Free_PairSet( &ps[m], format1, format2 );
1207 static void Free_PairPos1( HB_PairPosFormat1* ppf1,
1216 if ( ppf1->PairSet )
1218 count = ppf1->PairSetCount;
1221 for ( n = 0; n < count; n++ )
1222 Free_PairSet( &ps[n], format1, format2 );
1229 /* PairPosFormat2 */
1231 static HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
1238 HB_UShort m, n, k, count1, count2;
1239 HB_UInt cur_offset, new_offset1, new_offset2, base_offset;
1241 HB_Class1Record* c1r;
1242 HB_Class2Record* c2r;
1245 base_offset = FILE_Pos() - 8L;
1247 if ( ACCESS_Frame( 8L ) )
1250 new_offset1 = GET_UShort() + base_offset;
1251 new_offset2 = GET_UShort() + base_offset;
1253 /* `Class1Count' and `Class2Count' are the upper limits for class
1254 values, thus we read it now to make additional safety checks. */
1256 count1 = ppf2->Class1Count = GET_UShort();
1257 count2 = ppf2->Class2Count = GET_UShort();
1261 cur_offset = FILE_Pos();
1262 if ( FILE_Seek( new_offset1 ) ||
1263 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
1264 stream ) ) != HB_Err_Ok )
1266 if ( FILE_Seek( new_offset2 ) ||
1267 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
1268 stream ) ) != HB_Err_Ok )
1270 (void)FILE_Seek( cur_offset );
1272 ppf2->Class1Record = NULL;
1274 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
1277 c1r = ppf2->Class1Record;
1279 for ( m = 0; m < count1; m++ )
1281 c1r[m].Class2Record = NULL;
1283 if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
1286 c2r = c1r[m].Class2Record;
1288 for ( n = 0; n < count2; n++ )
1292 error = Load_ValueRecord( &c2r[n].Value1, format1,
1293 base_offset, stream );
1299 error = Load_ValueRecord( &c2r[n].Value2, format2,
1300 base_offset, stream );
1304 Free_ValueRecord( &c2r[n].Value1, format1 );
1313 for ( k = 0; k < n; k++ )
1316 Free_ValueRecord( &c2r[k].Value1, format1 );
1318 Free_ValueRecord( &c2r[k].Value2, format2 );
1326 for ( k = 0; k < m; k++ )
1328 c2r = c1r[k].Class2Record;
1330 for ( n = 0; n < count2; n++ )
1333 Free_ValueRecord( &c2r[n].Value1, format1 );
1335 Free_ValueRecord( &c2r[n].Value2, format2 );
1344 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1347 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1352 static void Free_PairPos2( HB_PairPosFormat2* ppf2,
1356 HB_UShort m, n, count1, count2;
1358 HB_Class1Record* c1r;
1359 HB_Class2Record* c2r;
1362 if ( ppf2->Class1Record )
1364 c1r = ppf2->Class1Record;
1365 count1 = ppf2->Class1Count;
1366 count2 = ppf2->Class2Count;
1368 for ( m = 0; m < count1; m++ )
1370 c2r = c1r[m].Class2Record;
1372 for ( n = 0; n < count2; n++ )
1375 Free_ValueRecord( &c2r[n].Value1, format1 );
1377 Free_ValueRecord( &c2r[n].Value2, format2 );
1385 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1386 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1391 static HB_Error Load_PairPos( HB_GPOS_SubTable* st,
1395 HB_PairPos* pp = &st->pair;
1397 HB_UShort format1, format2;
1398 HB_UInt cur_offset, new_offset, base_offset;
1401 base_offset = FILE_Pos();
1403 if ( ACCESS_Frame( 8L ) )
1406 pp->PosFormat = GET_UShort();
1407 new_offset = GET_UShort() + base_offset;
1409 format1 = pp->ValueFormat1 = GET_UShort();
1410 format2 = pp->ValueFormat2 = GET_UShort();
1414 cur_offset = FILE_Pos();
1415 if ( FILE_Seek( new_offset ) ||
1416 ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
1418 (void)FILE_Seek( cur_offset );
1420 switch ( pp->PosFormat )
1423 error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
1429 error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
1435 return ERR(HB_Err_Invalid_SubTable_Format);
1441 _HB_OPEN_Free_Coverage( &pp->Coverage );
1446 static void Free_PairPos( HB_GPOS_SubTable* st )
1448 HB_UShort format1, format2;
1449 HB_PairPos* pp = &st->pair;
1452 format1 = pp->ValueFormat1;
1453 format2 = pp->ValueFormat2;
1455 switch ( pp->PosFormat )
1458 Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
1462 Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
1469 _HB_OPEN_Free_Coverage( &pp->Coverage );
1473 static HB_Error Lookup_PairPos1( GPOS_Instance* gpi,
1474 HB_PairPosFormat1* ppf1,
1482 HB_UShort numpvr, glyph2;
1484 HB_PairValueRecord* pvr;
1487 if ( index >= ppf1->PairSetCount )
1488 return ERR(HB_Err_Invalid_SubTable);
1490 pvr = ppf1->PairSet[index].PairValueRecord;
1492 return ERR(HB_Err_Invalid_SubTable);
1494 glyph2 = IN_CURGLYPH();
1496 for ( numpvr = ppf1->PairSet[index].PairValueCount;
1500 if ( glyph2 == pvr->SecondGlyph )
1502 error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1503 POSITION( first_pos ) );
1506 return Get_ValueRecord( gpi, &pvr->Value2, format2,
1507 POSITION( buffer->in_pos ) );
1511 return HB_Err_Not_Covered;
1515 static HB_Error Lookup_PairPos2( GPOS_Instance* gpi,
1516 HB_PairPosFormat2* ppf2,
1523 HB_UShort cl1 = 0, cl2 = 0; /* shut compiler up */
1525 HB_Class1Record* c1r;
1526 HB_Class2Record* c2r;
1529 error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
1531 if ( error && error != HB_Err_Not_Covered )
1533 error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1535 if ( error && error != HB_Err_Not_Covered )
1538 c1r = &ppf2->Class1Record[cl1];
1540 return ERR(HB_Err_Invalid_SubTable);
1541 c2r = &c1r->Class2Record[cl2];
1543 error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1546 return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
1550 static HB_Error Lookup_PairPos( GPOS_Instance* gpi,
1551 HB_GPOS_SubTable* st,
1554 HB_UShort context_length,
1558 HB_UShort index, property;
1560 HB_GPOSHeader* gpos = gpi->gpos;
1561 HB_PairPos* pp = &st->pair;
1563 HB_UNUSED(nesting_level);
1565 if ( buffer->in_pos >= buffer->in_length - 1 )
1566 return HB_Err_Not_Covered; /* Not enough glyphs in stream */
1568 if ( context_length != 0xFFFF && context_length < 2 )
1569 return HB_Err_Not_Covered;
1571 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1574 error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1580 first_pos = buffer->in_pos;
1583 while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
1584 flags, &property ) )
1586 if ( error && error != HB_Err_Not_Covered )
1589 if ( buffer->in_pos == buffer->in_length )
1591 buffer->in_pos = first_pos;
1592 return HB_Err_Not_Covered;
1598 switch ( pp->PosFormat )
1601 error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1603 pp->ValueFormat1, pp->ValueFormat2 );
1607 error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1608 pp->ValueFormat1, pp->ValueFormat2 );
1612 return ERR(HB_Err_Invalid_SubTable_Format);
1615 /* if we don't have coverage for the second glyph don't skip it for
1616 further lookups but reset in_pos back to the first_glyph and let
1617 the caller in Do_String_Lookup increment in_pos */
1618 if ( error == HB_Err_Not_Covered )
1619 buffer->in_pos = first_pos;
1621 /* adjusting the `next' glyph */
1623 if ( pp->ValueFormat2 )
1632 /* CursivePosFormat1 */
1634 static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
1638 HB_CursivePos* cp = &st->cursive;
1640 HB_UShort n, m, count;
1641 HB_UInt cur_offset, new_offset, base_offset;
1643 HB_EntryExitRecord* eer;
1646 base_offset = FILE_Pos();
1648 if ( ACCESS_Frame( 4L ) )
1651 cp->PosFormat = GET_UShort();
1652 new_offset = GET_UShort() + base_offset;
1656 cur_offset = FILE_Pos();
1657 if ( FILE_Seek( new_offset ) ||
1658 ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
1660 (void)FILE_Seek( cur_offset );
1662 if ( ACCESS_Frame( 2L ) )
1665 count = cp->EntryExitCount = GET_UShort();
1669 cp->EntryExitRecord = NULL;
1671 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1674 eer = cp->EntryExitRecord;
1676 for ( n = 0; n < count; n++ )
1678 HB_UInt entry_offset;
1680 if ( ACCESS_Frame( 2L ) )
1683 entry_offset = new_offset = GET_UShort();
1689 new_offset += base_offset;
1691 cur_offset = FILE_Pos();
1692 if ( FILE_Seek( new_offset ) ||
1693 ( error = Load_Anchor( &eer[n].EntryAnchor,
1694 stream ) ) != HB_Err_Ok )
1696 (void)FILE_Seek( cur_offset );
1699 eer[n].EntryAnchor.PosFormat = 0;
1701 if ( ACCESS_Frame( 2L ) )
1704 new_offset = GET_UShort();
1710 new_offset += base_offset;
1712 cur_offset = FILE_Pos();
1713 if ( FILE_Seek( new_offset ) ||
1714 ( error = Load_Anchor( &eer[n].ExitAnchor,
1715 stream ) ) != HB_Err_Ok )
1718 Free_Anchor( &eer[n].EntryAnchor );
1721 (void)FILE_Seek( cur_offset );
1724 eer[n].ExitAnchor.PosFormat = 0;
1730 for ( m = 0; m < n; m++ )
1732 Free_Anchor( &eer[m].EntryAnchor );
1733 Free_Anchor( &eer[m].ExitAnchor );
1739 _HB_OPEN_Free_Coverage( &cp->Coverage );
1744 static void Free_CursivePos( HB_GPOS_SubTable* st )
1747 HB_CursivePos* cp = &st->cursive;
1749 HB_EntryExitRecord* eer;
1752 if ( cp->EntryExitRecord )
1754 count = cp->EntryExitCount;
1755 eer = cp->EntryExitRecord;
1757 for ( n = 0; n < count; n++ )
1759 Free_Anchor( &eer[n].EntryAnchor );
1760 Free_Anchor( &eer[n].ExitAnchor );
1766 _HB_OPEN_Free_Coverage( &cp->Coverage );
1770 static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
1771 HB_GPOS_SubTable* st,
1774 HB_UShort context_length,
1777 HB_UShort index, property;
1779 HB_GPOSHeader* gpos = gpi->gpos;
1780 HB_CursivePos* cp = &st->cursive;
1782 HB_EntryExitRecord* eer;
1783 HB_Fixed entry_x, entry_y;
1784 HB_Fixed exit_x, exit_y;
1786 HB_UNUSED(nesting_level);
1788 if ( context_length != 0xFFFF && context_length < 1 )
1791 return HB_Err_Not_Covered;
1794 /* Glyphs not having the right GDEF properties will be ignored, i.e.,
1795 gpi->last won't be reset (contrary to user defined properties). */
1797 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1800 /* We don't handle mark glyphs here. According to Andrei, this isn't
1801 possible, but who knows... */
1803 if ( property == HB_GDEF_MARK )
1806 return HB_Err_Not_Covered;
1809 error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1816 if ( index >= cp->EntryExitCount )
1817 return ERR(HB_Err_Invalid_SubTable);
1819 eer = &cp->EntryExitRecord[index];
1821 /* Now comes the messiest part of the whole OpenType
1822 specification. At first glance, cursive connections seem easy
1823 to understand, but there are pitfalls! The reason is that
1824 the specs don't mention how to compute the advance values
1825 resp. glyph offsets. I was told it would be an omission, to
1826 be fixed in the next OpenType version... Again many thanks to
1827 Andrei Burago <andreib@microsoft.com> for clarifications.
1829 Consider the following example:
1842 glyph1: advance width = 12
1843 anchor point = (3,1)
1845 glyph2: advance width = 11
1846 anchor point = (9,4)
1848 LSB is 1 for both glyphs (so the boxes drawn above are glyph
1849 bboxes). Writing direction is R2L; `0' denotes the glyph's
1852 Now the surprising part: The advance width of the *left* glyph
1853 (resp. of the *bottom* glyph) will be modified, no matter
1854 whether the writing direction is L2R or R2L (resp. T2B or
1855 B2T)! This assymetry is caused by the fact that the glyph's
1856 coordinate origin is always the lower left corner for all
1859 Continuing the above example, we can compute the new
1860 (horizontal) advance width of glyph2 as
1864 and the new vertical offset of glyph2 as
1869 Vertical writing direction is far more complicated:
1871 a) Assuming that we recompute the advance height of the lower glyph:
1876 +-----+--+ 1 | yadv1
1878 yadv2 | 0+--+------+ -- BSB1 --
1879 | 2 | -- -- y_offset
1881 BSB2 -- 0+--------+ --
1884 glyph1: advance height = 6
1885 anchor point = (3,1)
1887 glyph2: advance height = 7
1888 anchor point = (9,4)
1890 TSB is 1 for both glyphs; writing direction is T2B.
1893 BSB1 = yadv1 - (TSB1 + ymax1)
1894 BSB2 = yadv2 - (TSB2 + ymax2)
1897 vertical advance width of glyph2
1898 = y_offset + BSB2 - BSB1
1899 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1900 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1901 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1904 b) Assuming that we recompute the advance height of the upper glyph:
1909 TSB2 -- +-----+--+ 1 | yadv1 ymax1
1911 yadv2 | 0+--+------+ -- --
1912 ymax2 | 2 | -- y_offset
1917 glyph1: advance height = 6
1918 anchor point = (3,1)
1920 glyph2: advance height = 7
1921 anchor point = (9,4)
1923 TSB is 1 for both glyphs; writing direction is T2B.
1927 vertical advance width of glyph2
1928 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1929 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1932 Comparing a) with b) shows that b) is easier to compute. I'll wait
1933 for a reply from Andrei to see what should really be implemented...
1935 Since horizontal advance widths or vertical advance heights
1936 can be used alone but not together, no ambiguity occurs. */
1938 if ( gpi->last == 0xFFFF )
1941 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1944 error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1945 &entry_x, &entry_y );
1946 if ( error == HB_Err_Not_Covered )
1953 POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
1954 POSITION( buffer->in_pos )->new_advance = TRUE;
1958 POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
1959 POSITION( gpi->last )->new_advance = TRUE;
1962 if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
1964 POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
1965 POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
1969 POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
1970 POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
1974 error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
1976 if ( error == HB_Err_Not_Covered )
1980 gpi->last = buffer->in_pos;
1981 gpi->anchor_x = exit_x;
1982 gpi->anchor_y = exit_y;
1997 static HB_Error Load_BaseArray( HB_BaseArray* ba,
1998 HB_UShort num_classes,
2003 HB_UShort m, n, k, count;
2004 HB_UInt cur_offset, new_offset, base_offset;
2010 base_offset = FILE_Pos();
2012 if ( ACCESS_Frame( 2L ) )
2015 count = ba->BaseCount = GET_UShort();
2019 ba->BaseRecord = NULL;
2021 if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2024 br = ba->BaseRecord;
2026 for ( m = 0; m < count; m++ )
2028 br[m].BaseAnchor = NULL;
2030 if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, HB_Anchor ) )
2033 ban = br[m].BaseAnchor;
2035 for ( n = 0; n < num_classes; n++ )
2037 if ( ACCESS_Frame( 2L ) )
2040 new_offset = GET_UShort() + base_offset;
2044 if (new_offset == base_offset) {
2046 * Doulos SIL Regular is buggy and has zero offsets here.
2049 ban[n].PosFormat = 0;
2053 cur_offset = FILE_Pos();
2054 if ( FILE_Seek( new_offset ) ||
2055 ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
2057 (void)FILE_Seek( cur_offset );
2062 for ( k = 0; k < n; k++ )
2063 Free_Anchor( &ban[k] );
2070 for ( k = 0; k < m; k++ )
2072 ban = br[k].BaseAnchor;
2074 for ( n = 0; n < num_classes; n++ )
2075 Free_Anchor( &ban[n] );
2085 static void Free_BaseArray( HB_BaseArray* ba,
2086 HB_UShort num_classes )
2088 HB_UShort m, n, count;
2094 if ( ba->BaseRecord )
2096 count = ba->BaseCount;
2097 br = ba->BaseRecord;
2099 for ( m = 0; m < count; m++ )
2101 ban = br[m].BaseAnchor;
2103 for ( n = 0; n < num_classes; n++ )
2104 Free_Anchor( &ban[n] );
2114 /* MarkBasePosFormat1 */
2116 static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
2120 HB_MarkBasePos* mbp = &st->markbase;
2122 HB_UInt cur_offset, new_offset, base_offset;
2125 base_offset = FILE_Pos();
2127 if ( ACCESS_Frame( 4L ) )
2130 mbp->PosFormat = GET_UShort();
2131 new_offset = GET_UShort() + base_offset;
2135 if (mbp->PosFormat != 1)
2136 return ERR(HB_Err_Invalid_SubTable_Format);
2138 cur_offset = FILE_Pos();
2139 if ( FILE_Seek( new_offset ) ||
2140 ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
2142 (void)FILE_Seek( cur_offset );
2144 if ( ACCESS_Frame( 2L ) )
2147 new_offset = GET_UShort() + base_offset;
2151 cur_offset = FILE_Pos();
2152 if ( FILE_Seek( new_offset ) ||
2153 ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
2155 (void)FILE_Seek( cur_offset );
2157 if ( ACCESS_Frame( 4L ) )
2160 mbp->ClassCount = GET_UShort();
2161 new_offset = GET_UShort() + base_offset;
2165 cur_offset = FILE_Pos();
2166 if ( FILE_Seek( new_offset ) ||
2167 ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
2169 (void)FILE_Seek( cur_offset );
2171 if ( ACCESS_Frame( 2L ) )
2174 new_offset = GET_UShort() + base_offset;
2178 cur_offset = FILE_Pos();
2179 if ( FILE_Seek( new_offset ) ||
2180 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2181 stream ) ) != HB_Err_Ok )
2187 Free_MarkArray( &mbp->MarkArray );
2190 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2193 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2198 static void Free_MarkBasePos( HB_GPOS_SubTable* st )
2200 HB_MarkBasePos* mbp = &st->markbase;
2202 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
2203 Free_MarkArray( &mbp->MarkArray );
2204 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2205 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2209 static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
2210 HB_GPOS_SubTable* st,
2213 HB_UShort context_length,
2216 HB_UShort i, j, mark_index, base_index, property, class;
2217 HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value;
2219 HB_GPOSHeader* gpos = gpi->gpos;
2220 HB_MarkBasePos* mbp = &st->markbase;
2225 HB_Anchor* mark_anchor;
2226 HB_Anchor* base_anchor;
2230 HB_UNUSED(nesting_level);
2232 if ( context_length != 0xFFFF && context_length < 1 )
2233 return HB_Err_Not_Covered;
2235 if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
2236 return HB_Err_Not_Covered;
2238 if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2239 flags, &property ) )
2242 error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2247 /* now we search backwards for a non-mark glyph */
2250 j = buffer->in_pos - 1;
2252 while ( i <= buffer->in_pos )
2254 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2259 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2266 /* The following assertion is too strong -- at least for mangal.ttf. */
2268 if ( property != HB_GDEF_BASE_GLYPH )
2269 return HB_Err_Not_Covered;
2272 if ( i > buffer->in_pos )
2273 return HB_Err_Not_Covered;
2275 error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2280 ma = &mbp->MarkArray;
2282 if ( mark_index >= ma->MarkCount )
2283 return ERR(HB_Err_Invalid_SubTable);
2285 class = ma->MarkRecord[mark_index].Class;
2286 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2288 if ( class >= mbp->ClassCount )
2289 return ERR(HB_Err_Invalid_SubTable);
2291 ba = &mbp->BaseArray;
2293 if ( base_index >= ba->BaseCount )
2294 return ERR(HB_Err_Invalid_SubTable);
2296 br = &ba->BaseRecord[base_index];
2297 base_anchor = &br->BaseAnchor[class];
2299 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2300 &x_mark_value, &y_mark_value );
2304 error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2305 &x_base_value, &y_base_value );
2309 /* anchor points are not cumulative */
2311 o = POSITION( buffer->in_pos );
2313 o->x_pos = x_base_value - x_mark_value;
2314 o->y_pos = y_base_value - y_mark_value;
2327 /* LigatureAttach */
2329 static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
2330 HB_UShort num_classes,
2335 HB_UShort m, n, k, count;
2336 HB_UInt cur_offset, new_offset, base_offset;
2338 HB_ComponentRecord* cr;
2342 base_offset = FILE_Pos();
2344 if ( ACCESS_Frame( 2L ) )
2347 count = lat->ComponentCount = GET_UShort();
2351 lat->ComponentRecord = NULL;
2353 if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2356 cr = lat->ComponentRecord;
2358 for ( m = 0; m < count; m++ )
2360 cr[m].LigatureAnchor = NULL;
2362 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
2365 lan = cr[m].LigatureAnchor;
2367 for ( n = 0; n < num_classes; n++ )
2369 if ( ACCESS_Frame( 2L ) )
2372 new_offset = GET_UShort();
2378 new_offset += base_offset;
2380 cur_offset = FILE_Pos();
2381 if ( FILE_Seek( new_offset ) ||
2382 ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
2384 (void)FILE_Seek( cur_offset );
2387 lan[n].PosFormat = 0;
2392 for ( k = 0; k < n; k++ )
2393 Free_Anchor( &lan[k] );
2400 for ( k = 0; k < m; k++ )
2402 lan = cr[k].LigatureAnchor;
2404 for ( n = 0; n < num_classes; n++ )
2405 Free_Anchor( &lan[n] );
2415 static void Free_LigatureAttach( HB_LigatureAttach* lat,
2416 HB_UShort num_classes )
2418 HB_UShort m, n, count;
2420 HB_ComponentRecord* cr;
2424 if ( lat->ComponentRecord )
2426 count = lat->ComponentCount;
2427 cr = lat->ComponentRecord;
2429 for ( m = 0; m < count; m++ )
2431 lan = cr[m].LigatureAnchor;
2433 for ( n = 0; n < num_classes; n++ )
2434 Free_Anchor( &lan[n] );
2446 static HB_Error Load_LigatureArray( HB_LigatureArray* la,
2447 HB_UShort num_classes,
2452 HB_UShort n, m, count;
2453 HB_UInt cur_offset, new_offset, base_offset;
2455 HB_LigatureAttach* lat;
2458 base_offset = FILE_Pos();
2460 if ( ACCESS_Frame( 2L ) )
2463 count = la->LigatureCount = GET_UShort();
2467 la->LigatureAttach = NULL;
2469 if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2472 lat = la->LigatureAttach;
2474 for ( n = 0; n < count; n++ )
2476 if ( ACCESS_Frame( 2L ) )
2479 new_offset = GET_UShort() + base_offset;
2483 cur_offset = FILE_Pos();
2484 if ( FILE_Seek( new_offset ) ||
2485 ( error = Load_LigatureAttach( &lat[n], num_classes,
2486 stream ) ) != HB_Err_Ok )
2488 (void)FILE_Seek( cur_offset );
2494 for ( m = 0; m < n; m++ )
2495 Free_LigatureAttach( &lat[m], num_classes );
2502 static void Free_LigatureArray( HB_LigatureArray* la,
2503 HB_UShort num_classes )
2507 HB_LigatureAttach* lat;
2510 if ( la->LigatureAttach )
2512 count = la->LigatureCount;
2513 lat = la->LigatureAttach;
2515 for ( n = 0; n < count; n++ )
2516 Free_LigatureAttach( &lat[n], num_classes );
2523 /* MarkLigPosFormat1 */
2525 static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
2529 HB_MarkLigPos* mlp = &st->marklig;
2531 HB_UInt cur_offset, new_offset, base_offset;
2534 base_offset = FILE_Pos();
2536 if ( ACCESS_Frame( 4L ) )
2539 mlp->PosFormat = GET_UShort();
2540 new_offset = GET_UShort() + base_offset;
2544 cur_offset = FILE_Pos();
2545 if ( FILE_Seek( new_offset ) ||
2546 ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
2548 (void)FILE_Seek( cur_offset );
2550 if ( ACCESS_Frame( 2L ) )
2553 new_offset = GET_UShort() + base_offset;
2557 cur_offset = FILE_Pos();
2558 if ( FILE_Seek( new_offset ) ||
2559 ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2560 stream ) ) != HB_Err_Ok )
2562 (void)FILE_Seek( cur_offset );
2564 if ( ACCESS_Frame( 4L ) )
2567 mlp->ClassCount = GET_UShort();
2568 new_offset = GET_UShort() + base_offset;
2572 cur_offset = FILE_Pos();
2573 if ( FILE_Seek( new_offset ) ||
2574 ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
2576 (void)FILE_Seek( cur_offset );
2578 if ( ACCESS_Frame( 2L ) )
2581 new_offset = GET_UShort() + base_offset;
2585 cur_offset = FILE_Pos();
2586 if ( FILE_Seek( new_offset ) ||
2587 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2588 stream ) ) != HB_Err_Ok )
2594 Free_MarkArray( &mlp->MarkArray );
2597 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2600 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2605 static void Free_MarkLigPos( HB_GPOS_SubTable* st )
2607 HB_MarkLigPos* mlp = &st->marklig;
2609 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
2610 Free_MarkArray( &mlp->MarkArray );
2611 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2612 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2616 static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
2617 HB_GPOS_SubTable* st,
2620 HB_UShort context_length,
2623 HB_UShort i, j, mark_index, lig_index, property, class;
2624 HB_UShort mark_glyph;
2625 HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2627 HB_GPOSHeader* gpos = gpi->gpos;
2628 HB_MarkLigPos* mlp = &st->marklig;
2631 HB_LigatureArray* la;
2632 HB_LigatureAttach* lat;
2633 HB_ComponentRecord* cr;
2634 HB_UShort comp_index;
2635 HB_Anchor* mark_anchor;
2636 HB_Anchor* lig_anchor;
2640 HB_UNUSED(nesting_level);
2642 if ( context_length != 0xFFFF && context_length < 1 )
2643 return HB_Err_Not_Covered;
2645 if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
2646 return HB_Err_Not_Covered;
2648 mark_glyph = IN_CURGLYPH();
2650 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
2653 error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2657 /* now we search backwards for a non-mark glyph */
2660 j = buffer->in_pos - 1;
2662 while ( i <= buffer->in_pos )
2664 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2669 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2676 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2677 too strong, thus it is commented out. */
2679 if ( property != HB_GDEF_LIGATURE )
2680 return HB_Err_Not_Covered;
2683 if ( i > buffer->in_pos )
2684 return HB_Err_Not_Covered;
2686 error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2691 ma = &mlp->MarkArray;
2693 if ( mark_index >= ma->MarkCount )
2694 return ERR(HB_Err_Invalid_SubTable);
2696 class = ma->MarkRecord[mark_index].Class;
2697 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2699 if ( class >= mlp->ClassCount )
2700 return ERR(HB_Err_Invalid_SubTable);
2702 la = &mlp->LigatureArray;
2704 if ( lig_index >= la->LigatureCount )
2705 return ERR(HB_Err_Invalid_SubTable);
2707 lat = &la->LigatureAttach[lig_index];
2709 /* We must now check whether the ligature ID of the current mark glyph
2710 is identical to the ligature ID of the found ligature. If yes, we
2711 can directly use the component index. If not, we attach the mark
2712 glyph to the last component of the ligature. */
2714 if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
2716 comp_index = IN_COMPONENT( buffer->in_pos );
2717 if ( comp_index >= lat->ComponentCount )
2718 return HB_Err_Not_Covered;
2721 comp_index = lat->ComponentCount - 1;
2723 cr = &lat->ComponentRecord[comp_index];
2724 lig_anchor = &cr->LigatureAnchor[class];
2726 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2727 &x_mark_value, &y_mark_value );
2730 error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2731 &x_lig_value, &y_lig_value );
2735 /* anchor points are not cumulative */
2737 o = POSITION( buffer->in_pos );
2739 o->x_pos = x_lig_value - x_mark_value;
2740 o->y_pos = y_lig_value - y_mark_value;
2755 static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
2756 HB_UShort num_classes,
2761 HB_UShort k, m, n, count;
2762 HB_UInt cur_offset, new_offset, base_offset;
2764 HB_Mark2Record* m2r;
2768 base_offset = FILE_Pos();
2770 if ( ACCESS_Frame( 2L ) )
2773 count = m2a->Mark2Count = GET_UShort();
2777 m2a->Mark2Record = NULL;
2779 if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2782 m2r = m2a->Mark2Record;
2784 for ( m = 0; m < count; m++ )
2786 m2r[m].Mark2Anchor = NULL;
2788 if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, HB_Anchor ) )
2791 m2an = m2r[m].Mark2Anchor;
2793 for ( n = 0; n < num_classes; n++ )
2795 if ( ACCESS_Frame( 2L ) )
2798 new_offset = GET_UShort() + base_offset;
2802 if (new_offset == base_offset) {
2803 /* Anchor table not provided. Skip loading.
2804 * Some versions of FreeSans hit this. */
2805 m2an[n].PosFormat = 0;
2809 cur_offset = FILE_Pos();
2810 if ( FILE_Seek( new_offset ) ||
2811 ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
2813 (void)FILE_Seek( cur_offset );
2818 for ( k = 0; k < n; k++ )
2819 Free_Anchor( &m2an[k] );
2826 for ( k = 0; k < m; k++ )
2828 m2an = m2r[k].Mark2Anchor;
2830 for ( n = 0; n < num_classes; n++ )
2831 Free_Anchor( &m2an[n] );
2841 static void Free_Mark2Array( HB_Mark2Array* m2a,
2842 HB_UShort num_classes )
2844 HB_UShort m, n, count;
2846 HB_Mark2Record* m2r;
2850 if ( m2a->Mark2Record )
2852 count = m2a->Mark2Count;
2853 m2r = m2a->Mark2Record;
2855 for ( m = 0; m < count; m++ )
2857 m2an = m2r[m].Mark2Anchor;
2859 for ( n = 0; n < num_classes; n++ )
2860 Free_Anchor( &m2an[n] );
2870 /* MarkMarkPosFormat1 */
2872 static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
2876 HB_MarkMarkPos* mmp = &st->markmark;
2878 HB_UInt cur_offset, new_offset, base_offset;
2881 base_offset = FILE_Pos();
2883 if ( ACCESS_Frame( 4L ) )
2886 mmp->PosFormat = GET_UShort();
2887 new_offset = GET_UShort() + base_offset;
2891 cur_offset = FILE_Pos();
2892 if ( FILE_Seek( new_offset ) ||
2893 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2894 stream ) ) != HB_Err_Ok )
2896 (void)FILE_Seek( cur_offset );
2898 if ( ACCESS_Frame( 2L ) )
2901 new_offset = GET_UShort() + base_offset;
2905 cur_offset = FILE_Pos();
2906 if ( FILE_Seek( new_offset ) ||
2907 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2908 stream ) ) != HB_Err_Ok )
2910 (void)FILE_Seek( cur_offset );
2912 if ( ACCESS_Frame( 4L ) )
2915 mmp->ClassCount = GET_UShort();
2916 new_offset = GET_UShort() + base_offset;
2920 cur_offset = FILE_Pos();
2921 if ( FILE_Seek( new_offset ) ||
2922 ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
2924 (void)FILE_Seek( cur_offset );
2926 if ( ACCESS_Frame( 2L ) )
2929 new_offset = GET_UShort() + base_offset;
2933 cur_offset = FILE_Pos();
2934 if ( FILE_Seek( new_offset ) ||
2935 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2936 stream ) ) != HB_Err_Ok )
2942 Free_MarkArray( &mmp->Mark1Array );
2945 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2948 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2953 static void Free_MarkMarkPos( HB_GPOS_SubTable* st )
2955 HB_MarkMarkPos* mmp = &st->markmark;
2957 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2958 Free_MarkArray( &mmp->Mark1Array );
2959 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2960 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2964 static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
2965 HB_GPOS_SubTable* st,
2968 HB_UShort context_length,
2971 HB_UShort i, j, mark1_index, mark2_index, property, class;
2972 HB_Fixed x_mark1_value, y_mark1_value,
2973 x_mark2_value, y_mark2_value;
2975 HB_GPOSHeader* gpos = gpi->gpos;
2976 HB_MarkMarkPos* mmp = &st->markmark;
2980 HB_Mark2Record* m2r;
2981 HB_Anchor* mark1_anchor;
2982 HB_Anchor* mark2_anchor;
2986 HB_UNUSED(nesting_level);
2988 if ( context_length != 0xFFFF && context_length < 1 )
2989 return HB_Err_Not_Covered;
2991 if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
2992 return HB_Err_Not_Covered;
2994 if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2995 flags, &property ) )
2998 error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
3003 /* now we search backwards for a suitable mark glyph until a non-mark
3006 if ( buffer->in_pos == 0 )
3007 return HB_Err_Not_Covered;
3010 j = buffer->in_pos - 1;
3011 while ( i <= buffer->in_pos )
3013 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
3018 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
3019 return HB_Err_Not_Covered;
3021 if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
3023 if ( property == (flags & 0xFF00) )
3033 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3038 ma1 = &mmp->Mark1Array;
3040 if ( mark1_index >= ma1->MarkCount )
3041 return ERR(HB_Err_Invalid_SubTable);
3043 class = ma1->MarkRecord[mark1_index].Class;
3044 mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3046 if ( class >= mmp->ClassCount )
3047 return ERR(HB_Err_Invalid_SubTable);
3049 ma2 = &mmp->Mark2Array;
3051 if ( mark2_index >= ma2->Mark2Count )
3052 return ERR(HB_Err_Invalid_SubTable);
3054 m2r = &ma2->Mark2Record[mark2_index];
3055 mark2_anchor = &m2r->Mark2Anchor[class];
3057 error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3058 &x_mark1_value, &y_mark1_value );
3061 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3062 &x_mark2_value, &y_mark2_value );
3066 /* anchor points are not cumulative */
3068 o = POSITION( buffer->in_pos );
3070 o->x_pos = x_mark2_value - x_mark1_value;
3071 o->y_pos = y_mark2_value - y_mark1_value;
3082 /* Do the actual positioning for a context positioning (either format
3083 7 or 8). This is only called after we've determined that the stream
3084 matches the subrule. */
3086 static HB_Error Do_ContextPos( GPOS_Instance* gpi,
3087 HB_UShort GlyphCount,
3089 HB_PosLookupRecord* pos,
3099 while ( i < GlyphCount )
3101 if ( PosCount && i == pos->SequenceIndex )
3103 old_pos = buffer->in_pos;
3105 /* Do a positioning */
3107 error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3108 GlyphCount, nesting_level );
3115 i += buffer->in_pos - old_pos;
3132 static HB_Error Load_PosRule( HB_PosRule* pr,
3140 HB_PosLookupRecord* plr;
3143 if ( ACCESS_Frame( 4L ) )
3146 pr->GlyphCount = GET_UShort();
3147 pr->PosCount = GET_UShort();
3153 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3155 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3160 if ( ACCESS_Frame( count * 2L ) )
3163 for ( n = 0; n < count; n++ )
3164 i[n] = GET_UShort();
3168 pr->PosLookupRecord = NULL;
3170 count = pr->PosCount;
3172 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3175 plr = pr->PosLookupRecord;
3177 if ( ACCESS_Frame( count * 4L ) )
3180 for ( n = 0; n < count; n++ )
3182 plr[n].SequenceIndex = GET_UShort();
3183 plr[n].LookupListIndex = GET_UShort();
3199 static void Free_PosRule( HB_PosRule* pr )
3201 FREE( pr->PosLookupRecord );
3208 static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
3213 HB_UShort n, m, count;
3214 HB_UInt cur_offset, new_offset, base_offset;
3219 base_offset = FILE_Pos();
3221 if ( ACCESS_Frame( 2L ) )
3224 count = prs->PosRuleCount = GET_UShort();
3228 prs->PosRule = NULL;
3230 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3235 for ( n = 0; n < count; n++ )
3237 if ( ACCESS_Frame( 2L ) )
3240 new_offset = GET_UShort() + base_offset;
3244 cur_offset = FILE_Pos();
3245 if ( FILE_Seek( new_offset ) ||
3246 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3248 (void)FILE_Seek( cur_offset );
3254 for ( m = 0; m < n; m++ )
3255 Free_PosRule( &pr[m] );
3262 static void Free_PosRuleSet( HB_PosRuleSet* prs )
3271 count = prs->PosRuleCount;
3274 for ( n = 0; n < count; n++ )
3275 Free_PosRule( &pr[n] );
3282 /* ContextPosFormat1 */
3284 static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
3289 HB_UShort n, m, count;
3290 HB_UInt cur_offset, new_offset, base_offset;
3295 base_offset = FILE_Pos() - 2L;
3297 if ( ACCESS_Frame( 2L ) )
3300 new_offset = GET_UShort() + base_offset;
3304 cur_offset = FILE_Pos();
3305 if ( FILE_Seek( new_offset ) ||
3306 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3308 (void)FILE_Seek( cur_offset );
3310 if ( ACCESS_Frame( 2L ) )
3313 count = cpf1->PosRuleSetCount = GET_UShort();
3317 cpf1->PosRuleSet = NULL;
3319 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3322 prs = cpf1->PosRuleSet;
3324 for ( n = 0; n < count; n++ )
3326 if ( ACCESS_Frame( 2L ) )
3329 new_offset = GET_UShort() + base_offset;
3333 cur_offset = FILE_Pos();
3334 if ( FILE_Seek( new_offset ) ||
3335 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3337 (void)FILE_Seek( cur_offset );
3343 for ( m = 0; m < n; m++ )
3344 Free_PosRuleSet( &prs[m] );
3349 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3354 static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
3361 if ( cpf1->PosRuleSet )
3363 count = cpf1->PosRuleSetCount;
3364 prs = cpf1->PosRuleSet;
3366 for ( n = 0; n < count; n++ )
3367 Free_PosRuleSet( &prs[n] );
3372 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3378 static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
3379 HB_PosClassRule* pcr,
3387 HB_PosLookupRecord* plr;
3391 if ( ACCESS_Frame( 4L ) )
3394 pcr->GlyphCount = GET_UShort();
3395 pcr->PosCount = GET_UShort();
3399 if ( pcr->GlyphCount > cpf2->MaxContextLength )
3400 cpf2->MaxContextLength = pcr->GlyphCount;
3404 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3406 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3410 d = cpf2->ClassDef.Defined;
3412 if ( ACCESS_Frame( count * 2L ) )
3415 for ( n = 0; n < count; n++ )
3417 c[n] = GET_UShort();
3419 /* We check whether the specific class is used at all. If not,
3420 class 0 is used instead. */
3428 pcr->PosLookupRecord = NULL;
3430 count = pcr->PosCount;
3432 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3435 plr = pcr->PosLookupRecord;
3437 if ( ACCESS_Frame( count * 4L ) )
3440 for ( n = 0; n < count; n++ )
3442 plr[n].SequenceIndex = GET_UShort();
3443 plr[n].LookupListIndex = GET_UShort();
3459 static void Free_PosClassRule( HB_PosClassRule* pcr )
3461 FREE( pcr->PosLookupRecord );
3468 static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
3469 HB_PosClassSet* pcs,
3474 HB_UShort n, m, count;
3475 HB_UInt cur_offset, new_offset, base_offset;
3477 HB_PosClassRule* pcr;
3480 base_offset = FILE_Pos();
3482 if ( ACCESS_Frame( 2L ) )
3485 count = pcs->PosClassRuleCount = GET_UShort();
3489 pcs->PosClassRule = NULL;
3491 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3494 pcr = pcs->PosClassRule;
3496 for ( n = 0; n < count; n++ )
3498 if ( ACCESS_Frame( 2L ) )
3501 new_offset = GET_UShort() + base_offset;
3505 cur_offset = FILE_Pos();
3506 if ( FILE_Seek( new_offset ) ||
3507 ( error = Load_PosClassRule( cpf2, &pcr[n],
3508 stream ) ) != HB_Err_Ok )
3510 (void)FILE_Seek( cur_offset );
3516 for ( m = 0; m < n; m++ )
3517 Free_PosClassRule( &pcr[m] );
3524 static void Free_PosClassSet( HB_PosClassSet* pcs )
3528 HB_PosClassRule* pcr;
3531 if ( pcs->PosClassRule )
3533 count = pcs->PosClassRuleCount;
3534 pcr = pcs->PosClassRule;
3536 for ( n = 0; n < count; n++ )
3537 Free_PosClassRule( &pcr[n] );
3544 /* ContextPosFormat2 */
3546 static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
3551 HB_UShort n, m, count;
3552 HB_UInt cur_offset, new_offset, base_offset;
3554 HB_PosClassSet* pcs;
3557 base_offset = FILE_Pos() - 2;
3559 if ( ACCESS_Frame( 2L ) )
3562 new_offset = GET_UShort() + base_offset;
3566 cur_offset = FILE_Pos();
3567 if ( FILE_Seek( new_offset ) ||
3568 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3570 (void)FILE_Seek( cur_offset );
3572 if ( ACCESS_Frame( 4L ) )
3575 new_offset = GET_UShort() + base_offset;
3577 /* `PosClassSetCount' is the upper limit for class values, thus we
3578 read it now to make an additional safety check. */
3580 count = cpf2->PosClassSetCount = GET_UShort();
3584 cur_offset = FILE_Pos();
3585 if ( FILE_Seek( new_offset ) ||
3586 ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3587 stream ) ) != HB_Err_Ok )
3589 (void)FILE_Seek( cur_offset );
3591 cpf2->PosClassSet = NULL;
3592 cpf2->MaxContextLength = 0;
3594 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3597 pcs = cpf2->PosClassSet;
3599 for ( n = 0; n < count; n++ )
3601 if ( ACCESS_Frame( 2L ) )
3604 new_offset = GET_UShort() + base_offset;
3608 if ( new_offset != base_offset ) /* not a NULL offset */
3610 cur_offset = FILE_Pos();
3611 if ( FILE_Seek( new_offset ) ||
3612 ( error = Load_PosClassSet( cpf2, &pcs[n],
3613 stream ) ) != HB_Err_Ok )
3615 (void)FILE_Seek( cur_offset );
3619 /* we create a PosClassSet table with no entries */
3621 cpf2->PosClassSet[n].PosClassRuleCount = 0;
3622 cpf2->PosClassSet[n].PosClassRule = NULL;
3629 for ( m = 0; m < n; n++ )
3630 Free_PosClassSet( &pcs[m] );
3635 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3638 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3643 static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
3647 HB_PosClassSet* pcs;
3650 if ( cpf2->PosClassSet )
3652 count = cpf2->PosClassSetCount;
3653 pcs = cpf2->PosClassSet;
3655 for ( n = 0; n < count; n++ )
3656 Free_PosClassSet( &pcs[n] );
3661 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3662 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3666 /* ContextPosFormat3 */
3668 static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
3674 HB_UInt cur_offset, new_offset, base_offset;
3677 HB_PosLookupRecord* plr;
3680 base_offset = FILE_Pos() - 2L;
3682 if ( ACCESS_Frame( 4L ) )
3685 cpf3->GlyphCount = GET_UShort();
3686 cpf3->PosCount = GET_UShort();
3690 cpf3->Coverage = NULL;
3692 count = cpf3->GlyphCount;
3694 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3699 for ( n = 0; n < count; n++ )
3701 if ( ACCESS_Frame( 2L ) )
3704 new_offset = GET_UShort() + base_offset;
3708 cur_offset = FILE_Pos();
3709 if ( FILE_Seek( new_offset ) ||
3710 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3712 (void)FILE_Seek( cur_offset );
3715 cpf3->PosLookupRecord = NULL;
3717 count = cpf3->PosCount;
3719 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3722 plr = cpf3->PosLookupRecord;
3724 if ( ACCESS_Frame( count * 4L ) )
3727 for ( n = 0; n < count; n++ )
3729 plr[n].SequenceIndex = GET_UShort();
3730 plr[n].LookupListIndex = GET_UShort();
3741 for ( n = 0; n < count; n++ )
3742 _HB_OPEN_Free_Coverage( &c[n] );
3749 static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
3756 FREE( cpf3->PosLookupRecord );
3758 if ( cpf3->Coverage )
3760 count = cpf3->GlyphCount;
3763 for ( n = 0; n < count; n++ )
3764 _HB_OPEN_Free_Coverage( &c[n] );
3773 static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
3777 HB_ContextPos* cp = &st->context;
3780 if ( ACCESS_Frame( 2L ) )
3783 cp->PosFormat = GET_UShort();
3787 switch ( cp->PosFormat )
3790 return Load_ContextPos1( &cp->cpf.cpf1, stream );
3793 return Load_ContextPos2( &cp->cpf.cpf2, stream );
3796 return Load_ContextPos3( &cp->cpf.cpf3, stream );
3799 return ERR(HB_Err_Invalid_SubTable_Format);
3802 return HB_Err_Ok; /* never reached */
3806 static void Free_ContextPos( HB_GPOS_SubTable* st )
3808 HB_ContextPos* cp = &st->context;
3810 switch ( cp->PosFormat )
3812 case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break;
3813 case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break;
3814 case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break;
3820 static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3821 HB_ContextPosFormat1* cpf1,
3824 HB_UShort context_length,
3827 HB_UShort index, property;
3828 HB_UShort i, j, k, numpr;
3830 HB_GPOSHeader* gpos = gpi->gpos;
3833 HB_GDEFHeader* gdef;
3838 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3841 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3845 pr = cpf1->PosRuleSet[index].PosRule;
3846 numpr = cpf1->PosRuleSet[index].PosRuleCount;
3848 for ( k = 0; k < numpr; k++ )
3850 if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3853 if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3854 goto next_posrule; /* context is too long */
3856 for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3858 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3860 if ( error && error != HB_Err_Not_Covered )
3863 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3868 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3872 return Do_ContextPos( gpi, pr[k].GlyphCount,
3873 pr[k].PosCount, pr[k].PosLookupRecord,
3881 return HB_Err_Not_Covered;
3885 static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
3886 HB_ContextPosFormat2* cpf2,
3889 HB_UShort context_length,
3892 HB_UShort index, property;
3894 HB_UShort i, j, k, known_classes;
3898 HB_GPOSHeader* gpos = gpi->gpos;
3900 HB_PosClassSet* pcs;
3901 HB_PosClassRule* pr;
3902 HB_GDEFHeader* gdef;
3907 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3910 /* Note: The coverage table in format 2 doesn't give an index into
3911 anything. It just lets us know whether or not we need to
3912 do any lookup at all. */
3914 error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3918 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3921 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3922 &classes[0], NULL );
3923 if ( error && error != HB_Err_Not_Covered )
3927 pcs = &cpf2->PosClassSet[classes[0]];
3930 error = ERR(HB_Err_Invalid_SubTable);
3934 for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3936 pr = &pcs->PosClassRule[k];
3938 if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
3939 goto next_posclassrule;
3941 if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
3942 goto next_posclassrule; /* context is too long */
3946 /* Start at 1 because [0] is implied */
3948 for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
3950 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3952 if ( error && error != HB_Err_Not_Covered )
3955 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3956 goto next_posclassrule;
3960 if ( i > known_classes )
3962 /* Keeps us from having to do this for each rule */
3964 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
3965 if ( error && error != HB_Err_Not_Covered )
3970 if ( cl[i - 1] != classes[i] )
3971 goto next_posclassrule;
3974 error = Do_ContextPos( gpi, pr->GlyphCount,
3975 pr->PosCount, pr->PosLookupRecord,
3984 error = HB_Err_Not_Covered;
3992 static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
3993 HB_ContextPosFormat3* cpf3,
3996 HB_UShort context_length,
4000 HB_UShort index, i, j, property;
4001 HB_GPOSHeader* gpos = gpi->gpos;
4004 HB_GDEFHeader* gdef;
4009 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
4012 if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
4013 return HB_Err_Not_Covered;
4015 if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
4016 return HB_Err_Not_Covered; /* context is too long */
4020 for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
4022 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
4024 if ( error && error != HB_Err_Not_Covered )
4027 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
4028 return HB_Err_Not_Covered;
4032 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4037 return Do_ContextPos( gpi, cpf3->GlyphCount,
4038 cpf3->PosCount, cpf3->PosLookupRecord,
4044 static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
4045 HB_GPOS_SubTable* st,
4048 HB_UShort context_length,
4051 HB_ContextPos* cp = &st->context;
4053 switch ( cp->PosFormat )
4056 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4057 flags, context_length, nesting_level );
4060 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4061 flags, context_length, nesting_level );
4064 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4065 flags, context_length, nesting_level );
4068 return ERR(HB_Err_Invalid_SubTable_Format);
4071 return HB_Err_Ok; /* never reached */
4079 static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
4089 HB_PosLookupRecord* plr;
4092 if ( ACCESS_Frame( 2L ) )
4095 cpr->BacktrackGlyphCount = GET_UShort();
4099 cpr->Backtrack = NULL;
4101 count = cpr->BacktrackGlyphCount;
4103 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4108 if ( ACCESS_Frame( count * 2L ) )
4111 for ( n = 0; n < count; n++ )
4112 b[n] = GET_UShort();
4116 if ( ACCESS_Frame( 2L ) )
4119 cpr->InputGlyphCount = GET_UShort();
4125 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4127 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4132 if ( ACCESS_Frame( count * 2L ) )
4135 for ( n = 0; n < count; n++ )
4136 i[n] = GET_UShort();
4140 if ( ACCESS_Frame( 2L ) )
4143 cpr->LookaheadGlyphCount = GET_UShort();
4147 cpr->Lookahead = NULL;
4149 count = cpr->LookaheadGlyphCount;
4151 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4156 if ( ACCESS_Frame( count * 2L ) )
4159 for ( n = 0; n < count; n++ )
4160 l[n] = GET_UShort();
4164 if ( ACCESS_Frame( 2L ) )
4167 cpr->PosCount = GET_UShort();
4171 cpr->PosLookupRecord = NULL;
4173 count = cpr->PosCount;
4175 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4178 plr = cpr->PosLookupRecord;
4180 if ( ACCESS_Frame( count * 4L ) )
4183 for ( n = 0; n < count; n++ )
4185 plr[n].SequenceIndex = GET_UShort();
4186 plr[n].LookupListIndex = GET_UShort();
4208 static void Free_ChainPosRule( HB_ChainPosRule* cpr )
4210 FREE( cpr->PosLookupRecord );
4211 FREE( cpr->Lookahead );
4213 FREE( cpr->Backtrack );
4217 /* ChainPosRuleSet */
4219 static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4224 HB_UShort n, m, count;
4225 HB_UInt cur_offset, new_offset, base_offset;
4227 HB_ChainPosRule* cpr;
4230 base_offset = FILE_Pos();
4232 if ( ACCESS_Frame( 2L ) )
4235 count = cprs->ChainPosRuleCount = GET_UShort();
4239 cprs->ChainPosRule = NULL;
4241 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4244 cpr = cprs->ChainPosRule;
4246 for ( n = 0; n < count; n++ )
4248 if ( ACCESS_Frame( 2L ) )
4251 new_offset = GET_UShort() + base_offset;
4255 cur_offset = FILE_Pos();
4256 if ( FILE_Seek( new_offset ) ||
4257 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4259 (void)FILE_Seek( cur_offset );
4265 for ( m = 0; m < n; m++ )
4266 Free_ChainPosRule( &cpr[m] );
4273 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
4277 HB_ChainPosRule* cpr;
4280 if ( cprs->ChainPosRule )
4282 count = cprs->ChainPosRuleCount;
4283 cpr = cprs->ChainPosRule;
4285 for ( n = 0; n < count; n++ )
4286 Free_ChainPosRule( &cpr[n] );
4293 /* ChainContextPosFormat1 */
4295 static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4300 HB_UShort n, m, count;
4301 HB_UInt cur_offset, new_offset, base_offset;
4303 HB_ChainPosRuleSet* cprs;
4306 base_offset = FILE_Pos() - 2L;
4308 if ( ACCESS_Frame( 2L ) )
4311 new_offset = GET_UShort() + base_offset;
4315 cur_offset = FILE_Pos();
4316 if ( FILE_Seek( new_offset ) ||
4317 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4319 (void)FILE_Seek( cur_offset );
4321 if ( ACCESS_Frame( 2L ) )
4324 count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4328 ccpf1->ChainPosRuleSet = NULL;
4330 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4333 cprs = ccpf1->ChainPosRuleSet;
4335 for ( n = 0; n < count; n++ )
4337 if ( ACCESS_Frame( 2L ) )
4340 new_offset = GET_UShort() + base_offset;
4344 cur_offset = FILE_Pos();
4345 if ( FILE_Seek( new_offset ) ||
4346 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4348 (void)FILE_Seek( cur_offset );
4354 for ( m = 0; m < n; m++ )
4355 Free_ChainPosRuleSet( &cprs[m] );
4360 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4365 static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
4369 HB_ChainPosRuleSet* cprs;
4372 if ( ccpf1->ChainPosRuleSet )
4374 count = ccpf1->ChainPosRuleSetCount;
4375 cprs = ccpf1->ChainPosRuleSet;
4377 for ( n = 0; n < count; n++ )
4378 Free_ChainPosRuleSet( &cprs[n] );
4383 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4387 /* ChainPosClassRule */
4389 static HB_Error Load_ChainPosClassRule(
4390 HB_ChainContextPosFormat2* ccpf2,
4391 HB_ChainPosClassRule* cpcr,
4401 HB_PosLookupRecord* plr;
4405 if ( ACCESS_Frame( 2L ) )
4408 cpcr->BacktrackGlyphCount = GET_UShort();
4412 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4413 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4415 cpcr->Backtrack = NULL;
4417 count = cpcr->BacktrackGlyphCount;
4419 if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
4422 b = cpcr->Backtrack;
4423 d = ccpf2->BacktrackClassDef.Defined;
4425 if ( ACCESS_Frame( count * 2L ) )
4428 for ( n = 0; n < count; n++ )
4430 b[n] = GET_UShort();
4432 /* We check whether the specific class is used at all. If not,
4433 class 0 is used instead. */
4441 if ( ACCESS_Frame( 2L ) )
4444 cpcr->InputGlyphCount = GET_UShort();
4446 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4447 ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4453 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4455 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4459 d = ccpf2->InputClassDef.Defined;
4461 if ( ACCESS_Frame( count * 2L ) )
4464 for ( n = 0; n < count; n++ )
4466 i[n] = GET_UShort();
4474 if ( ACCESS_Frame( 2L ) )
4477 cpcr->LookaheadGlyphCount = GET_UShort();
4481 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4482 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4484 cpcr->Lookahead = NULL;
4486 count = cpcr->LookaheadGlyphCount;
4488 if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
4491 l = cpcr->Lookahead;
4492 d = ccpf2->LookaheadClassDef.Defined;
4494 if ( ACCESS_Frame( count * 2L ) )
4497 for ( n = 0; n < count; n++ )
4499 l[n] = GET_UShort();
4507 if ( ACCESS_Frame( 2L ) )
4510 cpcr->PosCount = GET_UShort();
4514 cpcr->PosLookupRecord = NULL;
4516 count = cpcr->PosCount;
4518 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4521 plr = cpcr->PosLookupRecord;
4523 if ( ACCESS_Frame( count * 4L ) )
4526 for ( n = 0; n < count; n++ )
4528 plr[n].SequenceIndex = GET_UShort();
4529 plr[n].LookupListIndex = GET_UShort();
4551 static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
4553 FREE( cpcr->PosLookupRecord );
4554 FREE( cpcr->Lookahead );
4555 FREE( cpcr->Input );
4556 FREE( cpcr->Backtrack );
4562 static HB_Error Load_ChainPosClassSet(
4563 HB_ChainContextPosFormat2* ccpf2,
4564 HB_ChainPosClassSet* cpcs,
4569 HB_UShort n, m, count;
4570 HB_UInt cur_offset, new_offset, base_offset;
4572 HB_ChainPosClassRule* cpcr;
4575 base_offset = FILE_Pos();
4577 if ( ACCESS_Frame( 2L ) )
4580 count = cpcs->ChainPosClassRuleCount = GET_UShort();
4584 cpcs->ChainPosClassRule = NULL;
4586 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4587 HB_ChainPosClassRule ) )
4590 cpcr = cpcs->ChainPosClassRule;
4592 for ( n = 0; n < count; n++ )
4594 if ( ACCESS_Frame( 2L ) )
4597 new_offset = GET_UShort() + base_offset;
4601 cur_offset = FILE_Pos();
4602 if ( FILE_Seek( new_offset ) ||
4603 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4604 stream ) ) != HB_Err_Ok )
4606 (void)FILE_Seek( cur_offset );
4612 for ( m = 0; m < n; m++ )
4613 Free_ChainPosClassRule( &cpcr[m] );
4620 static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
4624 HB_ChainPosClassRule* cpcr;
4627 if ( cpcs->ChainPosClassRule )
4629 count = cpcs->ChainPosClassRuleCount;
4630 cpcr = cpcs->ChainPosClassRule;
4632 for ( n = 0; n < count; n++ )
4633 Free_ChainPosClassRule( &cpcr[n] );
4640 /* ChainContextPosFormat2 */
4642 static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4647 HB_UShort n, m, count;
4648 HB_UInt cur_offset, new_offset, base_offset;
4649 HB_UInt backtrack_offset, input_offset, lookahead_offset;
4651 HB_ChainPosClassSet* cpcs;
4654 base_offset = FILE_Pos() - 2;
4656 if ( ACCESS_Frame( 2L ) )
4659 new_offset = GET_UShort() + base_offset;
4663 cur_offset = FILE_Pos();
4664 if ( FILE_Seek( new_offset ) ||
4665 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4667 (void)FILE_Seek( cur_offset );
4669 if ( ACCESS_Frame( 8L ) )
4672 backtrack_offset = GET_UShort();
4673 input_offset = GET_UShort();
4674 lookahead_offset = GET_UShort();
4676 /* `ChainPosClassSetCount' is the upper limit for input class values,
4677 thus we read it now to make an additional safety check. No limit
4678 is known or needed for the other two class definitions */
4680 count = ccpf2->ChainPosClassSetCount = GET_UShort();
4684 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4685 backtrack_offset, base_offset,
4686 stream ) ) != HB_Err_Ok )
4688 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4689 input_offset, base_offset,
4690 stream ) ) != HB_Err_Ok )
4692 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4693 lookahead_offset, base_offset,
4694 stream ) ) != HB_Err_Ok )
4697 ccpf2->ChainPosClassSet = NULL;
4698 ccpf2->MaxBacktrackLength = 0;
4699 ccpf2->MaxInputLength = 0;
4700 ccpf2->MaxLookaheadLength = 0;
4702 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4705 cpcs = ccpf2->ChainPosClassSet;
4707 for ( n = 0; n < count; n++ )
4709 if ( ACCESS_Frame( 2L ) )
4712 new_offset = GET_UShort() + base_offset;
4716 if ( new_offset != base_offset ) /* not a NULL offset */
4718 cur_offset = FILE_Pos();
4719 if ( FILE_Seek( new_offset ) ||
4720 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4721 stream ) ) != HB_Err_Ok )
4723 (void)FILE_Seek( cur_offset );
4727 /* we create a ChainPosClassSet table with no entries */
4729 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4730 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4737 for ( m = 0; m < n; m++ )
4738 Free_ChainPosClassSet( &cpcs[m] );
4743 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4746 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4749 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4752 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4757 static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
4761 HB_ChainPosClassSet* cpcs;
4764 if ( ccpf2->ChainPosClassSet )
4766 count = ccpf2->ChainPosClassSetCount;
4767 cpcs = ccpf2->ChainPosClassSet;
4769 for ( n = 0; n < count; n++ )
4770 Free_ChainPosClassSet( &cpcs[n] );
4775 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4776 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4777 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4779 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4783 /* ChainContextPosFormat3 */
4785 static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
4790 HB_UShort n, nb, ni, nl, m, count;
4791 HB_UShort backtrack_count, input_count, lookahead_count;
4792 HB_UInt cur_offset, new_offset, base_offset;
4797 HB_PosLookupRecord* plr;
4800 base_offset = FILE_Pos() - 2L;
4802 if ( ACCESS_Frame( 2L ) )
4805 ccpf3->BacktrackGlyphCount = GET_UShort();
4809 ccpf3->BacktrackCoverage = NULL;
4811 backtrack_count = ccpf3->BacktrackGlyphCount;
4813 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4817 b = ccpf3->BacktrackCoverage;
4819 for ( nb = 0; nb < backtrack_count; nb++ )
4821 if ( ACCESS_Frame( 2L ) )
4824 new_offset = GET_UShort() + base_offset;
4828 cur_offset = FILE_Pos();
4829 if ( FILE_Seek( new_offset ) ||
4830 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4832 (void)FILE_Seek( cur_offset );
4835 if ( ACCESS_Frame( 2L ) )
4838 ccpf3->InputGlyphCount = GET_UShort();
4842 ccpf3->InputCoverage = NULL;
4844 input_count = ccpf3->InputGlyphCount;
4846 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4849 i = ccpf3->InputCoverage;
4851 for ( ni = 0; ni < input_count; ni++ )
4853 if ( ACCESS_Frame( 2L ) )
4856 new_offset = GET_UShort() + base_offset;
4860 cur_offset = FILE_Pos();
4861 if ( FILE_Seek( new_offset ) ||
4862 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4864 (void)FILE_Seek( cur_offset );
4867 if ( ACCESS_Frame( 2L ) )
4870 ccpf3->LookaheadGlyphCount = GET_UShort();
4874 ccpf3->LookaheadCoverage = NULL;
4876 lookahead_count = ccpf3->LookaheadGlyphCount;
4878 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4882 l = ccpf3->LookaheadCoverage;
4884 for ( nl = 0; nl < lookahead_count; nl++ )
4886 if ( ACCESS_Frame( 2L ) )
4889 new_offset = GET_UShort() + base_offset;
4893 cur_offset = FILE_Pos();
4894 if ( FILE_Seek( new_offset ) ||
4895 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4897 (void)FILE_Seek( cur_offset );
4900 if ( ACCESS_Frame( 2L ) )
4903 ccpf3->PosCount = GET_UShort();
4907 ccpf3->PosLookupRecord = NULL;
4909 count = ccpf3->PosCount;
4911 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4914 plr = ccpf3->PosLookupRecord;
4916 if ( ACCESS_Frame( count * 4L ) )
4919 for ( n = 0; n < count; n++ )
4921 plr[n].SequenceIndex = GET_UShort();
4922 plr[n].LookupListIndex = GET_UShort();
4933 for ( m = 0; m < nl; m++ )
4934 _HB_OPEN_Free_Coverage( &l[m] );
4939 for ( m = 0; m < ni; m++ )
4940 _HB_OPEN_Free_Coverage( &i[m] );
4945 for ( m = 0; m < nb; m++ )
4946 _HB_OPEN_Free_Coverage( &b[m] );
4953 static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
4960 FREE( ccpf3->PosLookupRecord );
4962 if ( ccpf3->LookaheadCoverage )
4964 count = ccpf3->LookaheadGlyphCount;
4965 c = ccpf3->LookaheadCoverage;
4967 for ( n = 0; n < count; n++ )
4968 _HB_OPEN_Free_Coverage( &c[n] );
4973 if ( ccpf3->InputCoverage )
4975 count = ccpf3->InputGlyphCount;
4976 c = ccpf3->InputCoverage;
4978 for ( n = 0; n < count; n++ )
4979 _HB_OPEN_Free_Coverage( &c[n] );
4984 if ( ccpf3->BacktrackCoverage )
4986 count = ccpf3->BacktrackGlyphCount;
4987 c = ccpf3->BacktrackCoverage;
4989 for ( n = 0; n < count; n++ )
4990 _HB_OPEN_Free_Coverage( &c[n] );
4997 /* ChainContextPos */
4999 static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
5003 HB_ChainContextPos* ccp = &st->chain;
5006 if ( ACCESS_Frame( 2L ) )
5009 ccp->PosFormat = GET_UShort();
5013 switch ( ccp->PosFormat )
5016 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
5019 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
5022 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
5025 return ERR(HB_Err_Invalid_SubTable_Format);
5028 return HB_Err_Ok; /* never reached */
5032 static void Free_ChainContextPos( HB_GPOS_SubTable* st )
5034 HB_ChainContextPos* ccp = &st->chain;
5036 switch ( ccp->PosFormat )
5038 case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
5039 case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
5040 case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
5046 static HB_Error Lookup_ChainContextPos1(
5048 HB_ChainContextPosFormat1* ccpf1,
5051 HB_UShort context_length,
5054 HB_UShort index, property;
5055 HB_UShort i, j, k, num_cpr;
5056 HB_UShort bgc, igc, lgc;
5058 HB_GPOSHeader* gpos = gpi->gpos;
5060 HB_ChainPosRule* cpr;
5061 HB_ChainPosRule curr_cpr;
5062 HB_GDEFHeader* gdef;
5067 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5070 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5074 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5075 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5077 for ( k = 0; k < num_cpr; k++ )
5080 bgc = curr_cpr.BacktrackGlyphCount;
5081 igc = curr_cpr.InputGlyphCount;
5082 lgc = curr_cpr.LookaheadGlyphCount;
5084 if ( context_length != 0xFFFF && context_length < igc )
5085 goto next_chainposrule;
5087 /* check whether context is too long; it is a first guess only */
5089 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5090 goto next_chainposrule;
5094 /* Since we don't know in advance the number of glyphs to inspect,
5095 we search backwards for matches in the backtrack glyph array */
5097 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5099 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5101 if ( error && error != HB_Err_Not_Covered )
5104 if ( j + 1 == bgc - i )
5105 goto next_chainposrule;
5109 /* In OpenType 1.3, it is undefined whether the offsets of
5110 backtrack glyphs is in logical order or not. Version 1.4
5113 Logical order - a b c d e f g h i j
5116 Backtrack offsets - 3 2 1 0
5117 Lookahead offsets - 0 1 2 3 */
5119 if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5120 goto next_chainposrule;
5124 /* Start at 1 because [0] is implied */
5126 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5128 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5130 if ( error && error != HB_Err_Not_Covered )
5133 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5134 goto next_chainposrule;
5138 if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5139 goto next_chainposrule;
5142 /* we are starting to check for lookahead glyphs right after the
5143 last context glyph */
5145 for ( i = 0; i < lgc; i++, j++ )
5147 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5149 if ( error && error != HB_Err_Not_Covered )
5152 if ( j + lgc - i == (HB_Int)buffer->in_length )
5153 goto next_chainposrule;
5157 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5158 goto next_chainposrule;
5161 return Do_ContextPos( gpi, igc,
5163 curr_cpr.PosLookupRecord,
5171 return HB_Err_Not_Covered;
5175 static HB_Error Lookup_ChainContextPos2(
5177 HB_ChainContextPosFormat2* ccpf2,
5180 HB_UShort context_length,
5183 HB_UShort index, property;
5186 HB_UShort bgc, igc, lgc;
5187 HB_UShort known_backtrack_classes,
5188 known_input_classes,
5189 known_lookahead_classes;
5191 HB_UShort* backtrack_classes;
5192 HB_UShort* input_classes;
5193 HB_UShort* lookahead_classes;
5198 HB_GPOSHeader* gpos = gpi->gpos;
5200 HB_ChainPosClassSet* cpcs;
5201 HB_ChainPosClassRule cpcr;
5202 HB_GDEFHeader* gdef;
5207 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5210 /* Note: The coverage table in format 2 doesn't give an index into
5211 anything. It just lets us know whether or not we need to
5212 do any lookup at all. */
5214 error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5218 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5220 known_backtrack_classes = 0;
5222 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5224 known_input_classes = 1;
5226 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5228 known_lookahead_classes = 0;
5230 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5231 &input_classes[0], NULL );
5232 if ( error && error != HB_Err_Not_Covered )
5235 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5238 error = ERR(HB_Err_Invalid_SubTable);
5242 for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5244 cpcr = cpcs->ChainPosClassRule[k];
5245 bgc = cpcr.BacktrackGlyphCount;
5246 igc = cpcr.InputGlyphCount;
5247 lgc = cpcr.LookaheadGlyphCount;
5249 if ( context_length != 0xFFFF && context_length < igc )
5250 goto next_chainposclassrule;
5252 /* check whether context is too long; it is a first guess only */
5254 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5255 goto next_chainposclassrule;
5259 /* Since we don't know in advance the number of glyphs to inspect,
5260 we search backwards for matches in the backtrack glyph array.
5261 Note that `known_backtrack_classes' starts at index 0. */
5263 bc = cpcr.Backtrack;
5265 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5267 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5269 if ( error && error != HB_Err_Not_Covered )
5272 if ( j + 1 == bgc - i )
5273 goto next_chainposclassrule;
5277 if ( i >= known_backtrack_classes )
5279 /* Keeps us from having to do this for each rule */
5281 error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5282 &backtrack_classes[i], NULL );
5283 if ( error && error != HB_Err_Not_Covered )
5285 known_backtrack_classes = i;
5288 if ( bc[i] != backtrack_classes[i] )
5289 goto next_chainposclassrule;
5295 /* Start at 1 because [0] is implied */
5297 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5299 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5301 if ( error && error != HB_Err_Not_Covered )
5304 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5305 goto next_chainposclassrule;
5309 if ( i >= known_input_classes )
5311 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5312 &input_classes[i], NULL );
5313 if ( error && error != HB_Err_Not_Covered )
5315 known_input_classes = i;
5318 if ( ic[i - 1] != input_classes[i] )
5319 goto next_chainposclassrule;
5322 /* we are starting to check for lookahead glyphs right after the
5323 last context glyph */
5325 lc = cpcr.Lookahead;
5327 for ( i = 0; i < lgc; i++, j++ )
5329 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5331 if ( error && error != HB_Err_Not_Covered )
5334 if ( j + lgc - i == (HB_Int)buffer->in_length )
5335 goto next_chainposclassrule;
5339 if ( i >= known_lookahead_classes )
5341 error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5342 &lookahead_classes[i], NULL );
5343 if ( error && error != HB_Err_Not_Covered )
5345 known_lookahead_classes = i;
5348 if ( lc[i] != lookahead_classes[i] )
5349 goto next_chainposclassrule;
5352 error = Do_ContextPos( gpi, igc,
5354 cpcr.PosLookupRecord,
5359 next_chainposclassrule:
5363 error = HB_Err_Not_Covered;
5366 FREE( lookahead_classes );
5369 FREE( input_classes );
5372 FREE( backtrack_classes );
5377 static HB_Error Lookup_ChainContextPos3(
5379 HB_ChainContextPosFormat3* ccpf3,
5382 HB_UShort context_length,
5385 HB_UShort index, i, j, property;
5386 HB_UShort bgc, igc, lgc;
5388 HB_GPOSHeader* gpos = gpi->gpos;
5393 HB_GDEFHeader* gdef;
5398 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5401 bgc = ccpf3->BacktrackGlyphCount;
5402 igc = ccpf3->InputGlyphCount;
5403 lgc = ccpf3->LookaheadGlyphCount;
5405 if ( context_length != 0xFFFF && context_length < igc )
5406 return HB_Err_Not_Covered;
5408 /* check whether context is too long; it is a first guess only */
5410 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5411 return HB_Err_Not_Covered;
5415 /* Since we don't know in advance the number of glyphs to inspect,
5416 we search backwards for matches in the backtrack glyph array */
5418 bc = ccpf3->BacktrackCoverage;
5420 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5422 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5424 if ( error && error != HB_Err_Not_Covered )
5427 if ( j + 1 == bgc - i )
5428 return HB_Err_Not_Covered;
5432 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5438 ic = ccpf3->InputCoverage;
5440 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5442 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5443 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5445 if ( error && error != HB_Err_Not_Covered )
5448 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5449 return HB_Err_Not_Covered;
5453 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5458 /* we are starting to check for lookahead glyphs right after the
5459 last context glyph */
5461 lc = ccpf3->LookaheadCoverage;
5463 for ( i = 0; i < lgc; i++, j++ )
5465 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5467 if ( error && error != HB_Err_Not_Covered )
5470 if ( j + lgc - i == (HB_Int)buffer->in_length )
5471 return HB_Err_Not_Covered;
5475 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5480 return Do_ContextPos( gpi, igc,
5482 ccpf3->PosLookupRecord,
5488 static HB_Error Lookup_ChainContextPos(
5490 HB_GPOS_SubTable* st,
5493 HB_UShort context_length,
5496 HB_ChainContextPos* ccp = &st->chain;
5498 switch ( ccp->PosFormat )
5501 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5502 flags, context_length,
5506 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5507 flags, context_length,
5511 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5512 flags, context_length,
5516 return ERR(HB_Err_Invalid_SubTable_Format);
5519 return HB_Err_Ok; /* never reached */
5530 HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
5532 HB_UShort* script_index )
5537 HB_ScriptRecord* sr;
5540 if ( !gpos || !script_index )
5541 return ERR(HB_Err_Invalid_Argument);
5543 sl = &gpos->ScriptList;
5544 sr = sl->ScriptRecord;
5546 for ( n = 0; n < sl->ScriptCount; n++ )
5547 if ( script_tag == sr[n].ScriptTag )
5554 return HB_Err_Not_Covered;
5559 HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
5560 HB_UInt language_tag,
5561 HB_UShort script_index,
5562 HB_UShort* language_index,
5563 HB_UShort* req_feature_index )
5568 HB_ScriptRecord* sr;
5570 HB_LangSysRecord* lsr;
5573 if ( !gpos || !language_index || !req_feature_index )
5574 return ERR(HB_Err_Invalid_Argument);
5576 sl = &gpos->ScriptList;
5577 sr = sl->ScriptRecord;
5579 if ( script_index >= sl->ScriptCount )
5580 return ERR(HB_Err_Invalid_Argument);
5582 s = &sr[script_index].Script;
5583 lsr = s->LangSysRecord;
5585 for ( n = 0; n < s->LangSysCount; n++ )
5586 if ( language_tag == lsr[n].LangSysTag )
5588 *language_index = n;
5589 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5594 return HB_Err_Not_Covered;
5598 /* selecting 0xFFFF for language_index asks for the values of the
5599 default language (DefaultLangSys) */
5602 HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
5603 HB_UInt feature_tag,
5604 HB_UShort script_index,
5605 HB_UShort language_index,
5606 HB_UShort* feature_index )
5611 HB_ScriptRecord* sr;
5613 HB_LangSysRecord* lsr;
5618 HB_FeatureRecord* fr;
5621 if ( !gpos || !feature_index )
5622 return ERR(HB_Err_Invalid_Argument);
5624 sl = &gpos->ScriptList;
5625 sr = sl->ScriptRecord;
5627 fl = &gpos->FeatureList;
5628 fr = fl->FeatureRecord;
5630 if ( script_index >= sl->ScriptCount )
5631 return ERR(HB_Err_Invalid_Argument);
5633 s = &sr[script_index].Script;
5634 lsr = s->LangSysRecord;
5636 if ( language_index == 0xFFFF )
5637 ls = &s->DefaultLangSys;
5640 if ( language_index >= s->LangSysCount )
5641 return ERR(HB_Err_Invalid_Argument);
5643 ls = &lsr[language_index].LangSys;
5646 fi = ls->FeatureIndex;
5648 for ( n = 0; n < ls->FeatureCount; n++ )
5650 if ( fi[n] >= fl->FeatureCount )
5651 return ERR(HB_Err_Invalid_SubTable_Format);
5653 if ( feature_tag == fr[fi[n]].FeatureTag )
5655 *feature_index = fi[n];
5661 return HB_Err_Not_Covered;
5665 /* The next three functions return a null-terminated list */
5668 HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
5669 HB_UInt** script_tag_list )
5676 HB_ScriptRecord* sr;
5679 if ( !gpos || !script_tag_list )
5680 return ERR(HB_Err_Invalid_Argument);
5682 sl = &gpos->ScriptList;
5683 sr = sl->ScriptRecord;
5685 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
5688 for ( n = 0; n < sl->ScriptCount; n++ )
5689 stl[n] = sr[n].ScriptTag;
5692 *script_tag_list = stl;
5699 HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
5700 HB_UShort script_index,
5701 HB_UInt** language_tag_list )
5708 HB_ScriptRecord* sr;
5710 HB_LangSysRecord* lsr;
5713 if ( !gpos || !language_tag_list )
5714 return ERR(HB_Err_Invalid_Argument);
5716 sl = &gpos->ScriptList;
5717 sr = sl->ScriptRecord;
5719 if ( script_index >= sl->ScriptCount )
5720 return ERR(HB_Err_Invalid_Argument);
5722 s = &sr[script_index].Script;
5723 lsr = s->LangSysRecord;
5725 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
5728 for ( n = 0; n < s->LangSysCount; n++ )
5729 ltl[n] = lsr[n].LangSysTag;
5732 *language_tag_list = ltl;
5738 /* selecting 0xFFFF for language_index asks for the values of the
5739 default language (DefaultLangSys) */
5742 HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
5743 HB_UShort script_index,
5744 HB_UShort language_index,
5745 HB_UInt** feature_tag_list )
5752 HB_ScriptRecord* sr;
5754 HB_LangSysRecord* lsr;
5759 HB_FeatureRecord* fr;
5762 if ( !gpos || !feature_tag_list )
5763 return ERR(HB_Err_Invalid_Argument);
5765 sl = &gpos->ScriptList;
5766 sr = sl->ScriptRecord;
5768 fl = &gpos->FeatureList;
5769 fr = fl->FeatureRecord;
5771 if ( script_index >= sl->ScriptCount )
5772 return ERR(HB_Err_Invalid_Argument);
5774 s = &sr[script_index].Script;
5775 lsr = s->LangSysRecord;
5777 if ( language_index == 0xFFFF )
5778 ls = &s->DefaultLangSys;
5781 if ( language_index >= s->LangSysCount )
5782 return ERR(HB_Err_Invalid_Argument);
5784 ls = &lsr[language_index].LangSys;
5787 fi = ls->FeatureIndex;
5789 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
5792 for ( n = 0; n < ls->FeatureCount; n++ )
5794 if ( fi[n] >= fl->FeatureCount )
5797 return ERR(HB_Err_Invalid_SubTable_Format);
5799 ftl[n] = fr[fi[n]].FeatureTag;
5803 *feature_tag_list = ftl;
5809 /* Do an individual subtable lookup. Returns HB_Err_Ok if positioning
5810 has been done, or HB_Err_Not_Covered if not. */
5811 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
5812 HB_UShort lookup_index,
5814 HB_UShort context_length,
5817 HB_Error error = HB_Err_Not_Covered;
5818 HB_UShort i, flags, lookup_count;
5819 HB_GPOSHeader* gpos = gpi->gpos;
5826 if ( nesting_level > HB_MAX_NESTING_LEVEL )
5827 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
5829 lookup_count = gpos->LookupList.LookupCount;
5830 if (lookup_index >= lookup_count)
5833 lo = &gpos->LookupList.Lookup[lookup_index];
5834 flags = lo->LookupFlag;
5835 lookup_type = lo->LookupType;
5837 for ( i = 0; i < lo->SubTableCount; i++ )
5839 HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
5841 switch (lookup_type) {
5842 case HB_GPOS_LOOKUP_SINGLE:
5843 error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5844 case HB_GPOS_LOOKUP_PAIR:
5845 error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5846 case HB_GPOS_LOOKUP_CURSIVE:
5847 error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5848 case HB_GPOS_LOOKUP_MARKBASE:
5849 error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5850 case HB_GPOS_LOOKUP_MARKLIG:
5851 error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5852 case HB_GPOS_LOOKUP_MARKMARK:
5853 error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5854 case HB_GPOS_LOOKUP_CONTEXT:
5855 error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5856 case HB_GPOS_LOOKUP_CHAIN:
5857 error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5858 /*case HB_GPOS_LOOKUP_EXTENSION:
5859 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5861 error = HB_Err_Not_Covered;
5864 /* Check whether we have a successful positioning or an error other
5865 than HB_Err_Not_Covered */
5866 if ( error != HB_Err_Not_Covered )
5870 return HB_Err_Not_Covered;
5874 HB_INTERNAL HB_Error
5875 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5877 HB_UShort lookup_type )
5879 switch ( lookup_type ) {
5880 case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream );
5881 case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream );
5882 case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream );
5883 case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream );
5884 case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream );
5885 case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream );
5886 case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream );
5887 case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream );
5888 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/
5889 default: return ERR(HB_Err_Invalid_SubTable_Format);
5895 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
5896 HB_UShort lookup_type )
5898 switch ( lookup_type ) {
5899 case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return;
5900 case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return;
5901 case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return;
5902 case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return;
5903 case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return;
5904 case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return;
5905 case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return;
5906 case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return;
5907 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/
5913 /* apply one lookup to the input string object */
5915 static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
5916 HB_UShort lookup_index,
5919 HB_Error error, retError = HB_Err_Not_Covered;
5920 HB_GPOSHeader* gpos = gpi->gpos;
5922 HB_UInt* properties = gpos->LookupList.Properties;
5924 const int nesting_level = 0;
5925 /* 0xFFFF indicates that we don't have a context length yet */
5926 const HB_UShort context_length = 0xFFFF;
5929 gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
5932 while ( buffer->in_pos < buffer->in_length )
5934 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
5936 /* Note that the connection between mark and base glyphs hold
5937 exactly one (string) lookup. For example, it would be possible
5938 that in the first lookup, mark glyph X is attached to base
5939 glyph A, and in the next lookup it is attached to base glyph B.
5940 It is up to the font designer to provide meaningful lookups and
5943 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5944 if ( error && error != HB_Err_Not_Covered )
5949 /* Contrary to properties defined in GDEF, user-defined properties
5950 will always stop a possible cursive positioning. */
5953 error = HB_Err_Not_Covered;
5956 if ( error == HB_Err_Not_Covered )
5966 static HB_Error Position_CursiveChain ( HB_Buffer buffer )
5969 HB_Position positions = buffer->positions;
5971 /* First handle all left-to-right connections */
5972 for (j = 0; j < buffer->in_length; j++)
5974 if (positions[j].cursive_chain > 0)
5975 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5978 /* Then handle all right-to-left connections */
5979 for (i = buffer->in_length; i > 0; i--)
5983 if (positions[j].cursive_chain < 0)
5984 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5991 HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
5992 HB_UShort feature_index,
5998 HB_UInt* properties;
6000 HB_UShort lookup_count;
6002 /* Each feature can only be added once */
6005 feature_index >= gpos->FeatureList.FeatureCount ||
6006 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
6007 return ERR(HB_Err_Invalid_Argument);
6009 gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
6011 properties = gpos->LookupList.Properties;
6013 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6014 index = feature.LookupListIndex;
6015 lookup_count = gpos->LookupList.LookupCount;
6017 for ( i = 0; i < feature.LookupListCount; i++ )
6019 HB_UShort lookup_index = index[i];
6020 if (lookup_index < lookup_count)
6021 properties[lookup_index] |= property;
6029 HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
6033 HB_UInt* properties;
6037 return ERR(HB_Err_Invalid_Argument);
6039 gpos->FeatureList.ApplyCount = 0;
6041 properties = gpos->LookupList.Properties;
6043 for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
6051 HB_Error HB_GPOS_Register_Glyph_Function( HB_GPOSHeader* gpos,
6052 HB_GlyphFunction gfunc )
6055 return ERR(HB_Err_Invalid_Argument);
6057 gpos->gfunc = gfunc;
6064 HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
6065 HB_MMFunction mmfunc,
6069 return ERR(HB_Err_Invalid_Argument);
6071 gpos->mmfunc = mmfunc;
6077 /* If `dvi' is TRUE, glyph contour points for anchor points and device
6078 tables are ignored -- you will get device independent values. */
6081 HB_Error HB_GPOS_Apply_String( HB_Font font,
6082 HB_GPOSHeader* gpos,
6083 HB_UShort load_flags,
6088 HB_Error error, retError = HB_Err_Not_Covered;
6090 int i, j, lookup_count, num_features;
6092 if ( !font || !gpos || !buffer )
6093 return ERR(HB_Err_Invalid_Argument);
6095 if ( buffer->in_length == 0 )
6096 return HB_Err_Not_Covered;
6100 gpi.load_flags = load_flags;
6104 lookup_count = gpos->LookupList.LookupCount;
6105 num_features = gpos->FeatureList.ApplyCount;
6109 error = _hb_buffer_clear_positions( buffer );
6114 for ( i = 0; i < num_features; i++ )
6116 HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i];
6117 HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6119 for ( j = 0; j < feature.LookupListCount; j++ )
6121 HB_UShort lookup_index = feature.LookupListIndex[j];
6123 /* Skip nonexistant lookups */
6124 if (lookup_index >= lookup_count)
6127 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6130 if ( error != HB_Err_Not_Covered )
6140 error = Position_CursiveChain ( buffer );