1
/*******************************************************************
3
* Copyright 1996-2000 by
4
* David Turner, Robert Wilhelm, and Werner Lemberg.
6
* Copyright 2006 Behdad Esfahbod
8
* This is part of HarfBuzz, an OpenType Layout engine library.
10
* See the file name COPYING for licensing information.
12
******************************************************************/
13
#include "harfbuzz-impl.h"
14
#include "harfbuzz-gpos-private.h"
15
#include "harfbuzz-open-private.h"
16
#include "harfbuzz-gdef-private.h"
23
FT_UShort load_flags; /* how the glyph should be loaded */
26
FT_UShort last; /* the last valid glyph -- used
27
with cursive positioning */
28
FT_Pos anchor_x; /* the coordinates of the anchor point */
29
FT_Pos anchor_y; /* of the last valid glyph */
32
typedef struct GPOS_Instance_ GPOS_Instance;
35
static FT_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
36
FT_UShort lookup_index,
38
FT_UShort context_length,
43
/* the client application must replace this with something more
44
meaningful if multiple master fonts are to be supported. */
46
static FT_Error default_mmfunc( FT_Face face,
53
FT_UNUSED(metric_value);
55
return HB_Err_No_MM_Interpreter;
60
FT_Error HB_Load_GPOS_Table( FT_Face face,
61
HB_GPOSHeader** retptr,
64
FT_ULong cur_offset, new_offset, base_offset;
66
FT_UShort i, num_lookups;
70
FT_Stream stream = face->stream;
72
FT_Memory memory = face->memory;
76
return FT_Err_Invalid_Argument;
79
return FT_Err_Invalid_Face_Handle;
81
if (( error = _hb_ftglue_face_goto_table( face, TTAG_GPOS, stream ) ))
84
base_offset = FILE_Pos();
86
if ( ALLOC ( gpos, sizeof( *gpos ) ) )
89
gpos->memory = memory;
90
gpos->gfunc = FT_Load_Glyph;
91
gpos->mmfunc = default_mmfunc;
95
if ( FILE_Seek( base_offset + 4L ) ||
99
new_offset = GET_UShort() + base_offset;
103
cur_offset = FILE_Pos();
104
if ( FILE_Seek( new_offset ) ||
105
( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
106
stream ) ) != FT_Err_Ok )
108
(void)FILE_Seek( cur_offset );
110
if ( ACCESS_Frame( 2L ) )
113
new_offset = GET_UShort() + base_offset;
117
cur_offset = FILE_Pos();
118
if ( FILE_Seek( new_offset ) ||
119
( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
120
stream ) ) != FT_Err_Ok )
122
(void)FILE_Seek( cur_offset );
124
if ( ACCESS_Frame( 2L ) )
127
new_offset = GET_UShort() + base_offset;
131
cur_offset = FILE_Pos();
132
if ( FILE_Seek( new_offset ) ||
133
( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
134
stream, HB_Type_GPOS ) ) != FT_Err_Ok )
137
gpos->gdef = gdef; /* can be NULL */
139
/* We now check the LookupFlags for values larger than 0xFF to find
140
out whether we need to load the `MarkAttachClassDef' field of the
141
GDEF table -- this hack is necessary for OpenType 1.2 tables since
142
the version field of the GDEF table hasn't been incremented.
144
For constructed GDEF tables, we only load it if
145
`MarkAttachClassDef_offset' is not zero (nevertheless, a build of
146
a constructed mark attach table is not supported currently). */
149
gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
151
lo = gpos->LookupList.Lookup;
152
num_lookups = gpos->LookupList.LookupCount;
154
for ( i = 0; i < num_lookups; i++ )
156
if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
158
if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
159
( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
160
256, stream ) ) != FT_Err_Ok )
173
_HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS, memory );
176
_HB_OPEN_Free_FeatureList( &gpos->FeatureList, memory );
179
_HB_OPEN_Free_ScriptList( &gpos->ScriptList, memory );
188
FT_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
190
FT_Memory memory = gpos->memory;
192
_HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS, memory );
193
_HB_OPEN_Free_FeatureList( &gpos->FeatureList, memory );
194
_HB_OPEN_Free_ScriptList( &gpos->ScriptList, memory );
200
/*****************************
201
* SubTable related functions
202
*****************************/
208
/* There is a subtle difference in the specs between a `table' and a
209
`record' -- offsets for device tables in ValueRecords are taken from
210
the parent table and not the parent record. */
212
static FT_Error Load_ValueRecord( HB_ValueRecord* vr,
214
FT_ULong base_offset,
218
FT_Memory memory = stream->memory;
220
FT_ULong cur_offset, new_offset;
223
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
225
if ( ACCESS_Frame( 2L ) )
228
vr->XPlacement = GET_Short();
235
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
237
if ( ACCESS_Frame( 2L ) )
240
vr->YPlacement = GET_Short();
247
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
249
if ( ACCESS_Frame( 2L ) )
252
vr->XAdvance = GET_Short();
259
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
261
if ( ACCESS_Frame( 2L ) )
264
vr->YAdvance = GET_Short();
271
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
273
if ( ACCESS_Frame( 2L ) )
276
new_offset = GET_UShort();
282
new_offset += base_offset;
284
cur_offset = FILE_Pos();
285
if ( FILE_Seek( new_offset ) ||
286
( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
287
stream ) ) != FT_Err_Ok )
289
(void)FILE_Seek( cur_offset );
297
vr->XPlacementDevice.StartSize = 0;
298
vr->XPlacementDevice.EndSize = 0;
299
vr->XPlacementDevice.DeltaValue = NULL;
302
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
304
if ( ACCESS_Frame( 2L ) )
307
new_offset = GET_UShort();
313
new_offset += base_offset;
315
cur_offset = FILE_Pos();
316
if ( FILE_Seek( new_offset ) ||
317
( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
318
stream ) ) != FT_Err_Ok )
320
(void)FILE_Seek( cur_offset );
328
vr->YPlacementDevice.StartSize = 0;
329
vr->YPlacementDevice.EndSize = 0;
330
vr->YPlacementDevice.DeltaValue = NULL;
333
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
335
if ( ACCESS_Frame( 2L ) )
338
new_offset = GET_UShort();
344
new_offset += base_offset;
346
cur_offset = FILE_Pos();
347
if ( FILE_Seek( new_offset ) ||
348
( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice,
349
stream ) ) != FT_Err_Ok )
351
(void)FILE_Seek( cur_offset );
359
vr->XAdvanceDevice.StartSize = 0;
360
vr->XAdvanceDevice.EndSize = 0;
361
vr->XAdvanceDevice.DeltaValue = NULL;
364
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
366
if ( ACCESS_Frame( 2L ) )
369
new_offset = GET_UShort();
375
new_offset += base_offset;
377
cur_offset = FILE_Pos();
378
if ( FILE_Seek( new_offset ) ||
379
( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
380
stream ) ) != FT_Err_Ok )
382
(void)FILE_Seek( cur_offset );
390
vr->YAdvanceDevice.StartSize = 0;
391
vr->YAdvanceDevice.EndSize = 0;
392
vr->YAdvanceDevice.DeltaValue = NULL;
395
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
397
if ( ACCESS_Frame( 2L ) )
400
vr->XIdPlacement = GET_UShort();
405
vr->XIdPlacement = 0;
407
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
409
if ( ACCESS_Frame( 2L ) )
412
vr->YIdPlacement = GET_UShort();
417
vr->YIdPlacement = 0;
419
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
421
if ( ACCESS_Frame( 2L ) )
424
vr->XIdAdvance = GET_UShort();
431
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
433
if ( ACCESS_Frame( 2L ) )
436
vr->YIdAdvance = GET_UShort();
446
_HB_OPEN_Free_Device( &vr->YAdvanceDevice, memory );
449
_HB_OPEN_Free_Device( &vr->XAdvanceDevice, memory );
452
_HB_OPEN_Free_Device( &vr->YPlacementDevice, memory );
457
static void Free_ValueRecord( HB_ValueRecord* vr,
461
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
462
_HB_OPEN_Free_Device( &vr->YAdvanceDevice, memory );
463
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
464
_HB_OPEN_Free_Device( &vr->XAdvanceDevice, memory );
465
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
466
_HB_OPEN_Free_Device( &vr->YPlacementDevice, memory );
467
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
468
_HB_OPEN_Free_Device( &vr->XPlacementDevice, memory );
472
static FT_Error Get_ValueRecord( GPOS_Instance* gpi,
478
FT_Short pixel_value;
479
FT_Error error = FT_Err_Ok;
480
HB_GPOSHeader* gpos = gpi->gpos;
482
FT_UShort x_ppem, y_ppem;
483
FT_Fixed x_scale, y_scale;
489
x_ppem = gpi->face->size->metrics.x_ppem;
490
y_ppem = gpi->face->size->metrics.y_ppem;
491
x_scale = gpi->face->size->metrics.x_scale;
492
y_scale = gpi->face->size->metrics.y_scale;
494
/* design units -> fractional pixel */
496
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
497
gd->x_pos += x_scale * vr->XPlacement / 0x10000;
498
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
499
gd->y_pos += y_scale * vr->YPlacement / 0x10000;
500
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
501
gd->x_advance += x_scale * vr->XAdvance / 0x10000;
502
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
503
gd->y_advance += y_scale * vr->YAdvance / 0x10000;
507
/* pixel -> fractional pixel */
509
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
511
_HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
512
gd->x_pos += pixel_value << 6;
514
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
516
_HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
517
gd->y_pos += pixel_value << 6;
519
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
521
_HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
522
gd->x_advance += pixel_value << 6;
524
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
526
_HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
527
gd->y_advance += pixel_value << 6;
531
/* values returned from mmfunc() are already in fractional pixels */
533
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
535
error = (gpos->mmfunc)( gpi->face, vr->XIdPlacement,
536
&value, gpos->data );
541
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
543
error = (gpos->mmfunc)( gpi->face, vr->YIdPlacement,
544
&value, gpos->data );
549
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
551
error = (gpos->mmfunc)( gpi->face, vr->XIdAdvance,
552
&value, gpos->data );
555
gd->x_advance += value;
557
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
559
error = (gpos->mmfunc)( gpi->face, vr->YIdAdvance,
560
&value, gpos->data );
563
gd->y_advance += value;
575
static FT_Error Load_Anchor( HB_Anchor* an,
579
FT_Memory memory = stream->memory;
581
FT_ULong cur_offset, new_offset, base_offset;
584
base_offset = FILE_Pos();
586
if ( ACCESS_Frame( 2L ) )
589
an->PosFormat = GET_UShort();
593
switch ( an->PosFormat )
596
if ( ACCESS_Frame( 4L ) )
599
an->af.af1.XCoordinate = GET_Short();
600
an->af.af1.YCoordinate = GET_Short();
606
if ( ACCESS_Frame( 6L ) )
609
an->af.af2.XCoordinate = GET_Short();
610
an->af.af2.YCoordinate = GET_Short();
611
an->af.af2.AnchorPoint = GET_UShort();
617
if ( ACCESS_Frame( 6L ) )
620
an->af.af3.XCoordinate = GET_Short();
621
an->af.af3.YCoordinate = GET_Short();
623
new_offset = GET_UShort();
629
new_offset += base_offset;
631
cur_offset = FILE_Pos();
632
if ( FILE_Seek( new_offset ) ||
633
( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
634
stream ) ) != FT_Err_Ok )
636
(void)FILE_Seek( cur_offset );
640
an->af.af3.XDeviceTable.StartSize = 0;
641
an->af.af3.XDeviceTable.EndSize = 0;
642
an->af.af3.XDeviceTable.DeltaValue = NULL;
645
if ( ACCESS_Frame( 2L ) )
648
new_offset = GET_UShort();
654
new_offset += base_offset;
656
cur_offset = FILE_Pos();
657
if ( FILE_Seek( new_offset ) ||
658
( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
659
stream ) ) != FT_Err_Ok )
661
(void)FILE_Seek( cur_offset );
665
an->af.af3.YDeviceTable.StartSize = 0;
666
an->af.af3.YDeviceTable.EndSize = 0;
667
an->af.af3.YDeviceTable.DeltaValue = NULL;
672
if ( ACCESS_Frame( 4L ) )
675
an->af.af4.XIdAnchor = GET_UShort();
676
an->af.af4.YIdAnchor = GET_UShort();
682
return HB_Err_Invalid_GPOS_SubTable_Format;
688
_HB_OPEN_Free_Device( &an->af.af3.XDeviceTable, memory );
693
static void Free_Anchor( HB_Anchor* an,
696
if ( an->PosFormat == 3 )
698
_HB_OPEN_Free_Device( &an->af.af3.YDeviceTable, memory );
699
_HB_OPEN_Free_Device( &an->af.af3.XDeviceTable, memory );
704
static FT_Error Get_Anchor( GPOS_Instance* gpi,
706
FT_UShort glyph_index,
710
FT_Error error = FT_Err_Ok;
713
HB_GPOSHeader* gpos = gpi->gpos;
716
FT_Short pixel_value;
717
FT_UShort load_flags;
719
FT_UShort x_ppem, y_ppem;
720
FT_Fixed x_scale, y_scale;
723
x_ppem = gpi->face->size->metrics.x_ppem;
724
y_ppem = gpi->face->size->metrics.y_ppem;
725
x_scale = gpi->face->size->metrics.x_scale;
726
y_scale = gpi->face->size->metrics.y_scale;
728
switch ( an->PosFormat )
731
/* The special case of an empty AnchorTable */
733
return HB_Err_Not_Covered;
736
*x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
737
*y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
741
/* glyphs must be scaled */
743
load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE;
747
error = (gpos->gfunc)( gpi->face, glyph_index, load_flags );
751
if ( gpi->face->glyph->format != ft_glyph_format_outline )
752
return HB_Err_Invalid_GPOS_SubTable;
754
ap = an->af.af2.AnchorPoint;
756
outline = gpi->face->glyph->outline;
758
/* if outline.n_points is set to zero by gfunc(), we use the
759
design coordinate value pair. This can happen e.g. for
762
if ( !outline.n_points )
763
goto no_contour_point;
765
if ( ap >= outline.n_points )
766
return HB_Err_Invalid_GPOS_SubTable;
768
*x_value = outline.points[ap].x;
769
*y_value = outline.points[ap].y;
774
*x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
775
*y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
782
_HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
783
*x_value = pixel_value << 6;
784
_HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
785
*y_value = pixel_value << 6;
788
*x_value = *y_value = 0;
790
*x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
791
*y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
795
error = (gpos->mmfunc)( gpi->face, an->af.af4.XIdAnchor,
796
x_value, gpos->data );
800
error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor,
801
y_value, gpos->data );
813
static FT_Error Load_MarkArray ( HB_MarkArray* ma,
817
FT_Memory memory = stream->memory;
819
FT_UShort n, m, count;
820
FT_ULong cur_offset, new_offset, base_offset;
825
base_offset = FILE_Pos();
827
if ( ACCESS_Frame( 2L ) )
830
count = ma->MarkCount = GET_UShort();
834
ma->MarkRecord = NULL;
836
if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
841
for ( n = 0; n < count; n++ )
843
if ( ACCESS_Frame( 4L ) )
846
mr[n].Class = GET_UShort();
847
new_offset = GET_UShort() + base_offset;
851
cur_offset = FILE_Pos();
852
if ( FILE_Seek( new_offset ) ||
853
( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != FT_Err_Ok )
855
(void)FILE_Seek( cur_offset );
861
for ( m = 0; m < n; m++ )
862
Free_Anchor( &mr[m].MarkAnchor, memory );
869
static void Free_MarkArray( HB_MarkArray* ma,
877
if ( ma->MarkRecord )
879
count = ma->MarkCount;
882
for ( n = 0; n < count; n++ )
883
Free_Anchor( &mr[n].MarkAnchor, memory );
892
/* SinglePosFormat1 */
893
/* SinglePosFormat2 */
895
static FT_Error Load_SinglePos( HB_GPOS_SubTable* st,
899
FT_Memory memory = stream->memory;
900
HB_SinglePos* sp = &st->single;
902
FT_UShort n, m, count, format;
903
FT_ULong cur_offset, new_offset, base_offset;
908
base_offset = FILE_Pos();
910
if ( ACCESS_Frame( 6L ) )
913
sp->PosFormat = GET_UShort();
914
new_offset = GET_UShort() + base_offset;
916
format = sp->ValueFormat = GET_UShort();
921
return HB_Err_Invalid_GPOS_SubTable;
923
cur_offset = FILE_Pos();
924
if ( FILE_Seek( new_offset ) ||
925
( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != FT_Err_Ok )
927
(void)FILE_Seek( cur_offset );
929
switch ( sp->PosFormat )
932
error = Load_ValueRecord( &sp->spf.spf1.Value, format,
933
base_offset, stream );
939
if ( ACCESS_Frame( 2L ) )
942
count = sp->spf.spf2.ValueCount = GET_UShort();
946
sp->spf.spf2.Value = NULL;
948
if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
951
vr = sp->spf.spf2.Value;
953
for ( n = 0; n < count; n++ )
955
error = Load_ValueRecord( &vr[n], format, base_offset, stream );
962
return HB_Err_Invalid_GPOS_SubTable_Format;
968
for ( m = 0; m < n; m++ )
969
Free_ValueRecord( &vr[m], format, memory );
974
_HB_OPEN_Free_Coverage( &sp->Coverage, memory );
979
static void Free_SinglePos( HB_GPOS_SubTable* st,
982
FT_UShort n, count, format;
983
HB_SinglePos* sp = &st->single;
988
format = sp->ValueFormat;
990
switch ( sp->PosFormat )
993
Free_ValueRecord( &sp->spf.spf1.Value, format, memory );
997
if ( sp->spf.spf2.Value )
999
count = sp->spf.spf2.ValueCount;
1000
v = sp->spf.spf2.Value;
1002
for ( n = 0; n < count; n++ )
1003
Free_ValueRecord( &v[n], format, memory );
1010
_HB_OPEN_Free_Coverage( &sp->Coverage, memory );
1013
static FT_Error Lookup_DefaultPos( GPOS_Instance* gpi,
1014
HB_GPOS_SubTable* st,
1017
FT_UShort context_length,
1024
FT_UNUSED(context_length);
1025
FT_UNUSED(nesting_level);
1026
return HB_Err_Not_Covered;
1029
static FT_Error Lookup_SinglePos( GPOS_Instance* gpi,
1030
HB_GPOS_SubTable* st,
1033
FT_UShort context_length,
1036
FT_UShort index, property;
1038
HB_GPOSHeader* gpos = gpi->gpos;
1039
HB_SinglePos* sp = &st->single;
1041
FT_UNUSED(nesting_level);
1043
if ( context_length != 0xFFFF && context_length < 1 )
1044
return HB_Err_Not_Covered;
1046
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1049
error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
1053
switch ( sp->PosFormat )
1056
error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
1057
sp->ValueFormat, POSITION( buffer->in_pos ) );
1063
if ( index >= sp->spf.spf2.ValueCount )
1064
return HB_Err_Invalid_GPOS_SubTable;
1065
error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
1066
sp->ValueFormat, POSITION( buffer->in_pos ) );
1072
return HB_Err_Invalid_GPOS_SubTable;
1085
static FT_Error Load_PairSet ( HB_PairSet* ps,
1091
FT_Memory memory = stream->memory;
1093
FT_UShort n, m, count;
1094
FT_ULong base_offset;
1096
HB_PairValueRecord* pvr;
1099
base_offset = FILE_Pos();
1101
if ( ACCESS_Frame( 2L ) )
1104
count = ps->PairValueCount = GET_UShort();
1108
ps->PairValueRecord = NULL;
1110
if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
1113
pvr = ps->PairValueRecord;
1115
for ( n = 0; n < count; n++ )
1117
if ( ACCESS_Frame( 2L ) )
1120
pvr[n].SecondGlyph = GET_UShort();
1126
error = Load_ValueRecord( &pvr[n].Value1, format1,
1127
base_offset, stream );
1133
error = Load_ValueRecord( &pvr[n].Value2, format2,
1134
base_offset, stream );
1138
Free_ValueRecord( &pvr[n].Value1, format1, memory );
1147
for ( m = 0; m < n; m++ )
1150
Free_ValueRecord( &pvr[m].Value1, format1, memory );
1152
Free_ValueRecord( &pvr[m].Value2, format2, memory );
1160
static void Free_PairSet( HB_PairSet* ps,
1167
HB_PairValueRecord* pvr;
1170
if ( ps->PairValueRecord )
1172
count = ps->PairValueCount;
1173
pvr = ps->PairValueRecord;
1175
for ( n = 0; n < count; n++ )
1178
Free_ValueRecord( &pvr[n].Value1, format1, memory );
1180
Free_ValueRecord( &pvr[n].Value2, format2, memory );
1188
/* PairPosFormat1 */
1190
static FT_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
1196
FT_Memory memory = stream->memory;
1198
FT_UShort n, m, count;
1199
FT_ULong cur_offset, new_offset, base_offset;
1204
base_offset = FILE_Pos() - 8L;
1206
if ( ACCESS_Frame( 2L ) )
1209
count = ppf1->PairSetCount = GET_UShort();
1213
ppf1->PairSet = NULL;
1215
if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
1220
for ( n = 0; n < count; n++ )
1222
if ( ACCESS_Frame( 2L ) )
1225
new_offset = GET_UShort() + base_offset;
1229
cur_offset = FILE_Pos();
1230
if ( FILE_Seek( new_offset ) ||
1231
( error = Load_PairSet( &ps[n], format1,
1232
format2, stream ) ) != FT_Err_Ok )
1234
(void)FILE_Seek( cur_offset );
1240
for ( m = 0; m < n; m++ )
1241
Free_PairSet( &ps[m], format1, format2, memory );
1248
static void Free_PairPos1( HB_PairPosFormat1* ppf1,
1258
if ( ppf1->PairSet )
1260
count = ppf1->PairSetCount;
1263
for ( n = 0; n < count; n++ )
1264
Free_PairSet( &ps[n], format1, format2, memory );
1271
/* PairPosFormat2 */
1273
static FT_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
1279
FT_Memory memory = stream->memory;
1281
FT_UShort m, n, k, count1, count2;
1282
FT_ULong cur_offset, new_offset1, new_offset2, base_offset;
1284
HB_Class1Record* c1r;
1285
HB_Class2Record* c2r;
1288
base_offset = FILE_Pos() - 8L;
1290
if ( ACCESS_Frame( 8L ) )
1293
new_offset1 = GET_UShort() + base_offset;
1294
new_offset2 = GET_UShort() + base_offset;
1296
/* `Class1Count' and `Class2Count' are the upper limits for class
1297
values, thus we read it now to make additional safety checks. */
1299
count1 = ppf2->Class1Count = GET_UShort();
1300
count2 = ppf2->Class2Count = GET_UShort();
1304
cur_offset = FILE_Pos();
1305
if ( FILE_Seek( new_offset1 ) ||
1306
( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
1307
stream ) ) != FT_Err_Ok )
1309
if ( FILE_Seek( new_offset2 ) ||
1310
( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
1311
stream ) ) != FT_Err_Ok )
1313
(void)FILE_Seek( cur_offset );
1315
ppf2->Class1Record = NULL;
1317
if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
1320
c1r = ppf2->Class1Record;
1322
for ( m = 0; m < count1; m++ )
1324
c1r[m].Class2Record = NULL;
1326
if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
1329
c2r = c1r[m].Class2Record;
1331
for ( n = 0; n < count2; n++ )
1335
error = Load_ValueRecord( &c2r[n].Value1, format1,
1336
base_offset, stream );
1342
error = Load_ValueRecord( &c2r[n].Value2, format2,
1343
base_offset, stream );
1347
Free_ValueRecord( &c2r[n].Value1, format1, memory );
1356
for ( k = 0; k < n; k++ )
1359
Free_ValueRecord( &c2r[k].Value1, format1, memory );
1361
Free_ValueRecord( &c2r[k].Value2, format2, memory );
1369
for ( k = 0; k < m; k++ )
1371
c2r = c1r[k].Class2Record;
1373
for ( n = 0; n < count2; n++ )
1376
Free_ValueRecord( &c2r[n].Value1, format1, memory );
1378
Free_ValueRecord( &c2r[n].Value2, format2, memory );
1387
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2, memory );
1390
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1, memory );
1395
static void Free_PairPos2( HB_PairPosFormat2* ppf2,
1400
FT_UShort m, n, count1, count2;
1402
HB_Class1Record* c1r;
1403
HB_Class2Record* c2r;
1406
if ( ppf2->Class1Record )
1408
c1r = ppf2->Class1Record;
1409
count1 = ppf2->Class1Count;
1410
count2 = ppf2->Class2Count;
1412
for ( m = 0; m < count1; m++ )
1414
c2r = c1r[m].Class2Record;
1416
for ( n = 0; n < count2; n++ )
1419
Free_ValueRecord( &c2r[n].Value1, format1, memory );
1421
Free_ValueRecord( &c2r[n].Value2, format2, memory );
1429
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2, memory );
1430
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1, memory );
1435
static FT_Error Load_PairPos( HB_GPOS_SubTable* st,
1439
FT_Memory memory = stream->memory;
1440
HB_PairPos* pp = &st->pair;
1442
FT_UShort format1, format2;
1443
FT_ULong cur_offset, new_offset, base_offset;
1446
base_offset = FILE_Pos();
1448
if ( ACCESS_Frame( 8L ) )
1451
pp->PosFormat = GET_UShort();
1452
new_offset = GET_UShort() + base_offset;
1454
format1 = pp->ValueFormat1 = GET_UShort();
1455
format2 = pp->ValueFormat2 = GET_UShort();
1459
cur_offset = FILE_Pos();
1460
if ( FILE_Seek( new_offset ) ||
1461
( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != FT_Err_Ok )
1463
(void)FILE_Seek( cur_offset );
1465
switch ( pp->PosFormat )
1468
error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
1474
error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
1480
return HB_Err_Invalid_GPOS_SubTable_Format;
1486
_HB_OPEN_Free_Coverage( &pp->Coverage, memory );
1491
static void Free_PairPos( HB_GPOS_SubTable* st,
1494
FT_UShort format1, format2;
1495
HB_PairPos* pp = &st->pair;
1498
format1 = pp->ValueFormat1;
1499
format2 = pp->ValueFormat2;
1501
switch ( pp->PosFormat )
1504
Free_PairPos1( &pp->ppf.ppf1, format1, format2, memory );
1508
Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory );
1512
_HB_OPEN_Free_Coverage( &pp->Coverage, memory );
1516
static FT_Error Lookup_PairPos1( GPOS_Instance* gpi,
1517
HB_PairPosFormat1* ppf1,
1519
FT_UShort first_pos,
1525
FT_UShort numpvr, glyph2;
1527
HB_PairValueRecord* pvr;
1530
if ( index >= ppf1->PairSetCount )
1531
return HB_Err_Invalid_GPOS_SubTable;
1533
pvr = ppf1->PairSet[index].PairValueRecord;
1535
return HB_Err_Invalid_GPOS_SubTable;
1537
glyph2 = IN_CURGLYPH();
1539
for ( numpvr = ppf1->PairSet[index].PairValueCount;
1543
if ( glyph2 == pvr->SecondGlyph )
1545
error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1546
POSITION( first_pos ) );
1549
return Get_ValueRecord( gpi, &pvr->Value2, format2,
1550
POSITION( buffer->in_pos ) );
1554
return HB_Err_Not_Covered;
1558
static FT_Error Lookup_PairPos2( GPOS_Instance* gpi,
1559
HB_PairPosFormat2* ppf2,
1561
FT_UShort first_pos,
1568
HB_Class1Record* c1r;
1569
HB_Class2Record* c2r;
1572
error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
1574
if ( error && error != HB_Err_Not_Covered )
1576
error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1578
if ( error && error != HB_Err_Not_Covered )
1581
c1r = &ppf2->Class1Record[cl1];
1583
return HB_Err_Invalid_GPOS_SubTable;
1584
c2r = &c1r->Class2Record[cl2];
1586
error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1589
return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
1593
static FT_Error Lookup_PairPos( GPOS_Instance* gpi,
1594
HB_GPOS_SubTable* st,
1597
FT_UShort context_length,
1601
FT_UShort index, property, first_pos;
1602
HB_GPOSHeader* gpos = gpi->gpos;
1603
HB_PairPos* pp = &st->pair;
1605
FT_UNUSED(nesting_level);
1607
if ( buffer->in_pos >= buffer->in_length - 1 )
1608
return HB_Err_Not_Covered; /* Not enough glyphs in stream */
1610
if ( context_length != 0xFFFF && context_length < 2 )
1611
return HB_Err_Not_Covered;
1613
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1616
error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1622
first_pos = buffer->in_pos;
1625
while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
1626
flags, &property ) )
1628
if ( error && error != HB_Err_Not_Covered )
1631
if ( buffer->in_pos == buffer->in_length )
1632
return HB_Err_Not_Covered;
1636
switch ( pp->PosFormat )
1639
error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1641
pp->ValueFormat1, pp->ValueFormat2 );
1645
error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1646
pp->ValueFormat1, pp->ValueFormat2 );
1650
return HB_Err_Invalid_GPOS_SubTable_Format;
1653
/* adjusting the `next' glyph */
1655
if ( pp->ValueFormat2 )
1664
/* CursivePosFormat1 */
1666
static FT_Error Load_CursivePos( HB_GPOS_SubTable* st,
1670
FT_Memory memory = stream->memory;
1671
HB_CursivePos* cp = &st->cursive;
1673
FT_UShort n, m, count;
1674
FT_ULong cur_offset, new_offset, base_offset;
1676
HB_EntryExitRecord* eer;
1679
base_offset = FILE_Pos();
1681
if ( ACCESS_Frame( 4L ) )
1684
cp->PosFormat = GET_UShort();
1685
new_offset = GET_UShort() + base_offset;
1689
cur_offset = FILE_Pos();
1690
if ( FILE_Seek( new_offset ) ||
1691
( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != FT_Err_Ok )
1693
(void)FILE_Seek( cur_offset );
1695
if ( ACCESS_Frame( 2L ) )
1698
count = cp->EntryExitCount = GET_UShort();
1702
cp->EntryExitRecord = NULL;
1704
if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1707
eer = cp->EntryExitRecord;
1709
for ( n = 0; n < count; n++ )
1711
FT_ULong entry_offset;
1713
if ( ACCESS_Frame( 2L ) )
1716
entry_offset = new_offset = GET_UShort();
1722
new_offset += base_offset;
1724
cur_offset = FILE_Pos();
1725
if ( FILE_Seek( new_offset ) ||
1726
( error = Load_Anchor( &eer[n].EntryAnchor,
1727
stream ) ) != FT_Err_Ok )
1729
(void)FILE_Seek( cur_offset );
1732
eer[n].EntryAnchor.PosFormat = 0;
1734
if ( ACCESS_Frame( 2L ) )
1737
new_offset = GET_UShort();
1743
new_offset += base_offset;
1745
cur_offset = FILE_Pos();
1746
if ( FILE_Seek( new_offset ) ||
1747
( error = Load_Anchor( &eer[n].ExitAnchor,
1748
stream ) ) != FT_Err_Ok )
1751
Free_Anchor( &eer[n].EntryAnchor, memory );
1754
(void)FILE_Seek( cur_offset );
1757
eer[n].ExitAnchor.PosFormat = 0;
1763
for ( m = 0; m < n; m++ )
1765
Free_Anchor( &eer[m].EntryAnchor, memory );
1766
Free_Anchor( &eer[m].ExitAnchor, memory );
1772
_HB_OPEN_Free_Coverage( &cp->Coverage, memory );
1777
static void Free_CursivePos( HB_GPOS_SubTable* st,
1781
HB_CursivePos* cp = &st->cursive;
1783
HB_EntryExitRecord* eer;
1786
if ( cp->EntryExitRecord )
1788
count = cp->EntryExitCount;
1789
eer = cp->EntryExitRecord;
1791
for ( n = 0; n < count; n++ )
1793
Free_Anchor( &eer[n].EntryAnchor, memory );
1794
Free_Anchor( &eer[n].ExitAnchor, memory );
1800
_HB_OPEN_Free_Coverage( &cp->Coverage, memory );
1804
static FT_Error Lookup_CursivePos( GPOS_Instance* gpi,
1805
HB_GPOS_SubTable* st,
1808
FT_UShort context_length,
1811
FT_UShort index, property;
1813
HB_GPOSHeader* gpos = gpi->gpos;
1814
HB_CursivePos* cp = &st->cursive;
1816
HB_EntryExitRecord* eer;
1817
FT_Pos entry_x, entry_y;
1818
FT_Pos exit_x, exit_y;
1820
FT_UNUSED(nesting_level);
1822
if ( context_length != 0xFFFF && context_length < 1 )
1825
return HB_Err_Not_Covered;
1828
/* Glyphs not having the right GDEF properties will be ignored, i.e.,
1829
gpi->last won't be reset (contrary to user defined properties). */
1831
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1834
/* We don't handle mark glyphs here. According to Andrei, this isn't
1835
possible, but who knows... */
1837
if ( property == HB_GDEF_MARK )
1840
return HB_Err_Not_Covered;
1843
error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1850
if ( index >= cp->EntryExitCount )
1851
return HB_Err_Invalid_GPOS_SubTable;
1853
eer = &cp->EntryExitRecord[index];
1855
/* Now comes the messiest part of the whole OpenType
1856
specification. At first glance, cursive connections seem easy
1857
to understand, but there are pitfalls! The reason is that
1858
the specs don't mention how to compute the advance values
1859
resp. glyph offsets. I was told it would be an omission, to
1860
be fixed in the next OpenType version... Again many thanks to
1861
Andrei Burago <andreib@microsoft.com> for clarifications.
1863
Consider the following example:
1876
glyph1: advance width = 12
1877
anchor point = (3,1)
1879
glyph2: advance width = 11
1880
anchor point = (9,4)
1882
LSB is 1 for both glyphs (so the boxes drawn above are glyph
1883
bboxes). Writing direction is R2L; `0' denotes the glyph's
1886
Now the surprising part: The advance width of the *left* glyph
1887
(resp. of the *bottom* glyph) will be modified, no matter
1888
whether the writing direction is L2R or R2L (resp. T2B or
1889
B2T)! This assymetry is caused by the fact that the glyph's
1890
coordinate origin is always the lower left corner for all
1893
Continuing the above example, we can compute the new
1894
(horizontal) advance width of glyph2 as
1898
and the new vertical offset of glyph2 as
1903
Vertical writing direction is far more complicated:
1905
a) Assuming that we recompute the advance height of the lower glyph:
1910
+-----+--+ 1 | yadv1
1912
yadv2 | 0+--+------+ -- BSB1 --
1913
| 2 | -- -- y_offset
1915
BSB2 -- 0+--------+ --
1918
glyph1: advance height = 6
1919
anchor point = (3,1)
1921
glyph2: advance height = 7
1922
anchor point = (9,4)
1924
TSB is 1 for both glyphs; writing direction is T2B.
1927
BSB1 = yadv1 - (TSB1 + ymax1)
1928
BSB2 = yadv2 - (TSB2 + ymax2)
1931
vertical advance width of glyph2
1932
= y_offset + BSB2 - BSB1
1933
= (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1934
= y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1935
= y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1938
b) Assuming that we recompute the advance height of the upper glyph:
1943
TSB2 -- +-----+--+ 1 | yadv1 ymax1
1945
yadv2 | 0+--+------+ -- --
1946
ymax2 | 2 | -- y_offset
1951
glyph1: advance height = 6
1952
anchor point = (3,1)
1954
glyph2: advance height = 7
1955
anchor point = (9,4)
1957
TSB is 1 for both glyphs; writing direction is T2B.
1961
vertical advance width of glyph2
1962
= TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1963
= TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1966
Comparing a) with b) shows that b) is easier to compute. I'll wait
1967
for a reply from Andrei to see what should really be implemented...
1969
Since horizontal advance widths or vertical advance heights
1970
can be used alone but not together, no ambiguity occurs. */
1972
if ( gpi->last == 0xFFFF )
1975
/* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1978
error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1979
&entry_x, &entry_y );
1980
if ( error == HB_Err_Not_Covered )
1987
POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
1988
POSITION( buffer->in_pos )->new_advance = TRUE;
1992
POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
1993
POSITION( gpi->last )->new_advance = TRUE;
1996
if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
1998
POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
1999
POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
2003
POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
2004
POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
2008
error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
2010
if ( error == HB_Err_Not_Covered )
2014
gpi->last = buffer->in_pos;
2015
gpi->anchor_x = exit_x;
2016
gpi->anchor_y = exit_y;
2031
static FT_Error Load_BaseArray( HB_BaseArray* ba,
2032
FT_UShort num_classes,
2036
FT_Memory memory = stream->memory;
2038
FT_UShort m, n, k, count;
2039
FT_ULong cur_offset, new_offset, base_offset;
2045
base_offset = FILE_Pos();
2047
if ( ACCESS_Frame( 2L ) )
2050
count = ba->BaseCount = GET_UShort();
2054
ba->BaseRecord = NULL;
2056
if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2059
br = ba->BaseRecord;
2061
for ( m = 0; m < count; m++ )
2063
br[m].BaseAnchor = NULL;
2065
if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, HB_Anchor ) )
2068
ban = br[m].BaseAnchor;
2070
for ( n = 0; n < num_classes; n++ )
2072
if ( ACCESS_Frame( 2L ) )
2075
new_offset = GET_UShort() + base_offset;
2079
if (new_offset == base_offset) {
2080
/* Doulos SIL Regular is buggy and has zer offsets here. Skip */
2081
ban[n].PosFormat = 0;
2085
cur_offset = FILE_Pos();
2086
if ( FILE_Seek( new_offset ) ||
2087
( error = Load_Anchor( &ban[n], stream ) ) != FT_Err_Ok )
2089
(void)FILE_Seek( cur_offset );
2094
for ( k = 0; k < n; k++ )
2095
Free_Anchor( &ban[k], memory );
2102
for ( k = 0; k < m; k++ )
2104
ban = br[k].BaseAnchor;
2106
for ( n = 0; n < num_classes; n++ )
2107
Free_Anchor( &ban[n], memory );
2117
static void Free_BaseArray( HB_BaseArray* ba,
2118
FT_UShort num_classes,
2121
FT_UShort m, n, count;
2127
if ( ba->BaseRecord )
2129
count = ba->BaseCount;
2130
br = ba->BaseRecord;
2132
for ( m = 0; m < count; m++ )
2134
ban = br[m].BaseAnchor;
2136
for ( n = 0; n < num_classes; n++ )
2137
Free_Anchor( &ban[n], memory );
2147
/* MarkBasePosFormat1 */
2149
static FT_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
2153
FT_Memory memory = stream->memory;
2154
HB_MarkBasePos* mbp = &st->markbase;
2156
FT_ULong cur_offset, new_offset, base_offset;
2159
base_offset = FILE_Pos();
2161
if ( ACCESS_Frame( 4L ) )
2164
mbp->PosFormat = GET_UShort();
2165
new_offset = GET_UShort() + base_offset;
2169
if (mbp->PosFormat != 1)
2170
return HB_Err_Invalid_SubTable_Format;
2172
cur_offset = FILE_Pos();
2173
if ( FILE_Seek( new_offset ) ||
2174
( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != FT_Err_Ok )
2176
(void)FILE_Seek( cur_offset );
2178
if ( ACCESS_Frame( 2L ) )
2181
new_offset = GET_UShort() + base_offset;
2185
cur_offset = FILE_Pos();
2186
if ( FILE_Seek( new_offset ) ||
2187
( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != FT_Err_Ok )
2189
(void)FILE_Seek( cur_offset );
2191
if ( ACCESS_Frame( 4L ) )
2194
mbp->ClassCount = GET_UShort();
2195
new_offset = GET_UShort() + base_offset;
2199
cur_offset = FILE_Pos();
2200
if ( FILE_Seek( new_offset ) ||
2201
( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != FT_Err_Ok )
2203
(void)FILE_Seek( cur_offset );
2205
if ( ACCESS_Frame( 2L ) )
2208
new_offset = GET_UShort() + base_offset;
2212
cur_offset = FILE_Pos();
2213
if ( FILE_Seek( new_offset ) ||
2214
( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2215
stream ) ) != FT_Err_Ok )
2221
Free_MarkArray( &mbp->MarkArray, memory );
2224
_HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory );
2227
_HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory );
2232
static void Free_MarkBasePos( HB_GPOS_SubTable* st,
2235
HB_MarkBasePos* mbp = &st->markbase;
2237
Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory );
2238
Free_MarkArray( &mbp->MarkArray, memory );
2239
_HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory );
2240
_HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory );
2244
static FT_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
2245
HB_GPOS_SubTable* st,
2248
FT_UShort context_length,
2251
FT_UShort i, j, mark_index, base_index, property, class;
2252
FT_Pos x_mark_value, y_mark_value, x_base_value, y_base_value;
2254
HB_GPOSHeader* gpos = gpi->gpos;
2255
HB_MarkBasePos* mbp = &st->markbase;
2260
HB_Anchor* mark_anchor;
2261
HB_Anchor* base_anchor;
2265
FT_UNUSED(nesting_level);
2267
if ( context_length != 0xFFFF && context_length < 1 )
2268
return HB_Err_Not_Covered;
2270
if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
2271
return HB_Err_Not_Covered;
2273
if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2274
flags, &property ) )
2277
error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2282
/* now we search backwards for a non-mark glyph */
2285
j = buffer->in_pos - 1;
2287
while ( i <= buffer->in_pos )
2289
error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2294
if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2301
/* The following assertion is too strong -- at least for mangal.ttf. */
2303
if ( property != HB_GDEF_BASE_GLYPH )
2304
return HB_Err_Not_Covered;
2307
if ( i > buffer->in_pos )
2308
return HB_Err_Not_Covered;
2310
error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2315
ma = &mbp->MarkArray;
2317
if ( mark_index >= ma->MarkCount )
2318
return HB_Err_Invalid_GPOS_SubTable;
2320
class = ma->MarkRecord[mark_index].Class;
2321
mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2323
if ( class >= mbp->ClassCount )
2324
return HB_Err_Invalid_GPOS_SubTable;
2326
ba = &mbp->BaseArray;
2328
if ( base_index >= ba->BaseCount )
2329
return HB_Err_Invalid_GPOS_SubTable;
2331
br = &ba->BaseRecord[base_index];
2332
base_anchor = &br->BaseAnchor[class];
2334
error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2335
&x_mark_value, &y_mark_value );
2339
error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2340
&x_base_value, &y_base_value );
2344
/* anchor points are not cumulative */
2346
o = POSITION( buffer->in_pos );
2348
o->x_pos = x_base_value - x_mark_value;
2349
o->y_pos = y_base_value - y_mark_value;
2362
/* LigatureAttach */
2364
static FT_Error Load_LigatureAttach( HB_LigatureAttach* lat,
2365
FT_UShort num_classes,
2369
FT_Memory memory = stream->memory;
2371
FT_UShort m, n, k, count;
2372
FT_ULong cur_offset, new_offset, base_offset;
2374
HB_ComponentRecord* cr;
2378
base_offset = FILE_Pos();
2380
if ( ACCESS_Frame( 2L ) )
2383
count = lat->ComponentCount = GET_UShort();
2387
lat->ComponentRecord = NULL;
2389
if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2392
cr = lat->ComponentRecord;
2394
for ( m = 0; m < count; m++ )
2396
cr[m].LigatureAnchor = NULL;
2398
if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
2401
lan = cr[m].LigatureAnchor;
2403
for ( n = 0; n < num_classes; n++ )
2405
if ( ACCESS_Frame( 2L ) )
2408
new_offset = GET_UShort();
2414
new_offset += base_offset;
2416
cur_offset = FILE_Pos();
2417
if ( FILE_Seek( new_offset ) ||
2418
( error = Load_Anchor( &lan[n], stream ) ) != FT_Err_Ok )
2420
(void)FILE_Seek( cur_offset );
2423
lan[n].PosFormat = 0;
2428
for ( k = 0; k < n; k++ )
2429
Free_Anchor( &lan[k], memory );
2436
for ( k = 0; k < m; k++ )
2438
lan = cr[k].LigatureAnchor;
2440
for ( n = 0; n < num_classes; n++ )
2441
Free_Anchor( &lan[n], memory );
2451
static void Free_LigatureAttach( HB_LigatureAttach* lat,
2452
FT_UShort num_classes,
2455
FT_UShort m, n, count;
2457
HB_ComponentRecord* cr;
2461
if ( lat->ComponentRecord )
2463
count = lat->ComponentCount;
2464
cr = lat->ComponentRecord;
2466
for ( m = 0; m < count; m++ )
2468
lan = cr[m].LigatureAnchor;
2470
for ( n = 0; n < num_classes; n++ )
2471
Free_Anchor( &lan[n], memory );
2483
static FT_Error Load_LigatureArray( HB_LigatureArray* la,
2484
FT_UShort num_classes,
2488
FT_Memory memory = stream->memory;
2490
FT_UShort n, m, count;
2491
FT_ULong cur_offset, new_offset, base_offset;
2493
HB_LigatureAttach* lat;
2496
base_offset = FILE_Pos();
2498
if ( ACCESS_Frame( 2L ) )
2501
count = la->LigatureCount = GET_UShort();
2505
la->LigatureAttach = NULL;
2507
if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2510
lat = la->LigatureAttach;
2512
for ( n = 0; n < count; n++ )
2514
if ( ACCESS_Frame( 2L ) )
2517
new_offset = GET_UShort() + base_offset;
2521
cur_offset = FILE_Pos();
2522
if ( FILE_Seek( new_offset ) ||
2523
( error = Load_LigatureAttach( &lat[n], num_classes,
2524
stream ) ) != FT_Err_Ok )
2526
(void)FILE_Seek( cur_offset );
2532
for ( m = 0; m < n; m++ )
2533
Free_LigatureAttach( &lat[m], num_classes, memory );
2540
static void Free_LigatureArray( HB_LigatureArray* la,
2541
FT_UShort num_classes,
2546
HB_LigatureAttach* lat;
2549
if ( la->LigatureAttach )
2551
count = la->LigatureCount;
2552
lat = la->LigatureAttach;
2554
for ( n = 0; n < count; n++ )
2555
Free_LigatureAttach( &lat[n], num_classes, memory );
2562
/* MarkLigPosFormat1 */
2564
static FT_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
2568
FT_Memory memory = stream->memory;
2569
HB_MarkLigPos* mlp = &st->marklig;
2571
FT_ULong cur_offset, new_offset, base_offset;
2574
base_offset = FILE_Pos();
2576
if ( ACCESS_Frame( 4L ) )
2579
mlp->PosFormat = GET_UShort();
2580
new_offset = GET_UShort() + base_offset;
2584
cur_offset = FILE_Pos();
2585
if ( FILE_Seek( new_offset ) ||
2586
( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != FT_Err_Ok )
2588
(void)FILE_Seek( cur_offset );
2590
if ( ACCESS_Frame( 2L ) )
2593
new_offset = GET_UShort() + base_offset;
2597
cur_offset = FILE_Pos();
2598
if ( FILE_Seek( new_offset ) ||
2599
( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2600
stream ) ) != FT_Err_Ok )
2602
(void)FILE_Seek( cur_offset );
2604
if ( ACCESS_Frame( 4L ) )
2607
mlp->ClassCount = GET_UShort();
2608
new_offset = GET_UShort() + base_offset;
2612
cur_offset = FILE_Pos();
2613
if ( FILE_Seek( new_offset ) ||
2614
( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != FT_Err_Ok )
2616
(void)FILE_Seek( cur_offset );
2618
if ( ACCESS_Frame( 2L ) )
2621
new_offset = GET_UShort() + base_offset;
2625
cur_offset = FILE_Pos();
2626
if ( FILE_Seek( new_offset ) ||
2627
( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2628
stream ) ) != FT_Err_Ok )
2634
Free_MarkArray( &mlp->MarkArray, memory );
2637
_HB_OPEN_Free_Coverage( &mlp->LigatureCoverage, memory );
2640
_HB_OPEN_Free_Coverage( &mlp->MarkCoverage, memory );
2645
static void Free_MarkLigPos( HB_GPOS_SubTable* st,
2648
HB_MarkLigPos* mlp = &st->marklig;
2650
Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory );
2651
Free_MarkArray( &mlp->MarkArray, memory );
2652
_HB_OPEN_Free_Coverage( &mlp->LigatureCoverage, memory );
2653
_HB_OPEN_Free_Coverage( &mlp->MarkCoverage, memory );
2657
static FT_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
2658
HB_GPOS_SubTable* st,
2661
FT_UShort context_length,
2664
FT_UShort i, j, mark_index, lig_index, property, class;
2665
FT_UShort mark_glyph;
2666
FT_Pos x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2668
HB_GPOSHeader* gpos = gpi->gpos;
2669
HB_MarkLigPos* mlp = &st->marklig;
2672
HB_LigatureArray* la;
2673
HB_LigatureAttach* lat;
2674
HB_ComponentRecord* cr;
2675
FT_UShort comp_index;
2676
HB_Anchor* mark_anchor;
2677
HB_Anchor* lig_anchor;
2681
FT_UNUSED(nesting_level);
2683
if ( context_length != 0xFFFF && context_length < 1 )
2684
return HB_Err_Not_Covered;
2686
if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
2687
return HB_Err_Not_Covered;
2689
mark_glyph = IN_CURGLYPH();
2691
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
2694
error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2698
/* now we search backwards for a non-mark glyph */
2701
j = buffer->in_pos - 1;
2703
while ( i <= buffer->in_pos )
2705
error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2710
if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2717
/* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2718
too strong, thus it is commented out. */
2720
if ( property != HB_GDEF_LIGATURE )
2721
return HB_Err_Not_Covered;
2724
if ( i > buffer->in_pos )
2725
return HB_Err_Not_Covered;
2727
error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2732
ma = &mlp->MarkArray;
2734
if ( mark_index >= ma->MarkCount )
2735
return HB_Err_Invalid_GPOS_SubTable;
2737
class = ma->MarkRecord[mark_index].Class;
2738
mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2740
if ( class >= mlp->ClassCount )
2741
return HB_Err_Invalid_GPOS_SubTable;
2743
la = &mlp->LigatureArray;
2745
if ( lig_index >= la->LigatureCount )
2746
return HB_Err_Invalid_GPOS_SubTable;
2748
lat = &la->LigatureAttach[lig_index];
2750
/* We must now check whether the ligature ID of the current mark glyph
2751
is identical to the ligature ID of the found ligature. If yes, we
2752
can directly use the component index. If not, we attach the mark
2753
glyph to the last component of the ligature. */
2755
if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
2757
comp_index = IN_COMPONENT( buffer->in_pos );
2758
if ( comp_index >= lat->ComponentCount )
2759
return HB_Err_Not_Covered;
2762
comp_index = lat->ComponentCount - 1;
2764
cr = &lat->ComponentRecord[comp_index];
2765
lig_anchor = &cr->LigatureAnchor[class];
2767
error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2768
&x_mark_value, &y_mark_value );
2771
error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2772
&x_lig_value, &y_lig_value );
2776
/* anchor points are not cumulative */
2778
o = POSITION( buffer->in_pos );
2780
o->x_pos = x_lig_value - x_mark_value;
2781
o->y_pos = y_lig_value - y_mark_value;
2796
static FT_Error Load_Mark2Array( HB_Mark2Array* m2a,
2797
FT_UShort num_classes,
2801
FT_Memory memory = stream->memory;
2803
FT_UShort k, m, n, count;
2804
FT_ULong cur_offset, new_offset, base_offset;
2806
HB_Mark2Record* m2r;
2810
base_offset = FILE_Pos();
2812
if ( ACCESS_Frame( 2L ) )
2815
count = m2a->Mark2Count = GET_UShort();
2819
m2a->Mark2Record = NULL;
2821
if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2824
m2r = m2a->Mark2Record;
2826
for ( m = 0; m < count; m++ )
2828
m2r[m].Mark2Anchor = NULL;
2830
if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, HB_Anchor ) )
2833
m2an = m2r[m].Mark2Anchor;
2835
for ( n = 0; n < num_classes; n++ )
2837
if ( ACCESS_Frame( 2L ) )
2840
new_offset = GET_UShort() + base_offset;
2844
cur_offset = FILE_Pos();
2845
if ( FILE_Seek( new_offset ) ||
2846
( error = Load_Anchor( &m2an[n], stream ) ) != FT_Err_Ok )
2848
(void)FILE_Seek( cur_offset );
2853
for ( k = 0; k < n; k++ )
2854
Free_Anchor( &m2an[k], memory );
2861
for ( k = 0; k < m; k++ )
2863
m2an = m2r[k].Mark2Anchor;
2865
for ( n = 0; n < num_classes; n++ )
2866
Free_Anchor( &m2an[n], memory );
2876
static void Free_Mark2Array( HB_Mark2Array* m2a,
2877
FT_UShort num_classes,
2880
FT_UShort m, n, count;
2882
HB_Mark2Record* m2r;
2886
if ( m2a->Mark2Record )
2888
count = m2a->Mark2Count;
2889
m2r = m2a->Mark2Record;
2891
for ( m = 0; m < count; m++ )
2893
m2an = m2r[m].Mark2Anchor;
2895
for ( n = 0; n < num_classes; n++ )
2896
Free_Anchor( &m2an[n], memory );
2906
/* MarkMarkPosFormat1 */
2908
static FT_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
2912
FT_Memory memory = stream->memory;
2913
HB_MarkMarkPos* mmp = &st->markmark;
2915
FT_ULong cur_offset, new_offset, base_offset;
2918
base_offset = FILE_Pos();
2920
if ( ACCESS_Frame( 4L ) )
2923
mmp->PosFormat = GET_UShort();
2924
new_offset = GET_UShort() + base_offset;
2928
cur_offset = FILE_Pos();
2929
if ( FILE_Seek( new_offset ) ||
2930
( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2931
stream ) ) != FT_Err_Ok )
2933
(void)FILE_Seek( cur_offset );
2935
if ( ACCESS_Frame( 2L ) )
2938
new_offset = GET_UShort() + base_offset;
2942
cur_offset = FILE_Pos();
2943
if ( FILE_Seek( new_offset ) ||
2944
( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2945
stream ) ) != FT_Err_Ok )
2947
(void)FILE_Seek( cur_offset );
2949
if ( ACCESS_Frame( 4L ) )
2952
mmp->ClassCount = GET_UShort();
2953
new_offset = GET_UShort() + base_offset;
2957
cur_offset = FILE_Pos();
2958
if ( FILE_Seek( new_offset ) ||
2959
( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != FT_Err_Ok )
2961
(void)FILE_Seek( cur_offset );
2963
if ( ACCESS_Frame( 2L ) )
2966
new_offset = GET_UShort() + base_offset;
2970
cur_offset = FILE_Pos();
2971
if ( FILE_Seek( new_offset ) ||
2972
( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2973
stream ) ) != FT_Err_Ok )
2979
Free_MarkArray( &mmp->Mark1Array, memory );
2982
_HB_OPEN_Free_Coverage( &mmp->Mark2Coverage, memory );
2985
_HB_OPEN_Free_Coverage( &mmp->Mark1Coverage, memory );
2990
static void Free_MarkMarkPos( HB_GPOS_SubTable* st,
2993
HB_MarkMarkPos* mmp = &st->markmark;
2995
Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory );
2996
Free_MarkArray( &mmp->Mark1Array, memory );
2997
_HB_OPEN_Free_Coverage( &mmp->Mark2Coverage, memory );
2998
_HB_OPEN_Free_Coverage( &mmp->Mark1Coverage, memory );
3002
static FT_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
3003
HB_GPOS_SubTable* st,
3006
FT_UShort context_length,
3009
FT_UShort i, j, mark1_index, mark2_index, property, class;
3010
FT_Pos x_mark1_value, y_mark1_value,
3011
x_mark2_value, y_mark2_value;
3013
HB_GPOSHeader* gpos = gpi->gpos;
3014
HB_MarkMarkPos* mmp = &st->markmark;
3018
HB_Mark2Record* m2r;
3019
HB_Anchor* mark1_anchor;
3020
HB_Anchor* mark2_anchor;
3024
FT_UNUSED(nesting_level);
3026
if ( context_length != 0xFFFF && context_length < 1 )
3027
return HB_Err_Not_Covered;
3029
if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
3030
return HB_Err_Not_Covered;
3032
if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
3033
flags, &property ) )
3036
error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
3041
/* now we search backwards for a suitable mark glyph until a non-mark
3044
if ( buffer->in_pos == 0 )
3045
return HB_Err_Not_Covered;
3048
j = buffer->in_pos - 1;
3049
while ( i <= buffer->in_pos )
3051
error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
3056
if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
3057
return HB_Err_Not_Covered;
3059
if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
3061
if ( property == (flags & 0xFF00) )
3071
error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3076
ma1 = &mmp->Mark1Array;
3078
if ( mark1_index >= ma1->MarkCount )
3079
return HB_Err_Invalid_GPOS_SubTable;
3081
class = ma1->MarkRecord[mark1_index].Class;
3082
mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3084
if ( class >= mmp->ClassCount )
3085
return HB_Err_Invalid_GPOS_SubTable;
3087
ma2 = &mmp->Mark2Array;
3089
if ( mark2_index >= ma2->Mark2Count )
3090
return HB_Err_Invalid_GPOS_SubTable;
3092
m2r = &ma2->Mark2Record[mark2_index];
3093
mark2_anchor = &m2r->Mark2Anchor[class];
3095
error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3096
&x_mark1_value, &y_mark1_value );
3099
error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3100
&x_mark2_value, &y_mark2_value );
3104
/* anchor points are not cumulative */
3106
o = POSITION( buffer->in_pos );
3108
o->x_pos = x_mark2_value - x_mark1_value;
3109
o->y_pos = y_mark2_value - y_mark1_value;
3120
/* Do the actual positioning for a context positioning (either format
3121
7 or 8). This is only called after we've determined that the stream
3122
matches the subrule. */
3124
static FT_Error Do_ContextPos( GPOS_Instance* gpi,
3125
FT_UShort GlyphCount,
3127
HB_PosLookupRecord* pos,
3132
FT_UShort i, old_pos;
3137
while ( i < GlyphCount )
3139
if ( PosCount && i == pos->SequenceIndex )
3141
old_pos = buffer->in_pos;
3143
/* Do a positioning */
3145
error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3146
GlyphCount, nesting_level );
3153
i += buffer->in_pos - old_pos;
3170
static FT_Error Load_PosRule( HB_PosRule* pr,
3174
FT_Memory memory = stream->memory;
3179
HB_PosLookupRecord* plr;
3182
if ( ACCESS_Frame( 4L ) )
3185
pr->GlyphCount = GET_UShort();
3186
pr->PosCount = GET_UShort();
3192
count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3194
if ( ALLOC_ARRAY( pr->Input, count, FT_UShort ) )
3199
if ( ACCESS_Frame( count * 2L ) )
3202
for ( n = 0; n < count; n++ )
3203
i[n] = GET_UShort();
3207
pr->PosLookupRecord = NULL;
3209
count = pr->PosCount;
3211
if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3214
plr = pr->PosLookupRecord;
3216
if ( ACCESS_Frame( count * 4L ) )
3219
for ( n = 0; n < count; n++ )
3221
plr[n].SequenceIndex = GET_UShort();
3222
plr[n].LookupListIndex = GET_UShort();
3238
static void Free_PosRule( HB_PosRule* pr,
3241
FREE( pr->PosLookupRecord );
3248
static FT_Error Load_PosRuleSet( HB_PosRuleSet* prs,
3252
FT_Memory memory = stream->memory;
3254
FT_UShort n, m, count;
3255
FT_ULong cur_offset, new_offset, base_offset;
3260
base_offset = FILE_Pos();
3262
if ( ACCESS_Frame( 2L ) )
3265
count = prs->PosRuleCount = GET_UShort();
3269
prs->PosRule = NULL;
3271
if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3276
for ( n = 0; n < count; n++ )
3278
if ( ACCESS_Frame( 2L ) )
3281
new_offset = GET_UShort() + base_offset;
3285
cur_offset = FILE_Pos();
3286
if ( FILE_Seek( new_offset ) ||
3287
( error = Load_PosRule( &pr[n], stream ) ) != FT_Err_Ok )
3289
(void)FILE_Seek( cur_offset );
3295
for ( m = 0; m < n; m++ )
3296
Free_PosRule( &pr[m], memory );
3303
static void Free_PosRuleSet( HB_PosRuleSet* prs,
3313
count = prs->PosRuleCount;
3316
for ( n = 0; n < count; n++ )
3317
Free_PosRule( &pr[n], memory );
3324
/* ContextPosFormat1 */
3326
static FT_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
3330
FT_Memory memory = stream->memory;
3332
FT_UShort n, m, count;
3333
FT_ULong cur_offset, new_offset, base_offset;
3338
base_offset = FILE_Pos() - 2L;
3340
if ( ACCESS_Frame( 2L ) )
3343
new_offset = GET_UShort() + base_offset;
3347
cur_offset = FILE_Pos();
3348
if ( FILE_Seek( new_offset ) ||
3349
( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != FT_Err_Ok )
3351
(void)FILE_Seek( cur_offset );
3353
if ( ACCESS_Frame( 2L ) )
3356
count = cpf1->PosRuleSetCount = GET_UShort();
3360
cpf1->PosRuleSet = NULL;
3362
if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3365
prs = cpf1->PosRuleSet;
3367
for ( n = 0; n < count; n++ )
3369
if ( ACCESS_Frame( 2L ) )
3372
new_offset = GET_UShort() + base_offset;
3376
cur_offset = FILE_Pos();
3377
if ( FILE_Seek( new_offset ) ||
3378
( error = Load_PosRuleSet( &prs[n], stream ) ) != FT_Err_Ok )
3380
(void)FILE_Seek( cur_offset );
3386
for ( m = 0; m < n; m++ )
3387
Free_PosRuleSet( &prs[m], memory );
3392
_HB_OPEN_Free_Coverage( &cpf1->Coverage, memory );
3397
static void Free_ContextPos1( HB_ContextPosFormat1* cpf1,
3405
if ( cpf1->PosRuleSet )
3407
count = cpf1->PosRuleSetCount;
3408
prs = cpf1->PosRuleSet;
3410
for ( n = 0; n < count; n++ )
3411
Free_PosRuleSet( &prs[n], memory );
3416
_HB_OPEN_Free_Coverage( &cpf1->Coverage, memory );
3422
static FT_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
3423
HB_PosClassRule* pcr,
3427
FT_Memory memory = stream->memory;
3432
HB_PosLookupRecord* plr;
3436
if ( ACCESS_Frame( 4L ) )
3439
pcr->GlyphCount = GET_UShort();
3440
pcr->PosCount = GET_UShort();
3444
if ( pcr->GlyphCount > cpf2->MaxContextLength )
3445
cpf2->MaxContextLength = pcr->GlyphCount;
3449
count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3451
if ( ALLOC_ARRAY( pcr->Class, count, FT_UShort ) )
3455
d = cpf2->ClassDef.Defined;
3457
if ( ACCESS_Frame( count * 2L ) )
3460
for ( n = 0; n < count; n++ )
3462
c[n] = GET_UShort();
3464
/* We check whether the specific class is used at all. If not,
3465
class 0 is used instead. */
3473
pcr->PosLookupRecord = NULL;
3475
count = pcr->PosCount;
3477
if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3480
plr = pcr->PosLookupRecord;
3482
if ( ACCESS_Frame( count * 4L ) )
3485
for ( n = 0; n < count; n++ )
3487
plr[n].SequenceIndex = GET_UShort();
3488
plr[n].LookupListIndex = GET_UShort();
3504
static void Free_PosClassRule( HB_PosClassRule* pcr,
3507
FREE( pcr->PosLookupRecord );
3514
static FT_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
3515
HB_PosClassSet* pcs,
3519
FT_Memory memory = stream->memory;
3521
FT_UShort n, m, count;
3522
FT_ULong cur_offset, new_offset, base_offset;
3524
HB_PosClassRule* pcr;
3527
base_offset = FILE_Pos();
3529
if ( ACCESS_Frame( 2L ) )
3532
count = pcs->PosClassRuleCount = GET_UShort();
3536
pcs->PosClassRule = NULL;
3538
if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3541
pcr = pcs->PosClassRule;
3543
for ( n = 0; n < count; n++ )
3545
if ( ACCESS_Frame( 2L ) )
3548
new_offset = GET_UShort() + base_offset;
3552
cur_offset = FILE_Pos();
3553
if ( FILE_Seek( new_offset ) ||
3554
( error = Load_PosClassRule( cpf2, &pcr[n],
3555
stream ) ) != FT_Err_Ok )
3557
(void)FILE_Seek( cur_offset );
3563
for ( m = 0; m < n; m++ )
3564
Free_PosClassRule( &pcr[m], memory );
3571
static void Free_PosClassSet( HB_PosClassSet* pcs,
3576
HB_PosClassRule* pcr;
3579
if ( pcs->PosClassRule )
3581
count = pcs->PosClassRuleCount;
3582
pcr = pcs->PosClassRule;
3584
for ( n = 0; n < count; n++ )
3585
Free_PosClassRule( &pcr[n], memory );
3592
/* ContextPosFormat2 */
3594
static FT_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
3598
FT_Memory memory = stream->memory;
3600
FT_UShort n, m, count;
3601
FT_ULong cur_offset, new_offset, base_offset;
3603
HB_PosClassSet* pcs;
3606
base_offset = FILE_Pos() - 2;
3608
if ( ACCESS_Frame( 2L ) )
3611
new_offset = GET_UShort() + base_offset;
3615
cur_offset = FILE_Pos();
3616
if ( FILE_Seek( new_offset ) ||
3617
( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != FT_Err_Ok )
3619
(void)FILE_Seek( cur_offset );
3621
if ( ACCESS_Frame( 4L ) )
3624
new_offset = GET_UShort() + base_offset;
3626
/* `PosClassSetCount' is the upper limit for class values, thus we
3627
read it now to make an additional safety check. */
3629
count = cpf2->PosClassSetCount = GET_UShort();
3633
cur_offset = FILE_Pos();
3634
if ( FILE_Seek( new_offset ) ||
3635
( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3636
stream ) ) != FT_Err_Ok )
3638
(void)FILE_Seek( cur_offset );
3640
cpf2->PosClassSet = NULL;
3641
cpf2->MaxContextLength = 0;
3643
if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3646
pcs = cpf2->PosClassSet;
3648
for ( n = 0; n < count; n++ )
3650
if ( ACCESS_Frame( 2L ) )
3653
new_offset = GET_UShort() + base_offset;
3657
if ( new_offset != base_offset ) /* not a NULL offset */
3659
cur_offset = FILE_Pos();
3660
if ( FILE_Seek( new_offset ) ||
3661
( error = Load_PosClassSet( cpf2, &pcs[n],
3662
stream ) ) != FT_Err_Ok )
3664
(void)FILE_Seek( cur_offset );
3668
/* we create a PosClassSet table with no entries */
3670
cpf2->PosClassSet[n].PosClassRuleCount = 0;
3671
cpf2->PosClassSet[n].PosClassRule = NULL;
3678
for ( m = 0; m < n; n++ )
3679
Free_PosClassSet( &pcs[m], memory );
3684
_HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef, memory );
3687
_HB_OPEN_Free_Coverage( &cpf2->Coverage, memory );
3692
static void Free_ContextPos2( HB_ContextPosFormat2* cpf2,
3697
HB_PosClassSet* pcs;
3700
if ( cpf2->PosClassSet )
3702
count = cpf2->PosClassSetCount;
3703
pcs = cpf2->PosClassSet;
3705
for ( n = 0; n < count; n++ )
3706
Free_PosClassSet( &pcs[n], memory );
3711
_HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef, memory );
3712
_HB_OPEN_Free_Coverage( &cpf2->Coverage, memory );
3716
/* ContextPosFormat3 */
3718
static FT_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
3722
FT_Memory memory = stream->memory;
3725
FT_ULong cur_offset, new_offset, base_offset;
3728
HB_PosLookupRecord* plr;
3731
base_offset = FILE_Pos() - 2L;
3733
if ( ACCESS_Frame( 4L ) )
3736
cpf3->GlyphCount = GET_UShort();
3737
cpf3->PosCount = GET_UShort();
3741
cpf3->Coverage = NULL;
3743
count = cpf3->GlyphCount;
3745
if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3750
for ( n = 0; n < count; n++ )
3752
if ( ACCESS_Frame( 2L ) )
3755
new_offset = GET_UShort() + base_offset;
3759
cur_offset = FILE_Pos();
3760
if ( FILE_Seek( new_offset ) ||
3761
( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != FT_Err_Ok )
3763
(void)FILE_Seek( cur_offset );
3766
cpf3->PosLookupRecord = NULL;
3768
count = cpf3->PosCount;
3770
if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3773
plr = cpf3->PosLookupRecord;
3775
if ( ACCESS_Frame( count * 4L ) )
3778
for ( n = 0; n < count; n++ )
3780
plr[n].SequenceIndex = GET_UShort();
3781
plr[n].LookupListIndex = GET_UShort();
3792
for ( n = 0; n < count; n++ )
3793
_HB_OPEN_Free_Coverage( &c[n], memory );
3800
static void Free_ContextPos3( HB_ContextPosFormat3* cpf3,
3808
FREE( cpf3->PosLookupRecord );
3810
if ( cpf3->Coverage )
3812
count = cpf3->GlyphCount;
3815
for ( n = 0; n < count; n++ )
3816
_HB_OPEN_Free_Coverage( &c[n], memory );
3825
static FT_Error Load_ContextPos( HB_GPOS_SubTable* st,
3829
HB_ContextPos* cp = &st->context;
3832
if ( ACCESS_Frame( 2L ) )
3835
cp->PosFormat = GET_UShort();
3839
switch ( cp->PosFormat )
3842
return Load_ContextPos1( &cp->cpf.cpf1, stream );
3845
return Load_ContextPos2( &cp->cpf.cpf2, stream );
3848
return Load_ContextPos3( &cp->cpf.cpf3, stream );
3851
return HB_Err_Invalid_GPOS_SubTable_Format;
3854
return FT_Err_Ok; /* never reached */
3858
static void Free_ContextPos( HB_GPOS_SubTable* st,
3861
HB_ContextPos* cp = &st->context;
3863
switch ( cp->PosFormat )
3866
Free_ContextPos1( &cp->cpf.cpf1, memory );
3870
Free_ContextPos2( &cp->cpf.cpf2, memory );
3874
Free_ContextPos3( &cp->cpf.cpf3, memory );
3880
static FT_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3881
HB_ContextPosFormat1* cpf1,
3884
FT_UShort context_length,
3887
FT_UShort index, property;
3888
FT_UShort i, j, k, numpr;
3890
HB_GPOSHeader* gpos = gpi->gpos;
3893
HB_GDEFHeader* gdef;
3898
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3901
error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3905
pr = cpf1->PosRuleSet[index].PosRule;
3906
numpr = cpf1->PosRuleSet[index].PosRuleCount;
3908
for ( k = 0; k < numpr; k++ )
3910
if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3913
if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3914
goto next_posrule; /* context is too long */
3916
for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3918
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3920
if ( error && error != HB_Err_Not_Covered )
3923
if ( j + pr[k].GlyphCount - i == (FT_Long)buffer->in_length )
3928
if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3932
return Do_ContextPos( gpi, pr[k].GlyphCount,
3933
pr[k].PosCount, pr[k].PosLookupRecord,
3941
return HB_Err_Not_Covered;
3945
static FT_Error Lookup_ContextPos2( GPOS_Instance* gpi,
3946
HB_ContextPosFormat2* cpf2,
3949
FT_UShort context_length,
3952
FT_UShort index, property;
3954
FT_Memory memory = gpi->face->memory;
3955
FT_UShort i, j, k, known_classes;
3959
HB_GPOSHeader* gpos = gpi->gpos;
3961
HB_PosClassSet* pcs;
3962
HB_PosClassRule* pr;
3963
HB_GDEFHeader* gdef;
3968
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3971
/* Note: The coverage table in format 2 doesn't give an index into
3972
anything. It just lets us know whether or not we need to
3973
do any lookup at all. */
3975
error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3979
if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) )
3982
error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3983
&classes[0], NULL );
3984
if ( error && error != HB_Err_Not_Covered )
3988
pcs = &cpf2->PosClassSet[classes[0]];
3991
error = HB_Err_Invalid_GPOS_SubTable;
3995
for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3997
pr = &pcs->PosClassRule[k];
3999
if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
4000
goto next_posclassrule;
4002
if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
4003
goto next_posclassrule; /* context is too long */
4007
/* Start at 1 because [0] is implied */
4009
for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
4011
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
4013
if ( error && error != HB_Err_Not_Covered )
4016
if ( j + pr->GlyphCount - i == (FT_Long)buffer->in_length )
4017
goto next_posclassrule;
4021
if ( i > known_classes )
4023
/* Keeps us from having to do this for each rule */
4025
error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
4026
if ( error && error != HB_Err_Not_Covered )
4031
if ( cl[i - 1] != classes[i] )
4032
goto next_posclassrule;
4035
error = Do_ContextPos( gpi, pr->GlyphCount,
4036
pr->PosCount, pr->PosLookupRecord,
4045
error = HB_Err_Not_Covered;
4053
static FT_Error Lookup_ContextPos3( GPOS_Instance* gpi,
4054
HB_ContextPosFormat3* cpf3,
4057
FT_UShort context_length,
4061
FT_UShort index, i, j, property;
4062
HB_GPOSHeader* gpos = gpi->gpos;
4065
HB_GDEFHeader* gdef;
4070
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
4073
if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
4074
return HB_Err_Not_Covered;
4076
if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
4077
return HB_Err_Not_Covered; /* context is too long */
4081
for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
4083
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
4085
if ( error && error != HB_Err_Not_Covered )
4088
if ( j + cpf3->GlyphCount - i == (FT_Long)buffer->in_length )
4089
return HB_Err_Not_Covered;
4093
error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4098
return Do_ContextPos( gpi, cpf3->GlyphCount,
4099
cpf3->PosCount, cpf3->PosLookupRecord,
4105
static FT_Error Lookup_ContextPos( GPOS_Instance* gpi,
4106
HB_GPOS_SubTable* st,
4109
FT_UShort context_length,
4112
HB_ContextPos* cp = &st->context;
4114
switch ( cp->PosFormat )
4117
return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4118
flags, context_length, nesting_level );
4121
return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4122
flags, context_length, nesting_level );
4125
return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4126
flags, context_length, nesting_level );
4129
return HB_Err_Invalid_GPOS_SubTable_Format;
4132
return FT_Err_Ok; /* never reached */
4140
static FT_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
4144
FT_Memory memory = stream->memory;
4151
HB_PosLookupRecord* plr;
4154
if ( ACCESS_Frame( 2L ) )
4157
cpr->BacktrackGlyphCount = GET_UShort();
4161
cpr->Backtrack = NULL;
4163
count = cpr->BacktrackGlyphCount;
4165
if ( ALLOC_ARRAY( cpr->Backtrack, count, FT_UShort ) )
4170
if ( ACCESS_Frame( count * 2L ) )
4173
for ( n = 0; n < count; n++ )
4174
b[n] = GET_UShort();
4178
if ( ACCESS_Frame( 2L ) )
4181
cpr->InputGlyphCount = GET_UShort();
4187
count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4189
if ( ALLOC_ARRAY( cpr->Input, count, FT_UShort ) )
4194
if ( ACCESS_Frame( count * 2L ) )
4197
for ( n = 0; n < count; n++ )
4198
i[n] = GET_UShort();
4202
if ( ACCESS_Frame( 2L ) )
4205
cpr->LookaheadGlyphCount = GET_UShort();
4209
cpr->Lookahead = NULL;
4211
count = cpr->LookaheadGlyphCount;
4213
if ( ALLOC_ARRAY( cpr->Lookahead, count, FT_UShort ) )
4218
if ( ACCESS_Frame( count * 2L ) )
4221
for ( n = 0; n < count; n++ )
4222
l[n] = GET_UShort();
4226
if ( ACCESS_Frame( 2L ) )
4229
cpr->PosCount = GET_UShort();
4233
cpr->PosLookupRecord = NULL;
4235
count = cpr->PosCount;
4237
if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4240
plr = cpr->PosLookupRecord;
4242
if ( ACCESS_Frame( count * 4L ) )
4245
for ( n = 0; n < count; n++ )
4247
plr[n].SequenceIndex = GET_UShort();
4248
plr[n].LookupListIndex = GET_UShort();
4270
static void Free_ChainPosRule( HB_ChainPosRule* cpr,
4273
FREE( cpr->PosLookupRecord );
4274
FREE( cpr->Lookahead );
4276
FREE( cpr->Backtrack );
4280
/* ChainPosRuleSet */
4282
static FT_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4286
FT_Memory memory = stream->memory;
4288
FT_UShort n, m, count;
4289
FT_ULong cur_offset, new_offset, base_offset;
4291
HB_ChainPosRule* cpr;
4294
base_offset = FILE_Pos();
4296
if ( ACCESS_Frame( 2L ) )
4299
count = cprs->ChainPosRuleCount = GET_UShort();
4303
cprs->ChainPosRule = NULL;
4305
if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4308
cpr = cprs->ChainPosRule;
4310
for ( n = 0; n < count; n++ )
4312
if ( ACCESS_Frame( 2L ) )
4315
new_offset = GET_UShort() + base_offset;
4319
cur_offset = FILE_Pos();
4320
if ( FILE_Seek( new_offset ) ||
4321
( error = Load_ChainPosRule( &cpr[n], stream ) ) != FT_Err_Ok )
4323
(void)FILE_Seek( cur_offset );
4329
for ( m = 0; m < n; m++ )
4330
Free_ChainPosRule( &cpr[m], memory );
4337
static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4342
HB_ChainPosRule* cpr;
4345
if ( cprs->ChainPosRule )
4347
count = cprs->ChainPosRuleCount;
4348
cpr = cprs->ChainPosRule;
4350
for ( n = 0; n < count; n++ )
4351
Free_ChainPosRule( &cpr[n], memory );
4358
/* ChainContextPosFormat1 */
4360
static FT_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4364
FT_Memory memory = stream->memory;
4366
FT_UShort n, m, count;
4367
FT_ULong cur_offset, new_offset, base_offset;
4369
HB_ChainPosRuleSet* cprs;
4372
base_offset = FILE_Pos() - 2L;
4374
if ( ACCESS_Frame( 2L ) )
4377
new_offset = GET_UShort() + base_offset;
4381
cur_offset = FILE_Pos();
4382
if ( FILE_Seek( new_offset ) ||
4383
( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != FT_Err_Ok )
4385
(void)FILE_Seek( cur_offset );
4387
if ( ACCESS_Frame( 2L ) )
4390
count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4394
ccpf1->ChainPosRuleSet = NULL;
4396
if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4399
cprs = ccpf1->ChainPosRuleSet;
4401
for ( n = 0; n < count; n++ )
4403
if ( ACCESS_Frame( 2L ) )
4406
new_offset = GET_UShort() + base_offset;
4410
cur_offset = FILE_Pos();
4411
if ( FILE_Seek( new_offset ) ||
4412
( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != FT_Err_Ok )
4414
(void)FILE_Seek( cur_offset );
4420
for ( m = 0; m < n; m++ )
4421
Free_ChainPosRuleSet( &cprs[m], memory );
4426
_HB_OPEN_Free_Coverage( &ccpf1->Coverage, memory );
4431
static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4436
HB_ChainPosRuleSet* cprs;
4439
if ( ccpf1->ChainPosRuleSet )
4441
count = ccpf1->ChainPosRuleSetCount;
4442
cprs = ccpf1->ChainPosRuleSet;
4444
for ( n = 0; n < count; n++ )
4445
Free_ChainPosRuleSet( &cprs[n], memory );
4450
_HB_OPEN_Free_Coverage( &ccpf1->Coverage, memory );
4454
/* ChainPosClassRule */
4456
static FT_Error Load_ChainPosClassRule(
4457
HB_ChainContextPosFormat2* ccpf2,
4458
HB_ChainPosClassRule* cpcr,
4462
FT_Memory memory = stream->memory;
4469
HB_PosLookupRecord* plr;
4473
if ( ACCESS_Frame( 2L ) )
4476
cpcr->BacktrackGlyphCount = GET_UShort();
4480
if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4481
ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4483
cpcr->Backtrack = NULL;
4485
count = cpcr->BacktrackGlyphCount;
4487
if ( ALLOC_ARRAY( cpcr->Backtrack, count, FT_UShort ) )
4490
b = cpcr->Backtrack;
4491
d = ccpf2->BacktrackClassDef.Defined;
4493
if ( ACCESS_Frame( count * 2L ) )
4496
for ( n = 0; n < count; n++ )
4498
b[n] = GET_UShort();
4500
/* We check whether the specific class is used at all. If not,
4501
class 0 is used instead. */
4509
if ( ACCESS_Frame( 2L ) )
4512
cpcr->InputGlyphCount = GET_UShort();
4514
if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4515
ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4521
count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4523
if ( ALLOC_ARRAY( cpcr->Input, count, FT_UShort ) )
4527
d = ccpf2->InputClassDef.Defined;
4529
if ( ACCESS_Frame( count * 2L ) )
4532
for ( n = 0; n < count; n++ )
4534
i[n] = GET_UShort();
4542
if ( ACCESS_Frame( 2L ) )
4545
cpcr->LookaheadGlyphCount = GET_UShort();
4549
if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4550
ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4552
cpcr->Lookahead = NULL;
4554
count = cpcr->LookaheadGlyphCount;
4556
if ( ALLOC_ARRAY( cpcr->Lookahead, count, FT_UShort ) )
4559
l = cpcr->Lookahead;
4560
d = ccpf2->LookaheadClassDef.Defined;
4562
if ( ACCESS_Frame( count * 2L ) )
4565
for ( n = 0; n < count; n++ )
4567
l[n] = GET_UShort();
4575
if ( ACCESS_Frame( 2L ) )
4578
cpcr->PosCount = GET_UShort();
4582
cpcr->PosLookupRecord = NULL;
4584
count = cpcr->PosCount;
4586
if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4589
plr = cpcr->PosLookupRecord;
4591
if ( ACCESS_Frame( count * 4L ) )
4594
for ( n = 0; n < count; n++ )
4596
plr[n].SequenceIndex = GET_UShort();
4597
plr[n].LookupListIndex = GET_UShort();
4619
static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr,
4622
FREE( cpcr->PosLookupRecord );
4623
FREE( cpcr->Lookahead );
4624
FREE( cpcr->Input );
4625
FREE( cpcr->Backtrack );
4631
static FT_Error Load_ChainPosClassSet(
4632
HB_ChainContextPosFormat2* ccpf2,
4633
HB_ChainPosClassSet* cpcs,
4637
FT_Memory memory = stream->memory;
4639
FT_UShort n, m, count;
4640
FT_ULong cur_offset, new_offset, base_offset;
4642
HB_ChainPosClassRule* cpcr;
4645
base_offset = FILE_Pos();
4647
if ( ACCESS_Frame( 2L ) )
4650
count = cpcs->ChainPosClassRuleCount = GET_UShort();
4654
cpcs->ChainPosClassRule = NULL;
4656
if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4657
HB_ChainPosClassRule ) )
4660
cpcr = cpcs->ChainPosClassRule;
4662
for ( n = 0; n < count; n++ )
4664
if ( ACCESS_Frame( 2L ) )
4667
new_offset = GET_UShort() + base_offset;
4671
cur_offset = FILE_Pos();
4672
if ( FILE_Seek( new_offset ) ||
4673
( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4674
stream ) ) != FT_Err_Ok )
4676
(void)FILE_Seek( cur_offset );
4682
for ( m = 0; m < n; m++ )
4683
Free_ChainPosClassRule( &cpcr[m], memory );
4690
static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs,
4695
HB_ChainPosClassRule* cpcr;
4698
if ( cpcs->ChainPosClassRule )
4700
count = cpcs->ChainPosClassRuleCount;
4701
cpcr = cpcs->ChainPosClassRule;
4703
for ( n = 0; n < count; n++ )
4704
Free_ChainPosClassRule( &cpcr[n], memory );
4711
static FT_Error GPOS_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
4713
FT_ULong class_offset,
4714
FT_ULong base_offset,
4718
FT_ULong cur_offset;
4720
cur_offset = FILE_Pos();
4724
if ( !FILE_Seek( class_offset + base_offset ) )
4725
error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
4728
error = _HB_OPEN_Load_EmptyClassDefinition ( cd, stream );
4730
if (error == FT_Err_Ok)
4731
(void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
4736
/* ChainContextPosFormat2 */
4738
static FT_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4742
FT_Memory memory = stream->memory;
4744
FT_UShort n, m, count;
4745
FT_ULong cur_offset, new_offset, base_offset;
4746
FT_ULong backtrack_offset, input_offset, lookahead_offset;
4748
HB_ChainPosClassSet* cpcs;
4751
base_offset = FILE_Pos() - 2;
4753
if ( ACCESS_Frame( 2L ) )
4756
new_offset = GET_UShort() + base_offset;
4760
cur_offset = FILE_Pos();
4761
if ( FILE_Seek( new_offset ) ||
4762
( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != FT_Err_Ok )
4764
(void)FILE_Seek( cur_offset );
4766
if ( ACCESS_Frame( 8L ) )
4769
backtrack_offset = GET_UShort();
4770
input_offset = GET_UShort();
4771
lookahead_offset = GET_UShort();
4773
/* `ChainPosClassSetCount' is the upper limit for input class values,
4774
thus we read it now to make an additional safety check. No limit
4775
is known or needed for the other two class definitions */
4777
count = ccpf2->ChainPosClassSetCount = GET_UShort();
4781
if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4782
backtrack_offset, base_offset,
4783
stream ) ) != FT_Err_Ok )
4785
if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4786
input_offset, base_offset,
4787
stream ) ) != FT_Err_Ok )
4789
if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4790
lookahead_offset, base_offset,
4791
stream ) ) != FT_Err_Ok )
4794
ccpf2->ChainPosClassSet = NULL;
4795
ccpf2->MaxBacktrackLength = 0;
4796
ccpf2->MaxInputLength = 0;
4797
ccpf2->MaxLookaheadLength = 0;
4799
if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4802
cpcs = ccpf2->ChainPosClassSet;
4804
for ( n = 0; n < count; n++ )
4806
if ( ACCESS_Frame( 2L ) )
4809
new_offset = GET_UShort() + base_offset;
4813
if ( new_offset != base_offset ) /* not a NULL offset */
4815
cur_offset = FILE_Pos();
4816
if ( FILE_Seek( new_offset ) ||
4817
( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4818
stream ) ) != FT_Err_Ok )
4820
(void)FILE_Seek( cur_offset );
4824
/* we create a ChainPosClassSet table with no entries */
4826
ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4827
ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4834
for ( m = 0; m < n; m++ )
4835
Free_ChainPosClassSet( &cpcs[m], memory );
4840
_HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
4843
_HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef, memory );
4846
_HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
4849
_HB_OPEN_Free_Coverage( &ccpf2->Coverage, memory );
4854
static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4859
HB_ChainPosClassSet* cpcs;
4862
if ( ccpf2->ChainPosClassSet )
4864
count = ccpf2->ChainPosClassSetCount;
4865
cpcs = ccpf2->ChainPosClassSet;
4867
for ( n = 0; n < count; n++ )
4868
Free_ChainPosClassSet( &cpcs[n], memory );
4873
_HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
4874
_HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef, memory );
4875
_HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
4877
_HB_OPEN_Free_Coverage( &ccpf2->Coverage, memory );
4881
/* ChainContextPosFormat3 */
4883
static FT_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
4887
FT_Memory memory = stream->memory;
4889
FT_UShort n, nb, ni, nl, m, count;
4890
FT_UShort backtrack_count, input_count, lookahead_count;
4891
FT_ULong cur_offset, new_offset, base_offset;
4896
HB_PosLookupRecord* plr;
4899
base_offset = FILE_Pos() - 2L;
4901
if ( ACCESS_Frame( 2L ) )
4904
ccpf3->BacktrackGlyphCount = GET_UShort();
4908
ccpf3->BacktrackCoverage = NULL;
4910
backtrack_count = ccpf3->BacktrackGlyphCount;
4912
if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4916
b = ccpf3->BacktrackCoverage;
4918
for ( nb = 0; nb < backtrack_count; nb++ )
4920
if ( ACCESS_Frame( 2L ) )
4923
new_offset = GET_UShort() + base_offset;
4927
cur_offset = FILE_Pos();
4928
if ( FILE_Seek( new_offset ) ||
4929
( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != FT_Err_Ok )
4931
(void)FILE_Seek( cur_offset );
4934
if ( ACCESS_Frame( 2L ) )
4937
ccpf3->InputGlyphCount = GET_UShort();
4941
ccpf3->InputCoverage = NULL;
4943
input_count = ccpf3->InputGlyphCount;
4945
if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4948
i = ccpf3->InputCoverage;
4950
for ( ni = 0; ni < input_count; ni++ )
4952
if ( ACCESS_Frame( 2L ) )
4955
new_offset = GET_UShort() + base_offset;
4959
cur_offset = FILE_Pos();
4960
if ( FILE_Seek( new_offset ) ||
4961
( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != FT_Err_Ok )
4963
(void)FILE_Seek( cur_offset );
4966
if ( ACCESS_Frame( 2L ) )
4969
ccpf3->LookaheadGlyphCount = GET_UShort();
4973
ccpf3->LookaheadCoverage = NULL;
4975
lookahead_count = ccpf3->LookaheadGlyphCount;
4977
if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4981
l = ccpf3->LookaheadCoverage;
4983
for ( nl = 0; nl < lookahead_count; nl++ )
4985
if ( ACCESS_Frame( 2L ) )
4988
new_offset = GET_UShort() + base_offset;
4992
cur_offset = FILE_Pos();
4993
if ( FILE_Seek( new_offset ) ||
4994
( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != FT_Err_Ok )
4996
(void)FILE_Seek( cur_offset );
4999
if ( ACCESS_Frame( 2L ) )
5002
ccpf3->PosCount = GET_UShort();
5006
ccpf3->PosLookupRecord = NULL;
5008
count = ccpf3->PosCount;
5010
if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
5013
plr = ccpf3->PosLookupRecord;
5015
if ( ACCESS_Frame( count * 4L ) )
5018
for ( n = 0; n < count; n++ )
5020
plr[n].SequenceIndex = GET_UShort();
5021
plr[n].LookupListIndex = GET_UShort();
5032
for ( m = 0; m < nl; m++ )
5033
_HB_OPEN_Free_Coverage( &l[m], memory );
5038
for ( m = 0; m < ni; m++ )
5039
_HB_OPEN_Free_Coverage( &i[m], memory );
5044
for ( m = 0; m < nb; m++ )
5045
_HB_OPEN_Free_Coverage( &b[m], memory );
5052
static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
5060
FREE( ccpf3->PosLookupRecord );
5062
if ( ccpf3->LookaheadCoverage )
5064
count = ccpf3->LookaheadGlyphCount;
5065
c = ccpf3->LookaheadCoverage;
5067
for ( n = 0; n < count; n++ )
5068
_HB_OPEN_Free_Coverage( &c[n], memory );
5073
if ( ccpf3->InputCoverage )
5075
count = ccpf3->InputGlyphCount;
5076
c = ccpf3->InputCoverage;
5078
for ( n = 0; n < count; n++ )
5079
_HB_OPEN_Free_Coverage( &c[n], memory );
5084
if ( ccpf3->BacktrackCoverage )
5086
count = ccpf3->BacktrackGlyphCount;
5087
c = ccpf3->BacktrackCoverage;
5089
for ( n = 0; n < count; n++ )
5090
_HB_OPEN_Free_Coverage( &c[n], memory );
5097
/* ChainContextPos */
5099
static FT_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
5103
HB_ChainContextPos* ccp = &st->chain;
5106
if ( ACCESS_Frame( 2L ) )
5109
ccp->PosFormat = GET_UShort();
5113
switch ( ccp->PosFormat )
5116
return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
5119
return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
5122
return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
5125
return HB_Err_Invalid_GPOS_SubTable_Format;
5128
return FT_Err_Ok; /* never reached */
5132
static void Free_ChainContextPos( HB_GPOS_SubTable* st,
5135
HB_ChainContextPos* ccp = &st->chain;
5137
switch ( ccp->PosFormat )
5140
Free_ChainContextPos1( &ccp->ccpf.ccpf1, memory );
5144
Free_ChainContextPos2( &ccp->ccpf.ccpf2, memory );
5148
Free_ChainContextPos3( &ccp->ccpf.ccpf3, memory );
5154
static FT_Error Lookup_ChainContextPos1(
5156
HB_ChainContextPosFormat1* ccpf1,
5159
FT_UShort context_length,
5162
FT_UShort index, property;
5163
FT_UShort i, j, k, num_cpr;
5164
FT_UShort bgc, igc, lgc;
5166
HB_GPOSHeader* gpos = gpi->gpos;
5168
HB_ChainPosRule* cpr;
5169
HB_ChainPosRule curr_cpr;
5170
HB_GDEFHeader* gdef;
5175
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5178
error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5182
cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5183
num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5185
for ( k = 0; k < num_cpr; k++ )
5188
bgc = curr_cpr.BacktrackGlyphCount;
5189
igc = curr_cpr.InputGlyphCount;
5190
lgc = curr_cpr.LookaheadGlyphCount;
5192
if ( context_length != 0xFFFF && context_length < igc )
5193
goto next_chainposrule;
5195
/* check whether context is too long; it is a first guess only */
5197
if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5198
goto next_chainposrule;
5202
/* Since we don't know in advance the number of glyphs to inspect,
5203
we search backwards for matches in the backtrack glyph array */
5205
for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5207
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5209
if ( error && error != HB_Err_Not_Covered )
5212
if ( j + 1 == bgc - i )
5213
goto next_chainposrule;
5217
/* In OpenType 1.3, it is undefined whether the offsets of
5218
backtrack glyphs is in logical order or not. Version 1.4
5221
Logical order - a b c d e f g h i j
5224
Backtrack offsets - 3 2 1 0
5225
Lookahead offsets - 0 1 2 3 */
5227
if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5228
goto next_chainposrule;
5232
/* Start at 1 because [0] is implied */
5234
for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5236
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5238
if ( error && error != HB_Err_Not_Covered )
5241
if ( j + igc - i + lgc == (FT_Long)buffer->in_length )
5242
goto next_chainposrule;
5246
if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5247
goto next_chainposrule;
5250
/* we are starting to check for lookahead glyphs right after the
5251
last context glyph */
5253
for ( i = 0; i < lgc; i++, j++ )
5255
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5257
if ( error && error != HB_Err_Not_Covered )
5260
if ( j + lgc - i == (FT_Long)buffer->in_length )
5261
goto next_chainposrule;
5265
if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5266
goto next_chainposrule;
5269
return Do_ContextPos( gpi, igc,
5271
curr_cpr.PosLookupRecord,
5279
return HB_Err_Not_Covered;
5283
static FT_Error Lookup_ChainContextPos2(
5285
HB_ChainContextPosFormat2* ccpf2,
5288
FT_UShort context_length,
5291
FT_UShort index, property;
5292
FT_Memory memory = gpi->face->memory;
5295
FT_UShort bgc, igc, lgc;
5296
FT_UShort known_backtrack_classes,
5297
known_input_classes,
5298
known_lookahead_classes;
5300
FT_UShort* backtrack_classes;
5301
FT_UShort* input_classes;
5302
FT_UShort* lookahead_classes;
5307
HB_GPOSHeader* gpos = gpi->gpos;
5309
HB_ChainPosClassSet* cpcs;
5310
HB_ChainPosClassRule cpcr;
5311
HB_GDEFHeader* gdef;
5316
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5319
/* Note: The coverage table in format 2 doesn't give an index into
5320
anything. It just lets us know whether or not we need to
5321
do any lookup at all. */
5323
error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5327
if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, FT_UShort ) )
5329
known_backtrack_classes = 0;
5331
if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) )
5333
known_input_classes = 1;
5335
if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_UShort ) )
5337
known_lookahead_classes = 0;
5339
error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5340
&input_classes[0], NULL );
5341
if ( error && error != HB_Err_Not_Covered )
5344
cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5347
error = HB_Err_Invalid_GPOS_SubTable;
5351
for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5353
cpcr = cpcs->ChainPosClassRule[k];
5354
bgc = cpcr.BacktrackGlyphCount;
5355
igc = cpcr.InputGlyphCount;
5356
lgc = cpcr.LookaheadGlyphCount;
5358
if ( context_length != 0xFFFF && context_length < igc )
5359
goto next_chainposclassrule;
5361
/* check whether context is too long; it is a first guess only */
5363
if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5364
goto next_chainposclassrule;
5368
/* Since we don't know in advance the number of glyphs to inspect,
5369
we search backwards for matches in the backtrack glyph array.
5370
Note that `known_backtrack_classes' starts at index 0. */
5372
bc = cpcr.Backtrack;
5374
for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5376
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5378
if ( error && error != HB_Err_Not_Covered )
5381
if ( j + 1 == bgc - i )
5382
goto next_chainposclassrule;
5386
if ( i >= known_backtrack_classes )
5388
/* Keeps us from having to do this for each rule */
5390
error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5391
&backtrack_classes[i], NULL );
5392
if ( error && error != HB_Err_Not_Covered )
5394
known_backtrack_classes = i;
5397
if ( bc[i] != backtrack_classes[i] )
5398
goto next_chainposclassrule;
5404
/* Start at 1 because [0] is implied */
5406
for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5408
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5410
if ( error && error != HB_Err_Not_Covered )
5413
if ( j + igc - i + lgc == (FT_Long)buffer->in_length )
5414
goto next_chainposclassrule;
5418
if ( i >= known_input_classes )
5420
error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5421
&input_classes[i], NULL );
5422
if ( error && error != HB_Err_Not_Covered )
5424
known_input_classes = i;
5427
if ( ic[i - 1] != input_classes[i] )
5428
goto next_chainposclassrule;
5431
/* we are starting to check for lookahead glyphs right after the
5432
last context glyph */
5434
lc = cpcr.Lookahead;
5436
for ( i = 0; i < lgc; i++, j++ )
5438
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5440
if ( error && error != HB_Err_Not_Covered )
5443
if ( j + lgc - i == (FT_Long)buffer->in_length )
5444
goto next_chainposclassrule;
5448
if ( i >= known_lookahead_classes )
5450
error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5451
&lookahead_classes[i], NULL );
5452
if ( error && error != HB_Err_Not_Covered )
5454
known_lookahead_classes = i;
5457
if ( lc[i] != lookahead_classes[i] )
5458
goto next_chainposclassrule;
5461
error = Do_ContextPos( gpi, igc,
5463
cpcr.PosLookupRecord,
5468
next_chainposclassrule:
5472
error = HB_Err_Not_Covered;
5475
FREE( lookahead_classes );
5478
FREE( input_classes );
5481
FREE( backtrack_classes );
5486
static FT_Error Lookup_ChainContextPos3(
5488
HB_ChainContextPosFormat3* ccpf3,
5491
FT_UShort context_length,
5494
FT_UShort index, i, j, property;
5495
FT_UShort bgc, igc, lgc;
5497
HB_GPOSHeader* gpos = gpi->gpos;
5502
HB_GDEFHeader* gdef;
5507
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5510
bgc = ccpf3->BacktrackGlyphCount;
5511
igc = ccpf3->InputGlyphCount;
5512
lgc = ccpf3->LookaheadGlyphCount;
5514
if ( context_length != 0xFFFF && context_length < igc )
5515
return HB_Err_Not_Covered;
5517
/* check whether context is too long; it is a first guess only */
5519
if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5520
return HB_Err_Not_Covered;
5524
/* Since we don't know in advance the number of glyphs to inspect,
5525
we search backwards for matches in the backtrack glyph array */
5527
bc = ccpf3->BacktrackCoverage;
5529
for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5531
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5533
if ( error && error != HB_Err_Not_Covered )
5536
if ( j + 1 == bgc - i )
5537
return HB_Err_Not_Covered;
5541
error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5547
ic = ccpf3->InputCoverage;
5549
for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5551
/* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5552
while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5554
if ( error && error != HB_Err_Not_Covered )
5557
if ( j + igc - i + lgc == (FT_Long)buffer->in_length )
5558
return HB_Err_Not_Covered;
5562
error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5567
/* we are starting to check for lookahead glyphs right after the
5568
last context glyph */
5570
lc = ccpf3->LookaheadCoverage;
5572
for ( i = 0; i < lgc; i++, j++ )
5574
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5576
if ( error && error != HB_Err_Not_Covered )
5579
if ( j + lgc - i == (FT_Long)buffer->in_length )
5580
return HB_Err_Not_Covered;
5584
error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5589
return Do_ContextPos( gpi, igc,
5591
ccpf3->PosLookupRecord,
5597
static FT_Error Lookup_ChainContextPos(
5599
HB_GPOS_SubTable* st,
5602
FT_UShort context_length,
5605
HB_ChainContextPos* ccp = &st->chain;
5607
switch ( ccp->PosFormat )
5610
return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5611
flags, context_length,
5615
return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5616
flags, context_length,
5620
return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5621
flags, context_length,
5625
return HB_Err_Invalid_GPOS_SubTable_Format;
5628
return FT_Err_Ok; /* never reached */
5639
FT_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
5640
FT_ULong script_tag,
5641
FT_UShort* script_index )
5646
HB_ScriptRecord* sr;
5649
if ( !gpos || !script_index )
5650
return FT_Err_Invalid_Argument;
5652
sl = &gpos->ScriptList;
5653
sr = sl->ScriptRecord;
5655
for ( n = 0; n < sl->ScriptCount; n++ )
5656
if ( script_tag == sr[n].ScriptTag )
5663
return HB_Err_Not_Covered;
5668
FT_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
5669
FT_ULong language_tag,
5670
FT_UShort script_index,
5671
FT_UShort* language_index,
5672
FT_UShort* req_feature_index )
5677
HB_ScriptRecord* sr;
5679
HB_LangSysRecord* lsr;
5682
if ( !gpos || !language_index || !req_feature_index )
5683
return FT_Err_Invalid_Argument;
5685
sl = &gpos->ScriptList;
5686
sr = sl->ScriptRecord;
5688
if ( script_index >= sl->ScriptCount )
5689
return FT_Err_Invalid_Argument;
5691
s = &sr[script_index].Script;
5692
lsr = s->LangSysRecord;
5694
for ( n = 0; n < s->LangSysCount; n++ )
5695
if ( language_tag == lsr[n].LangSysTag )
5697
*language_index = n;
5698
*req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5703
return HB_Err_Not_Covered;
5707
/* selecting 0xFFFF for language_index asks for the values of the
5708
default language (DefaultLangSys) */
5711
FT_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
5712
FT_ULong feature_tag,
5713
FT_UShort script_index,
5714
FT_UShort language_index,
5715
FT_UShort* feature_index )
5720
HB_ScriptRecord* sr;
5722
HB_LangSysRecord* lsr;
5727
HB_FeatureRecord* fr;
5730
if ( !gpos || !feature_index )
5731
return FT_Err_Invalid_Argument;
5733
sl = &gpos->ScriptList;
5734
sr = sl->ScriptRecord;
5736
fl = &gpos->FeatureList;
5737
fr = fl->FeatureRecord;
5739
if ( script_index >= sl->ScriptCount )
5740
return FT_Err_Invalid_Argument;
5742
s = &sr[script_index].Script;
5743
lsr = s->LangSysRecord;
5745
if ( language_index == 0xFFFF )
5746
ls = &s->DefaultLangSys;
5749
if ( language_index >= s->LangSysCount )
5750
return FT_Err_Invalid_Argument;
5752
ls = &lsr[language_index].LangSys;
5755
fi = ls->FeatureIndex;
5757
for ( n = 0; n < ls->FeatureCount; n++ )
5759
if ( fi[n] >= fl->FeatureCount )
5760
return HB_Err_Invalid_GPOS_SubTable_Format;
5762
if ( feature_tag == fr[fi[n]].FeatureTag )
5764
*feature_index = fi[n];
5770
return HB_Err_Not_Covered;
5774
/* The next three functions return a null-terminated list */
5777
FT_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
5778
FT_ULong** script_tag_list )
5786
HB_ScriptRecord* sr;
5789
if ( !gpos || !script_tag_list )
5790
return FT_Err_Invalid_Argument;
5792
memory = gpos->memory;
5793
sl = &gpos->ScriptList;
5794
sr = sl->ScriptRecord;
5796
if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
5799
for ( n = 0; n < sl->ScriptCount; n++ )
5800
stl[n] = sr[n].ScriptTag;
5803
*script_tag_list = stl;
5810
FT_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
5811
FT_UShort script_index,
5812
FT_ULong** language_tag_list )
5820
HB_ScriptRecord* sr;
5822
HB_LangSysRecord* lsr;
5825
if ( !gpos || !language_tag_list )
5826
return FT_Err_Invalid_Argument;
5828
memory = gpos->memory;
5829
sl = &gpos->ScriptList;
5830
sr = sl->ScriptRecord;
5832
if ( script_index >= sl->ScriptCount )
5833
return FT_Err_Invalid_Argument;
5835
s = &sr[script_index].Script;
5836
lsr = s->LangSysRecord;
5838
if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
5841
for ( n = 0; n < s->LangSysCount; n++ )
5842
ltl[n] = lsr[n].LangSysTag;
5845
*language_tag_list = ltl;
5851
/* selecting 0xFFFF for language_index asks for the values of the
5852
default language (DefaultLangSys) */
5855
FT_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
5856
FT_UShort script_index,
5857
FT_UShort language_index,
5858
FT_ULong** feature_tag_list )
5866
HB_ScriptRecord* sr;
5868
HB_LangSysRecord* lsr;
5873
HB_FeatureRecord* fr;
5876
if ( !gpos || !feature_tag_list )
5877
return FT_Err_Invalid_Argument;
5879
memory = gpos->memory;
5880
sl = &gpos->ScriptList;
5881
sr = sl->ScriptRecord;
5883
fl = &gpos->FeatureList;
5884
fr = fl->FeatureRecord;
5886
if ( script_index >= sl->ScriptCount )
5887
return FT_Err_Invalid_Argument;
5889
s = &sr[script_index].Script;
5890
lsr = s->LangSysRecord;
5892
if ( language_index == 0xFFFF )
5893
ls = &s->DefaultLangSys;
5896
if ( language_index >= s->LangSysCount )
5897
return FT_Err_Invalid_Argument;
5899
ls = &lsr[language_index].LangSys;
5902
fi = ls->FeatureIndex;
5904
if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
5907
for ( n = 0; n < ls->FeatureCount; n++ )
5909
if ( fi[n] >= fl->FeatureCount )
5912
return HB_Err_Invalid_GPOS_SubTable_Format;
5914
ftl[n] = fr[fi[n]].FeatureTag;
5918
*feature_tag_list = ftl;
5924
typedef FT_Error (*Lookup_Pos_Func_Type) ( GPOS_Instance* gpi,
5925
HB_GPOS_SubTable* st,
5928
FT_UShort context_length,
5929
int nesting_level );
5930
static const Lookup_Pos_Func_Type Lookup_Pos_Call_Table[] = {
5932
Lookup_SinglePos, /* HB_GPOS_LOOKUP_SINGLE 1 */
5933
Lookup_PairPos, /* HB_GPOS_LOOKUP_PAIR 2 */
5934
Lookup_CursivePos, /* HB_GPOS_LOOKUP_CURSIVE 3 */
5935
Lookup_MarkBasePos, /* HB_GPOS_LOOKUP_MARKBASE 4 */
5936
Lookup_MarkLigPos, /* HB_GPOS_LOOKUP_MARKLIG 5 */
5937
Lookup_MarkMarkPos, /* HB_GPOS_LOOKUP_MARKMARK 6 */
5938
Lookup_ContextPos, /* HB_GPOS_LOOKUP_CONTEXT 7 */
5939
Lookup_ChainContextPos, /* HB_GPOS_LOOKUP_CHAIN 8 */
5940
Lookup_DefaultPos, /* HB_GPOS_LOOKUP_EXTENSION 9 */
5943
/* Do an individual subtable lookup. Returns FT_Err_Ok if positioning
5944
has been done, or HB_Err_Not_Covered if not. */
5945
static FT_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
5946
FT_UShort lookup_index,
5948
FT_UShort context_length,
5951
FT_Error error = HB_Err_Not_Covered;
5952
FT_UShort i, flags, lookup_count;
5953
HB_GPOSHeader* gpos = gpi->gpos;
5956
Lookup_Pos_Func_Type Func;
5961
if ( nesting_level > HB_MAX_NESTING_LEVEL )
5962
return HB_Err_Too_Many_Nested_Contexts;
5964
lookup_count = gpos->LookupList.LookupCount;
5965
if (lookup_index >= lookup_count)
5968
lo = &gpos->LookupList.Lookup[lookup_index];
5969
flags = lo->LookupFlag;
5970
lookup_type = lo->LookupType;
5971
if (lookup_type >= ARRAY_LEN (Lookup_Pos_Call_Table))
5973
Func = Lookup_Pos_Call_Table[lookup_type];
5975
for ( i = 0; i < lo->SubTableCount; i++ )
5978
&lo->SubTable[i].st.gpos,
5980
flags, context_length,
5983
/* Check whether we have a successful positioning or an error other
5984
than HB_Err_Not_Covered */
5986
if ( error != HB_Err_Not_Covered )
5990
return HB_Err_Not_Covered;
5994
static FT_Error Load_DefaultPos( HB_GPOS_SubTable* st,
5999
return HB_Err_Invalid_GPOS_SubTable_Format;
6002
typedef FT_Error (*Load_Pos_Func_Type)( HB_GPOS_SubTable* st,
6004
static const Load_Pos_Func_Type Load_Pos_Call_Table[] = {
6006
Load_SinglePos, /* HB_GPOS_LOOKUP_SINGLE 1 */
6007
Load_PairPos, /* HB_GPOS_LOOKUP_PAIR 2 */
6008
Load_CursivePos, /* HB_GPOS_LOOKUP_CURSIVE 3 */
6009
Load_MarkBasePos, /* HB_GPOS_LOOKUP_MARKBASE 4 */
6010
Load_MarkLigPos, /* HB_GPOS_LOOKUP_MARKLIG 5 */
6011
Load_MarkMarkPos, /* HB_GPOS_LOOKUP_MARKMARK 6 */
6012
Load_ContextPos, /* HB_GPOS_LOOKUP_CONTEXT 7 */
6013
Load_ChainContextPos, /* HB_GPOS_LOOKUP_CHAIN 8 */
6014
Load_DefaultPos, /* HB_GPOS_LOOKUP_EXTENSION 9 */
6017
FT_Error _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
6019
FT_UShort lookup_type )
6021
Load_Pos_Func_Type Func;
6023
if (lookup_type >= ARRAY_LEN (Load_Pos_Call_Table))
6026
Func = Load_Pos_Call_Table[lookup_type];
6028
return Func ( st, stream );
6032
static void Free_DefaultPos( HB_GPOS_SubTable* st,
6039
typedef void (*Free_Pos_Func_Type)( HB_GPOS_SubTable* st,
6041
static const Free_Pos_Func_Type Free_Pos_Call_Table[] = {
6043
Free_SinglePos, /* HB_GPOS_LOOKUP_SINGLE 1 */
6044
Free_PairPos, /* HB_GPOS_LOOKUP_PAIR 2 */
6045
Free_CursivePos, /* HB_GPOS_LOOKUP_CURSIVE 3 */
6046
Free_MarkBasePos, /* HB_GPOS_LOOKUP_MARKBASE 4 */
6047
Free_MarkLigPos, /* HB_GPOS_LOOKUP_MARKLIG 5 */
6048
Free_MarkMarkPos, /* HB_GPOS_LOOKUP_MARKMARK 6 */
6049
Free_ContextPos, /* HB_GPOS_LOOKUP_CONTEXT 7 */
6050
Free_ChainContextPos, /* HB_GPOS_LOOKUP_CHAIN 8 */
6051
Free_DefaultPos, /* HB_GPOS_LOOKUP_EXTENSION 9 */
6054
void _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
6056
FT_UShort lookup_type )
6058
Free_Pos_Func_Type Func;
6060
if (lookup_type >= ARRAY_LEN (Free_Pos_Call_Table))
6063
Func = Free_Pos_Call_Table[lookup_type];
6065
Func ( st, memory );
6070
/* apply one lookup to the input string object */
6072
static FT_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
6073
FT_UShort lookup_index,
6076
FT_Error error, retError = HB_Err_Not_Covered;
6077
HB_GPOSHeader* gpos = gpi->gpos;
6079
FT_UInt* properties = gpos->LookupList.Properties;
6081
int nesting_level = 0;
6084
gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
6088
while ( buffer->in_pos < buffer->in_length )
6090
if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
6092
/* 0xFFFF indicates that we don't have a context length yet. */
6094
/* Note that the connection between mark and base glyphs hold
6095
exactly one (string) lookup. For example, it would be possible
6096
that in the first lookup, mark glyph X is attached to base
6097
glyph A, and in the next lookup it is attached to base glyph B.
6098
It is up to the font designer to provide meaningful lookups and
6101
error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer,
6102
0xFFFF, nesting_level );
6103
if ( error && error != HB_Err_Not_Covered )
6108
/* Contrary to properties defined in GDEF, user-defined properties
6109
will always stop a possible cursive positioning. */
6112
error = HB_Err_Not_Covered;
6115
if ( error == HB_Err_Not_Covered )
6125
static FT_Error Position_CursiveChain ( HB_Buffer buffer )
6128
HB_Position positions = buffer->positions;
6130
/* First handle all left-to-right connections */
6131
for (j = 0; j < buffer->in_length; j--)
6133
if (positions[j].cursive_chain > 0)
6134
positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
6137
/* Then handle all right-to-left connections */
6138
for (i = buffer->in_length; i > 0; i--)
6142
if (positions[j].cursive_chain < 0)
6143
positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
6150
FT_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
6151
FT_UShort feature_index,
6157
FT_UInt* properties;
6159
FT_UShort lookup_count;
6161
/* Each feature can only be added once */
6164
feature_index >= gpos->FeatureList.FeatureCount ||
6165
gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
6166
return FT_Err_Invalid_Argument;
6168
gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
6170
properties = gpos->LookupList.Properties;
6172
feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6173
index = feature.LookupListIndex;
6174
lookup_count = gpos->LookupList.LookupCount;
6176
for ( i = 0; i < feature.LookupListCount; i++ )
6178
FT_UShort lookup_index = index[i];
6179
if (lookup_index < lookup_count)
6180
properties[lookup_index] |= property;
6188
FT_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
6192
FT_UInt* properties;
6196
return FT_Err_Invalid_Argument;
6198
gpos->FeatureList.ApplyCount = 0;
6200
properties = gpos->LookupList.Properties;
6202
for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
6210
FT_Error HB_GPOS_Register_Glyph_Function( HB_GPOSHeader* gpos,
6211
HB_GlyphFunction gfunc )
6214
return FT_Err_Invalid_Argument;
6216
gpos->gfunc = gfunc;
6223
FT_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
6224
HB_MMFunction mmfunc,
6228
return FT_Err_Invalid_Argument;
6230
gpos->mmfunc = mmfunc;
6236
/* If `dvi' is TRUE, glyph contour points for anchor points and device
6237
tables are ignored -- you will get device independent values. */
6240
FT_Error HB_GPOS_Apply_String( FT_Face face,
6241
HB_GPOSHeader* gpos,
6242
FT_UShort load_flags,
6247
FT_Error error, retError = HB_Err_Not_Covered;
6249
FT_UShort i, j, feature_index, lookup_count;
6252
if ( !face || !gpos ||
6253
!buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
6254
return FT_Err_Invalid_Argument;
6258
gpi.load_flags = load_flags;
6262
lookup_count = gpos->LookupList.LookupCount;
6264
for ( i = 0; i < gpos->FeatureList.ApplyCount; i++ )
6266
/* index of i'th feature */
6267
feature_index = gpos->FeatureList.ApplyOrder[i];
6268
feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6270
for ( j = 0; j < feature.LookupListCount; j++ )
6272
FT_UShort lookup_index = feature.LookupListIndex[j];
6274
/* Skip nonexistant lookups */
6275
if (lookup_index >= lookup_count)
6278
error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6281
if ( error != HB_Err_Not_Covered )
6289
error = Position_CursiveChain ( buffer );