1
/*******************************************************************
5
* TrueType Open GPOS table support.
7
* Copyright 1996-2000 by
8
* David Turner, Robert Wilhelm, and Werner Lemberg.
10
* This file is part of the FreeType project, and may only be used
11
* modified and distributed under the terms of the FreeType project
12
* license, LICENSE.TXT. By continuing to use, modify, or distribute
13
* this file you indicate that you have read the license and
14
* understand and accept it fully.
16
******************************************************************/
18
/* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but
19
I don't care currently. I believe that it would be possible to
20
save about 50% of TTO code by carefully designing the structures,
21
sharing as much as possible with extensive use of macros. This
22
is something for a volunteer :-) */
24
#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
26
#include <freetype/tttags.h>
28
#include <freetype/internal/ftstream.h>
29
#include <freetype/internal/ftmemory.h>
30
#include <freetype/internal/tttypes.h>
32
#include "fterrcompat.h"
44
FT_UShort load_flags; /* how the glyph should be loaded */
47
FT_UShort first; /* the first glyph in a chain of
48
cursive connections */
49
FT_UShort last; /* the last valid glyph -- used
50
with cursive positioning */
51
FT_Pos anchor_x; /* the coordinates of the anchor point */
52
FT_Pos anchor_y; /* of the last valid glyph */
55
typedef struct GPOS_Instance_ GPOS_Instance;
58
static FT_Error GPos_Do_Glyph_Lookup( GPOS_Instance* gpi,
59
FT_UShort lookup_index,
62
FT_UShort context_length,
66
/* the client application must replace this with something more
67
meaningful if multiple master fonts are to be supported. */
68
static FT_Error default_mmfunc( FT_Face face,
77
return TTO_Err_No_MM_Interpreter;
82
#define GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' )
84
/**********************
86
**********************/
88
static FT_Error GPOS_Create( void* ext,
92
FT_Memory memory = stream->memory;
94
TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
103
/* a null offset indicates that there is no GPOS table */
107
/* we store the start offset and the size of the subtable */
109
table = face->lookup_table ( face, TTAG_GPOS );
111
return TT_Err_Ok; /* The table is optional */
113
if ( FILE_Seek( face->dirTables[table].Offset ) ||
117
gpos->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
118
gpos->Version = GET_ULong();
122
/* a default mmfunc() handler which just returns an error */
124
gpos->mmfunc = default_mmfunc;
126
/* the default glyph function is TT_Load_Glyph() */
128
gpos->gfunc = FT_Load_Glyph;
130
gpos->loaded = FALSE;
136
static FT_Error GPOS_Destroy( void* ext,
139
TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
149
Free_LookupList( &gpos->LookupList, GPOS );
150
Free_FeatureList( &gpos->FeatureList );
151
Free_ScriptList( &gpos->ScriptList );
159
FT_Error TT_Init_GPOS_Extension( TT_Engine engine )
161
PEngine_Instance _engine = HANDLE_Engine( engine );
165
return TT_Err_Invalid_Engine;
167
return TT_Register_Extension( _engine,
169
sizeof ( TTO_GPOSHeader ),
176
FT_Error TT_Load_GPOS_Table( FT_Face face,
177
TTO_GPOSHeader** retptr,
178
TTO_GDEFHeader* gdef )
180
FT_ULong cur_offset, new_offset, base_offset;
182
/* FT_UShort i, num_lookups; */
183
TTO_GPOSHeader* gpos;
184
/* TTO_Lookup* lo; */
185
TT_Face tt_face = (TT_Face)face;
187
FT_Stream stream = face->stream;
189
FT_Memory memory = face->memory;
193
return TT_Err_Invalid_Argument;
196
return TT_Err_Invalid_Face_Handle;
198
if (( error = tt_face->goto_table( tt_face, TTAG_GPOS, stream, 0 ) ))
201
base_offset = FILE_Pos();
203
if ( ALLOC ( gpos, sizeof( *gpos ) ) )
206
gpos->memory = memory;
207
gpos->gfunc = FT_Load_Glyph;
208
gpos->mmfunc = default_mmfunc;
212
if ( FILE_Seek( base_offset + 4L ) ||
216
new_offset = GET_UShort() + base_offset;
220
cur_offset = FILE_Pos();
221
if ( FILE_Seek( new_offset ) ||
222
( error = Load_ScriptList( &gpos->ScriptList,
223
stream ) ) != TT_Err_Ok )
225
(void)FILE_Seek( cur_offset );
227
if ( ACCESS_Frame( 2L ) )
230
new_offset = GET_UShort() + base_offset;
234
cur_offset = FILE_Pos();
235
if ( FILE_Seek( new_offset ) ||
236
( error = Load_FeatureList( &gpos->FeatureList,
237
stream ) ) != TT_Err_Ok )
239
(void)FILE_Seek( cur_offset );
241
if ( ACCESS_Frame( 2L ) )
244
new_offset = GET_UShort() + base_offset;
248
cur_offset = FILE_Pos();
249
if ( FILE_Seek( new_offset ) ||
250
( error = Load_LookupList( &gpos->LookupList,
251
stream, GPOS ) ) != TT_Err_Ok )
254
gpos->gdef = gdef; /* can be NULL */
256
/* We now check the LookupFlags for values larger than 0xFF to find
257
out whether we need to load the `MarkAttachClassDef' field of the
258
GDEF table -- this hack is necessary for OpenType 1.2 tables since
259
the version field of the GDEF table hasn't been incremented.
261
For constructed GDEF tables, we only load it if
262
`MarkAttachClassDef_offset' is not zero (nevertheless, a build of
263
a constructed mark attach table is not supported currently). */
267
gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
269
lo = gpos->LookupList.Lookup;
270
num_lookups = gpos->LookupList.LookupCount;
272
for ( i = 0; i < num_lookups; i++ )
274
if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
276
if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
280
new_offset = GET_UShort();
285
return TTO_Err_Invalid_GDEF_SubTable;
287
new_offset += base_offset;
289
if ( FILE_Seek( new_offset ) ||
290
( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
291
256, stream ) ) != TT_Err_Ok )
305
Free_LookupList( &gpos->LookupList, GPOS, memory );
309
Free_FeatureList( &gpos->FeatureList, memory );
312
Free_ScriptList( &gpos->ScriptList, memory );
321
FT_Error TT_Done_GPOS_Table( TTO_GPOSHeader* gpos )
323
FT_Memory memory = gpos->memory;
325
Free_LookupList( &gpos->LookupList, GPOS, memory );
326
Free_FeatureList( &gpos->FeatureList, memory );
327
Free_ScriptList( &gpos->ScriptList, memory );
333
/*****************************
334
* SubTable related functions
335
*****************************/
341
/* There is a subtle difference in the specs between a `table' and a
342
`record' -- offsets for device tables in ValueRecords are taken from
343
the parent table and not the parent record. */
345
static FT_Error Load_ValueRecord( TTO_ValueRecord* vr,
347
FT_ULong base_offset,
351
FT_Memory memory = stream->memory;
353
FT_ULong cur_offset, new_offset;
356
if ( format & HAVE_X_PLACEMENT )
358
if ( ACCESS_Frame( 2L ) )
361
vr->XPlacement = GET_Short();
368
if ( format & HAVE_Y_PLACEMENT )
370
if ( ACCESS_Frame( 2L ) )
373
vr->YPlacement = GET_Short();
380
if ( format & HAVE_X_ADVANCE )
382
if ( ACCESS_Frame( 2L ) )
385
vr->XAdvance = GET_Short();
392
if ( format & HAVE_Y_ADVANCE )
394
if ( ACCESS_Frame( 2L ) )
397
vr->YAdvance = GET_Short();
404
if ( format & HAVE_X_PLACEMENT_DEVICE )
406
if ( ACCESS_Frame( 2L ) )
409
new_offset = GET_UShort();
415
new_offset += base_offset;
417
cur_offset = FILE_Pos();
418
if ( FILE_Seek( new_offset ) ||
419
( error = Load_Device( &vr->XPlacementDevice,
420
stream ) ) != TT_Err_Ok )
422
(void)FILE_Seek( cur_offset );
430
vr->XPlacementDevice.StartSize = 0;
431
vr->XPlacementDevice.EndSize = 0;
432
vr->XPlacementDevice.DeltaValue = NULL;
435
if ( format & HAVE_Y_PLACEMENT_DEVICE )
437
if ( ACCESS_Frame( 2L ) )
440
new_offset = GET_UShort();
446
new_offset += base_offset;
448
cur_offset = FILE_Pos();
449
if ( FILE_Seek( new_offset ) ||
450
( error = Load_Device( &vr->YPlacementDevice,
451
stream ) ) != TT_Err_Ok )
453
(void)FILE_Seek( cur_offset );
461
vr->YPlacementDevice.StartSize = 0;
462
vr->YPlacementDevice.EndSize = 0;
463
vr->YPlacementDevice.DeltaValue = NULL;
466
if ( format & HAVE_X_ADVANCE_DEVICE )
468
if ( ACCESS_Frame( 2L ) )
471
new_offset = GET_UShort();
477
new_offset += base_offset;
479
cur_offset = FILE_Pos();
480
if ( FILE_Seek( new_offset ) ||
481
( error = Load_Device( &vr->XAdvanceDevice,
482
stream ) ) != TT_Err_Ok )
484
(void)FILE_Seek( cur_offset );
492
vr->XAdvanceDevice.StartSize = 0;
493
vr->XAdvanceDevice.EndSize = 0;
494
vr->XAdvanceDevice.DeltaValue = NULL;
497
if ( format & HAVE_Y_ADVANCE_DEVICE )
499
if ( ACCESS_Frame( 2L ) )
502
new_offset = GET_UShort();
508
new_offset += base_offset;
510
cur_offset = FILE_Pos();
511
if ( FILE_Seek( new_offset ) ||
512
( error = Load_Device( &vr->YAdvanceDevice,
513
stream ) ) != TT_Err_Ok )
515
(void)FILE_Seek( cur_offset );
523
vr->YAdvanceDevice.StartSize = 0;
524
vr->YAdvanceDevice.EndSize = 0;
525
vr->YAdvanceDevice.DeltaValue = NULL;
528
if ( format & HAVE_X_ID_PLACEMENT )
530
if ( ACCESS_Frame( 2L ) )
533
vr->XIdPlacement = GET_UShort();
538
vr->XIdPlacement = 0;
540
if ( format & HAVE_Y_ID_PLACEMENT )
542
if ( ACCESS_Frame( 2L ) )
545
vr->YIdPlacement = GET_UShort();
550
vr->YIdPlacement = 0;
552
if ( format & HAVE_X_ID_ADVANCE )
554
if ( ACCESS_Frame( 2L ) )
557
vr->XIdAdvance = GET_UShort();
564
if ( format & HAVE_Y_ID_ADVANCE )
566
if ( ACCESS_Frame( 2L ) )
569
vr->YIdAdvance = GET_UShort();
579
Free_Device( &vr->YAdvanceDevice, memory );
582
Free_Device( &vr->XAdvanceDevice, memory );
585
Free_Device( &vr->YPlacementDevice, memory );
590
static void Free_ValueRecord( TTO_ValueRecord* vr,
594
if ( format & HAVE_Y_ADVANCE_DEVICE )
595
Free_Device( &vr->YAdvanceDevice, memory );
596
if ( format & HAVE_X_ADVANCE_DEVICE )
597
Free_Device( &vr->XAdvanceDevice, memory );
598
if ( format & HAVE_Y_PLACEMENT_DEVICE )
599
Free_Device( &vr->YPlacementDevice, memory );
600
if ( format & HAVE_X_PLACEMENT_DEVICE )
601
Free_Device( &vr->XPlacementDevice, memory );
605
static FT_Error Get_ValueRecord( GPOS_Instance* gpi,
611
FT_Short pixel_value;
612
FT_Error error = TT_Err_Ok;
613
TTO_GPOSHeader* gpos = gpi->gpos;
615
FT_UShort x_ppem, y_ppem;
616
FT_Fixed x_scale, y_scale;
622
x_ppem = gpi->face->size->metrics.x_ppem;
623
y_ppem = gpi->face->size->metrics.y_ppem;
624
x_scale = gpi->face->size->metrics.x_scale;
625
y_scale = gpi->face->size->metrics.y_scale;
627
/* design units -> fractional pixel */
629
if ( format & HAVE_X_PLACEMENT )
630
gd->x_pos += x_scale * vr->XPlacement / 0x10000;
631
if ( format & HAVE_Y_PLACEMENT )
632
gd->y_pos += y_scale * vr->YPlacement / 0x10000;
633
if ( format & HAVE_X_ADVANCE )
634
gd->x_advance += x_scale * vr->XAdvance / 0x10000;
635
if ( format & HAVE_Y_ADVANCE )
636
gd->y_advance += y_scale * vr->YAdvance / 0x10000;
640
/* pixel -> fractional pixel */
642
if ( format & HAVE_X_PLACEMENT_DEVICE )
644
Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
645
gd->x_pos += pixel_value << 6;
647
if ( format & HAVE_Y_PLACEMENT_DEVICE )
649
Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
650
gd->y_pos += pixel_value << 6;
652
if ( format & HAVE_X_ADVANCE_DEVICE )
654
Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
655
gd->x_advance += pixel_value << 6;
657
if ( format & HAVE_Y_ADVANCE_DEVICE )
659
Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
660
gd->y_advance += pixel_value << 6;
664
/* values returned from mmfunc() are already in fractional pixels */
666
if ( format & HAVE_X_ID_PLACEMENT )
668
error = (gpos->mmfunc)( gpi->face, vr->XIdPlacement,
669
&value, gpos->data );
674
if ( format & HAVE_Y_ID_PLACEMENT )
676
error = (gpos->mmfunc)( gpi->face, vr->YIdPlacement,
677
&value, gpos->data );
682
if ( format & HAVE_X_ID_ADVANCE )
684
error = (gpos->mmfunc)( gpi->face, vr->XIdAdvance,
685
&value, gpos->data );
688
gd->x_advance += value;
690
if ( format & HAVE_Y_ID_ADVANCE )
692
error = (gpos->mmfunc)( gpi->face, vr->YIdAdvance,
693
&value, gpos->data );
696
gd->y_advance += value;
708
static FT_Error Load_Anchor( TTO_Anchor* an,
712
FT_Memory memory = stream->memory;
714
FT_ULong cur_offset, new_offset, base_offset;
717
base_offset = FILE_Pos();
719
if ( ACCESS_Frame( 2L ) )
722
an->PosFormat = GET_UShort();
726
switch ( an->PosFormat )
729
if ( ACCESS_Frame( 4L ) )
732
an->af.af1.XCoordinate = GET_Short();
733
an->af.af1.YCoordinate = GET_Short();
739
if ( ACCESS_Frame( 6L ) )
742
an->af.af2.XCoordinate = GET_Short();
743
an->af.af2.YCoordinate = GET_Short();
744
an->af.af2.AnchorPoint = GET_UShort();
750
if ( ACCESS_Frame( 6L ) )
753
an->af.af3.XCoordinate = GET_Short();
754
an->af.af3.YCoordinate = GET_Short();
756
new_offset = GET_UShort();
762
new_offset += base_offset;
764
cur_offset = FILE_Pos();
765
if ( FILE_Seek( new_offset ) ||
766
( error = Load_Device( &an->af.af3.XDeviceTable,
767
stream ) ) != TT_Err_Ok )
769
(void)FILE_Seek( cur_offset );
773
an->af.af3.XDeviceTable.StartSize = 0;
774
an->af.af3.XDeviceTable.EndSize = 0;
775
an->af.af3.XDeviceTable.DeltaValue = 0;
778
if ( ACCESS_Frame( 2L ) )
781
new_offset = GET_UShort();
787
new_offset += base_offset;
789
cur_offset = FILE_Pos();
790
if ( FILE_Seek( new_offset ) ||
791
( error = Load_Device( &an->af.af3.YDeviceTable,
792
stream ) ) != TT_Err_Ok )
794
(void)FILE_Seek( cur_offset );
798
an->af.af3.YDeviceTable.StartSize = 0;
799
an->af.af3.YDeviceTable.EndSize = 0;
800
an->af.af3.YDeviceTable.DeltaValue = 0;
805
if ( ACCESS_Frame( 4L ) )
808
an->af.af4.XIdAnchor = GET_UShort();
809
an->af.af4.YIdAnchor = GET_UShort();
815
return TTO_Err_Invalid_GPOS_SubTable_Format;
821
Free_Device( &an->af.af3.XDeviceTable, memory );
826
static void Free_Anchor( TTO_Anchor* an,
829
if ( an->PosFormat == 3 )
831
Free_Device( &an->af.af3.YDeviceTable, memory );
832
Free_Device( &an->af.af3.XDeviceTable, memory );
837
static FT_Error Get_Anchor( GPOS_Instance* gpi,
839
FT_UShort glyph_index,
843
FT_Error error = TT_Err_Ok;
846
TTO_GPOSHeader* gpos = gpi->gpos;
849
FT_Short pixel_value;
850
FT_UShort load_flags;
852
FT_UShort x_ppem, y_ppem;
853
FT_Fixed x_scale, y_scale;
856
x_ppem = gpi->face->size->metrics.x_ppem;
857
y_ppem = gpi->face->size->metrics.y_ppem;
858
x_scale = gpi->face->size->metrics.x_scale;
859
y_scale = gpi->face->size->metrics.y_scale;
861
switch ( an->PosFormat )
864
/* The special case of an empty AnchorTable */
866
return TTO_Err_Not_Covered;
869
*x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
870
*y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
874
/* glyphs must be scaled */
876
load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE;
880
error = (gpos->gfunc)( gpi->face, glyph_index, load_flags );
884
if ( gpi->face->glyph->format != ft_glyph_format_outline )
885
return TTO_Err_Invalid_GPOS_SubTable;
887
ap = an->af.af2.AnchorPoint;
889
outline = gpi->face->glyph->outline;
891
/* if outline.n_points is set to zero by gfunc(), we use the
892
design coordinate value pair. This can happen e.g. for
895
if ( !outline.n_points )
896
goto no_contour_point;
898
if ( ap >= outline.n_points )
899
return TTO_Err_Invalid_GPOS_SubTable;
901
*x_value = outline.points[ap].x;
902
*y_value = outline.points[ap].y;
907
*x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
908
*y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
915
Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
916
*x_value = pixel_value << 6;
917
Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
918
*y_value = pixel_value << 6;
921
*x_value = *y_value = 0;
923
*x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
924
*y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
928
error = (gpos->mmfunc)( gpi->face, an->af.af4.XIdAnchor,
929
x_value, gpos->data );
933
error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor,
934
y_value, gpos->data );
946
static FT_Error Load_MarkArray ( TTO_MarkArray* ma,
950
FT_Memory memory = stream->memory;
952
FT_UShort n, m, count;
953
FT_ULong cur_offset, new_offset, base_offset;
958
base_offset = FILE_Pos();
960
if ( ACCESS_Frame( 2L ) )
963
count = ma->MarkCount = GET_UShort();
967
ma->MarkRecord = NULL;
969
if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) )
974
for ( n = 0; n < count; n++ )
976
if ( ACCESS_Frame( 4L ) )
979
mr[n].Class = GET_UShort();
980
new_offset = GET_UShort() + base_offset;
984
cur_offset = FILE_Pos();
985
if ( FILE_Seek( new_offset ) ||
986
( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != TT_Err_Ok )
988
(void)FILE_Seek( cur_offset );
994
for ( m = 0; m < n; m++ )
995
Free_Anchor( &mr[m].MarkAnchor, memory );
1002
static void Free_MarkArray( TTO_MarkArray* ma,
1010
if ( ma->MarkRecord )
1012
count = ma->MarkCount;
1013
mr = ma->MarkRecord;
1015
for ( n = 0; n < count; n++ )
1016
Free_Anchor( &mr[n].MarkAnchor, memory );
1025
/* SinglePosFormat1 */
1026
/* SinglePosFormat2 */
1028
FT_Error Load_SinglePos( TTO_SinglePos* sp,
1032
FT_Memory memory = stream->memory;
1034
FT_UShort n, m, count, format;
1035
FT_ULong cur_offset, new_offset, base_offset;
1037
TTO_ValueRecord* vr;
1040
base_offset = FILE_Pos();
1042
if ( ACCESS_Frame( 6L ) )
1045
sp->PosFormat = GET_UShort();
1046
new_offset = GET_UShort() + base_offset;
1048
format = sp->ValueFormat = GET_UShort();
1053
return TTO_Err_Invalid_GPOS_SubTable;
1055
cur_offset = FILE_Pos();
1056
if ( FILE_Seek( new_offset ) ||
1057
( error = Load_Coverage( &sp->Coverage, stream ) ) != TT_Err_Ok )
1059
(void)FILE_Seek( cur_offset );
1061
switch ( sp->PosFormat )
1064
error = Load_ValueRecord( &sp->spf.spf1.Value, format,
1065
base_offset, stream );
1071
if ( ACCESS_Frame( 2L ) )
1074
count = sp->spf.spf2.ValueCount = GET_UShort();
1078
sp->spf.spf2.Value = NULL;
1080
if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) )
1083
vr = sp->spf.spf2.Value;
1085
for ( n = 0; n < count; n++ )
1087
error = Load_ValueRecord( &vr[n], format, base_offset, stream );
1094
return TTO_Err_Invalid_GPOS_SubTable_Format;
1100
for ( m = 0; m < n; m++ )
1101
Free_ValueRecord( &vr[m], format, memory );
1106
Free_Coverage( &sp->Coverage, memory );
1111
void Free_SinglePos( TTO_SinglePos* sp,
1114
FT_UShort n, count, format;
1119
format = sp->ValueFormat;
1121
switch ( sp->PosFormat )
1124
Free_ValueRecord( &sp->spf.spf1.Value, format, memory );
1128
if ( sp->spf.spf2.Value )
1130
count = sp->spf.spf2.ValueCount;
1131
v = sp->spf.spf2.Value;
1133
for ( n = 0; n < count; n++ )
1134
Free_ValueRecord( &v[n], format, memory );
1141
Free_Coverage( &sp->Coverage, memory );
1145
static FT_Error Lookup_SinglePos( GPOS_Instance* gpi,
1147
TTO_GSUB_String* in,
1150
FT_UShort context_length )
1152
FT_UShort index, property;
1154
TTO_GPOSHeader* gpos = gpi->gpos;
1157
if ( context_length != 0xFFFF && context_length < 1 )
1158
return TTO_Err_Not_Covered;
1160
if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
1163
error = Coverage_Index( &sp->Coverage, in->string[in->pos], &index );
1167
switch ( sp->PosFormat )
1170
error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
1171
sp->ValueFormat, &out[in->pos] );
1177
if ( index >= sp->spf.spf2.ValueCount )
1178
return TTO_Err_Invalid_GPOS_SubTable;
1179
error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
1180
sp->ValueFormat, &out[in->pos] );
1186
return TTO_Err_Invalid_GPOS_SubTable;
1199
static FT_Error Load_PairSet ( TTO_PairSet* ps,
1205
FT_Memory memory = stream->memory;
1207
FT_UShort n, m, count;
1208
FT_ULong base_offset;
1210
TTO_PairValueRecord* pvr;
1213
base_offset = FILE_Pos();
1215
if ( ACCESS_Frame( 2L ) )
1218
count = ps->PairValueCount = GET_UShort();
1222
ps->PairValueRecord = NULL;
1224
if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) )
1227
pvr = ps->PairValueRecord;
1229
for ( n = 0; n < count; n++ )
1231
if ( ACCESS_Frame( 2L ) )
1234
pvr[n].SecondGlyph = GET_UShort();
1240
error = Load_ValueRecord( &pvr[n].Value1, format1,
1241
base_offset, stream );
1247
error = Load_ValueRecord( &pvr[n].Value2, format2,
1248
base_offset, stream );
1252
Free_ValueRecord( &pvr[n].Value1, format1, memory );
1261
for ( m = 0; m < n; m++ )
1264
Free_ValueRecord( &pvr[m].Value1, format1, memory );
1266
Free_ValueRecord( &pvr[m].Value2, format2, memory );
1274
static void Free_PairSet( TTO_PairSet* ps,
1281
TTO_PairValueRecord* pvr;
1284
if ( ps->PairValueRecord )
1286
count = ps->PairValueCount;
1287
pvr = ps->PairValueRecord;
1289
for ( n = 0; n < count; n++ )
1292
Free_ValueRecord( &pvr[n].Value1, format1, memory );
1294
Free_ValueRecord( &pvr[n].Value2, format2, memory );
1302
/* PairPosFormat1 */
1304
static FT_Error Load_PairPos1( TTO_PairPosFormat1* ppf1,
1310
FT_Memory memory = stream->memory;
1312
FT_UShort n, m, count;
1313
FT_ULong cur_offset, new_offset, base_offset;
1318
base_offset = FILE_Pos() - 8L;
1320
if ( ACCESS_Frame( 2L ) )
1323
count = ppf1->PairSetCount = GET_UShort();
1327
ppf1->PairSet = NULL;
1329
if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) )
1334
for ( n = 0; n < count; n++ )
1336
if ( ACCESS_Frame( 2L ) )
1339
new_offset = GET_UShort() + base_offset;
1343
cur_offset = FILE_Pos();
1344
if ( FILE_Seek( new_offset ) ||
1345
( error = Load_PairSet( &ps[n], format1,
1346
format2, stream ) ) != TT_Err_Ok )
1348
(void)FILE_Seek( cur_offset );
1354
for ( m = 0; m < n; m++ )
1355
Free_PairSet( &ps[m], format1, format2, memory );
1362
static void Free_PairPos1( TTO_PairPosFormat1* ppf1,
1372
if ( ppf1->PairSet )
1374
count = ppf1->PairSetCount;
1377
for ( n = 0; n < count; n++ )
1378
Free_PairSet( &ps[n], format1, format2, memory );
1385
/* PairPosFormat2 */
1387
static FT_Error Load_PairPos2( TTO_PairPosFormat2* ppf2,
1393
FT_Memory memory = stream->memory;
1395
FT_UShort m, n, k, count1, count2;
1396
FT_ULong cur_offset, new_offset1, new_offset2, base_offset;
1398
TTO_Class1Record* c1r;
1399
TTO_Class2Record* c2r;
1402
base_offset = FILE_Pos() - 8L;
1404
if ( ACCESS_Frame( 8L ) )
1407
new_offset1 = GET_UShort() + base_offset;
1408
new_offset2 = GET_UShort() + base_offset;
1410
/* `Class1Count' and `Class2Count' are the upper limits for class
1411
values, thus we read it now to make additional safety checks. */
1413
count1 = ppf2->Class1Count = GET_UShort();
1414
count2 = ppf2->Class2Count = GET_UShort();
1418
cur_offset = FILE_Pos();
1419
if ( FILE_Seek( new_offset1 ) ||
1420
( error = Load_ClassDefinition( &ppf2->ClassDef1, count1,
1421
stream ) ) != TT_Err_Ok )
1423
if ( FILE_Seek( new_offset2 ) ||
1424
( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
1425
stream ) ) != TT_Err_Ok )
1427
(void)FILE_Seek( cur_offset );
1429
ppf2->Class1Record = NULL;
1431
if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
1434
c1r = ppf2->Class1Record;
1436
for ( m = 0; m < count1; m++ )
1438
c1r[m].Class2Record = NULL;
1440
if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) )
1443
c2r = c1r[m].Class2Record;
1445
for ( n = 0; n < count2; n++ )
1449
error = Load_ValueRecord( &c2r[n].Value1, format1,
1450
base_offset, stream );
1456
error = Load_ValueRecord( &c2r[n].Value2, format2,
1457
base_offset, stream );
1461
Free_ValueRecord( &c2r[n].Value1, format1, memory );
1470
for ( k = 0; k < n; k++ )
1473
Free_ValueRecord( &c2r[k].Value1, format1, memory );
1475
Free_ValueRecord( &c2r[k].Value2, format2, memory );
1483
for ( k = 0; k < m; k++ )
1485
c2r = c1r[k].Class2Record;
1487
for ( n = 0; n < count2; n++ )
1490
Free_ValueRecord( &c2r[n].Value1, format1, memory );
1492
Free_ValueRecord( &c2r[n].Value2, format2, memory );
1501
Free_ClassDefinition( &ppf2->ClassDef2, memory );
1504
Free_ClassDefinition( &ppf2->ClassDef1, memory );
1509
static void Free_PairPos2( TTO_PairPosFormat2* ppf2,
1514
FT_UShort m, n, count1, count2;
1516
TTO_Class1Record* c1r;
1517
TTO_Class2Record* c2r;
1520
if ( ppf2->Class1Record )
1522
c1r = ppf2->Class1Record;
1523
count1 = ppf2->Class1Count;
1524
count2 = ppf2->Class2Count;
1526
for ( m = 0; m < count1; m++ )
1528
c2r = c1r[m].Class2Record;
1530
for ( n = 0; n < count2; n++ )
1533
Free_ValueRecord( &c2r[n].Value1, format1, memory );
1535
Free_ValueRecord( &c2r[n].Value2, format2, memory );
1543
Free_ClassDefinition( &ppf2->ClassDef2, memory );
1544
Free_ClassDefinition( &ppf2->ClassDef1, memory );
1549
FT_Error Load_PairPos( TTO_PairPos* pp,
1553
FT_Memory memory = stream->memory;
1555
FT_UShort format1, format2;
1556
FT_ULong cur_offset, new_offset, base_offset;
1559
base_offset = FILE_Pos();
1561
if ( ACCESS_Frame( 8L ) )
1564
pp->PosFormat = GET_UShort();
1565
new_offset = GET_UShort() + base_offset;
1567
format1 = pp->ValueFormat1 = GET_UShort();
1568
format2 = pp->ValueFormat2 = GET_UShort();
1572
cur_offset = FILE_Pos();
1573
if ( FILE_Seek( new_offset ) ||
1574
( error = Load_Coverage( &pp->Coverage, stream ) ) != TT_Err_Ok )
1576
(void)FILE_Seek( cur_offset );
1578
switch ( pp->PosFormat )
1581
error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
1587
error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
1593
return TTO_Err_Invalid_GPOS_SubTable_Format;
1599
Free_Coverage( &pp->Coverage, memory );
1604
void Free_PairPos( TTO_PairPos* pp,
1607
FT_UShort format1, format2;
1610
format1 = pp->ValueFormat1;
1611
format2 = pp->ValueFormat2;
1613
switch ( pp->PosFormat )
1616
Free_PairPos1( &pp->ppf.ppf1, format1, format2, memory );
1620
Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory );
1624
Free_Coverage( &pp->Coverage, memory );
1628
static FT_Error Lookup_PairPos1( GPOS_Instance* gpi,
1629
TTO_PairPosFormat1* ppf1,
1630
TTO_GSUB_String* in,
1632
FT_UShort first_pos,
1638
FT_UShort numpvr, glyph2;
1640
TTO_PairValueRecord* pvr;
1643
if ( index >= ppf1->PairSetCount )
1644
return TTO_Err_Invalid_GPOS_SubTable;
1646
pvr = ppf1->PairSet[index].PairValueRecord;
1648
return TTO_Err_Invalid_GPOS_SubTable;
1650
glyph2 = in->string[in->pos];
1652
for ( numpvr = ppf1->PairSet[index].PairValueCount;
1656
if ( glyph2 == pvr->SecondGlyph )
1658
error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1662
return Get_ValueRecord( gpi, &pvr->Value2, format2,
1667
return TTO_Err_Not_Covered;
1671
static FT_Error Lookup_PairPos2( GPOS_Instance* gpi,
1672
TTO_PairPosFormat2* ppf2,
1673
TTO_GSUB_String* in,
1675
FT_UShort first_pos,
1682
TTO_Class1Record* c1r;
1683
TTO_Class2Record* c2r;
1686
error = Get_Class( &ppf2->ClassDef1, in->string[first_pos],
1688
if ( error && error != TTO_Err_Not_Covered )
1690
error = Get_Class( &ppf2->ClassDef2, in->string[in->pos],
1692
if ( error && error != TTO_Err_Not_Covered )
1695
c1r = &ppf2->Class1Record[cl1];
1697
return TTO_Err_Invalid_GPOS_SubTable;
1698
c2r = &c1r->Class2Record[cl2];
1700
error = Get_ValueRecord( gpi, &c2r->Value1, format1, &out[first_pos] );
1703
return Get_ValueRecord( gpi, &c2r->Value2, format2, &out[in->pos] );
1707
static FT_Error Lookup_PairPos( GPOS_Instance* gpi,
1709
TTO_GSUB_String* in,
1712
FT_UShort context_length )
1715
FT_UShort index, property, first_pos;
1716
TTO_GPOSHeader* gpos = gpi->gpos;
1719
if ( in->pos >= in->length - 1 )
1720
return TTO_Err_Not_Covered; /* Not enough glyphs in stream */
1722
if ( context_length != 0xFFFF && context_length < 2 )
1723
return TTO_Err_Not_Covered;
1725
error = Coverage_Index( &pp->Coverage, in->string[in->pos], &index );
1729
if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
1734
first_pos = in->pos;
1737
while ( CHECK_Property( gpos->gdef, in->string[in->pos],
1738
flags, &property ) )
1740
if ( error && error != TTO_Err_Not_Covered )
1743
if ( in->pos < in->length )
1749
if ( pp->PosFormat == 1 )
1750
error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, in, out,
1752
pp->ValueFormat1, pp->ValueFormat2 );
1753
else if ( pp->PosFormat == 2 )
1754
error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, in, out, first_pos,
1755
pp->ValueFormat1, pp->ValueFormat2 );
1757
return TTO_Err_Invalid_GPOS_SubTable_Format;
1759
/* adjusting the `next' glyph */
1761
if ( pp->ValueFormat2 )
1770
/* CursivePosFormat1 */
1772
FT_Error Load_CursivePos( TTO_CursivePos* cp,
1776
FT_Memory memory = stream->memory;
1778
FT_UShort n, m, count;
1779
FT_ULong cur_offset, new_offset, base_offset;
1781
TTO_EntryExitRecord* eer;
1784
base_offset = FILE_Pos();
1786
if ( ACCESS_Frame( 4L ) )
1789
cp->PosFormat = GET_UShort();
1790
new_offset = GET_UShort() + base_offset;
1794
cur_offset = FILE_Pos();
1795
if ( FILE_Seek( new_offset ) ||
1796
( error = Load_Coverage( &cp->Coverage, stream ) ) != TT_Err_Ok )
1798
(void)FILE_Seek( cur_offset );
1800
if ( ACCESS_Frame( 2L ) )
1803
count = cp->EntryExitCount = GET_UShort();
1807
cp->EntryExitRecord = NULL;
1809
if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) )
1812
eer = cp->EntryExitRecord;
1814
for ( n = 0; n < count; n++ )
1816
FT_ULong entry_offset;
1818
if ( ACCESS_Frame( 2L ) )
1821
entry_offset = new_offset = GET_UShort();
1827
new_offset += base_offset;
1829
cur_offset = FILE_Pos();
1830
if ( FILE_Seek( new_offset ) ||
1831
( error = Load_Anchor( &eer[n].EntryAnchor,
1832
stream ) ) != TT_Err_Ok )
1834
(void)FILE_Seek( cur_offset );
1837
eer[n].EntryAnchor.PosFormat = 0;
1839
if ( ACCESS_Frame( 2L ) )
1842
new_offset = GET_UShort();
1848
new_offset += base_offset;
1850
cur_offset = FILE_Pos();
1851
if ( FILE_Seek( new_offset ) ||
1852
( error = Load_Anchor( &eer[n].ExitAnchor,
1853
stream ) ) != TT_Err_Ok )
1856
Free_Anchor( &eer[n].EntryAnchor, memory );
1859
(void)FILE_Seek( cur_offset );
1862
eer[n].ExitAnchor.PosFormat = 0;
1868
for ( m = 0; m < n; m++ )
1870
Free_Anchor( &eer[m].EntryAnchor, memory );
1871
Free_Anchor( &eer[m].ExitAnchor, memory );
1877
Free_Coverage( &cp->Coverage, memory );
1882
void Free_CursivePos( TTO_CursivePos* cp,
1887
TTO_EntryExitRecord* eer;
1890
if ( cp->EntryExitRecord )
1892
count = cp->EntryExitCount;
1893
eer = cp->EntryExitRecord;
1895
for ( n = 0; n < count; n++ )
1897
Free_Anchor( &eer[n].EntryAnchor, memory );
1898
Free_Anchor( &eer[n].ExitAnchor, memory );
1904
Free_Coverage( &cp->Coverage, memory );
1908
static FT_Error Lookup_CursivePos( GPOS_Instance* gpi,
1910
TTO_GSUB_String* in,
1913
FT_UShort context_length )
1915
FT_UShort index, property;
1917
TTO_GPOSHeader* gpos = gpi->gpos;
1919
TTO_EntryExitRecord* eer;
1920
FT_Pos entry_x, entry_y;
1921
FT_Pos exit_x, exit_y;
1924
if ( context_length != 0xFFFF && context_length < 1 )
1927
return TTO_Err_Not_Covered;
1930
error = Coverage_Index( &cp->Coverage, in->string[in->pos], &index );
1937
if ( index >= cp->EntryExitCount )
1938
return TTO_Err_Invalid_GPOS_SubTable;
1940
/* Glyphs not having the right GDEF properties will be ignored, i.e.,
1941
gpi->last won't be reset (contrary to user defined properties). */
1943
if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
1946
/* We don't handle mark glyphs here. According to Andrei, this isn't
1947
possible, but who knows... */
1949
if ( property == MARK_GLYPH )
1952
return TTO_Err_Not_Covered;
1956
eer = &cp->EntryExitRecord[index];
1958
/* Now comes the messiest part of the whole OpenType
1959
specification. At first glance, cursive connections seem easy
1960
to understand, but there are pitfalls! The reason is that
1961
the specs don't mention how to compute the advance values
1962
resp. glyph offsets. I was told it would be an omission, to
1963
be fixed in the next OpenType version... Again many thanks to
1964
Andrei Burago <andreib@microsoft.com> for clarifications.
1966
Consider the following example:
1979
glyph1: advance width = 12
1980
anchor point = (3,1)
1982
glyph2: advance width = 11
1983
anchor point = (9,4)
1985
LSB is 1 for both glyphs (so the boxes drawn above are glyph
1986
bboxes). Writing direction is R2L; `0' denotes the glyph's
1989
Now the surprising part: The advance width of the *left* glyph
1990
(resp. of the *bottom* glyph) will be modified, no matter
1991
whether the writing direction is L2R or R2L (resp. T2B or
1992
B2T)! This assymetry is caused by the fact that the glyph's
1993
coordinate origin is always the lower left corner for all
1996
Continuing the above example, we can compute the new
1997
(horizontal) advance width of glyph2 as
2001
and the new vertical offset of glyph2 as
2006
Vertical writing direction is far more complicated:
2008
a) Assuming that we recompute the advance height of the lower glyph:
2013
+-----+--+ 1 | yadv1
2015
yadv2 | 0+--+------+ -- BSB1 --
2016
| 2 | -- -- y_offset
2018
BSB2 -- 0+--------+ --
2021
glyph1: advance height = 6
2022
anchor point = (3,1)
2024
glyph2: advance height = 7
2025
anchor point = (9,4)
2027
TSB is 1 for both glyphs; writing direction is T2B.
2030
BSB1 = yadv1 - (TSB1 + ymax1)
2031
BSB2 = yadv2 - (TSB2 + ymax2)
2034
vertical advance width of glyph2
2035
= y_offset + BSB2 - BSB1
2036
= (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
2037
= y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
2038
= y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
2041
b) Assuming that we recompute the advance height of the upper glyph:
2046
TSB2 -- +-----+--+ 1 | yadv1 ymax1
2048
yadv2 | 0+--+------+ -- --
2049
ymax2 | 2 | -- y_offset
2054
glyph1: advance height = 6
2055
anchor point = (3,1)
2057
glyph2: advance height = 7
2058
anchor point = (9,4)
2060
TSB is 1 for both glyphs; writing direction is T2B.
2064
vertical advance width of glyph2
2065
= TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
2066
= TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
2069
Comparing a) with b) shows that b) is easier to compute. I'll wait
2070
for a reply from Andrei to see what should really be implemented...
2072
Since horizontal advance widths or vertical advance heights
2073
can be used alone but not together, no ambiguity occurs. */
2075
if ( gpi->last == 0xFFFF )
2078
/* Get_Anchor() returns TTO_Err_Not_Covered if there is no anchor
2081
error = Get_Anchor( gpi, &eer->EntryAnchor, in->string[in->pos],
2082
&entry_x, &entry_y );
2083
if ( error == TTO_Err_Not_Covered )
2090
out[in->pos].x_advance = entry_x - gpi->anchor_x;
2091
out[in->pos].new_advance = TRUE;
2095
out[gpi->last].x_advance = gpi->anchor_x - entry_x;
2096
out[gpi->last].new_advance = TRUE;
2099
out[in->pos].y_pos = gpi->anchor_y - entry_y + out[gpi->last].y_pos;
2102
error = Get_Anchor( gpi, &eer->ExitAnchor, in->string[in->pos],
2104
if ( error == TTO_Err_Not_Covered )
2108
if ( gpi->first == 0xFFFF )
2109
gpi->first = in->pos;
2110
gpi->last = in->pos;
2111
gpi->anchor_x = exit_x;
2112
gpi->anchor_y = exit_y;
2127
static FT_Error Load_BaseArray( TTO_BaseArray* ba,
2128
FT_UShort num_classes,
2132
FT_Memory memory = stream->memory;
2134
FT_UShort m, n, k, count;
2135
FT_ULong cur_offset, new_offset, base_offset;
2141
base_offset = FILE_Pos();
2143
if ( ACCESS_Frame( 2L ) )
2146
count = ba->BaseCount = GET_UShort();
2150
ba->BaseRecord = NULL;
2152
if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) )
2155
br = ba->BaseRecord;
2157
for ( m = 0; m < count; m++ )
2159
br[m].BaseAnchor = NULL;
2161
if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) )
2164
ban = br[m].BaseAnchor;
2166
for ( n = 0; n < num_classes; n++ )
2168
if ( ACCESS_Frame( 2L ) )
2171
new_offset = GET_UShort() + base_offset;
2175
cur_offset = FILE_Pos();
2176
if ( FILE_Seek( new_offset ) ||
2177
( error = Load_Anchor( &ban[n], stream ) ) != TT_Err_Ok )
2179
(void)FILE_Seek( cur_offset );
2184
for ( k = 0; k < n; k++ )
2185
Free_Anchor( &ban[k], memory );
2192
for ( k = 0; k < m; k++ )
2194
ban = br[k].BaseAnchor;
2196
for ( n = 0; n < num_classes; n++ )
2197
Free_Anchor( &ban[n], memory );
2207
static void Free_BaseArray( TTO_BaseArray* ba,
2208
FT_UShort num_classes,
2211
FT_UShort m, n, count;
2217
if ( ba->BaseRecord )
2219
count = ba->BaseCount;
2220
br = ba->BaseRecord;
2222
for ( m = 0; m < count; m++ )
2224
ban = br[m].BaseAnchor;
2226
for ( n = 0; n < num_classes; n++ )
2227
Free_Anchor( &ban[n], memory );
2237
/* MarkBasePosFormat1 */
2239
FT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp,
2243
FT_Memory memory = stream->memory;
2245
FT_ULong cur_offset, new_offset, base_offset;
2248
base_offset = FILE_Pos();
2250
if ( ACCESS_Frame( 4L ) )
2253
mbp->PosFormat = GET_UShort();
2254
new_offset = GET_UShort() + base_offset;
2258
cur_offset = FILE_Pos();
2259
if ( FILE_Seek( new_offset ) ||
2260
( error = Load_Coverage( &mbp->MarkCoverage, stream ) ) != TT_Err_Ok )
2262
(void)FILE_Seek( cur_offset );
2264
if ( ACCESS_Frame( 2L ) )
2267
new_offset = GET_UShort() + base_offset;
2271
cur_offset = FILE_Pos();
2272
if ( FILE_Seek( new_offset ) ||
2273
( error = Load_Coverage( &mbp->BaseCoverage, stream ) ) != TT_Err_Ok )
2275
(void)FILE_Seek( cur_offset );
2277
if ( ACCESS_Frame( 4L ) )
2280
mbp->ClassCount = GET_UShort();
2281
new_offset = GET_UShort() + base_offset;
2285
cur_offset = FILE_Pos();
2286
if ( FILE_Seek( new_offset ) ||
2287
( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != TT_Err_Ok )
2289
(void)FILE_Seek( cur_offset );
2291
if ( ACCESS_Frame( 2L ) )
2294
new_offset = GET_UShort() + base_offset;
2298
cur_offset = FILE_Pos();
2299
if ( FILE_Seek( new_offset ) ||
2300
( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2301
stream ) ) != TT_Err_Ok )
2307
Free_MarkArray( &mbp->MarkArray, memory );
2310
Free_Coverage( &mbp->BaseCoverage, memory );
2313
Free_Coverage( &mbp->MarkCoverage, memory );
2318
void Free_MarkBasePos( TTO_MarkBasePos* mbp,
2321
Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory );
2322
Free_MarkArray( &mbp->MarkArray, memory );
2323
Free_Coverage( &mbp->BaseCoverage, memory );
2324
Free_Coverage( &mbp->MarkCoverage, memory );
2328
static FT_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
2329
TTO_MarkBasePos* mbp,
2330
TTO_GSUB_String* in,
2333
FT_UShort context_length )
2335
FT_UShort i, j, mark_index, base_index, property, klass;
2336
FT_Pos x_mark_value, y_mark_value, x_base_value, y_base_value;
2338
TTO_GPOSHeader* gpos = gpi->gpos;
2343
TTO_Anchor* mark_anchor;
2344
TTO_Anchor* base_anchor;
2349
if ( context_length != 0xFFFF && context_length < 1 )
2350
return TTO_Err_Not_Covered;
2352
if ( flags & IGNORE_BASE_GLYPHS )
2353
return TTO_Err_Not_Covered;
2355
error = Coverage_Index( &mbp->MarkCoverage, in->string[in->pos],
2360
if ( CHECK_Property( gpos->gdef, in->string[in->pos],
2361
flags, &property ) )
2364
/* now we search backwards for a non-mark glyph */
2369
while ( i <= in->pos )
2371
error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
2376
if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) )
2383
/* The following assertion is too strong -- at least for mangal.ttf. */
2385
if ( property != TTO_BASE_GLYPH )
2386
return TTO_Err_Not_Covered;
2390
return TTO_Err_Not_Covered;
2392
error = Coverage_Index( &mbp->BaseCoverage, in->string[j],
2397
ma = &mbp->MarkArray;
2399
if ( mark_index >= ma->MarkCount )
2400
return TTO_Err_Invalid_GPOS_SubTable;
2402
klass = ma->MarkRecord[mark_index].Class;
2403
mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2405
if ( klass >= mbp->ClassCount )
2406
return TTO_Err_Invalid_GPOS_SubTable;
2408
ba = &mbp->BaseArray;
2410
if ( base_index >= ba->BaseCount )
2411
return TTO_Err_Invalid_GPOS_SubTable;
2413
br = &ba->BaseRecord[base_index];
2414
base_anchor = &br->BaseAnchor[klass];
2416
error = Get_Anchor( gpi, mark_anchor, in->string[in->pos],
2417
&x_mark_value, &y_mark_value );
2420
error = Get_Anchor( gpi, base_anchor, in->string[j],
2421
&x_base_value, &y_base_value );
2425
/* anchor points are not cumulative */
2429
o->x_pos = x_base_value - x_mark_value;
2430
o->y_pos = y_base_value - y_mark_value;
2443
/* LigatureAttach */
2445
static FT_Error Load_LigatureAttach( TTO_LigatureAttach* lat,
2446
FT_UShort num_classes,
2450
FT_Memory memory = stream->memory;
2452
FT_UShort m, n, k, count;
2453
FT_ULong cur_offset, new_offset, base_offset;
2455
TTO_ComponentRecord* cr;
2459
base_offset = FILE_Pos();
2461
if ( ACCESS_Frame( 2L ) )
2464
count = lat->ComponentCount = GET_UShort();
2468
lat->ComponentRecord = NULL;
2470
if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) )
2473
cr = lat->ComponentRecord;
2475
for ( m = 0; m < count; m++ )
2477
cr[m].LigatureAnchor = NULL;
2479
if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) )
2482
lan = cr[m].LigatureAnchor;
2484
for ( n = 0; n < num_classes; n++ )
2486
if ( ACCESS_Frame( 2L ) )
2489
new_offset = GET_UShort();
2495
new_offset += base_offset;
2497
cur_offset = FILE_Pos();
2498
if ( FILE_Seek( new_offset ) ||
2499
( error = Load_Anchor( &lan[n], stream ) ) != TT_Err_Ok )
2501
(void)FILE_Seek( cur_offset );
2504
lan[n].PosFormat = 0;
2509
for ( k = 0; k < n; k++ )
2510
Free_Anchor( &lan[k], memory );
2517
for ( k = 0; k < m; k++ )
2519
lan = cr[k].LigatureAnchor;
2521
for ( n = 0; n < num_classes; n++ )
2522
Free_Anchor( &lan[n], memory );
2532
static void Free_LigatureAttach( TTO_LigatureAttach* lat,
2533
FT_UShort num_classes,
2536
FT_UShort m, n, count;
2538
TTO_ComponentRecord* cr;
2542
if ( lat->ComponentRecord )
2544
count = lat->ComponentCount;
2545
cr = lat->ComponentRecord;
2547
for ( m = 0; m < count; m++ )
2549
lan = cr[m].LigatureAnchor;
2551
for ( n = 0; n < num_classes; n++ )
2552
Free_Anchor( &lan[n], memory );
2564
static FT_Error Load_LigatureArray( TTO_LigatureArray* la,
2565
FT_UShort num_classes,
2569
FT_Memory memory = stream->memory;
2571
FT_UShort n, m, count;
2572
FT_ULong cur_offset, new_offset, base_offset;
2574
TTO_LigatureAttach* lat;
2577
base_offset = FILE_Pos();
2579
if ( ACCESS_Frame( 2L ) )
2582
count = la->LigatureCount = GET_UShort();
2586
la->LigatureAttach = NULL;
2588
if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) )
2591
lat = la->LigatureAttach;
2593
for ( n = 0; n < count; n++ )
2595
if ( ACCESS_Frame( 2L ) )
2598
new_offset = GET_UShort() + base_offset;
2602
cur_offset = FILE_Pos();
2603
if ( FILE_Seek( new_offset ) ||
2604
( error = Load_LigatureAttach( &lat[n], num_classes,
2605
stream ) ) != TT_Err_Ok )
2607
(void)FILE_Seek( cur_offset );
2613
for ( m = 0; m < n; m++ )
2614
Free_LigatureAttach( &lat[m], num_classes, memory );
2621
static void Free_LigatureArray( TTO_LigatureArray* la,
2622
FT_UShort num_classes,
2627
TTO_LigatureAttach* lat;
2630
if ( la->LigatureAttach )
2632
count = la->LigatureCount;
2633
lat = la->LigatureAttach;
2635
for ( n = 0; n < count; n++ )
2636
Free_LigatureAttach( &lat[n], num_classes, memory );
2643
/* MarkLigPosFormat1 */
2645
FT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp,
2649
FT_Memory memory = stream->memory;
2651
FT_ULong cur_offset, new_offset, base_offset;
2654
base_offset = FILE_Pos();
2656
if ( ACCESS_Frame( 4L ) )
2659
mlp->PosFormat = GET_UShort();
2660
new_offset = GET_UShort() + base_offset;
2664
cur_offset = FILE_Pos();
2665
if ( FILE_Seek( new_offset ) ||
2666
( error = Load_Coverage( &mlp->MarkCoverage, stream ) ) != TT_Err_Ok )
2668
(void)FILE_Seek( cur_offset );
2670
if ( ACCESS_Frame( 2L ) )
2673
new_offset = GET_UShort() + base_offset;
2677
cur_offset = FILE_Pos();
2678
if ( FILE_Seek( new_offset ) ||
2679
( error = Load_Coverage( &mlp->LigatureCoverage,
2680
stream ) ) != TT_Err_Ok )
2682
(void)FILE_Seek( cur_offset );
2684
if ( ACCESS_Frame( 4L ) )
2687
mlp->ClassCount = GET_UShort();
2688
new_offset = GET_UShort() + base_offset;
2692
cur_offset = FILE_Pos();
2693
if ( FILE_Seek( new_offset ) ||
2694
( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != TT_Err_Ok )
2696
(void)FILE_Seek( cur_offset );
2698
if ( ACCESS_Frame( 2L ) )
2701
new_offset = GET_UShort() + base_offset;
2705
cur_offset = FILE_Pos();
2706
if ( FILE_Seek( new_offset ) ||
2707
( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2708
stream ) ) != TT_Err_Ok )
2714
Free_MarkArray( &mlp->MarkArray, memory );
2717
Free_Coverage( &mlp->LigatureCoverage, memory );
2720
Free_Coverage( &mlp->MarkCoverage, memory );
2725
void Free_MarkLigPos( TTO_MarkLigPos* mlp,
2728
Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory );
2729
Free_MarkArray( &mlp->MarkArray, memory );
2730
Free_Coverage( &mlp->LigatureCoverage, memory );
2731
Free_Coverage( &mlp->MarkCoverage, memory );
2735
static FT_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
2736
TTO_MarkLigPos* mlp,
2737
TTO_GSUB_String* in,
2740
FT_UShort context_length )
2742
FT_UShort i, j, mark_index, lig_index, property, klass;
2743
FT_UShort mark_glyph;
2744
FT_Pos x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2746
TTO_GPOSHeader* gpos = gpi->gpos;
2749
TTO_LigatureArray* la;
2750
TTO_LigatureAttach* lat;
2751
TTO_ComponentRecord* cr;
2752
FT_UShort comp_index;
2753
TTO_Anchor* mark_anchor;
2754
TTO_Anchor* lig_anchor;
2759
if ( context_length != 0xFFFF && context_length < 1 )
2760
return TTO_Err_Not_Covered;
2762
if ( flags & IGNORE_LIGATURES )
2763
return TTO_Err_Not_Covered;
2765
mark_glyph = in->string[in->pos];
2767
error = Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2771
if ( CHECK_Property( gpos->gdef, mark_glyph, flags, &property ) )
2774
/* now we search backwards for a non-mark glyph */
2779
while ( i <= in->pos )
2781
error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
2786
if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) )
2793
/* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2794
too strong, thus it is commented out. */
2796
if ( property != TTO_LIGATURE )
2797
return TTO_Err_Not_Covered;
2801
return TTO_Err_Not_Covered;
2803
error = Coverage_Index( &mlp->LigatureCoverage, in->string[j],
2808
ma = &mlp->MarkArray;
2810
if ( mark_index >= ma->MarkCount )
2811
return TTO_Err_Invalid_GPOS_SubTable;
2813
klass = ma->MarkRecord[mark_index].Class;
2814
mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2816
if ( klass >= mlp->ClassCount )
2817
return TTO_Err_Invalid_GPOS_SubTable;
2819
la = &mlp->LigatureArray;
2821
if ( lig_index >= la->LigatureCount )
2822
return TTO_Err_Invalid_GPOS_SubTable;
2824
lat = &la->LigatureAttach[lig_index];
2826
/* Use the component id if defined. If not we simply attach the
2827
mark glyph to the last component of the ligature */
2829
comp_index = in->glyph_properties[in->pos].component;
2831
/* ###### why the hell doesn't this compile?
2832
if (comp_index == MAX_COMPONENT_INDEX)
2833
comp_index = lat->ComponentCount - 1; */
2834
if ( comp_index >= lat->ComponentCount )
2835
return TTO_Err_Not_Covered;
2837
cr = &lat->ComponentRecord[comp_index];
2838
lig_anchor = &cr->LigatureAnchor[klass];
2840
error = Get_Anchor( gpi, mark_anchor, in->string[in->pos],
2841
&x_mark_value, &y_mark_value );
2844
error = Get_Anchor( gpi, lig_anchor, in->string[j],
2845
&x_lig_value, &y_lig_value );
2849
/* anchor points are not cumulative */
2853
o->x_pos = x_lig_value - x_mark_value;
2854
o->y_pos = y_lig_value - y_mark_value;
2869
static FT_Error Load_Mark2Array( TTO_Mark2Array* m2a,
2870
FT_UShort num_classes,
2874
FT_Memory memory = stream->memory;
2876
FT_UShort k, m, n, count;
2877
FT_ULong cur_offset, new_offset, base_offset;
2879
TTO_Mark2Record* m2r;
2883
base_offset = FILE_Pos();
2885
if ( ACCESS_Frame( 2L ) )
2888
count = m2a->Mark2Count = GET_UShort();
2892
m2a->Mark2Record = NULL;
2894
if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) )
2897
m2r = m2a->Mark2Record;
2899
for ( m = 0; m < count; m++ )
2901
m2r[m].Mark2Anchor = NULL;
2903
if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) )
2906
m2an = m2r[m].Mark2Anchor;
2908
for ( n = 0; n < num_classes; n++ )
2910
if ( ACCESS_Frame( 2L ) )
2913
new_offset = GET_UShort() + base_offset;
2917
cur_offset = FILE_Pos();
2918
if ( FILE_Seek( new_offset ) ||
2919
( error = Load_Anchor( &m2an[n], stream ) ) != TT_Err_Ok )
2921
(void)FILE_Seek( cur_offset );
2926
for ( k = 0; k < n; k++ )
2927
Free_Anchor( &m2an[k], memory );
2934
for ( k = 0; k < m; k++ )
2936
m2an = m2r[k].Mark2Anchor;
2938
for ( n = 0; n < num_classes; n++ )
2939
Free_Anchor( &m2an[n], memory );
2949
static void Free_Mark2Array( TTO_Mark2Array* m2a,
2950
FT_UShort num_classes,
2953
FT_UShort m, n, count;
2955
TTO_Mark2Record* m2r;
2959
if ( m2a->Mark2Record )
2961
count = m2a->Mark2Count;
2962
m2r = m2a->Mark2Record;
2964
for ( m = 0; m < count; m++ )
2966
m2an = m2r[m].Mark2Anchor;
2968
for ( n = 0; n < num_classes; n++ )
2969
Free_Anchor( &m2an[n], memory );
2979
/* MarkMarkPosFormat1 */
2981
FT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp,
2985
FT_Memory memory = stream->memory;
2987
FT_ULong cur_offset, new_offset, base_offset;
2990
base_offset = FILE_Pos();
2992
if ( ACCESS_Frame( 4L ) )
2995
mmp->PosFormat = GET_UShort();
2996
new_offset = GET_UShort() + base_offset;
3000
cur_offset = FILE_Pos();
3001
if ( FILE_Seek( new_offset ) ||
3002
( error = Load_Coverage( &mmp->Mark1Coverage,
3003
stream ) ) != TT_Err_Ok )
3005
(void)FILE_Seek( cur_offset );
3007
if ( ACCESS_Frame( 2L ) )
3010
new_offset = GET_UShort() + base_offset;
3014
cur_offset = FILE_Pos();
3015
if ( FILE_Seek( new_offset ) ||
3016
( error = Load_Coverage( &mmp->Mark2Coverage,
3017
stream ) ) != TT_Err_Ok )
3019
(void)FILE_Seek( cur_offset );
3021
if ( ACCESS_Frame( 4L ) )
3024
mmp->ClassCount = GET_UShort();
3025
new_offset = GET_UShort() + base_offset;
3029
cur_offset = FILE_Pos();
3030
if ( FILE_Seek( new_offset ) ||
3031
( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != TT_Err_Ok )
3033
(void)FILE_Seek( cur_offset );
3035
if ( ACCESS_Frame( 2L ) )
3038
new_offset = GET_UShort() + base_offset;
3042
cur_offset = FILE_Pos();
3043
if ( FILE_Seek( new_offset ) ||
3044
( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
3045
stream ) ) != TT_Err_Ok )
3051
Free_MarkArray( &mmp->Mark1Array, memory );
3054
Free_Coverage( &mmp->Mark2Coverage, memory );
3057
Free_Coverage( &mmp->Mark1Coverage, memory );
3062
void Free_MarkMarkPos( TTO_MarkMarkPos* mmp,
3065
Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory );
3066
Free_MarkArray( &mmp->Mark1Array, memory );
3067
Free_Coverage( &mmp->Mark2Coverage, memory );
3068
Free_Coverage( &mmp->Mark1Coverage, memory );
3072
static FT_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
3073
TTO_MarkMarkPos* mmp,
3074
TTO_GSUB_String* in,
3077
FT_UShort context_length )
3079
FT_UShort j, mark1_index, mark2_index, property, klass;
3080
FT_Pos x_mark1_value, y_mark1_value,
3081
x_mark2_value, y_mark2_value;
3083
TTO_GPOSHeader* gpos = gpi->gpos;
3086
TTO_Mark2Array* ma2;
3087
TTO_Mark2Record* m2r;
3088
TTO_Anchor* mark1_anchor;
3089
TTO_Anchor* mark2_anchor;
3094
if ( context_length != 0xFFFF && context_length < 1 )
3095
return TTO_Err_Not_Covered;
3097
if ( flags & IGNORE_MARKS )
3098
return TTO_Err_Not_Covered;
3100
error = Coverage_Index( &mmp->Mark1Coverage, in->string[in->pos],
3105
if ( CHECK_Property( gpos->gdef, in->string[in->pos],
3106
flags, &property ) )
3110
/* now we check the preceding glyph whether it is a suitable
3114
return TTO_Err_Not_Covered;
3117
error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
3122
if ( flags & IGNORE_SPECIAL_MARKS )
3124
if ( property != (flags & 0xFF00) )
3125
return TTO_Err_Not_Covered;
3129
if ( property != TTO_MARK )
3130
return TTO_Err_Not_Covered;
3133
error = Coverage_Index( &mmp->Mark2Coverage, in->string[j],
3138
ma1 = &mmp->Mark1Array;
3140
if ( mark1_index >= ma1->MarkCount )
3141
return TTO_Err_Invalid_GPOS_SubTable;
3143
klass = ma1->MarkRecord[mark1_index].Class;
3144
mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3146
if ( klass >= mmp->ClassCount )
3147
return TTO_Err_Invalid_GPOS_SubTable;
3149
ma2 = &mmp->Mark2Array;
3151
if ( mark2_index >= ma2->Mark2Count )
3152
return TTO_Err_Invalid_GPOS_SubTable;
3154
m2r = &ma2->Mark2Record[mark2_index];
3155
mark2_anchor = &m2r->Mark2Anchor[klass];
3157
error = Get_Anchor( gpi, mark1_anchor, in->string[in->pos],
3158
&x_mark1_value, &y_mark1_value );
3161
error = Get_Anchor( gpi, mark2_anchor, in->string[j],
3162
&x_mark2_value, &y_mark2_value );
3166
/* anchor points are not cumulative */
3170
o->x_pos = x_mark2_value - x_mark1_value;
3171
o->y_pos = y_mark2_value - y_mark1_value;
3182
/* Do the actual positioning for a context positioning (either format
3183
7 or 8). This is only called after we've determined that the stream
3184
matches the subrule. */
3186
static FT_Error Do_ContextPos( GPOS_Instance* gpi,
3187
FT_UShort GlyphCount,
3189
TTO_PosLookupRecord* pos,
3190
TTO_GSUB_String* in,
3195
FT_UShort i, old_pos;
3200
while ( i < GlyphCount )
3202
if ( PosCount && i == pos->SequenceIndex )
3206
/* Do a positioning */
3208
error = GPos_Do_Glyph_Lookup( gpi, pos->LookupListIndex, in, out,
3209
GlyphCount, nesting_level );
3216
i += in->pos - old_pos;
3233
static FT_Error Load_PosRule( TTO_PosRule* pr,
3237
FT_Memory memory = stream->memory;
3242
TTO_PosLookupRecord* plr;
3245
if ( ACCESS_Frame( 4L ) )
3248
pr->GlyphCount = GET_UShort();
3249
pr->PosCount = GET_UShort();
3255
count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3257
if ( ALLOC_ARRAY( pr->Input, count, FT_UShort ) )
3262
if ( ACCESS_Frame( count * 2L ) )
3265
for ( n = 0; n < count; n++ )
3266
i[n] = GET_UShort();
3270
pr->PosLookupRecord = NULL;
3272
count = pr->PosCount;
3274
if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) )
3277
plr = pr->PosLookupRecord;
3279
if ( ACCESS_Frame( count * 4L ) )
3282
for ( n = 0; n < count; n++ )
3284
plr[n].SequenceIndex = GET_UShort();
3285
plr[n].LookupListIndex = GET_UShort();
3301
static void Free_PosRule( TTO_PosRule* pr,
3304
FREE( pr->PosLookupRecord );
3311
static FT_Error Load_PosRuleSet( TTO_PosRuleSet* prs,
3315
FT_Memory memory = stream->memory;
3317
FT_UShort n, m, count;
3318
FT_ULong cur_offset, new_offset, base_offset;
3323
base_offset = FILE_Pos();
3325
if ( ACCESS_Frame( 2L ) )
3328
count = prs->PosRuleCount = GET_UShort();
3332
prs->PosRule = NULL;
3334
if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) )
3339
for ( n = 0; n < count; n++ )
3341
if ( ACCESS_Frame( 2L ) )
3344
new_offset = GET_UShort() + base_offset;
3348
cur_offset = FILE_Pos();
3349
if ( FILE_Seek( new_offset ) ||
3350
( error = Load_PosRule( &pr[n], stream ) ) != TT_Err_Ok )
3352
(void)FILE_Seek( cur_offset );
3358
for ( m = 0; m < n; m++ )
3359
Free_PosRule( &pr[m], memory );
3366
static void Free_PosRuleSet( TTO_PosRuleSet* prs,
3376
count = prs->PosRuleCount;
3379
for ( n = 0; n < count; n++ )
3380
Free_PosRule( &pr[n], memory );
3387
/* ContextPosFormat1 */
3389
static FT_Error Load_ContextPos1( TTO_ContextPosFormat1* cpf1,
3393
FT_Memory memory = stream->memory;
3395
FT_UShort n, m, count;
3396
FT_ULong cur_offset, new_offset, base_offset;
3398
TTO_PosRuleSet* prs;
3401
base_offset = FILE_Pos() - 2L;
3403
if ( ACCESS_Frame( 2L ) )
3406
new_offset = GET_UShort() + base_offset;
3410
cur_offset = FILE_Pos();
3411
if ( FILE_Seek( new_offset ) ||
3412
( error = Load_Coverage( &cpf1->Coverage, stream ) ) != TT_Err_Ok )
3414
(void)FILE_Seek( cur_offset );
3416
if ( ACCESS_Frame( 2L ) )
3419
count = cpf1->PosRuleSetCount = GET_UShort();
3423
cpf1->PosRuleSet = NULL;
3425
if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) )
3428
prs = cpf1->PosRuleSet;
3430
for ( n = 0; n < count; n++ )
3432
if ( ACCESS_Frame( 2L ) )
3435
new_offset = GET_UShort() + base_offset;
3439
cur_offset = FILE_Pos();
3440
if ( FILE_Seek( new_offset ) ||
3441
( error = Load_PosRuleSet( &prs[n], stream ) ) != TT_Err_Ok )
3443
(void)FILE_Seek( cur_offset );
3449
for ( m = 0; m < n; m++ )
3450
Free_PosRuleSet( &prs[m], memory );
3455
Free_Coverage( &cpf1->Coverage, memory );
3460
static void GPos_Free_Context1( TTO_ContextPosFormat1* cpf1,
3465
TTO_PosRuleSet* prs;
3468
if ( cpf1->PosRuleSet )
3470
count = cpf1->PosRuleSetCount;
3471
prs = cpf1->PosRuleSet;
3473
for ( n = 0; n < count; n++ )
3474
Free_PosRuleSet( &prs[n], memory );
3479
Free_Coverage( &cpf1->Coverage, memory );
3485
static FT_Error Load_PosClassRule( TTO_ContextPosFormat2* cpf2,
3486
TTO_PosClassRule* pcr,
3490
FT_Memory memory = stream->memory;
3495
TTO_PosLookupRecord* plr;
3499
if ( ACCESS_Frame( 4L ) )
3502
pcr->GlyphCount = GET_UShort();
3503
pcr->PosCount = GET_UShort();
3507
if ( pcr->GlyphCount > cpf2->MaxContextLength )
3508
cpf2->MaxContextLength = pcr->GlyphCount;
3512
count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3514
if ( ALLOC_ARRAY( pcr->Class, count, FT_UShort ) )
3518
d = cpf2->ClassDef.Defined;
3520
if ( ACCESS_Frame( count * 2L ) )
3523
for ( n = 0; n < count; n++ )
3525
c[n] = GET_UShort();
3527
/* We check whether the specific class is used at all. If not,
3528
class 0 is used instead. */
3538
pcr->PosLookupRecord = NULL;
3540
count = pcr->PosCount;
3542
if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
3545
plr = pcr->PosLookupRecord;
3547
if ( ACCESS_Frame( count * 4L ) )
3550
for ( n = 0; n < count; n++ )
3552
plr[n].SequenceIndex = GET_UShort();
3553
plr[n].LookupListIndex = GET_UShort();
3569
static void Free_PosClassRule( TTO_PosClassRule* pcr,
3572
FREE( pcr->PosLookupRecord );
3579
static FT_Error Load_PosClassSet( TTO_ContextPosFormat2* cpf2,
3580
TTO_PosClassSet* pcs,
3584
FT_Memory memory = stream->memory;
3586
FT_UShort n, m, count;
3587
FT_ULong cur_offset, new_offset, base_offset;
3589
TTO_PosClassRule* pcr;
3592
base_offset = FILE_Pos();
3594
if ( ACCESS_Frame( 2L ) )
3597
count = pcs->PosClassRuleCount = GET_UShort();
3601
pcs->PosClassRule = NULL;
3603
if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) )
3606
pcr = pcs->PosClassRule;
3608
for ( n = 0; n < count; n++ )
3610
if ( ACCESS_Frame( 2L ) )
3613
new_offset = GET_UShort() + base_offset;
3617
cur_offset = FILE_Pos();
3618
if ( FILE_Seek( new_offset ) ||
3619
( error = Load_PosClassRule( cpf2, &pcr[n],
3620
stream ) ) != TT_Err_Ok )
3622
(void)FILE_Seek( cur_offset );
3628
for ( m = 0; m < n; m++ )
3629
Free_PosClassRule( &pcr[m], memory );
3636
static void Free_PosClassSet( TTO_PosClassSet* pcs,
3641
TTO_PosClassRule* pcr;
3644
if ( pcs->PosClassRule )
3646
count = pcs->PosClassRuleCount;
3647
pcr = pcs->PosClassRule;
3649
for ( n = 0; n < count; n++ )
3650
Free_PosClassRule( &pcr[n], memory );
3657
/* ContextPosFormat2 */
3659
static FT_Error Load_ContextPos2( TTO_ContextPosFormat2* cpf2,
3663
FT_Memory memory = stream->memory;
3665
FT_UShort n, m, count;
3666
FT_ULong cur_offset, new_offset, base_offset;
3668
TTO_PosClassSet* pcs;
3671
base_offset = FILE_Pos() - 2;
3673
if ( ACCESS_Frame( 2L ) )
3676
new_offset = GET_UShort() + base_offset;
3680
cur_offset = FILE_Pos();
3681
if ( FILE_Seek( new_offset ) ||
3682
( error = Load_Coverage( &cpf2->Coverage, stream ) ) != TT_Err_Ok )
3684
(void)FILE_Seek( cur_offset );
3686
if ( ACCESS_Frame( 4L ) )
3689
new_offset = GET_UShort() + base_offset;
3691
/* `PosClassSetCount' is the upper limit for class values, thus we
3692
read it now to make an additional safety check. */
3694
count = cpf2->PosClassSetCount = GET_UShort();
3698
cur_offset = FILE_Pos();
3699
if ( FILE_Seek( new_offset ) ||
3700
( error = Load_ClassDefinition( &cpf2->ClassDef, count,
3701
stream ) ) != TT_Err_Ok )
3703
(void)FILE_Seek( cur_offset );
3705
cpf2->PosClassSet = NULL;
3706
cpf2->MaxContextLength = 0;
3708
if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) )
3711
pcs = cpf2->PosClassSet;
3713
for ( n = 0; n < count; n++ )
3715
if ( ACCESS_Frame( 2L ) )
3718
new_offset = GET_UShort() + base_offset;
3722
if ( new_offset != base_offset ) /* not a NULL offset */
3724
cur_offset = FILE_Pos();
3725
if ( FILE_Seek( new_offset ) ||
3726
( error = Load_PosClassSet( cpf2, &pcs[n],
3727
stream ) ) != TT_Err_Ok )
3729
(void)FILE_Seek( cur_offset );
3733
/* we create a PosClassSet table with no entries */
3735
cpf2->PosClassSet[n].PosClassRuleCount = 0;
3736
cpf2->PosClassSet[n].PosClassRule = NULL;
3743
for ( m = 0; m < n; n++ )
3744
Free_PosClassSet( &pcs[m], memory );
3749
Free_ClassDefinition( &cpf2->ClassDef, memory );
3752
Free_Coverage( &cpf2->Coverage, memory );
3757
static void GPos_Free_Context2( TTO_ContextPosFormat2* cpf2,
3762
TTO_PosClassSet* pcs;
3765
if ( cpf2->PosClassSet )
3767
count = cpf2->PosClassSetCount;
3768
pcs = cpf2->PosClassSet;
3770
for ( n = 0; n < count; n++ )
3771
Free_PosClassSet( &pcs[n], memory );
3776
Free_ClassDefinition( &cpf2->ClassDef, memory );
3777
Free_Coverage( &cpf2->Coverage, memory );
3781
/* ContextPosFormat3 */
3783
static FT_Error Load_ContextPos3( TTO_ContextPosFormat3* cpf3,
3787
FT_Memory memory = stream->memory;
3790
FT_ULong cur_offset, new_offset, base_offset;
3793
TTO_PosLookupRecord* plr;
3796
base_offset = FILE_Pos() - 2L;
3798
if ( ACCESS_Frame( 4L ) )
3801
cpf3->GlyphCount = GET_UShort();
3802
cpf3->PosCount = GET_UShort();
3806
cpf3->Coverage = NULL;
3808
count = cpf3->GlyphCount;
3810
if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) )
3815
for ( n = 0; n < count; n++ )
3817
if ( ACCESS_Frame( 2L ) )
3820
new_offset = GET_UShort() + base_offset;
3824
cur_offset = FILE_Pos();
3825
if ( FILE_Seek( new_offset ) ||
3826
( error = Load_Coverage( &c[n], stream ) ) != TT_Err_Ok )
3828
(void)FILE_Seek( cur_offset );
3831
cpf3->PosLookupRecord = NULL;
3833
count = cpf3->PosCount;
3835
if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
3838
plr = cpf3->PosLookupRecord;
3840
if ( ACCESS_Frame( count * 4L ) )
3843
for ( n = 0; n < count; n++ )
3845
plr[n].SequenceIndex = GET_UShort();
3846
plr[n].LookupListIndex = GET_UShort();
3857
for ( n = 0; n < count; n++ )
3858
Free_Coverage( &c[n], memory );
3865
static void GPos_Free_Context3( TTO_ContextPosFormat3* cpf3,
3873
FREE( cpf3->PosLookupRecord );
3875
if ( cpf3->Coverage )
3877
count = cpf3->GlyphCount;
3880
for ( n = 0; n < count; n++ )
3881
Free_Coverage( &c[n], memory );
3890
FT_Error Load_ContextPos( TTO_ContextPos* cp,
3896
if ( ACCESS_Frame( 2L ) )
3899
cp->PosFormat = GET_UShort();
3903
switch ( cp->PosFormat )
3906
return Load_ContextPos1( &cp->cpf.cpf1, stream );
3909
return Load_ContextPos2( &cp->cpf.cpf2, stream );
3912
return Load_ContextPos3( &cp->cpf.cpf3, stream );
3915
return TTO_Err_Invalid_GPOS_SubTable_Format;
3918
return TT_Err_Ok; /* never reached */
3922
void Free_ContextPos( TTO_ContextPos* cp,
3925
switch ( cp->PosFormat )
3928
GPos_Free_Context1( &cp->cpf.cpf1, memory );
3932
GPos_Free_Context2( &cp->cpf.cpf2, memory );
3936
GPos_Free_Context3( &cp->cpf.cpf3, memory );
3942
static FT_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3943
TTO_ContextPosFormat1* cpf1,
3944
TTO_GSUB_String* in,
3947
FT_UShort context_length,
3950
FT_UShort index, property;
3951
FT_UShort i, j, k, numpr;
3954
TTO_GPOSHeader* gpos = gpi->gpos;
3957
TTO_GDEFHeader* gdef;
3959
error = Coverage_Index( &cpf1->Coverage, in->string[in->pos], &index );
3965
if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
3968
pr = cpf1->PosRuleSet[index].PosRule;
3969
numpr = cpf1->PosRuleSet[index].PosRuleCount;
3971
for ( k = 0; k < numpr; k++ )
3973
if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3976
if ( in->pos + pr[k].GlyphCount > in->length )
3977
continue; /* context is too long */
3979
s_in = &in->string[in->pos];
3981
for ( i = 1, j = 1; i < pr[k].GlyphCount; i++, j++ )
3983
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
3985
if ( error && error != TTO_Err_Not_Covered )
3988
if ( in->pos + j < in->length )
3994
if ( s_in[j] != pr[k].Input[i - 1] )
3998
if ( i == pr[k].GlyphCount )
3999
return Do_ContextPos( gpi, pr[k].GlyphCount,
4000
pr[k].PosCount, pr[k].PosLookupRecord,
4005
return TTO_Err_Not_Covered;
4009
static FT_Error Lookup_ContextPos2( GPOS_Instance* gpi,
4010
TTO_ContextPosFormat2* cpf2,
4011
TTO_GSUB_String* in,
4014
FT_UShort context_length,
4017
FT_UShort index, property;
4019
FT_Memory memory = gpi->face->memory;
4020
FT_UShort i, j, k, known_classes;
4025
TTO_GPOSHeader* gpos = gpi->gpos;
4027
TTO_PosClassSet* pcs;
4028
TTO_PosClassRule* pr;
4029
TTO_GDEFHeader* gdef;
4031
/* Note: The coverage table in format 2 doesn't give an index into
4032
anything. It just lets us know whether or not we need to
4033
do any lookup at all. */
4035
error = Coverage_Index( &cpf2->Coverage, in->string[in->pos], &index );
4041
if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
4044
if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) )
4047
error = Get_Class( &cpf2->ClassDef, in->string[in->pos],
4048
&classes[0], NULL );
4049
if ( error && error != TTO_Err_Not_Covered )
4053
pcs = &cpf2->PosClassSet[classes[0]];
4056
error = TTO_Err_Invalid_GPOS_SubTable;
4060
for ( k = 0; k < pcs->PosClassRuleCount; k++ )
4062
pr = &pcs->PosClassRule[k];
4064
if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
4067
if ( in->pos + pr->GlyphCount > in->length )
4068
continue; /* context is too long */
4070
s_in = &in->string[in->pos];
4073
/* Start at 1 because [0] is implied */
4075
for ( i = 1, j = 1; i < pr->GlyphCount; i++, j++ )
4077
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
4079
if ( error && error != TTO_Err_Not_Covered )
4082
if ( in->pos + j < in->length )
4088
if ( i > known_classes )
4090
/* Keeps us from having to do this for each rule */
4092
error = Get_Class( &cpf2->ClassDef, s_in[j], &classes[i], NULL );
4093
if ( error && error != TTO_Err_Not_Covered )
4098
if ( cl[i - 1] != classes[i] )
4102
if ( i == pr->GlyphCount )
4104
error = Do_ContextPos( gpi, pr->GlyphCount,
4105
pr->PosCount, pr->PosLookupRecord,
4112
error = TTO_Err_Not_Covered;
4120
static FT_Error Lookup_ContextPos3( GPOS_Instance* gpi,
4121
TTO_ContextPosFormat3* cpf3,
4122
TTO_GSUB_String* in,
4125
FT_UShort context_length,
4129
FT_UShort index, i, j, property;
4131
TTO_GPOSHeader* gpos = gpi->gpos;
4134
TTO_GDEFHeader* gdef;
4139
if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
4140
return TTO_Err_Not_Covered;
4142
if ( in->pos + cpf3->GlyphCount > in->length )
4143
return TTO_Err_Not_Covered; /* context is too long */
4145
if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
4148
s_in = &in->string[in->pos];
4151
for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
4153
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
4155
if ( error && error != TTO_Err_Not_Covered )
4158
if ( in->pos + j < in->length )
4161
return TTO_Err_Not_Covered;
4164
error = Coverage_Index( &c[i], s_in[j], &index );
4169
return Do_ContextPos( gpi, cpf3->GlyphCount,
4170
cpf3->PosCount, cpf3->PosLookupRecord,
4176
static FT_Error Lookup_ContextPos( GPOS_Instance* gpi,
4178
TTO_GSUB_String* in,
4181
FT_UShort context_length,
4184
switch ( cp->PosFormat )
4187
return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, in, out,
4188
flags, context_length, nesting_level );
4191
return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, in, out,
4192
flags, context_length, nesting_level );
4195
return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, in, out,
4196
flags, context_length, nesting_level );
4199
return TTO_Err_Invalid_GPOS_SubTable_Format;
4202
return TT_Err_Ok; /* never reached */
4210
static FT_Error Load_ChainPosRule( TTO_ChainPosRule* cpr,
4214
FT_Memory memory = stream->memory;
4221
TTO_PosLookupRecord* plr;
4224
if ( ACCESS_Frame( 2L ) )
4227
cpr->BacktrackGlyphCount = GET_UShort();
4231
cpr->Backtrack = NULL;
4233
count = cpr->BacktrackGlyphCount;
4235
if ( ALLOC_ARRAY( cpr->Backtrack, count, FT_UShort ) )
4240
if ( ACCESS_Frame( count * 2L ) )
4243
for ( n = 0; n < count; n++ )
4244
b[n] = GET_UShort();
4248
if ( ACCESS_Frame( 2L ) )
4251
cpr->InputGlyphCount = GET_UShort();
4257
count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4259
if ( ALLOC_ARRAY( cpr->Input, count, FT_UShort ) )
4264
if ( ACCESS_Frame( count * 2L ) )
4267
for ( n = 0; n < count; n++ )
4268
i[n] = GET_UShort();
4272
if ( ACCESS_Frame( 2L ) )
4275
cpr->LookaheadGlyphCount = GET_UShort();
4279
cpr->Lookahead = NULL;
4281
count = cpr->LookaheadGlyphCount;
4283
if ( ALLOC_ARRAY( cpr->Lookahead, count, FT_UShort ) )
4288
if ( ACCESS_Frame( count * 2L ) )
4291
for ( n = 0; n < count; n++ )
4292
l[n] = GET_UShort();
4296
if ( ACCESS_Frame( 2L ) )
4299
cpr->PosCount = GET_UShort();
4303
cpr->PosLookupRecord = NULL;
4305
count = cpr->PosCount;
4307
if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) )
4310
plr = cpr->PosLookupRecord;
4312
if ( ACCESS_Frame( count * 4L ) )
4315
for ( n = 0; n < count; n++ )
4317
plr[n].SequenceIndex = GET_UShort();
4318
plr[n].LookupListIndex = GET_UShort();
4340
static void Free_ChainPosRule( TTO_ChainPosRule* cpr,
4343
FREE( cpr->PosLookupRecord );
4344
FREE( cpr->Lookahead );
4346
FREE( cpr->Backtrack );
4350
/* ChainPosRuleSet */
4352
static FT_Error Load_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs,
4356
FT_Memory memory = stream->memory;
4358
FT_UShort n, m, count;
4359
FT_ULong cur_offset, new_offset, base_offset;
4361
TTO_ChainPosRule* cpr;
4364
base_offset = FILE_Pos();
4366
if ( ACCESS_Frame( 2L ) )
4369
count = cprs->ChainPosRuleCount = GET_UShort();
4373
cprs->ChainPosRule = NULL;
4375
if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) )
4378
cpr = cprs->ChainPosRule;
4380
for ( n = 0; n < count; n++ )
4382
if ( ACCESS_Frame( 2L ) )
4385
new_offset = GET_UShort() + base_offset;
4389
cur_offset = FILE_Pos();
4390
if ( FILE_Seek( new_offset ) ||
4391
( error = Load_ChainPosRule( &cpr[n], stream ) ) != TT_Err_Ok )
4393
(void)FILE_Seek( cur_offset );
4399
for ( m = 0; m < n; m++ )
4400
Free_ChainPosRule( &cpr[m], memory );
4407
static void Free_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs,
4412
TTO_ChainPosRule* cpr;
4415
if ( cprs->ChainPosRule )
4417
count = cprs->ChainPosRuleCount;
4418
cpr = cprs->ChainPosRule;
4420
for ( n = 0; n < count; n++ )
4421
Free_ChainPosRule( &cpr[n], memory );
4428
/* ChainContextPosFormat1 */
4430
static FT_Error Load_ChainContextPos1( TTO_ChainContextPosFormat1* ccpf1,
4434
FT_Memory memory = stream->memory;
4436
FT_UShort n, m, count;
4437
FT_ULong cur_offset, new_offset, base_offset;
4439
TTO_ChainPosRuleSet* cprs;
4442
base_offset = FILE_Pos() - 2L;
4444
if ( ACCESS_Frame( 2L ) )
4447
new_offset = GET_UShort() + base_offset;
4451
cur_offset = FILE_Pos();
4452
if ( FILE_Seek( new_offset ) ||
4453
( error = Load_Coverage( &ccpf1->Coverage, stream ) ) != TT_Err_Ok )
4455
(void)FILE_Seek( cur_offset );
4457
if ( ACCESS_Frame( 2L ) )
4460
count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4464
ccpf1->ChainPosRuleSet = NULL;
4466
if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) )
4469
cprs = ccpf1->ChainPosRuleSet;
4471
for ( n = 0; n < count; n++ )
4473
if ( ACCESS_Frame( 2L ) )
4476
new_offset = GET_UShort() + base_offset;
4480
cur_offset = FILE_Pos();
4481
if ( FILE_Seek( new_offset ) ||
4482
( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != TT_Err_Ok )
4484
(void)FILE_Seek( cur_offset );
4490
for ( m = 0; m < n; m++ )
4491
Free_ChainPosRuleSet( &cprs[m], memory );
4496
Free_Coverage( &ccpf1->Coverage, memory );
4501
static void GPos_Free_ChainContext1( TTO_ChainContextPosFormat1* ccpf1,
4506
TTO_ChainPosRuleSet* cprs;
4509
if ( ccpf1->ChainPosRuleSet )
4511
count = ccpf1->ChainPosRuleSetCount;
4512
cprs = ccpf1->ChainPosRuleSet;
4514
for ( n = 0; n < count; n++ )
4515
Free_ChainPosRuleSet( &cprs[n], memory );
4520
Free_Coverage( &ccpf1->Coverage, memory );
4524
/* ChainPosClassRule */
4526
static FT_Error Load_ChainPosClassRule(
4527
TTO_ChainContextPosFormat2* ccpf2,
4528
TTO_ChainPosClassRule* cpcr,
4532
FT_Memory memory = stream->memory;
4539
TTO_PosLookupRecord* plr;
4543
if ( ACCESS_Frame( 2L ) )
4546
cpcr->BacktrackGlyphCount = GET_UShort();
4550
if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4551
ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4553
cpcr->Backtrack = NULL;
4555
count = cpcr->BacktrackGlyphCount;
4557
if ( ALLOC_ARRAY( cpcr->Backtrack, count, FT_UShort ) )
4560
b = cpcr->Backtrack;
4561
d = ccpf2->BacktrackClassDef.Defined;
4563
if ( ACCESS_Frame( count * 2L ) )
4566
for ( n = 0; n < count; n++ )
4568
b[n] = GET_UShort();
4570
/* We check whether the specific class is used at all. If not,
4571
class 0 is used instead. */
4580
if ( ACCESS_Frame( 2L ) )
4583
cpcr->InputGlyphCount = GET_UShort();
4585
if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4586
ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4592
count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4594
if ( ALLOC_ARRAY( cpcr->Input, count, FT_UShort ) )
4598
d = ccpf2->InputClassDef.Defined;
4600
if ( ACCESS_Frame( count * 2L ) )
4603
for ( n = 0; n < count; n++ )
4605
i[n] = GET_UShort();
4615
if ( ACCESS_Frame( 2L ) )
4618
cpcr->LookaheadGlyphCount = GET_UShort();
4622
if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4623
ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4625
cpcr->Lookahead = NULL;
4627
count = cpcr->LookaheadGlyphCount;
4629
if ( ALLOC_ARRAY( cpcr->Lookahead, count, FT_UShort ) )
4632
l = cpcr->Lookahead;
4633
d = ccpf2->LookaheadClassDef.Defined;
4635
if ( ACCESS_Frame( count * 2L ) )
4638
for ( n = 0; n < count; n++ )
4640
l[n] = GET_UShort();
4650
if ( ACCESS_Frame( 2L ) )
4653
cpcr->PosCount = GET_UShort();
4657
cpcr->PosLookupRecord = NULL;
4659
count = cpcr->PosCount;
4661
if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
4664
plr = cpcr->PosLookupRecord;
4666
if ( ACCESS_Frame( count * 4L ) )
4669
for ( n = 0; n < count; n++ )
4671
plr[n].SequenceIndex = GET_UShort();
4672
plr[n].LookupListIndex = GET_UShort();
4694
static void Free_ChainPosClassRule( TTO_ChainPosClassRule* cpcr,
4697
FREE( cpcr->PosLookupRecord );
4698
FREE( cpcr->Lookahead );
4699
FREE( cpcr->Input );
4700
FREE( cpcr->Backtrack );
4706
static FT_Error Load_ChainPosClassSet(
4707
TTO_ChainContextPosFormat2* ccpf2,
4708
TTO_ChainPosClassSet* cpcs,
4712
FT_Memory memory = stream->memory;
4714
FT_UShort n, m, count;
4715
FT_ULong cur_offset, new_offset, base_offset;
4717
TTO_ChainPosClassRule* cpcr;
4720
base_offset = FILE_Pos();
4722
if ( ACCESS_Frame( 2L ) )
4725
count = cpcs->ChainPosClassRuleCount = GET_UShort();
4729
cpcs->ChainPosClassRule = NULL;
4731
if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4732
TTO_ChainPosClassRule ) )
4735
cpcr = cpcs->ChainPosClassRule;
4737
for ( n = 0; n < count; n++ )
4739
if ( ACCESS_Frame( 2L ) )
4742
new_offset = GET_UShort() + base_offset;
4746
cur_offset = FILE_Pos();
4747
if ( FILE_Seek( new_offset ) ||
4748
( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4749
stream ) ) != TT_Err_Ok )
4751
(void)FILE_Seek( cur_offset );
4757
for ( m = 0; m < n; m++ )
4758
Free_ChainPosClassRule( &cpcr[m], memory );
4765
static void Free_ChainPosClassSet( TTO_ChainPosClassSet* cpcs,
4770
TTO_ChainPosClassRule* cpcr;
4773
if ( cpcs->ChainPosClassRule )
4775
count = cpcs->ChainPosClassRuleCount;
4776
cpcr = cpcs->ChainPosClassRule;
4778
for ( n = 0; n < count; n++ )
4779
Free_ChainPosClassRule( &cpcr[n], memory );
4786
static FT_Error Load_EmptyOrClassDefinition( TTO_ClassDefinition* cd,
4788
FT_ULong class_offset,
4789
FT_ULong base_offset,
4793
FT_ULong cur_offset;
4795
cur_offset = FILE_Pos();
4799
if ( !FILE_Seek( class_offset + base_offset ) )
4800
error = Load_ClassDefinition( cd, limit, stream );
4803
error = Load_EmptyClassDefinition ( cd, stream );
4805
if (error == TT_Err_Ok)
4806
(void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
4811
/* ChainContextPosFormat2 */
4813
static FT_Error Load_ChainContextPos2( TTO_ChainContextPosFormat2* ccpf2,
4817
FT_Memory memory = stream->memory;
4819
FT_UShort n, m, count;
4820
FT_ULong cur_offset, new_offset, base_offset;
4821
FT_ULong backtrack_offset, input_offset, lookahead_offset;
4823
TTO_ChainPosClassSet* cpcs;
4826
base_offset = FILE_Pos() - 2;
4828
if ( ACCESS_Frame( 2L ) )
4831
new_offset = GET_UShort() + base_offset;
4835
cur_offset = FILE_Pos();
4836
if ( FILE_Seek( new_offset ) ||
4837
( error = Load_Coverage( &ccpf2->Coverage, stream ) ) != TT_Err_Ok )
4839
(void)FILE_Seek( cur_offset );
4841
if ( ACCESS_Frame( 8L ) )
4844
backtrack_offset = GET_UShort();
4845
input_offset = GET_UShort();
4846
lookahead_offset = GET_UShort();
4848
/* `ChainPosClassSetCount' is the upper limit for input class values,
4849
thus we read it now to make an additional safety check. */
4851
count = ccpf2->ChainPosClassSetCount = GET_UShort();
4855
if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, count,
4856
backtrack_offset, base_offset,
4857
stream ) ) != TT_Err_Ok )
4859
if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4860
input_offset, base_offset,
4861
stream ) ) != TT_Err_Ok )
4863
if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, count,
4864
lookahead_offset, base_offset,
4865
stream ) ) != TT_Err_Ok )
4868
ccpf2->ChainPosClassSet = NULL;
4869
ccpf2->MaxBacktrackLength = 0;
4870
ccpf2->MaxInputLength = 0;
4871
ccpf2->MaxLookaheadLength = 0;
4873
if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) )
4876
cpcs = ccpf2->ChainPosClassSet;
4878
for ( n = 0; n < count; n++ )
4880
if ( ACCESS_Frame( 2L ) )
4883
new_offset = GET_UShort() + base_offset;
4887
if ( new_offset != base_offset ) /* not a NULL offset */
4889
cur_offset = FILE_Pos();
4890
if ( FILE_Seek( new_offset ) ||
4891
( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4892
stream ) ) != TT_Err_Ok )
4894
(void)FILE_Seek( cur_offset );
4898
/* we create a ChainPosClassSet table with no entries */
4900
ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4901
ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4908
for ( m = 0; m < n; m++ )
4909
Free_ChainPosClassSet( &cpcs[m], memory );
4914
Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
4917
Free_ClassDefinition( &ccpf2->InputClassDef, memory );
4920
Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
4923
Free_Coverage( &ccpf2->Coverage, memory );
4928
static void GPos_Free_ChainContext2( TTO_ChainContextPosFormat2* ccpf2,
4933
TTO_ChainPosClassSet* cpcs;
4936
if ( ccpf2->ChainPosClassSet )
4938
count = ccpf2->ChainPosClassSetCount;
4939
cpcs = ccpf2->ChainPosClassSet;
4941
for ( n = 0; n < count; n++ )
4942
Free_ChainPosClassSet( &cpcs[n], memory );
4947
Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
4948
Free_ClassDefinition( &ccpf2->InputClassDef, memory );
4949
Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
4951
Free_Coverage( &ccpf2->Coverage, memory );
4955
/* ChainContextPosFormat3 */
4957
static FT_Error Load_ChainContextPos3( TTO_ChainContextPosFormat3* ccpf3,
4961
FT_Memory memory = stream->memory;
4963
FT_UShort n, nb, ni, nl, m, count;
4964
FT_UShort backtrack_count, input_count, lookahead_count;
4965
FT_ULong cur_offset, new_offset, base_offset;
4970
TTO_PosLookupRecord* plr;
4973
base_offset = FILE_Pos() - 2L;
4975
if ( ACCESS_Frame( 2L ) )
4978
ccpf3->BacktrackGlyphCount = GET_UShort();
4982
ccpf3->BacktrackCoverage = NULL;
4984
backtrack_count = ccpf3->BacktrackGlyphCount;
4986
if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4990
b = ccpf3->BacktrackCoverage;
4992
for ( nb = 0; nb < backtrack_count; nb++ )
4994
if ( ACCESS_Frame( 2L ) )
4997
new_offset = GET_UShort() + base_offset;
5001
cur_offset = FILE_Pos();
5002
if ( FILE_Seek( new_offset ) ||
5003
( error = Load_Coverage( &b[nb], stream ) ) != TT_Err_Ok )
5005
(void)FILE_Seek( cur_offset );
5008
if ( ACCESS_Frame( 2L ) )
5011
ccpf3->InputGlyphCount = GET_UShort();
5015
ccpf3->InputCoverage = NULL;
5017
input_count = ccpf3->InputGlyphCount;
5019
if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) )
5022
i = ccpf3->InputCoverage;
5024
for ( ni = 0; ni < input_count; ni++ )
5026
if ( ACCESS_Frame( 2L ) )
5029
new_offset = GET_UShort() + base_offset;
5033
cur_offset = FILE_Pos();
5034
if ( FILE_Seek( new_offset ) ||
5035
( error = Load_Coverage( &i[ni], stream ) ) != TT_Err_Ok )
5037
(void)FILE_Seek( cur_offset );
5040
if ( ACCESS_Frame( 2L ) )
5043
ccpf3->LookaheadGlyphCount = GET_UShort();
5047
ccpf3->LookaheadCoverage = NULL;
5049
lookahead_count = ccpf3->LookaheadGlyphCount;
5051
if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
5055
l = ccpf3->LookaheadCoverage;
5057
for ( nl = 0; nl < lookahead_count; nl++ )
5059
if ( ACCESS_Frame( 2L ) )
5062
new_offset = GET_UShort() + base_offset;
5066
cur_offset = FILE_Pos();
5067
if ( FILE_Seek( new_offset ) ||
5068
( error = Load_Coverage( &l[nl], stream ) ) != TT_Err_Ok )
5070
(void)FILE_Seek( cur_offset );
5073
if ( ACCESS_Frame( 2L ) )
5076
ccpf3->PosCount = GET_UShort();
5080
ccpf3->PosLookupRecord = NULL;
5082
count = ccpf3->PosCount;
5084
if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
5087
plr = ccpf3->PosLookupRecord;
5089
if ( ACCESS_Frame( count * 4L ) )
5092
for ( n = 0; n < count; n++ )
5094
plr[n].SequenceIndex = GET_UShort();
5095
plr[n].LookupListIndex = GET_UShort();
5106
for ( m = 0; m < nl; nl++ )
5107
Free_Coverage( &l[m], memory );
5112
for ( m = 0; m < ni; n++ )
5113
Free_Coverage( &i[m], memory );
5118
for ( m = 0; m < nb; n++ )
5119
Free_Coverage( &b[m], memory );
5126
static void GPos_Free_ChainContext3( TTO_ChainContextPosFormat3* ccpf3,
5134
FREE( ccpf3->PosLookupRecord );
5136
if ( ccpf3->LookaheadCoverage )
5138
count = ccpf3->LookaheadGlyphCount;
5139
c = ccpf3->LookaheadCoverage;
5141
for ( n = 0; n < count; n++ )
5142
Free_Coverage( &c[n], memory );
5147
if ( ccpf3->InputCoverage )
5149
count = ccpf3->InputGlyphCount;
5150
c = ccpf3->InputCoverage;
5152
for ( n = 0; n < count; n++ )
5153
Free_Coverage( &c[n], memory );
5158
if ( ccpf3->BacktrackCoverage )
5160
count = ccpf3->BacktrackGlyphCount;
5161
c = ccpf3->BacktrackCoverage;
5163
for ( n = 0; n < count; n++ )
5164
Free_Coverage( &c[n], memory );
5171
/* ChainContextPos */
5173
FT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp,
5179
if ( ACCESS_Frame( 2L ) )
5182
ccp->PosFormat = GET_UShort();
5186
switch ( ccp->PosFormat )
5189
return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
5192
return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
5195
return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
5198
return TTO_Err_Invalid_GPOS_SubTable_Format;
5201
return TT_Err_Ok; /* never reached */
5205
void Free_ChainContextPos( TTO_ChainContextPos* ccp,
5208
switch ( ccp->PosFormat )
5211
GPos_Free_ChainContext1( &ccp->ccpf.ccpf1, memory );
5215
GPos_Free_ChainContext2( &ccp->ccpf.ccpf2, memory );
5219
GPos_Free_ChainContext3( &ccp->ccpf.ccpf3, memory );
5225
static FT_Error Lookup_ChainContextPos1(
5227
TTO_ChainContextPosFormat1* ccpf1,
5228
TTO_GSUB_String* in,
5231
FT_UShort context_length,
5234
FT_UShort index, property;
5235
FT_UShort i, j, k, num_cpr, curr_pos;
5236
FT_UShort bgc, igc, lgc;
5239
TTO_GPOSHeader* gpos = gpi->gpos;
5241
TTO_ChainPosRule* cpr;
5242
TTO_ChainPosRule curr_cpr;
5243
TTO_GDEFHeader* gdef;
5246
error = Coverage_Index( &ccpf1->Coverage, in->string[in->pos], &index );
5252
if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
5255
cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5256
num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5258
for ( k = 0; k < num_cpr; k++ )
5261
bgc = curr_cpr.BacktrackGlyphCount;
5262
igc = curr_cpr.InputGlyphCount;
5263
lgc = curr_cpr.LookaheadGlyphCount;
5265
if ( context_length != 0xFFFF && context_length < igc )
5268
/* check whether context is too long; it is a first guess only */
5270
if ( bgc > in->pos || in->pos + igc + lgc > in->length )
5275
/* Since we don't know in advance the number of glyphs to inspect,
5276
we search backwards for matches in the backtrack glyph array */
5279
s_in = &in->string[curr_pos];
5281
for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
5283
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5285
if ( error && error != TTO_Err_Not_Covered )
5294
/* In OpenType 1.3, it is undefined whether the offsets of
5295
backtrack glyphs is in logical order or not. Version 1.4
5298
Logical order - a b c d e f g h i j
5301
Backtrack offsets - 3 2 1 0
5302
Lookahead offsets - 0 1 2 3 */
5304
if ( s_in[j] != curr_cpr.Backtrack[i] )
5313
s_in = &in->string[curr_pos];
5315
/* Start at 1 because [0] is implied */
5317
for ( i = 1, j = 1; i < igc; i++, j++ )
5319
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5321
if ( error && error != TTO_Err_Not_Covered )
5324
if ( curr_pos + j < (int)in->length )
5330
if ( s_in[j] != curr_cpr.Input[i - 1] )
5337
/* we are starting to check for lookahead glyphs right after the
5338
last context glyph */
5341
s_in = &in->string[curr_pos];
5343
for ( i = 0, j = 0; i < lgc; i++, j++ )
5345
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5347
if ( error && error != TTO_Err_Not_Covered )
5350
if ( curr_pos + j < (int)in->length )
5356
if ( s_in[j] != curr_cpr.Lookahead[i] )
5361
return Do_ContextPos( gpi, igc,
5363
curr_cpr.PosLookupRecord,
5368
return TTO_Err_Not_Covered;
5372
static FT_Error Lookup_ChainContextPos2(
5374
TTO_ChainContextPosFormat2* ccpf2,
5375
TTO_GSUB_String* in,
5378
FT_UShort context_length,
5381
FT_UShort index, property;
5382
FT_Memory memory = gpi->face->memory;
5384
FT_UShort i, j, k, curr_pos;
5385
FT_UShort bgc, igc, lgc;
5386
FT_UShort known_backtrack_classes,
5387
known_input_classes,
5388
known_lookahead_classes;
5390
FT_UShort* backtrack_classes;
5391
FT_UShort* input_classes;
5392
FT_UShort* lookahead_classes;
5399
TTO_GPOSHeader* gpos = gpi->gpos;
5401
TTO_ChainPosClassSet* cpcs;
5402
TTO_ChainPosClassRule cpcr;
5403
TTO_GDEFHeader* gdef;
5408
/* Note: The coverage table in format 2 doesn't give an index into
5409
anything. It just lets us know whether or not we need to
5410
do any lookup at all. */
5412
error = Coverage_Index( &ccpf2->Coverage, in->string[in->pos], &index );
5416
if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
5419
if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, FT_UShort ) )
5421
known_backtrack_classes = 0;
5423
if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) )
5425
known_input_classes = 1;
5427
if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_UShort ) )
5429
known_lookahead_classes = 0;
5431
error = Get_Class( &ccpf2->InputClassDef, in->string[in->pos],
5432
&input_classes[0], NULL );
5433
if ( error && error != TTO_Err_Not_Covered )
5436
cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5439
error = TTO_Err_Invalid_GPOS_SubTable;
5443
for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5445
cpcr = cpcs->ChainPosClassRule[k];
5446
bgc = cpcr.BacktrackGlyphCount;
5447
igc = cpcr.InputGlyphCount;
5448
lgc = cpcr.LookaheadGlyphCount;
5450
if ( context_length != 0xFFFF && context_length < igc )
5453
/* check whether context is too long; it is a first guess only */
5455
if ( bgc > in->pos || in->pos + igc + lgc > in->length )
5460
/* Since we don't know in advance the number of glyphs to inspect,
5461
we search backwards for matches in the backtrack glyph array.
5462
Note that `known_backtrack_classes' starts at index 0. */
5465
s_in = &in->string[curr_pos];
5466
bc = cpcr.Backtrack;
5468
for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
5470
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5472
if ( error && error != TTO_Err_Not_Covered )
5481
if ( i >= known_backtrack_classes )
5483
/* Keeps us from having to do this for each rule */
5485
error = Get_Class( &ccpf2->BacktrackClassDef, s_in[j],
5486
&backtrack_classes[i], NULL );
5487
if ( error && error != TTO_Err_Not_Covered )
5489
known_backtrack_classes = i;
5492
if ( bc[i] != backtrack_classes[i] )
5501
s_in = &in->string[curr_pos];
5504
/* Start at 1 because [0] is implied */
5506
for ( i = 1, j = 1; i < igc; i++, j++ )
5508
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5510
if ( error && error != TTO_Err_Not_Covered )
5513
if ( curr_pos + j < (int)in->length )
5519
if ( i >= known_input_classes )
5521
error = Get_Class( &ccpf2->InputClassDef, s_in[j],
5522
&input_classes[i], NULL );
5523
if ( error && error != TTO_Err_Not_Covered )
5525
known_input_classes = i;
5528
if ( ic[i - 1] != input_classes[i] )
5535
/* we are starting to check for lookahead glyphs right after the
5536
last context glyph */
5539
s_in = &in->string[curr_pos];
5540
lc = cpcr.Lookahead;
5542
for ( i = 0, j = 0; i < lgc; i++, j++ )
5544
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5546
if ( error && error != TTO_Err_Not_Covered )
5549
if ( curr_pos + j < (int)in->length )
5555
if ( i >= known_lookahead_classes )
5557
error = Get_Class( &ccpf2->LookaheadClassDef, s_in[j],
5558
&lookahead_classes[i], NULL );
5559
if ( error && error != TTO_Err_Not_Covered )
5561
known_lookahead_classes = i;
5564
if ( lc[i] != lookahead_classes[i] )
5570
error = Do_ContextPos( gpi, igc,
5572
cpcr.PosLookupRecord,
5579
error = TTO_Err_Not_Covered;
5582
FREE( lookahead_classes );
5585
FREE( input_classes );
5588
FREE( backtrack_classes );
5593
static FT_Error Lookup_ChainContextPos3(
5595
TTO_ChainContextPosFormat3* ccpf3,
5596
TTO_GSUB_String* in,
5599
FT_UShort context_length,
5602
FT_UShort index, i, j, curr_pos, property;
5603
FT_UShort bgc, igc, lgc;
5606
TTO_GPOSHeader* gpos = gpi->gpos;
5611
TTO_GDEFHeader* gdef;
5614
bgc = ccpf3->BacktrackGlyphCount;
5615
igc = ccpf3->InputGlyphCount;
5616
lgc = ccpf3->LookaheadGlyphCount;
5618
if ( context_length != 0xFFFF && context_length < igc )
5619
return TTO_Err_Not_Covered;
5621
/* check whether context is too long; it is a first guess only */
5623
if ( bgc > in->pos || in->pos + igc + lgc > in->length )
5624
return TTO_Err_Not_Covered;
5628
if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
5633
/* Since we don't know in advance the number of glyphs to inspect,
5634
we search backwards for matches in the backtrack glyph array */
5637
s_in = &in->string[curr_pos];
5638
bc = ccpf3->BacktrackCoverage;
5640
for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
5642
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5644
if ( error && error != TTO_Err_Not_Covered )
5650
return TTO_Err_Not_Covered;
5653
error = Coverage_Index( &bc[i], s_in[j], &index );
5660
s_in = &in->string[curr_pos];
5661
ic = ccpf3->InputCoverage;
5663
for ( i = 0, j = 0; i < igc; i++, j++ )
5665
/* We already called CHECK_Property for s_in[0] */
5666
while ( j > 0 && CHECK_Property( gdef, s_in[j], flags, &property ) )
5668
if ( error && error != TTO_Err_Not_Covered )
5671
if ( curr_pos + j < (int)in->length )
5674
return TTO_Err_Not_Covered;
5677
error = Coverage_Index( &ic[i], s_in[j], &index );
5682
/* we are starting to check for lookahead glyphs right after the
5683
last context glyph */
5686
s_in = &in->string[curr_pos];
5687
lc = ccpf3->LookaheadCoverage;
5689
for ( i = 0, j = 0; i < lgc; i++, j++ )
5691
while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
5693
if ( error && error != TTO_Err_Not_Covered )
5696
if ( curr_pos + j < (int)in->length )
5699
return TTO_Err_Not_Covered;
5702
error = Coverage_Index( &lc[i], s_in[j], &index );
5707
return Do_ContextPos( gpi, igc,
5709
ccpf3->PosLookupRecord,
5715
static FT_Error Lookup_ChainContextPos(
5717
TTO_ChainContextPos* ccp,
5718
TTO_GSUB_String* in,
5721
FT_UShort context_length,
5724
switch ( ccp->PosFormat )
5727
return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, in, out,
5728
flags, context_length,
5732
return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, in, out,
5733
flags, context_length,
5737
return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, in, out,
5738
flags, context_length,
5742
return TTO_Err_Invalid_GPOS_SubTable_Format;
5745
return TT_Err_Ok; /* never reached */
5756
FT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos,
5757
FT_ULong script_tag,
5758
FT_UShort* script_index )
5763
TTO_ScriptRecord* sr;
5766
if ( !gpos || !script_index )
5767
return TT_Err_Invalid_Argument;
5769
sl = &gpos->ScriptList;
5770
sr = sl->ScriptRecord;
5772
for ( n = 0; n < sl->ScriptCount; n++ )
5773
if ( script_tag == sr[n].ScriptTag )
5780
return TTO_Err_Not_Covered;
5785
FT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos,
5786
FT_ULong language_tag,
5787
FT_UShort script_index,
5788
FT_UShort* language_index,
5789
FT_UShort* req_feature_index )
5794
TTO_ScriptRecord* sr;
5796
TTO_LangSysRecord* lsr;
5799
if ( !gpos || !language_index || !req_feature_index )
5800
return TT_Err_Invalid_Argument;
5802
sl = &gpos->ScriptList;
5803
sr = sl->ScriptRecord;
5805
if ( script_index >= sl->ScriptCount )
5806
return TT_Err_Invalid_Argument;
5808
s = &sr[script_index].Script;
5809
lsr = s->LangSysRecord;
5811
for ( n = 0; n < s->LangSysCount; n++ )
5812
if ( language_tag == lsr[n].LangSysTag )
5814
*language_index = n;
5815
*req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5820
return TTO_Err_Not_Covered;
5824
/* selecting 0xFFFF for language_index asks for the values of the
5825
default language (DefaultLangSys) */
5828
FT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos,
5829
FT_ULong feature_tag,
5830
FT_UShort script_index,
5831
FT_UShort language_index,
5832
FT_UShort* feature_index )
5837
TTO_ScriptRecord* sr;
5839
TTO_LangSysRecord* lsr;
5843
TTO_FeatureList* fl;
5844
TTO_FeatureRecord* fr;
5847
if ( !gpos || !feature_index )
5848
return TT_Err_Invalid_Argument;
5850
sl = &gpos->ScriptList;
5851
sr = sl->ScriptRecord;
5853
fl = &gpos->FeatureList;
5854
fr = fl->FeatureRecord;
5856
if ( script_index >= sl->ScriptCount )
5857
return TT_Err_Invalid_Argument;
5859
s = &sr[script_index].Script;
5860
lsr = s->LangSysRecord;
5862
if ( language_index == 0xFFFF )
5863
ls = &s->DefaultLangSys;
5866
if ( language_index >= s->LangSysCount )
5867
return TT_Err_Invalid_Argument;
5869
ls = &lsr[language_index].LangSys;
5872
fi = ls->FeatureIndex;
5874
for ( n = 0; n < ls->FeatureCount; n++ )
5876
if ( fi[n] >= fl->FeatureCount )
5877
return TTO_Err_Invalid_GPOS_SubTable_Format;
5879
if ( feature_tag == fr[fi[n]].FeatureTag )
5881
*feature_index = fi[n];
5887
return TTO_Err_Not_Covered;
5891
/* The next three functions return a null-terminated list */
5894
FT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos,
5895
FT_ULong** script_tag_list )
5898
FT_Memory memory = gpos->memory;
5903
TTO_ScriptRecord* sr;
5906
if ( !gpos || !script_tag_list )
5907
return TT_Err_Invalid_Argument;
5909
sl = &gpos->ScriptList;
5910
sr = sl->ScriptRecord;
5912
if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
5915
for ( n = 0; n < sl->ScriptCount; n++ )
5916
stl[n] = sr[n].ScriptTag;
5919
*script_tag_list = stl;
5926
FT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos,
5927
FT_UShort script_index,
5928
FT_ULong** language_tag_list )
5931
FT_Memory memory = gpos->memory;
5936
TTO_ScriptRecord* sr;
5938
TTO_LangSysRecord* lsr;
5941
if ( !gpos || !language_tag_list )
5942
return TT_Err_Invalid_Argument;
5944
sl = &gpos->ScriptList;
5945
sr = sl->ScriptRecord;
5947
if ( script_index >= sl->ScriptCount )
5948
return TT_Err_Invalid_Argument;
5950
s = &sr[script_index].Script;
5951
lsr = s->LangSysRecord;
5953
if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
5956
for ( n = 0; n < s->LangSysCount; n++ )
5957
ltl[n] = lsr[n].LangSysTag;
5960
*language_tag_list = ltl;
5966
/* selecting 0xFFFF for language_index asks for the values of the
5967
default language (DefaultLangSys) */
5970
FT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos,
5971
FT_UShort script_index,
5972
FT_UShort language_index,
5973
FT_ULong** feature_tag_list )
5977
FT_Memory memory = gpos->memory;
5981
TTO_ScriptRecord* sr;
5983
TTO_LangSysRecord* lsr;
5987
TTO_FeatureList* fl;
5988
TTO_FeatureRecord* fr;
5991
if ( !gpos || !feature_tag_list )
5992
return TT_Err_Invalid_Argument;
5994
sl = &gpos->ScriptList;
5995
sr = sl->ScriptRecord;
5997
fl = &gpos->FeatureList;
5998
fr = fl->FeatureRecord;
6000
if ( script_index >= sl->ScriptCount )
6001
return TT_Err_Invalid_Argument;
6003
s = &sr[script_index].Script;
6004
lsr = s->LangSysRecord;
6006
if ( language_index == 0xFFFF )
6007
ls = &s->DefaultLangSys;
6010
if ( language_index >= s->LangSysCount )
6011
return TT_Err_Invalid_Argument;
6013
ls = &lsr[language_index].LangSys;
6016
fi = ls->FeatureIndex;
6018
if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
6021
for ( n = 0; n < ls->FeatureCount; n++ )
6023
if ( fi[n] >= fl->FeatureCount )
6026
return TTO_Err_Invalid_GPOS_SubTable_Format;
6028
ftl[n] = fr[fi[n]].FeatureTag;
6032
*feature_tag_list = ftl;
6038
/* Do an individual subtable lookup. Returns TT_Err_Ok if positioning
6039
has been done, or TTO_Err_Not_Covered if not. */
6041
static FT_Error GPos_Do_Glyph_Lookup( GPOS_Instance* gpi,
6042
FT_UShort lookup_index,
6043
TTO_GSUB_String* in,
6045
FT_UShort context_length,
6048
FT_Error error = TT_Err_Ok;
6050
TTO_GPOSHeader* gpos = gpi->gpos;
6056
if ( nesting_level > TTO_MAX_NESTING_LEVEL )
6057
return TTO_Err_Too_Many_Nested_Contexts;
6059
lo = &gpos->LookupList.Lookup[lookup_index];
6060
flags = lo->LookupFlag;
6062
for ( i = 0; i < lo->SubTableCount; i++ )
6064
switch ( lo->LookupType )
6066
case GPOS_LOOKUP_SINGLE:
6067
error = Lookup_SinglePos( gpi,
6068
&lo->SubTable[i].st.gpos.single,
6070
flags, context_length );
6073
case GPOS_LOOKUP_PAIR:
6074
error = Lookup_PairPos( gpi,
6075
&lo->SubTable[i].st.gpos.pair,
6077
flags, context_length );
6080
case GPOS_LOOKUP_CURSIVE:
6081
error = Lookup_CursivePos( gpi,
6082
&lo->SubTable[i].st.gpos.cursive,
6084
flags, context_length );
6087
case GPOS_LOOKUP_MARKBASE:
6088
error = Lookup_MarkBasePos( gpi,
6089
&lo->SubTable[i].st.gpos.markbase,
6091
flags, context_length );
6094
case GPOS_LOOKUP_MARKLIG:
6095
error = Lookup_MarkLigPos( gpi,
6096
&lo->SubTable[i].st.gpos.marklig,
6098
flags, context_length );
6101
case GPOS_LOOKUP_MARKMARK:
6102
error = Lookup_MarkMarkPos( gpi,
6103
&lo->SubTable[i].st.gpos.markmark,
6105
flags, context_length );
6108
case GPOS_LOOKUP_CONTEXT:
6109
error = Lookup_ContextPos( gpi,
6110
&lo->SubTable[i].st.gpos.context,
6112
flags, context_length,
6116
case GPOS_LOOKUP_CHAIN:
6117
error = Lookup_ChainContextPos( gpi,
6118
&lo->SubTable[i].st.gpos.chain,
6120
flags, context_length,
6125
/* Check whether we have a successful positioning or an error other
6126
than TTO_Err_Not_Covered */
6128
if ( error != TTO_Err_Not_Covered )
6132
return TTO_Err_Not_Covered;
6136
/* apply one lookup to the input string object */
6138
static FT_Error GPos_Do_String_Lookup( GPOS_Instance* gpi,
6139
FT_UShort lookup_index,
6140
/* unsigned char *where_to_apply, */
6141
TTO_GSUB_String* in,
6142
TTO_GPOS_Data* out )
6144
FT_Error error = TTO_Err_Not_Covered;
6146
int nesting_level = 0;
6151
gpi->first = 0xFFFF;
6152
gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
6156
while ( in->pos < in->length )
6158
if (1) /* where_to_apply[in->pos]) */
6160
/* 0xFFFF indicates that we don't have a context length yet. */
6162
/* Note that the connection between mark and base glyphs hold
6163
exactly one (string) lookup. For example, it would be possible
6164
that in the first lookup, mark glyph X is attached to base
6165
glyph A, and in the next lookup it is attached to base glyph B.
6166
It is up to the font designer to provide meaningful lookups and
6169
error = GPos_Do_Glyph_Lookup( gpi, lookup_index, in, out,
6170
0xFFFF, nesting_level );
6171
if ( error && error != TTO_Err_Not_Covered )
6176
/* Contrary to properties defined in GDEF, user-defined properties
6177
will always stop a possible cursive positioning. */
6180
error = TTO_Err_Not_Covered;
6183
/* test whether we have to adjust the offsets for cursive connections */
6185
if ( gpi->first != 0xFFFF && gpi->last == 0xFFFF &&
6186
gpi->gpos->LookupList.Lookup[lookup_index].LookupFlag & RIGHT_TO_LEFT )
6188
offset = out[in->pos].y_pos;
6190
/* no horizontal offsets (for vertical writing direction)
6193
for ( i = gpi->first; i <= in->pos; i++ )
6194
out[i].y_pos -= offset;
6196
gpi->first = 0xFFFF;
6199
if ( error == TTO_Err_Not_Covered )
6210
FT_Error TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader* gpos,
6211
TTO_GlyphFunction gfunc )
6214
return TT_Err_Invalid_Argument;
6216
gpos->gfunc = gfunc;
6223
FT_Error TT_GPOS_Register_MM_Function( TTO_GPOSHeader* gpos,
6224
TTO_MMFunction mmfunc,
6228
return TT_Err_Invalid_Argument;
6230
gpos->mmfunc = mmfunc;
6237
/* If `dvi' is TRUE, glyph contour points for anchor points and device
6238
tables are ignored -- you will get device independent values. */
6241
FT_Error TT_GPOS_Apply_Feature(FT_Face face,
6242
TTO_GPOSHeader* gpos,
6243
FT_UShort feature_index,
6244
FT_UShort load_flags,
6245
TTO_GSUB_String* in,
6246
TTO_GPOS_Data** out,
6250
FT_Error error = TTO_Err_Not_Covered;
6252
TTO_Feature feature;
6257
if ( !face || !gpos ||
6258
!in || in->length == 0 || in->pos >= in->length )
6259
return TT_Err_Invalid_Argument;
6263
gpi.load_flags = load_flags;
6267
feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6268
index = feature.LookupListIndex;
6271
###### need to order lookups in the order they appear in the
6272
###### lookup list, not the order they appear in the
6276
for ( j = 0; j < feature.LookupListCount; j++ ) {
6277
error = GPos_Do_String_Lookup( &gpi, index[j], in, *out );
6278
if ( error && error != TTO_Err_Not_Covered )