2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
4 * Copyright (C) 2007 Red Hat, Inc.
6 * This is part of HarfBuzz, an OpenType Layout engine library.
8 * Permission is hereby granted, without written agreement and without
9 * license or royalty fees, to use, copy, modify, and distribute this
10 * software and its documentation for any purpose, provided that the
11 * above copyright notice and the following two paragraphs appear in
12 * all copies of this software.
14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 * Red Hat Author(s): Behdad Esfahbod
29 #include "harfbuzz-impl.h"
30 #include "harfbuzz-gpos-private.h"
31 #include "harfbuzz-open-private.h"
32 #include "harfbuzz-gdef-private.h"
33 #include "harfbuzz-shaper.h"
40 HB_UShort load_flags
; /* how the glyph should be loaded */
43 HB_UShort last
; /* the last valid glyph -- used
44 with cursive positioning */
45 HB_Fixed anchor_x
; /* the coordinates of the anchor point */
46 HB_Fixed anchor_y
; /* of the last valid glyph */
49 typedef struct GPOS_Instance_ GPOS_Instance
;
52 static HB_Error
GPOS_Do_Glyph_Lookup( GPOS_Instance
* gpi
,
53 HB_UShort lookup_index
,
55 HB_UShort context_length
,
60 #ifdef HB_SUPPORT_MULTIPLE_MASTER
61 /* the client application must replace this with something more
62 meaningful if multiple master fonts are to be supported. */
64 static HB_Error
default_mmfunc( HB_Font font
,
66 HB_Fixed
* metric_value
,
71 HB_UNUSED(metric_value
);
73 return ERR(HB_Err_Not_Covered
); /* ERR() call intended */
79 HB_Error
HB_Load_GPOS_Table( HB_Stream stream
,
80 HB_GPOSHeader
** retptr
,
82 HB_Stream gdefStream
)
84 HB_UInt cur_offset
, new_offset
, base_offset
;
92 return ERR(HB_Err_Invalid_Argument
);
94 if ( GOTO_Table( TTAG_GPOS
) )
97 base_offset
= FILE_Pos();
99 if ( ALLOC ( gpos
, sizeof( *gpos
) ) )
102 #ifdef HB_SUPPORT_MULTIPLE_MASTER
103 gpos
->mmfunc
= default_mmfunc
;
108 if ( FILE_Seek( base_offset
+ 4L ) ||
112 new_offset
= GET_UShort() + base_offset
;
116 cur_offset
= FILE_Pos();
117 if ( FILE_Seek( new_offset
) ||
118 ( error
= _HB_OPEN_Load_ScriptList( &gpos
->ScriptList
,
119 stream
) ) != HB_Err_Ok
)
121 (void)FILE_Seek( cur_offset
);
123 if ( ACCESS_Frame( 2L ) )
126 new_offset
= GET_UShort() + base_offset
;
130 cur_offset
= FILE_Pos();
131 if ( FILE_Seek( new_offset
) ||
132 ( error
= _HB_OPEN_Load_FeatureList( &gpos
->FeatureList
,
133 stream
) ) != HB_Err_Ok
)
135 (void)FILE_Seek( cur_offset
);
137 if ( ACCESS_Frame( 2L ) )
140 new_offset
= GET_UShort() + base_offset
;
144 cur_offset
= FILE_Pos();
145 if ( FILE_Seek( new_offset
) ||
146 ( error
= _HB_OPEN_Load_LookupList( &gpos
->LookupList
,
147 stream
, HB_Type_GPOS
) ) != HB_Err_Ok
)
150 gpos
->gdef
= gdef
; /* can be NULL */
152 if ( ( error
= _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef
, gdefStream
,
153 gpos
->LookupList
.Lookup
,
154 gpos
->LookupList
.LookupCount
) ) )
162 _HB_OPEN_Free_LookupList( &gpos
->LookupList
, HB_Type_GPOS
);
165 _HB_OPEN_Free_FeatureList( &gpos
->FeatureList
);
168 _HB_OPEN_Free_ScriptList( &gpos
->ScriptList
);
177 HB_Error
HB_Done_GPOS_Table( HB_GPOSHeader
* gpos
)
179 _HB_OPEN_Free_LookupList( &gpos
->LookupList
, HB_Type_GPOS
);
180 _HB_OPEN_Free_FeatureList( &gpos
->FeatureList
);
181 _HB_OPEN_Free_ScriptList( &gpos
->ScriptList
);
189 /*****************************
190 * SubTable related functions
191 *****************************/
197 /* There is a subtle difference in the specs between a `table' and a
198 `record' -- offsets for device tables in ValueRecords are taken from
199 the parent table and not the parent record. */
201 static HB_Error
Load_ValueRecord( HB_ValueRecord
* vr
,
208 HB_UInt cur_offset
, new_offset
;
211 if ( format
& HB_GPOS_FORMAT_HAVE_X_PLACEMENT
)
213 if ( ACCESS_Frame( 2L ) )
216 vr
->XPlacement
= GET_Short();
223 if ( format
& HB_GPOS_FORMAT_HAVE_Y_PLACEMENT
)
225 if ( ACCESS_Frame( 2L ) )
228 vr
->YPlacement
= GET_Short();
235 if ( format
& HB_GPOS_FORMAT_HAVE_X_ADVANCE
)
237 if ( ACCESS_Frame( 2L ) )
240 vr
->XAdvance
= GET_Short();
247 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ADVANCE
)
249 if ( ACCESS_Frame( 2L ) )
252 vr
->YAdvance
= GET_Short();
259 if ( format
& HB_GPOS_FORMAT_HAVE_DEVICE_TABLES
)
261 if ( ALLOC_ARRAY( vr
->DeviceTables
, 4, HB_Device
) )
263 vr
->DeviceTables
[VR_X_ADVANCE_DEVICE
] = 0;
264 vr
->DeviceTables
[VR_Y_ADVANCE_DEVICE
] = 0;
265 vr
->DeviceTables
[VR_X_PLACEMENT_DEVICE
] = 0;
266 vr
->DeviceTables
[VR_Y_PLACEMENT_DEVICE
] = 0;
270 vr
->DeviceTables
= 0;
273 if ( format
& HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE
)
275 if ( ACCESS_Frame( 2L ) )
278 new_offset
= GET_UShort();
284 new_offset
+= base_offset
;
286 cur_offset
= FILE_Pos();
287 if ( FILE_Seek( new_offset
) ||
288 ( error
= _HB_OPEN_Load_Device( &vr
->DeviceTables
[VR_X_PLACEMENT_DEVICE
],
289 stream
) ) != HB_Err_Ok
)
291 (void)FILE_Seek( cur_offset
);
295 if ( format
& HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE
)
297 if ( ACCESS_Frame( 2L ) )
300 new_offset
= GET_UShort();
306 new_offset
+= base_offset
;
308 cur_offset
= FILE_Pos();
309 if ( FILE_Seek( new_offset
) ||
310 ( error
= _HB_OPEN_Load_Device( &vr
->DeviceTables
[VR_Y_PLACEMENT_DEVICE
],
311 stream
) ) != HB_Err_Ok
)
313 (void)FILE_Seek( cur_offset
);
317 if ( format
& HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE
)
319 if ( ACCESS_Frame( 2L ) )
322 new_offset
= GET_UShort();
328 new_offset
+= base_offset
;
330 cur_offset
= FILE_Pos();
331 if ( FILE_Seek( new_offset
) ||
332 ( error
= _HB_OPEN_Load_Device( &vr
->DeviceTables
[VR_X_ADVANCE_DEVICE
],
333 stream
) ) != HB_Err_Ok
)
335 (void)FILE_Seek( cur_offset
);
339 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE
)
341 if ( ACCESS_Frame( 2L ) )
344 new_offset
= GET_UShort();
350 new_offset
+= base_offset
;
352 cur_offset
= FILE_Pos();
353 if ( FILE_Seek( new_offset
) ||
354 ( error
= _HB_OPEN_Load_Device( &vr
->DeviceTables
[VR_Y_ADVANCE_DEVICE
],
355 stream
) ) != HB_Err_Ok
)
357 (void)FILE_Seek( cur_offset
);
361 if ( format
& HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT
)
363 if ( ACCESS_Frame( 2L ) )
366 #ifdef HB_SUPPORT_MULTIPLE_MASTER
367 vr
->XIdPlacement
= GET_UShort();
374 #ifdef HB_SUPPORT_MULTIPLE_MASTER
376 vr
->XIdPlacement
= 0;
379 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT
)
381 if ( ACCESS_Frame( 2L ) )
384 #ifdef HB_SUPPORT_MULTIPLE_MASTER
385 vr
->YIdPlacement
= GET_UShort();
392 #ifdef HB_SUPPORT_MULTIPLE_MASTER
394 vr
->YIdPlacement
= 0;
397 if ( format
& HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE
)
399 if ( ACCESS_Frame( 2L ) )
402 #ifdef HB_SUPPORT_MULTIPLE_MASTER
403 vr
->XIdAdvance
= GET_UShort();
410 #ifdef HB_SUPPORT_MULTIPLE_MASTER
415 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE
)
417 if ( ACCESS_Frame( 2L ) )
420 #ifdef HB_SUPPORT_MULTIPLE_MASTER
421 vr
->YIdAdvance
= GET_UShort();
428 #ifdef HB_SUPPORT_MULTIPLE_MASTER
436 if ( vr
->DeviceTables
)
437 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_Y_ADVANCE_DEVICE
] );
440 if ( vr
->DeviceTables
)
441 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_X_ADVANCE_DEVICE
] );
444 if ( vr
->DeviceTables
)
445 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_Y_PLACEMENT_DEVICE
] );
448 FREE( vr
->DeviceTables
);
453 static void Free_ValueRecord( HB_ValueRecord
* vr
,
456 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE
)
457 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_Y_ADVANCE_DEVICE
] );
458 if ( format
& HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE
)
459 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_X_ADVANCE_DEVICE
] );
460 if ( format
& HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE
)
461 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_Y_PLACEMENT_DEVICE
] );
462 if ( format
& HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE
)
463 _HB_OPEN_Free_Device( vr
->DeviceTables
[VR_X_PLACEMENT_DEVICE
] );
464 FREE( vr
->DeviceTables
);
468 static HB_Error
Get_ValueRecord( GPOS_Instance
* gpi
,
473 HB_Short pixel_value
;
474 HB_Error error
= HB_Err_Ok
;
475 #ifdef HB_SUPPORT_MULTIPLE_MASTER
476 HB_GPOSHeader
* gpos
= gpi
->gpos
;
480 HB_UShort x_ppem
, y_ppem
;
481 HB_16Dot16 x_scale
, y_scale
;
487 x_ppem
= gpi
->font
->x_ppem
;
488 y_ppem
= gpi
->font
->y_ppem
;
489 x_scale
= gpi
->font
->x_scale
;
490 y_scale
= gpi
->font
->y_scale
;
492 /* design units -> fractional pixel */
494 if ( format
& HB_GPOS_FORMAT_HAVE_X_PLACEMENT
)
495 gd
->x_pos
+= x_scale
* vr
->XPlacement
/ 0x10000;
496 if ( format
& HB_GPOS_FORMAT_HAVE_Y_PLACEMENT
)
497 gd
->y_pos
+= y_scale
* vr
->YPlacement
/ 0x10000;
498 if ( format
& HB_GPOS_FORMAT_HAVE_X_ADVANCE
)
499 gd
->x_advance
+= x_scale
* vr
->XAdvance
/ 0x10000;
500 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ADVANCE
)
501 gd
->y_advance
+= y_scale
* vr
->YAdvance
/ 0x10000;
505 /* pixel -> fractional pixel */
507 if ( format
& HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE
)
509 _HB_OPEN_Get_Device( vr
->DeviceTables
[VR_X_PLACEMENT_DEVICE
], x_ppem
, &pixel_value
);
510 gd
->x_pos
+= pixel_value
<< 6;
512 if ( format
& HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE
)
514 _HB_OPEN_Get_Device( vr
->DeviceTables
[VR_Y_PLACEMENT_DEVICE
], y_ppem
, &pixel_value
);
515 gd
->y_pos
+= pixel_value
<< 6;
517 if ( format
& HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE
)
519 _HB_OPEN_Get_Device( vr
->DeviceTables
[VR_X_ADVANCE_DEVICE
], x_ppem
, &pixel_value
);
520 gd
->x_advance
+= pixel_value
<< 6;
522 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE
)
524 _HB_OPEN_Get_Device( vr
->DeviceTables
[VR_Y_ADVANCE_DEVICE
], y_ppem
, &pixel_value
);
525 gd
->y_advance
+= pixel_value
<< 6;
529 #ifdef HB_SUPPORT_MULTIPLE_MASTER
530 /* values returned from mmfunc() are already in fractional pixels */
532 if ( format
& HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT
)
534 error
= (gpos
->mmfunc
)( gpi
->font
, vr
->XIdPlacement
,
535 &value
, gpos
->data
);
540 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT
)
542 error
= (gpos
->mmfunc
)( gpi
->font
, vr
->YIdPlacement
,
543 &value
, gpos
->data
);
548 if ( format
& HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE
)
550 error
= (gpos
->mmfunc
)( gpi
->font
, vr
->XIdAdvance
,
551 &value
, gpos
->data
);
554 gd
->x_advance
+= value
;
556 if ( format
& HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE
)
558 error
= (gpos
->mmfunc
)( gpi
->font
, vr
->YIdAdvance
,
559 &value
, gpos
->data
);
562 gd
->y_advance
+= value
;
575 static HB_Error
Load_Anchor( HB_Anchor
* an
,
580 HB_UInt cur_offset
, new_offset
, base_offset
;
583 base_offset
= FILE_Pos();
585 if ( ACCESS_Frame( 2L ) )
588 an
->PosFormat
= GET_UShort();
592 switch ( an
->PosFormat
)
595 if ( ACCESS_Frame( 4L ) )
598 an
->af
.af1
.XCoordinate
= GET_Short();
599 an
->af
.af1
.YCoordinate
= GET_Short();
605 if ( ACCESS_Frame( 6L ) )
608 an
->af
.af2
.XCoordinate
= GET_Short();
609 an
->af
.af2
.YCoordinate
= GET_Short();
610 an
->af
.af2
.AnchorPoint
= GET_UShort();
616 if ( ACCESS_Frame( 6L ) )
619 an
->af
.af3
.XCoordinate
= GET_Short();
620 an
->af
.af3
.YCoordinate
= GET_Short();
622 new_offset
= GET_UShort();
628 if ( ALLOC_ARRAY( an
->af
.af3
.DeviceTables
, 2, HB_Device
) )
631 an
->af
.af3
.DeviceTables
[AF3_X_DEVICE_TABLE
] = 0;
632 an
->af
.af3
.DeviceTables
[AF3_Y_DEVICE_TABLE
] = 0;
634 new_offset
+= base_offset
;
636 cur_offset
= FILE_Pos();
637 if ( FILE_Seek( new_offset
) ||
638 ( error
= _HB_OPEN_Load_Device( &an
->af
.af3
.DeviceTables
[AF3_X_DEVICE_TABLE
],
639 stream
) ) != HB_Err_Ok
)
641 (void)FILE_Seek( cur_offset
);
644 if ( ACCESS_Frame( 2L ) )
647 new_offset
= GET_UShort();
653 if ( !an
->af
.af3
.DeviceTables
)
655 if ( ALLOC_ARRAY( an
->af
.af3
.DeviceTables
, 2, HB_Device
) )
658 an
->af
.af3
.DeviceTables
[AF3_X_DEVICE_TABLE
] = 0;
659 an
->af
.af3
.DeviceTables
[AF3_Y_DEVICE_TABLE
] = 0;
662 new_offset
+= base_offset
;
664 cur_offset
= FILE_Pos();
665 if ( FILE_Seek( new_offset
) ||
666 ( error
= _HB_OPEN_Load_Device( &an
->af
.af3
.DeviceTables
[AF3_Y_DEVICE_TABLE
],
667 stream
) ) != HB_Err_Ok
)
669 (void)FILE_Seek( cur_offset
);
674 if ( ACCESS_Frame( 4L ) )
677 #ifdef HB_SUPPORT_MULTIPLE_MASTER
678 an
->af
.af4
.XIdAnchor
= GET_UShort();
679 an
->af
.af4
.YIdAnchor
= GET_UShort();
689 return ERR(HB_Err_Invalid_SubTable_Format
);
695 if ( an
->af
.af3
.DeviceTables
)
696 _HB_OPEN_Free_Device( an
->af
.af3
.DeviceTables
[AF3_X_DEVICE_TABLE
] );
699 FREE( an
->af
.af3
.DeviceTables
);
704 static void Free_Anchor( HB_Anchor
* an
)
706 if ( an
->PosFormat
== 3 && an
->af
.af3
.DeviceTables
)
708 _HB_OPEN_Free_Device( an
->af
.af3
.DeviceTables
[AF3_X_DEVICE_TABLE
] );
709 _HB_OPEN_Free_Device( an
->af
.af3
.DeviceTables
[AF3_Y_DEVICE_TABLE
] );
710 FREE( an
->af
.af3
.DeviceTables
);
715 static HB_Error
Get_Anchor( GPOS_Instance
* gpi
,
717 HB_UShort glyph_index
,
721 HB_Error error
= HB_Err_Ok
;
723 #ifdef HB_SUPPORT_MULTIPLE_MASTER
724 HB_GPOSHeader
* gpos
= gpi
->gpos
;
728 HB_Short pixel_value
;
730 HB_UShort x_ppem
, y_ppem
;
731 HB_16Dot16 x_scale
, y_scale
;
734 x_ppem
= gpi
->font
->x_ppem
;
735 y_ppem
= gpi
->font
->y_ppem
;
736 x_scale
= gpi
->font
->x_scale
;
737 y_scale
= gpi
->font
->y_scale
;
739 switch ( an
->PosFormat
)
742 /* The special case of an empty AnchorTable */
745 return HB_Err_Not_Covered
;
748 *x_value
= x_scale
* an
->af
.af1
.XCoordinate
/ 0x10000;
749 *y_value
= y_scale
* an
->af
.af1
.YCoordinate
/ 0x10000;
755 hb_uint32 n_points
= 0;
756 ap
= an
->af
.af2
.AnchorPoint
;
757 if (!gpi
->font
->klass
->getPointInOutline
)
758 goto no_contour_point
;
759 error
= gpi
->font
->klass
->getPointInOutline(gpi
->font
, glyph_index
, gpi
->load_flags
, ap
, x_value
, y_value
, &n_points
);
762 /* if n_points is set to zero, we use the design coordinate value pair.
763 * This can happen e.g. for sbit glyphs. */
765 goto no_contour_point
;
770 *x_value
= x_scale
* an
->af
.af3
.XCoordinate
/ 0x10000;
771 *y_value
= y_scale
* an
->af
.af3
.YCoordinate
/ 0x10000;
778 _HB_OPEN_Get_Device( an
->af
.af3
.DeviceTables
[AF3_X_DEVICE_TABLE
], x_ppem
, &pixel_value
);
779 *x_value
= pixel_value
<< 6;
780 _HB_OPEN_Get_Device( an
->af
.af3
.DeviceTables
[AF3_Y_DEVICE_TABLE
], y_ppem
, &pixel_value
);
781 *y_value
= pixel_value
<< 6;
784 *x_value
= *y_value
= 0;
786 *x_value
+= x_scale
* an
->af
.af3
.XCoordinate
/ 0x10000;
787 *y_value
+= y_scale
* an
->af
.af3
.YCoordinate
/ 0x10000;
791 #ifdef HB_SUPPORT_MULTIPLE_MASTER
792 error
= (gpos
->mmfunc
)( gpi
->font
, an
->af
.af4
.XIdAnchor
,
793 x_value
, gpos
->data
);
797 error
= (gpos
->mmfunc
)( gpi
->font
, an
->af
.af4
.YIdAnchor
,
798 y_value
, gpos
->data
);
803 return ERR(HB_Err_Not_Covered
);
813 static HB_Error
Load_MarkArray ( HB_MarkArray
* ma
,
818 HB_UShort n
, m
, count
;
819 HB_UInt cur_offset
, new_offset
, base_offset
;
824 base_offset
= FILE_Pos();
826 if ( ACCESS_Frame( 2L ) )
829 count
= ma
->MarkCount
= GET_UShort();
833 ma
->MarkRecord
= NULL
;
835 if ( ALLOC_ARRAY( ma
->MarkRecord
, count
, HB_MarkRecord
) )
840 for ( n
= 0; n
< count
; n
++ )
842 if ( ACCESS_Frame( 4L ) )
845 mr
[n
].Class
= GET_UShort();
846 new_offset
= GET_UShort() + base_offset
;
850 cur_offset
= FILE_Pos();
851 if ( FILE_Seek( new_offset
) ||
852 ( error
= Load_Anchor( &mr
[n
].MarkAnchor
, stream
) ) != HB_Err_Ok
)
854 (void)FILE_Seek( cur_offset
);
860 for ( m
= 0; m
< n
; m
++ )
861 Free_Anchor( &mr
[m
].MarkAnchor
);
868 static void Free_MarkArray( HB_MarkArray
* ma
)
875 if ( ma
->MarkRecord
)
877 count
= ma
->MarkCount
;
880 for ( n
= 0; n
< count
; n
++ )
881 Free_Anchor( &mr
[n
].MarkAnchor
);
890 /* SinglePosFormat1 */
891 /* SinglePosFormat2 */
893 static HB_Error
Load_SinglePos( HB_GPOS_SubTable
* st
,
897 HB_SinglePos
* sp
= &st
->single
;
899 HB_UShort n
, m
, count
, format
;
900 HB_UInt cur_offset
, new_offset
, base_offset
;
905 base_offset
= FILE_Pos();
907 if ( ACCESS_Frame( 6L ) )
910 sp
->PosFormat
= GET_UShort();
911 new_offset
= GET_UShort() + base_offset
;
913 format
= sp
->ValueFormat
= GET_UShort();
918 return ERR(HB_Err_Invalid_SubTable
);
920 cur_offset
= FILE_Pos();
921 if ( FILE_Seek( new_offset
) ||
922 ( error
= _HB_OPEN_Load_Coverage( &sp
->Coverage
, stream
) ) != HB_Err_Ok
)
924 (void)FILE_Seek( cur_offset
);
926 switch ( sp
->PosFormat
)
929 error
= Load_ValueRecord( &sp
->spf
.spf1
.Value
, format
,
930 base_offset
, stream
);
936 if ( ACCESS_Frame( 2L ) )
939 count
= sp
->spf
.spf2
.ValueCount
= GET_UShort();
943 sp
->spf
.spf2
.Value
= NULL
;
945 if ( ALLOC_ARRAY( sp
->spf
.spf2
.Value
, count
, HB_ValueRecord
) )
948 vr
= sp
->spf
.spf2
.Value
;
950 for ( n
= 0; n
< count
; n
++ )
952 error
= Load_ValueRecord( &vr
[n
], format
, base_offset
, stream
);
959 return ERR(HB_Err_Invalid_SubTable_Format
);
965 for ( m
= 0; m
< n
; m
++ )
966 Free_ValueRecord( &vr
[m
], format
);
971 _HB_OPEN_Free_Coverage( &sp
->Coverage
);
976 static void Free_SinglePos( HB_GPOS_SubTable
* st
)
978 HB_UShort n
, count
, format
;
979 HB_SinglePos
* sp
= &st
->single
;
984 format
= sp
->ValueFormat
;
986 switch ( sp
->PosFormat
)
989 Free_ValueRecord( &sp
->spf
.spf1
.Value
, format
);
993 if ( sp
->spf
.spf2
.Value
)
995 count
= sp
->spf
.spf2
.ValueCount
;
996 v
= sp
->spf
.spf2
.Value
;
998 for ( n
= 0; n
< count
; n
++ )
999 Free_ValueRecord( &v
[n
], format
);
1008 _HB_OPEN_Free_Coverage( &sp
->Coverage
);
1011 static HB_Error
Lookup_SinglePos( GPOS_Instance
* gpi
,
1012 HB_GPOS_SubTable
* st
,
1015 HB_UShort context_length
,
1018 HB_UShort index
, property
;
1020 HB_GPOSHeader
* gpos
= gpi
->gpos
;
1021 HB_SinglePos
* sp
= &st
->single
;
1023 HB_UNUSED(nesting_level
);
1025 if ( context_length
!= 0xFFFF && context_length
< 1 )
1026 return HB_Err_Not_Covered
;
1028 if ( CHECK_Property( gpos
->gdef
, IN_CURITEM(), flags
, &property
) )
1031 error
= _HB_OPEN_Coverage_Index( &sp
->Coverage
, IN_CURGLYPH(), &index
);
1035 switch ( sp
->PosFormat
)
1038 error
= Get_ValueRecord( gpi
, &sp
->spf
.spf1
.Value
,
1039 sp
->ValueFormat
, POSITION( buffer
->in_pos
) );
1045 if ( index
>= sp
->spf
.spf2
.ValueCount
)
1046 return ERR(HB_Err_Invalid_SubTable
);
1047 error
= Get_ValueRecord( gpi
, &sp
->spf
.spf2
.Value
[index
],
1048 sp
->ValueFormat
, POSITION( buffer
->in_pos
) );
1054 return ERR(HB_Err_Invalid_SubTable
);
1067 static HB_Error
Load_PairSet ( HB_PairSet
* ps
,
1074 HB_UShort n
, m
, count
;
1075 HB_UInt base_offset
;
1077 HB_PairValueRecord
* pvr
;
1080 base_offset
= FILE_Pos();
1082 if ( ACCESS_Frame( 2L ) )
1085 count
= ps
->PairValueCount
= GET_UShort();
1089 ps
->PairValueRecord
= NULL
;
1091 if ( ALLOC_ARRAY( ps
->PairValueRecord
, count
, HB_PairValueRecord
) )
1094 pvr
= ps
->PairValueRecord
;
1096 for ( n
= 0; n
< count
; n
++ )
1098 if ( ACCESS_Frame( 2L ) )
1101 pvr
[n
].SecondGlyph
= GET_UShort();
1107 error
= Load_ValueRecord( &pvr
[n
].Value1
, format1
,
1108 base_offset
, stream
);
1114 error
= Load_ValueRecord( &pvr
[n
].Value2
, format2
,
1115 base_offset
, stream
);
1119 Free_ValueRecord( &pvr
[n
].Value1
, format1
);
1128 for ( m
= 0; m
< n
; m
++ )
1131 Free_ValueRecord( &pvr
[m
].Value1
, format1
);
1133 Free_ValueRecord( &pvr
[m
].Value2
, format2
);
1141 static void Free_PairSet( HB_PairSet
* ps
,
1147 HB_PairValueRecord
* pvr
;
1150 if ( ps
->PairValueRecord
)
1152 count
= ps
->PairValueCount
;
1153 pvr
= ps
->PairValueRecord
;
1155 for ( n
= 0; n
< count
; n
++ )
1158 Free_ValueRecord( &pvr
[n
].Value1
, format1
);
1160 Free_ValueRecord( &pvr
[n
].Value2
, format2
);
1168 /* PairPosFormat1 */
1170 static HB_Error
Load_PairPos1( HB_PairPosFormat1
* ppf1
,
1177 HB_UShort n
, m
, count
;
1178 HB_UInt cur_offset
, new_offset
, base_offset
;
1183 base_offset
= FILE_Pos() - 8L;
1185 if ( ACCESS_Frame( 2L ) )
1188 count
= ppf1
->PairSetCount
= GET_UShort();
1192 ppf1
->PairSet
= NULL
;
1194 if ( ALLOC_ARRAY( ppf1
->PairSet
, count
, HB_PairSet
) )
1199 for ( n
= 0; n
< count
; n
++ )
1201 if ( ACCESS_Frame( 2L ) )
1204 new_offset
= GET_UShort() + base_offset
;
1208 cur_offset
= FILE_Pos();
1209 if ( FILE_Seek( new_offset
) ||
1210 ( error
= Load_PairSet( &ps
[n
], format1
,
1211 format2
, stream
) ) != HB_Err_Ok
)
1213 (void)FILE_Seek( cur_offset
);
1219 for ( m
= 0; m
< n
; m
++ )
1220 Free_PairSet( &ps
[m
], format1
, format2
);
1227 static void Free_PairPos1( HB_PairPosFormat1
* ppf1
,
1236 if ( ppf1
->PairSet
)
1238 count
= ppf1
->PairSetCount
;
1241 for ( n
= 0; n
< count
; n
++ )
1242 Free_PairSet( &ps
[n
], format1
, format2
);
1249 /* PairPosFormat2 */
1251 static HB_Error
Load_PairPos2( HB_PairPosFormat2
* ppf2
,
1258 HB_UShort m
, n
, k
, count1
, count2
;
1259 HB_UInt cur_offset
, new_offset1
, new_offset2
, base_offset
;
1261 HB_Class1Record
* c1r
;
1262 HB_Class2Record
* c2r
;
1265 base_offset
= FILE_Pos() - 8L;
1267 if ( ACCESS_Frame( 8L ) )
1270 new_offset1
= GET_UShort() + base_offset
;
1271 new_offset2
= GET_UShort() + base_offset
;
1273 /* `Class1Count' and `Class2Count' are the upper limits for class
1274 values, thus we read it now to make additional safety checks. */
1276 count1
= ppf2
->Class1Count
= GET_UShort();
1277 count2
= ppf2
->Class2Count
= GET_UShort();
1281 cur_offset
= FILE_Pos();
1282 if ( FILE_Seek( new_offset1
) ||
1283 ( error
= _HB_OPEN_Load_ClassDefinition( &ppf2
->ClassDef1
, count1
,
1284 stream
) ) != HB_Err_Ok
)
1286 if ( FILE_Seek( new_offset2
) ||
1287 ( error
= _HB_OPEN_Load_ClassDefinition( &ppf2
->ClassDef2
, count2
,
1288 stream
) ) != HB_Err_Ok
)
1290 (void)FILE_Seek( cur_offset
);
1292 ppf2
->Class1Record
= NULL
;
1294 if ( ALLOC_ARRAY( ppf2
->Class1Record
, count1
, HB_Class1Record
) )
1297 c1r
= ppf2
->Class1Record
;
1299 for ( m
= 0; m
< count1
; m
++ )
1301 c1r
[m
].Class2Record
= NULL
;
1303 if ( ALLOC_ARRAY( c1r
[m
].Class2Record
, count2
, HB_Class2Record
) )
1306 c2r
= c1r
[m
].Class2Record
;
1308 for ( n
= 0; n
< count2
; n
++ )
1312 error
= Load_ValueRecord( &c2r
[n
].Value1
, format1
,
1313 base_offset
, stream
);
1319 error
= Load_ValueRecord( &c2r
[n
].Value2
, format2
,
1320 base_offset
, stream
);
1324 Free_ValueRecord( &c2r
[n
].Value1
, format1
);
1333 for ( k
= 0; k
< n
; k
++ )
1336 Free_ValueRecord( &c2r
[k
].Value1
, format1
);
1338 Free_ValueRecord( &c2r
[k
].Value2
, format2
);
1346 for ( k
= 0; k
< m
; k
++ )
1348 c2r
= c1r
[k
].Class2Record
;
1350 for ( n
= 0; n
< count2
; n
++ )
1353 Free_ValueRecord( &c2r
[n
].Value1
, format1
);
1355 Free_ValueRecord( &c2r
[n
].Value2
, format2
);
1364 _HB_OPEN_Free_ClassDefinition( &ppf2
->ClassDef2
);
1367 _HB_OPEN_Free_ClassDefinition( &ppf2
->ClassDef1
);
1372 static void Free_PairPos2( HB_PairPosFormat2
* ppf2
,
1376 HB_UShort m
, n
, count1
, count2
;
1378 HB_Class1Record
* c1r
;
1379 HB_Class2Record
* c2r
;
1382 if ( ppf2
->Class1Record
)
1384 c1r
= ppf2
->Class1Record
;
1385 count1
= ppf2
->Class1Count
;
1386 count2
= ppf2
->Class2Count
;
1388 for ( m
= 0; m
< count1
; m
++ )
1390 c2r
= c1r
[m
].Class2Record
;
1392 for ( n
= 0; n
< count2
; n
++ )
1395 Free_ValueRecord( &c2r
[n
].Value1
, format1
);
1397 Free_ValueRecord( &c2r
[n
].Value2
, format2
);
1405 _HB_OPEN_Free_ClassDefinition( &ppf2
->ClassDef2
);
1406 _HB_OPEN_Free_ClassDefinition( &ppf2
->ClassDef1
);
1411 static HB_Error
Load_PairPos( HB_GPOS_SubTable
* st
,
1415 HB_PairPos
* pp
= &st
->pair
;
1417 HB_UShort format1
, format2
;
1418 HB_UInt cur_offset
, new_offset
, base_offset
;
1421 base_offset
= FILE_Pos();
1423 if ( ACCESS_Frame( 8L ) )
1426 pp
->PosFormat
= GET_UShort();
1427 new_offset
= GET_UShort() + base_offset
;
1429 format1
= pp
->ValueFormat1
= GET_UShort();
1430 format2
= pp
->ValueFormat2
= GET_UShort();
1434 cur_offset
= FILE_Pos();
1435 if ( FILE_Seek( new_offset
) ||
1436 ( error
= _HB_OPEN_Load_Coverage( &pp
->Coverage
, stream
) ) != HB_Err_Ok
)
1438 (void)FILE_Seek( cur_offset
);
1440 switch ( pp
->PosFormat
)
1443 error
= Load_PairPos1( &pp
->ppf
.ppf1
, format1
, format2
, stream
);
1449 error
= Load_PairPos2( &pp
->ppf
.ppf2
, format1
, format2
, stream
);
1455 return ERR(HB_Err_Invalid_SubTable_Format
);
1461 _HB_OPEN_Free_Coverage( &pp
->Coverage
);
1466 static void Free_PairPos( HB_GPOS_SubTable
* st
)
1468 HB_UShort format1
, format2
;
1469 HB_PairPos
* pp
= &st
->pair
;
1472 format1
= pp
->ValueFormat1
;
1473 format2
= pp
->ValueFormat2
;
1475 switch ( pp
->PosFormat
)
1478 Free_PairPos1( &pp
->ppf
.ppf1
, format1
, format2
);
1482 Free_PairPos2( &pp
->ppf
.ppf2
, format1
, format2
);
1489 _HB_OPEN_Free_Coverage( &pp
->Coverage
);
1493 static HB_Error
Lookup_PairPos1( GPOS_Instance
* gpi
,
1494 HB_PairPosFormat1
* ppf1
,
1502 HB_UShort numpvr
, glyph2
;
1504 HB_PairValueRecord
* pvr
;
1507 if ( index
>= ppf1
->PairSetCount
)
1508 return ERR(HB_Err_Invalid_SubTable
);
1510 pvr
= ppf1
->PairSet
[index
].PairValueRecord
;
1512 return ERR(HB_Err_Invalid_SubTable
);
1514 glyph2
= IN_CURGLYPH();
1516 for ( numpvr
= ppf1
->PairSet
[index
].PairValueCount
;
1520 if ( glyph2
== pvr
->SecondGlyph
)
1522 error
= Get_ValueRecord( gpi
, &pvr
->Value1
, format1
,
1523 POSITION( first_pos
) );
1526 return Get_ValueRecord( gpi
, &pvr
->Value2
, format2
,
1527 POSITION( buffer
->in_pos
) );
1531 return HB_Err_Not_Covered
;
1535 static HB_Error
Lookup_PairPos2( GPOS_Instance
* gpi
,
1536 HB_PairPosFormat2
* ppf2
,
1543 HB_UShort cl1
= 0, cl2
= 0; /* shut compiler up */
1545 HB_Class1Record
* c1r
;
1546 HB_Class2Record
* c2r
;
1549 error
= _HB_OPEN_Get_Class( &ppf2
->ClassDef1
, IN_GLYPH( first_pos
),
1551 if ( error
&& error
!= HB_Err_Not_Covered
)
1553 error
= _HB_OPEN_Get_Class( &ppf2
->ClassDef2
, IN_CURGLYPH(),
1555 if ( error
&& error
!= HB_Err_Not_Covered
)
1558 c1r
= &ppf2
->Class1Record
[cl1
];
1560 return ERR(HB_Err_Invalid_SubTable
);
1561 c2r
= &c1r
->Class2Record
[cl2
];
1563 error
= Get_ValueRecord( gpi
, &c2r
->Value1
, format1
, POSITION( first_pos
) );
1566 return Get_ValueRecord( gpi
, &c2r
->Value2
, format2
, POSITION( buffer
->in_pos
) );
1570 static HB_Error
Lookup_PairPos( GPOS_Instance
* gpi
,
1571 HB_GPOS_SubTable
* st
,
1574 HB_UShort context_length
,
1578 HB_UShort index
, property
;
1580 HB_GPOSHeader
* gpos
= gpi
->gpos
;
1581 HB_PairPos
* pp
= &st
->pair
;
1583 HB_UNUSED(nesting_level
);
1585 if ( buffer
->in_pos
>= buffer
->in_length
- 1 )
1586 return HB_Err_Not_Covered
; /* Not enough glyphs in stream */
1588 if ( context_length
!= 0xFFFF && context_length
< 2 )
1589 return HB_Err_Not_Covered
;
1591 if ( CHECK_Property( gpos
->gdef
, IN_CURITEM(), flags
, &property
) )
1594 error
= _HB_OPEN_Coverage_Index( &pp
->Coverage
, IN_CURGLYPH(), &index
);
1600 first_pos
= buffer
->in_pos
;
1603 while ( CHECK_Property( gpos
->gdef
, IN_CURITEM(),
1604 flags
, &property
) )
1606 if ( error
&& error
!= HB_Err_Not_Covered
)
1609 if ( buffer
->in_pos
== buffer
->in_length
)
1611 buffer
->in_pos
= first_pos
;
1612 return HB_Err_Not_Covered
;
1618 switch ( pp
->PosFormat
)
1621 error
= Lookup_PairPos1( gpi
, &pp
->ppf
.ppf1
, buffer
,
1623 pp
->ValueFormat1
, pp
->ValueFormat2
);
1627 error
= Lookup_PairPos2( gpi
, &pp
->ppf
.ppf2
, buffer
, first_pos
,
1628 pp
->ValueFormat1
, pp
->ValueFormat2
);
1632 return ERR(HB_Err_Invalid_SubTable_Format
);
1635 /* if we don't have coverage for the second glyph don't skip it for
1636 further lookups but reset in_pos back to the first_glyph and let
1637 the caller in Do_String_Lookup increment in_pos */
1638 if ( error
== HB_Err_Not_Covered
)
1639 buffer
->in_pos
= first_pos
;
1641 /* adjusting the `next' glyph */
1643 if ( pp
->ValueFormat2
)
1652 /* CursivePosFormat1 */
1654 static HB_Error
Load_CursivePos( HB_GPOS_SubTable
* st
,
1658 HB_CursivePos
* cp
= &st
->cursive
;
1660 HB_UShort n
, m
, count
;
1661 HB_UInt cur_offset
, new_offset
, base_offset
;
1663 HB_EntryExitRecord
* eer
;
1666 base_offset
= FILE_Pos();
1668 if ( ACCESS_Frame( 4L ) )
1671 cp
->PosFormat
= GET_UShort();
1672 new_offset
= GET_UShort() + base_offset
;
1676 cur_offset
= FILE_Pos();
1677 if ( FILE_Seek( new_offset
) ||
1678 ( error
= _HB_OPEN_Load_Coverage( &cp
->Coverage
, stream
) ) != HB_Err_Ok
)
1680 (void)FILE_Seek( cur_offset
);
1682 if ( ACCESS_Frame( 2L ) )
1685 count
= cp
->EntryExitCount
= GET_UShort();
1689 cp
->EntryExitRecord
= NULL
;
1691 if ( ALLOC_ARRAY( cp
->EntryExitRecord
, count
, HB_EntryExitRecord
) )
1694 eer
= cp
->EntryExitRecord
;
1696 for ( n
= 0; n
< count
; n
++ )
1698 HB_UInt entry_offset
;
1700 if ( ACCESS_Frame( 2L ) )
1703 entry_offset
= new_offset
= GET_UShort();
1709 new_offset
+= base_offset
;
1711 cur_offset
= FILE_Pos();
1712 if ( FILE_Seek( new_offset
) ||
1713 ( error
= Load_Anchor( &eer
[n
].EntryAnchor
,
1714 stream
) ) != HB_Err_Ok
)
1716 (void)FILE_Seek( cur_offset
);
1719 eer
[n
].EntryAnchor
.PosFormat
= 0;
1721 if ( ACCESS_Frame( 2L ) )
1724 new_offset
= GET_UShort();
1730 new_offset
+= base_offset
;
1732 cur_offset
= FILE_Pos();
1733 if ( FILE_Seek( new_offset
) ||
1734 ( error
= Load_Anchor( &eer
[n
].ExitAnchor
,
1735 stream
) ) != HB_Err_Ok
)
1738 Free_Anchor( &eer
[n
].EntryAnchor
);
1741 (void)FILE_Seek( cur_offset
);
1744 eer
[n
].ExitAnchor
.PosFormat
= 0;
1750 for ( m
= 0; m
< n
; m
++ )
1752 Free_Anchor( &eer
[m
].EntryAnchor
);
1753 Free_Anchor( &eer
[m
].ExitAnchor
);
1759 _HB_OPEN_Free_Coverage( &cp
->Coverage
);
1764 static void Free_CursivePos( HB_GPOS_SubTable
* st
)
1767 HB_CursivePos
* cp
= &st
->cursive
;
1769 HB_EntryExitRecord
* eer
;
1772 if ( cp
->EntryExitRecord
)
1774 count
= cp
->EntryExitCount
;
1775 eer
= cp
->EntryExitRecord
;
1777 for ( n
= 0; n
< count
; n
++ )
1779 Free_Anchor( &eer
[n
].EntryAnchor
);
1780 Free_Anchor( &eer
[n
].ExitAnchor
);
1786 _HB_OPEN_Free_Coverage( &cp
->Coverage
);
1790 static HB_Error
Lookup_CursivePos( GPOS_Instance
* gpi
,
1791 HB_GPOS_SubTable
* st
,
1794 HB_UShort context_length
,
1797 HB_UShort index
, property
;
1799 HB_GPOSHeader
* gpos
= gpi
->gpos
;
1800 HB_CursivePos
* cp
= &st
->cursive
;
1802 HB_EntryExitRecord
* eer
;
1803 HB_Fixed entry_x
, entry_y
;
1804 HB_Fixed exit_x
, exit_y
;
1806 HB_UNUSED(nesting_level
);
1808 if ( context_length
!= 0xFFFF && context_length
< 1 )
1811 return HB_Err_Not_Covered
;
1814 /* Glyphs not having the right GDEF properties will be ignored, i.e.,
1815 gpi->last won't be reset (contrary to user defined properties). */
1817 if ( CHECK_Property( gpos
->gdef
, IN_CURITEM(), flags
, &property
) )
1820 /* We don't handle mark glyphs here. According to Andrei, this isn't
1821 possible, but who knows... */
1823 if ( property
== HB_GDEF_MARK
)
1826 return HB_Err_Not_Covered
;
1829 error
= _HB_OPEN_Coverage_Index( &cp
->Coverage
, IN_CURGLYPH(), &index
);
1836 if ( index
>= cp
->EntryExitCount
)
1837 return ERR(HB_Err_Invalid_SubTable
);
1839 eer
= &cp
->EntryExitRecord
[index
];
1841 /* Now comes the messiest part of the whole OpenType
1842 specification. At first glance, cursive connections seem easy
1843 to understand, but there are pitfalls! The reason is that
1844 the specs don't mention how to compute the advance values
1845 resp. glyph offsets. I was told it would be an omission, to
1846 be fixed in the next OpenType version... Again many thanks to
1847 Andrei Burago <andreib@microsoft.com> for clarifications.
1849 Consider the following example:
1862 glyph1: advance width = 12
1863 anchor point = (3,1)
1865 glyph2: advance width = 11
1866 anchor point = (9,4)
1868 LSB is 1 for both glyphs (so the boxes drawn above are glyph
1869 bboxes). Writing direction is R2L; `0' denotes the glyph's
1872 Now the surprising part: The advance width of the *left* glyph
1873 (resp. of the *bottom* glyph) will be modified, no matter
1874 whether the writing direction is L2R or R2L (resp. T2B or
1875 B2T)! This assymetry is caused by the fact that the glyph's
1876 coordinate origin is always the lower left corner for all
1879 Continuing the above example, we can compute the new
1880 (horizontal) advance width of glyph2 as
1884 and the new vertical offset of glyph2 as
1889 Vertical writing direction is far more complicated:
1891 a) Assuming that we recompute the advance height of the lower glyph:
1896 +-----+--+ 1 | yadv1
1898 yadv2 | 0+--+------+ -- BSB1 --
1899 | 2 | -- -- y_offset
1901 BSB2 -- 0+--------+ --
1904 glyph1: advance height = 6
1905 anchor point = (3,1)
1907 glyph2: advance height = 7
1908 anchor point = (9,4)
1910 TSB is 1 for both glyphs; writing direction is T2B.
1913 BSB1 = yadv1 - (TSB1 + ymax1)
1914 BSB2 = yadv2 - (TSB2 + ymax2)
1917 vertical advance width of glyph2
1918 = y_offset + BSB2 - BSB1
1919 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1920 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1921 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1924 b) Assuming that we recompute the advance height of the upper glyph:
1929 TSB2 -- +-----+--+ 1 | yadv1 ymax1
1931 yadv2 | 0+--+------+ -- --
1932 ymax2 | 2 | -- y_offset
1937 glyph1: advance height = 6
1938 anchor point = (3,1)
1940 glyph2: advance height = 7
1941 anchor point = (9,4)
1943 TSB is 1 for both glyphs; writing direction is T2B.
1947 vertical advance width of glyph2
1948 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1949 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1952 Comparing a) with b) shows that b) is easier to compute. I'll wait
1953 for a reply from Andrei to see what should really be implemented...
1955 Since horizontal advance widths or vertical advance heights
1956 can be used alone but not together, no ambiguity occurs. */
1958 if ( gpi
->last
== 0xFFFF )
1961 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1964 error
= Get_Anchor( gpi
, &eer
->EntryAnchor
, IN_CURGLYPH(),
1965 &entry_x
, &entry_y
);
1966 if ( error
== HB_Err_Not_Covered
)
1973 POSITION( buffer
->in_pos
)->x_advance
= entry_x
- gpi
->anchor_x
;
1974 POSITION( buffer
->in_pos
)->new_advance
= TRUE
;
1978 POSITION( gpi
->last
)->x_advance
= gpi
->anchor_x
- entry_x
;
1979 POSITION( gpi
->last
)->new_advance
= TRUE
;
1982 if ( flags
& HB_LOOKUP_FLAG_RIGHT_TO_LEFT
)
1984 POSITION( gpi
->last
)->cursive_chain
= gpi
->last
- buffer
->in_pos
;
1985 POSITION( gpi
->last
)->y_pos
= entry_y
- gpi
->anchor_y
;
1989 POSITION( buffer
->in_pos
)->cursive_chain
= buffer
->in_pos
- gpi
->last
;
1990 POSITION( buffer
->in_pos
)->y_pos
= gpi
->anchor_y
- entry_y
;
1994 error
= Get_Anchor( gpi
, &eer
->ExitAnchor
, IN_CURGLYPH(),
1996 if ( error
== HB_Err_Not_Covered
)
2000 gpi
->last
= buffer
->in_pos
;
2001 gpi
->anchor_x
= exit_x
;
2002 gpi
->anchor_y
= exit_y
;
2017 static HB_Error
Load_BaseArray( HB_BaseArray
* ba
,
2018 HB_UShort num_classes
,
2023 HB_UShort m
, n
, count
;
2024 HB_UInt cur_offset
, new_offset
, base_offset
;
2027 HB_Anchor
*ban
, *bans
;
2030 base_offset
= FILE_Pos();
2032 if ( ACCESS_Frame( 2L ) )
2035 count
= ba
->BaseCount
= GET_UShort();
2039 ba
->BaseRecord
= NULL
;
2041 if ( ALLOC_ARRAY( ba
->BaseRecord
, count
, HB_BaseRecord
) )
2044 br
= ba
->BaseRecord
;
2048 if ( ALLOC_ARRAY( bans
, count
* num_classes
, HB_Anchor
) )
2051 for ( m
= 0; m
< count
; m
++ )
2053 br
[m
].BaseAnchor
= NULL
;
2055 ban
= br
[m
].BaseAnchor
= bans
+ m
* num_classes
;
2057 for ( n
= 0; n
< num_classes
; n
++ )
2059 if ( ACCESS_Frame( 2L ) )
2062 new_offset
= GET_UShort() + base_offset
;
2066 if (new_offset
== base_offset
) {
2068 * Doulos SIL Regular is buggy and has zero offsets here.
2071 ban
[n
].PosFormat
= 0;
2075 cur_offset
= FILE_Pos();
2076 if ( FILE_Seek( new_offset
) ||
2077 ( error
= Load_Anchor( &ban
[n
], stream
) ) != HB_Err_Ok
)
2079 (void)FILE_Seek( cur_offset
);
2092 static void Free_BaseArray( HB_BaseArray
* ba
,
2093 HB_UShort num_classes
)
2098 if ( ba
->BaseRecord
)
2100 br
= ba
->BaseRecord
;
2102 if ( ba
->BaseCount
)
2105 count
= num_classes
* ba
->BaseCount
;
2106 bans
= br
[0].BaseAnchor
;
2107 for (i
= 0; i
< count
; i
++)
2108 Free_Anchor (&bans
[i
]);
2117 /* MarkBasePosFormat1 */
2119 static HB_Error
Load_MarkBasePos( HB_GPOS_SubTable
* st
,
2123 HB_MarkBasePos
* mbp
= &st
->markbase
;
2125 HB_UInt cur_offset
, new_offset
, base_offset
;
2128 base_offset
= FILE_Pos();
2130 if ( ACCESS_Frame( 4L ) )
2133 mbp
->PosFormat
= GET_UShort();
2134 new_offset
= GET_UShort() + base_offset
;
2138 if (mbp
->PosFormat
!= 1)
2139 return ERR(HB_Err_Invalid_SubTable_Format
);
2141 cur_offset
= FILE_Pos();
2142 if ( FILE_Seek( new_offset
) ||
2143 ( error
= _HB_OPEN_Load_Coverage( &mbp
->MarkCoverage
, stream
) ) != HB_Err_Ok
)
2145 (void)FILE_Seek( cur_offset
);
2147 if ( ACCESS_Frame( 2L ) )
2150 new_offset
= GET_UShort() + base_offset
;
2154 cur_offset
= FILE_Pos();
2155 if ( FILE_Seek( new_offset
) ||
2156 ( error
= _HB_OPEN_Load_Coverage( &mbp
->BaseCoverage
, stream
) ) != HB_Err_Ok
)
2158 (void)FILE_Seek( cur_offset
);
2160 if ( ACCESS_Frame( 4L ) )
2163 mbp
->ClassCount
= GET_UShort();
2164 new_offset
= GET_UShort() + base_offset
;
2168 cur_offset
= FILE_Pos();
2169 if ( FILE_Seek( new_offset
) ||
2170 ( error
= Load_MarkArray( &mbp
->MarkArray
, stream
) ) != HB_Err_Ok
)
2172 (void)FILE_Seek( cur_offset
);
2174 if ( ACCESS_Frame( 2L ) )
2177 new_offset
= GET_UShort() + base_offset
;
2181 cur_offset
= FILE_Pos();
2182 if ( FILE_Seek( new_offset
) ||
2183 ( error
= Load_BaseArray( &mbp
->BaseArray
, mbp
->ClassCount
,
2184 stream
) ) != HB_Err_Ok
)
2190 Free_MarkArray( &mbp
->MarkArray
);
2193 _HB_OPEN_Free_Coverage( &mbp
->BaseCoverage
);
2196 _HB_OPEN_Free_Coverage( &mbp
->MarkCoverage
);
2201 static void Free_MarkBasePos( HB_GPOS_SubTable
* st
)
2203 HB_MarkBasePos
* mbp
= &st
->markbase
;
2205 Free_BaseArray( &mbp
->BaseArray
, mbp
->ClassCount
);
2206 Free_MarkArray( &mbp
->MarkArray
);
2207 _HB_OPEN_Free_Coverage( &mbp
->BaseCoverage
);
2208 _HB_OPEN_Free_Coverage( &mbp
->MarkCoverage
);
2212 static HB_Error
Lookup_MarkBasePos( GPOS_Instance
* gpi
,
2213 HB_GPOS_SubTable
* st
,
2216 HB_UShort context_length
,
2219 HB_UShort i
, j
, mark_index
, base_index
, property
, class;
2220 HB_Fixed x_mark_value
, y_mark_value
, x_base_value
, y_base_value
;
2222 HB_GPOSHeader
* gpos
= gpi
->gpos
;
2223 HB_MarkBasePos
* mbp
= &st
->markbase
;
2228 HB_Anchor
* mark_anchor
;
2229 HB_Anchor
* base_anchor
;
2233 HB_UNUSED(nesting_level
);
2235 if ( context_length
!= 0xFFFF && context_length
< 1 )
2236 return HB_Err_Not_Covered
;
2238 if ( flags
& HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS
)
2239 return HB_Err_Not_Covered
;
2241 if ( CHECK_Property( gpos
->gdef
, IN_CURITEM(),
2242 flags
, &property
) )
2245 error
= _HB_OPEN_Coverage_Index( &mbp
->MarkCoverage
, IN_CURGLYPH(),
2250 /* now we search backwards for a non-mark glyph */
2253 j
= buffer
->in_pos
- 1;
2255 while ( i
<= buffer
->in_pos
)
2257 error
= HB_GDEF_Get_Glyph_Property( gpos
->gdef
, IN_GLYPH( j
),
2262 if ( !( property
== HB_GDEF_MARK
|| property
& HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS
) )
2269 /* The following assertion is too strong -- at least for mangal.ttf. */
2271 if ( property
!= HB_GDEF_BASE_GLYPH
)
2272 return HB_Err_Not_Covered
;
2275 if ( i
> buffer
->in_pos
)
2276 return HB_Err_Not_Covered
;
2278 error
= _HB_OPEN_Coverage_Index( &mbp
->BaseCoverage
, IN_GLYPH( j
),
2283 ma
= &mbp
->MarkArray
;
2285 if ( mark_index
>= ma
->MarkCount
)
2286 return ERR(HB_Err_Invalid_SubTable
);
2288 class = ma
->MarkRecord
[mark_index
].Class
;
2289 mark_anchor
= &ma
->MarkRecord
[mark_index
].MarkAnchor
;
2291 if ( class >= mbp
->ClassCount
)
2292 return ERR(HB_Err_Invalid_SubTable
);
2294 ba
= &mbp
->BaseArray
;
2296 if ( base_index
>= ba
->BaseCount
)
2297 return ERR(HB_Err_Invalid_SubTable
);
2299 br
= &ba
->BaseRecord
[base_index
];
2300 base_anchor
= &br
->BaseAnchor
[class];
2302 error
= Get_Anchor( gpi
, mark_anchor
, IN_CURGLYPH(),
2303 &x_mark_value
, &y_mark_value
);
2307 error
= Get_Anchor( gpi
, base_anchor
, IN_GLYPH( j
),
2308 &x_base_value
, &y_base_value
);
2312 /* anchor points are not cumulative */
2314 o
= POSITION( buffer
->in_pos
);
2316 o
->x_pos
= x_base_value
- x_mark_value
;
2317 o
->y_pos
= y_base_value
- y_mark_value
;
2330 /* LigatureAttach */
2332 static HB_Error
Load_LigatureAttach( HB_LigatureAttach
* lat
,
2333 HB_UShort num_classes
,
2338 HB_UShort m
, n
, k
, count
;
2339 HB_UInt cur_offset
, new_offset
, base_offset
;
2341 HB_ComponentRecord
* cr
;
2345 base_offset
= FILE_Pos();
2347 if ( ACCESS_Frame( 2L ) )
2350 count
= lat
->ComponentCount
= GET_UShort();
2354 lat
->ComponentRecord
= NULL
;
2356 if ( ALLOC_ARRAY( lat
->ComponentRecord
, count
, HB_ComponentRecord
) )
2359 cr
= lat
->ComponentRecord
;
2361 for ( m
= 0; m
< count
; m
++ )
2363 cr
[m
].LigatureAnchor
= NULL
;
2365 if ( ALLOC_ARRAY( cr
[m
].LigatureAnchor
, num_classes
, HB_Anchor
) )
2368 lan
= cr
[m
].LigatureAnchor
;
2370 for ( n
= 0; n
< num_classes
; n
++ )
2372 if ( ACCESS_Frame( 2L ) )
2375 new_offset
= GET_UShort();
2381 new_offset
+= base_offset
;
2383 cur_offset
= FILE_Pos();
2384 if ( FILE_Seek( new_offset
) ||
2385 ( error
= Load_Anchor( &lan
[n
], stream
) ) != HB_Err_Ok
)
2387 (void)FILE_Seek( cur_offset
);
2390 lan
[n
].PosFormat
= 0;
2395 for ( k
= 0; k
< n
; k
++ )
2396 Free_Anchor( &lan
[k
] );
2403 for ( k
= 0; k
< m
; k
++ )
2405 lan
= cr
[k
].LigatureAnchor
;
2407 for ( n
= 0; n
< num_classes
; n
++ )
2408 Free_Anchor( &lan
[n
] );
2418 static void Free_LigatureAttach( HB_LigatureAttach
* lat
,
2419 HB_UShort num_classes
)
2421 HB_UShort m
, n
, count
;
2423 HB_ComponentRecord
* cr
;
2427 if ( lat
->ComponentRecord
)
2429 count
= lat
->ComponentCount
;
2430 cr
= lat
->ComponentRecord
;
2432 for ( m
= 0; m
< count
; m
++ )
2434 lan
= cr
[m
].LigatureAnchor
;
2436 for ( n
= 0; n
< num_classes
; n
++ )
2437 Free_Anchor( &lan
[n
] );
2449 static HB_Error
Load_LigatureArray( HB_LigatureArray
* la
,
2450 HB_UShort num_classes
,
2455 HB_UShort n
, m
, count
;
2456 HB_UInt cur_offset
, new_offset
, base_offset
;
2458 HB_LigatureAttach
* lat
;
2461 base_offset
= FILE_Pos();
2463 if ( ACCESS_Frame( 2L ) )
2466 count
= la
->LigatureCount
= GET_UShort();
2470 la
->LigatureAttach
= NULL
;
2472 if ( ALLOC_ARRAY( la
->LigatureAttach
, count
, HB_LigatureAttach
) )
2475 lat
= la
->LigatureAttach
;
2477 for ( n
= 0; n
< count
; n
++ )
2479 if ( ACCESS_Frame( 2L ) )
2482 new_offset
= GET_UShort() + base_offset
;
2486 cur_offset
= FILE_Pos();
2487 if ( FILE_Seek( new_offset
) ||
2488 ( error
= Load_LigatureAttach( &lat
[n
], num_classes
,
2489 stream
) ) != HB_Err_Ok
)
2491 (void)FILE_Seek( cur_offset
);
2497 for ( m
= 0; m
< n
; m
++ )
2498 Free_LigatureAttach( &lat
[m
], num_classes
);
2505 static void Free_LigatureArray( HB_LigatureArray
* la
,
2506 HB_UShort num_classes
)
2510 HB_LigatureAttach
* lat
;
2513 if ( la
->LigatureAttach
)
2515 count
= la
->LigatureCount
;
2516 lat
= la
->LigatureAttach
;
2518 for ( n
= 0; n
< count
; n
++ )
2519 Free_LigatureAttach( &lat
[n
], num_classes
);
2526 /* MarkLigPosFormat1 */
2528 static HB_Error
Load_MarkLigPos( HB_GPOS_SubTable
* st
,
2532 HB_MarkLigPos
* mlp
= &st
->marklig
;
2534 HB_UInt cur_offset
, new_offset
, base_offset
;
2537 base_offset
= FILE_Pos();
2539 if ( ACCESS_Frame( 4L ) )
2542 mlp
->PosFormat
= GET_UShort();
2543 new_offset
= GET_UShort() + base_offset
;
2547 cur_offset
= FILE_Pos();
2548 if ( FILE_Seek( new_offset
) ||
2549 ( error
= _HB_OPEN_Load_Coverage( &mlp
->MarkCoverage
, stream
) ) != HB_Err_Ok
)
2551 (void)FILE_Seek( cur_offset
);
2553 if ( ACCESS_Frame( 2L ) )
2556 new_offset
= GET_UShort() + base_offset
;
2560 cur_offset
= FILE_Pos();
2561 if ( FILE_Seek( new_offset
) ||
2562 ( error
= _HB_OPEN_Load_Coverage( &mlp
->LigatureCoverage
,
2563 stream
) ) != HB_Err_Ok
)
2565 (void)FILE_Seek( cur_offset
);
2567 if ( ACCESS_Frame( 4L ) )
2570 mlp
->ClassCount
= GET_UShort();
2571 new_offset
= GET_UShort() + base_offset
;
2575 cur_offset
= FILE_Pos();
2576 if ( FILE_Seek( new_offset
) ||
2577 ( error
= Load_MarkArray( &mlp
->MarkArray
, stream
) ) != HB_Err_Ok
)
2579 (void)FILE_Seek( cur_offset
);
2581 if ( ACCESS_Frame( 2L ) )
2584 new_offset
= GET_UShort() + base_offset
;
2588 cur_offset
= FILE_Pos();
2589 if ( FILE_Seek( new_offset
) ||
2590 ( error
= Load_LigatureArray( &mlp
->LigatureArray
, mlp
->ClassCount
,
2591 stream
) ) != HB_Err_Ok
)
2597 Free_MarkArray( &mlp
->MarkArray
);
2600 _HB_OPEN_Free_Coverage( &mlp
->LigatureCoverage
);
2603 _HB_OPEN_Free_Coverage( &mlp
->MarkCoverage
);
2608 static void Free_MarkLigPos( HB_GPOS_SubTable
* st
)
2610 HB_MarkLigPos
* mlp
= &st
->marklig
;
2612 Free_LigatureArray( &mlp
->LigatureArray
, mlp
->ClassCount
);
2613 Free_MarkArray( &mlp
->MarkArray
);
2614 _HB_OPEN_Free_Coverage( &mlp
->LigatureCoverage
);
2615 _HB_OPEN_Free_Coverage( &mlp
->MarkCoverage
);
2619 static HB_Error
Lookup_MarkLigPos( GPOS_Instance
* gpi
,
2620 HB_GPOS_SubTable
* st
,
2623 HB_UShort context_length
,
2626 HB_UShort i
, j
, mark_index
, lig_index
, property
, class;
2627 HB_UShort mark_glyph
;
2628 HB_Fixed x_mark_value
, y_mark_value
, x_lig_value
, y_lig_value
;
2630 HB_GPOSHeader
* gpos
= gpi
->gpos
;
2631 HB_MarkLigPos
* mlp
= &st
->marklig
;
2634 HB_LigatureArray
* la
;
2635 HB_LigatureAttach
* lat
;
2636 HB_ComponentRecord
* cr
;
2637 HB_UShort comp_index
;
2638 HB_Anchor
* mark_anchor
;
2639 HB_Anchor
* lig_anchor
;
2643 HB_UNUSED(nesting_level
);
2645 if ( context_length
!= 0xFFFF && context_length
< 1 )
2646 return HB_Err_Not_Covered
;
2648 if ( flags
& HB_LOOKUP_FLAG_IGNORE_LIGATURES
)
2649 return HB_Err_Not_Covered
;
2651 mark_glyph
= IN_CURGLYPH();
2653 if ( CHECK_Property( gpos
->gdef
, IN_CURITEM(), flags
, &property
) )
2656 error
= _HB_OPEN_Coverage_Index( &mlp
->MarkCoverage
, mark_glyph
, &mark_index
);
2660 /* now we search backwards for a non-mark glyph */
2663 j
= buffer
->in_pos
- 1;
2665 while ( i
<= buffer
->in_pos
)
2667 error
= HB_GDEF_Get_Glyph_Property( gpos
->gdef
, IN_GLYPH( j
),
2672 if ( !( property
== HB_GDEF_MARK
|| property
& HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS
) )
2679 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2680 too strong, thus it is commented out. */
2682 if ( property
!= HB_GDEF_LIGATURE
)
2683 return HB_Err_Not_Covered
;
2686 if ( i
> buffer
->in_pos
)
2687 return HB_Err_Not_Covered
;
2689 error
= _HB_OPEN_Coverage_Index( &mlp
->LigatureCoverage
, IN_GLYPH( j
),
2694 ma
= &mlp
->MarkArray
;
2696 if ( mark_index
>= ma
->MarkCount
)
2697 return ERR(HB_Err_Invalid_SubTable
);
2699 class = ma
->MarkRecord
[mark_index
].Class
;
2700 mark_anchor
= &ma
->MarkRecord
[mark_index
].MarkAnchor
;
2702 if ( class >= mlp
->ClassCount
)
2703 return ERR(HB_Err_Invalid_SubTable
);
2705 la
= &mlp
->LigatureArray
;
2707 if ( lig_index
>= la
->LigatureCount
)
2708 return ERR(HB_Err_Invalid_SubTable
);
2710 lat
= &la
->LigatureAttach
[lig_index
];
2712 /* We must now check whether the ligature ID of the current mark glyph
2713 is identical to the ligature ID of the found ligature. If yes, we
2714 can directly use the component index. If not, we attach the mark
2715 glyph to the last component of the ligature. */
2717 if ( IN_LIGID( j
) == IN_LIGID( buffer
->in_pos
) )
2719 comp_index
= IN_COMPONENT( buffer
->in_pos
);
2720 if ( comp_index
>= lat
->ComponentCount
)
2721 return HB_Err_Not_Covered
;
2724 comp_index
= lat
->ComponentCount
- 1;
2726 cr
= &lat
->ComponentRecord
[comp_index
];
2727 lig_anchor
= &cr
->LigatureAnchor
[class];
2729 error
= Get_Anchor( gpi
, mark_anchor
, IN_CURGLYPH(),
2730 &x_mark_value
, &y_mark_value
);
2733 error
= Get_Anchor( gpi
, lig_anchor
, IN_GLYPH( j
),
2734 &x_lig_value
, &y_lig_value
);
2738 /* anchor points are not cumulative */
2740 o
= POSITION( buffer
->in_pos
);
2742 o
->x_pos
= x_lig_value
- x_mark_value
;
2743 o
->y_pos
= y_lig_value
- y_mark_value
;
2758 static HB_Error
Load_Mark2Array( HB_Mark2Array
* m2a
,
2759 HB_UShort num_classes
,
2764 HB_UShort m
, n
, count
;
2765 HB_UInt cur_offset
, new_offset
, base_offset
;
2767 HB_Mark2Record
*m2r
;
2768 HB_Anchor
*m2an
, *m2ans
;
2771 base_offset
= FILE_Pos();
2773 if ( ACCESS_Frame( 2L ) )
2776 count
= m2a
->Mark2Count
= GET_UShort();
2780 m2a
->Mark2Record
= NULL
;
2782 if ( ALLOC_ARRAY( m2a
->Mark2Record
, count
, HB_Mark2Record
) )
2785 m2r
= m2a
->Mark2Record
;
2789 if ( ALLOC_ARRAY( m2ans
, count
* num_classes
, HB_Anchor
) )
2792 for ( m
= 0; m
< count
; m
++ )
2794 m2an
= m2r
[m
].Mark2Anchor
= m2ans
+ m
* num_classes
;
2796 for ( n
= 0; n
< num_classes
; n
++ )
2798 if ( ACCESS_Frame( 2L ) )
2801 new_offset
= GET_UShort() + base_offset
;
2805 if (new_offset
== base_offset
) {
2806 /* Anchor table not provided. Skip loading.
2807 * Some versions of FreeSans hit this. */
2808 m2an
[n
].PosFormat
= 0;
2812 cur_offset
= FILE_Pos();
2813 if ( FILE_Seek( new_offset
) ||
2814 ( error
= Load_Anchor( &m2an
[n
], stream
) ) != HB_Err_Ok
)
2816 (void)FILE_Seek( cur_offset
);
2829 static void Free_Mark2Array( HB_Mark2Array
* m2a
,
2830 HB_UShort num_classes
)
2832 HB_Mark2Record
*m2r
;
2835 HB_UNUSED(num_classes
);
2837 if ( m2a
->Mark2Record
)
2839 m2r
= m2a
->Mark2Record
;
2841 if ( m2a
->Mark2Count
)
2843 m2ans
= m2r
[0].Mark2Anchor
;
2852 /* MarkMarkPosFormat1 */
2854 static HB_Error
Load_MarkMarkPos( HB_GPOS_SubTable
* st
,
2858 HB_MarkMarkPos
* mmp
= &st
->markmark
;
2860 HB_UInt cur_offset
, new_offset
, base_offset
;
2863 base_offset
= FILE_Pos();
2865 if ( ACCESS_Frame( 4L ) )
2868 mmp
->PosFormat
= GET_UShort();
2869 new_offset
= GET_UShort() + base_offset
;
2873 cur_offset
= FILE_Pos();
2874 if ( FILE_Seek( new_offset
) ||
2875 ( error
= _HB_OPEN_Load_Coverage( &mmp
->Mark1Coverage
,
2876 stream
) ) != HB_Err_Ok
)
2878 (void)FILE_Seek( cur_offset
);
2880 if ( ACCESS_Frame( 2L ) )
2883 new_offset
= GET_UShort() + base_offset
;
2887 cur_offset
= FILE_Pos();
2888 if ( FILE_Seek( new_offset
) ||
2889 ( error
= _HB_OPEN_Load_Coverage( &mmp
->Mark2Coverage
,
2890 stream
) ) != HB_Err_Ok
)
2892 (void)FILE_Seek( cur_offset
);
2894 if ( ACCESS_Frame( 4L ) )
2897 mmp
->ClassCount
= GET_UShort();
2898 new_offset
= GET_UShort() + base_offset
;
2902 cur_offset
= FILE_Pos();
2903 if ( FILE_Seek( new_offset
) ||
2904 ( error
= Load_MarkArray( &mmp
->Mark1Array
, stream
) ) != HB_Err_Ok
)
2906 (void)FILE_Seek( cur_offset
);
2908 if ( ACCESS_Frame( 2L ) )
2911 new_offset
= GET_UShort() + base_offset
;
2915 cur_offset
= FILE_Pos();
2916 if ( FILE_Seek( new_offset
) ||
2917 ( error
= Load_Mark2Array( &mmp
->Mark2Array
, mmp
->ClassCount
,
2918 stream
) ) != HB_Err_Ok
)
2924 Free_MarkArray( &mmp
->Mark1Array
);
2927 _HB_OPEN_Free_Coverage( &mmp
->Mark2Coverage
);
2930 _HB_OPEN_Free_Coverage( &mmp
->Mark1Coverage
);
2935 static void Free_MarkMarkPos( HB_GPOS_SubTable
* st
)
2937 HB_MarkMarkPos
* mmp
= &st
->markmark
;
2939 Free_Mark2Array( &mmp
->Mark2Array
, mmp
->ClassCount
);
2940 Free_MarkArray( &mmp
->Mark1Array
);
2941 _HB_OPEN_Free_Coverage( &mmp
->Mark2Coverage
);
2942 _HB_OPEN_Free_Coverage( &mmp
->Mark1Coverage
);
2946 static HB_Error
Lookup_MarkMarkPos( GPOS_Instance
* gpi
,
2947 HB_GPOS_SubTable
* st
,
2950 HB_UShort context_length
,
2953 HB_UShort i
, j
, mark1_index
, mark2_index
, property
, class;
2954 HB_Fixed x_mark1_value
, y_mark1_value
,
2955 x_mark2_value
, y_mark2_value
;
2957 HB_GPOSHeader
* gpos
= gpi
->gpos
;
2958 HB_MarkMarkPos
* mmp
= &st
->markmark
;
2962 HB_Mark2Record
* m2r
;
2963 HB_Anchor
* mark1_anchor
;
2964 HB_Anchor
* mark2_anchor
;
2968 HB_UNUSED(nesting_level
);
2970 if ( context_length
!= 0xFFFF && context_length
< 1 )
2971 return HB_Err_Not_Covered
;
2973 if ( flags
& HB_LOOKUP_FLAG_IGNORE_MARKS
)
2974 return HB_Err_Not_Covered
;
2976 if ( CHECK_Property( gpos
->gdef
, IN_CURITEM(),
2977 flags
, &property
) )
2980 error
= _HB_OPEN_Coverage_Index( &mmp
->Mark1Coverage
, IN_CURGLYPH(),
2985 /* now we search backwards for a suitable mark glyph until a non-mark
2988 if ( buffer
->in_pos
== 0 )
2989 return HB_Err_Not_Covered
;
2992 j
= buffer
->in_pos
- 1;
2993 while ( i
<= buffer
->in_pos
)
2995 error
= HB_GDEF_Get_Glyph_Property( gpos
->gdef
, IN_GLYPH( j
),
3000 if ( !( property
== HB_GDEF_MARK
|| property
& HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS
) )
3001 return HB_Err_Not_Covered
;
3003 if ( flags
& HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS
)
3005 if ( property
== (flags
& 0xFF00) )
3015 if ( i
> buffer
->in_pos
)
3016 return HB_Err_Not_Covered
;
3018 error
= _HB_OPEN_Coverage_Index( &mmp
->Mark2Coverage
, IN_GLYPH( j
),
3023 ma1
= &mmp
->Mark1Array
;
3025 if ( mark1_index
>= ma1
->MarkCount
)
3026 return ERR(HB_Err_Invalid_SubTable
);
3028 class = ma1
->MarkRecord
[mark1_index
].Class
;
3029 mark1_anchor
= &ma1
->MarkRecord
[mark1_index
].MarkAnchor
;
3031 if ( class >= mmp
->ClassCount
)
3032 return ERR(HB_Err_Invalid_SubTable
);
3034 ma2
= &mmp
->Mark2Array
;
3036 if ( mark2_index
>= ma2
->Mark2Count
)
3037 return ERR(HB_Err_Invalid_SubTable
);
3039 m2r
= &ma2
->Mark2Record
[mark2_index
];
3040 mark2_anchor
= &m2r
->Mark2Anchor
[class];
3042 error
= Get_Anchor( gpi
, mark1_anchor
, IN_CURGLYPH(),
3043 &x_mark1_value
, &y_mark1_value
);
3046 error
= Get_Anchor( gpi
, mark2_anchor
, IN_GLYPH( j
),
3047 &x_mark2_value
, &y_mark2_value
);
3051 /* anchor points are not cumulative */
3053 o
= POSITION( buffer
->in_pos
);
3055 o
->x_pos
= x_mark2_value
- x_mark1_value
;
3056 o
->y_pos
= y_mark2_value
- y_mark1_value
;
3067 /* Do the actual positioning for a context positioning (either format
3068 7 or 8). This is only called after we've determined that the stream
3069 matches the subrule. */
3071 static HB_Error
Do_ContextPos( GPOS_Instance
* gpi
,
3072 HB_UShort GlyphCount
,
3074 HB_PosLookupRecord
* pos
,
3084 while ( i
< GlyphCount
)
3086 if ( PosCount
&& i
== pos
->SequenceIndex
)
3088 old_pos
= buffer
->in_pos
;
3090 /* Do a positioning */
3092 error
= GPOS_Do_Glyph_Lookup( gpi
, pos
->LookupListIndex
, buffer
,
3093 GlyphCount
, nesting_level
);
3100 i
+= buffer
->in_pos
- old_pos
;
3117 static HB_Error
Load_PosRule( HB_PosRule
* pr
,
3125 HB_PosLookupRecord
* plr
;
3128 if ( ACCESS_Frame( 4L ) )
3131 pr
->GlyphCount
= GET_UShort();
3132 pr
->PosCount
= GET_UShort();
3138 count
= pr
->GlyphCount
- 1; /* only GlyphCount - 1 elements */
3140 if ( ALLOC_ARRAY( pr
->Input
, count
, HB_UShort
) )
3145 if ( ACCESS_Frame( count
* 2L ) )
3148 for ( n
= 0; n
< count
; n
++ )
3149 i
[n
] = GET_UShort();
3153 pr
->PosLookupRecord
= NULL
;
3155 count
= pr
->PosCount
;
3157 if ( ALLOC_ARRAY( pr
->PosLookupRecord
, count
, HB_PosLookupRecord
) )
3160 plr
= pr
->PosLookupRecord
;
3162 if ( ACCESS_Frame( count
* 4L ) )
3165 for ( n
= 0; n
< count
; n
++ )
3167 plr
[n
].SequenceIndex
= GET_UShort();
3168 plr
[n
].LookupListIndex
= GET_UShort();
3184 static void Free_PosRule( HB_PosRule
* pr
)
3186 FREE( pr
->PosLookupRecord
);
3193 static HB_Error
Load_PosRuleSet( HB_PosRuleSet
* prs
,
3198 HB_UShort n
, m
, count
;
3199 HB_UInt cur_offset
, new_offset
, base_offset
;
3204 base_offset
= FILE_Pos();
3206 if ( ACCESS_Frame( 2L ) )
3209 count
= prs
->PosRuleCount
= GET_UShort();
3213 prs
->PosRule
= NULL
;
3215 if ( ALLOC_ARRAY( prs
->PosRule
, count
, HB_PosRule
) )
3220 for ( n
= 0; n
< count
; n
++ )
3222 if ( ACCESS_Frame( 2L ) )
3225 new_offset
= GET_UShort() + base_offset
;
3229 cur_offset
= FILE_Pos();
3230 if ( FILE_Seek( new_offset
) ||
3231 ( error
= Load_PosRule( &pr
[n
], stream
) ) != HB_Err_Ok
)
3233 (void)FILE_Seek( cur_offset
);
3239 for ( m
= 0; m
< n
; m
++ )
3240 Free_PosRule( &pr
[m
] );
3247 static void Free_PosRuleSet( HB_PosRuleSet
* prs
)
3256 count
= prs
->PosRuleCount
;
3259 for ( n
= 0; n
< count
; n
++ )
3260 Free_PosRule( &pr
[n
] );
3267 /* ContextPosFormat1 */
3269 static HB_Error
Load_ContextPos1( HB_ContextPosFormat1
* cpf1
,
3274 HB_UShort n
, m
, count
;
3275 HB_UInt cur_offset
, new_offset
, base_offset
;
3280 base_offset
= FILE_Pos() - 2L;
3282 if ( ACCESS_Frame( 2L ) )
3285 new_offset
= GET_UShort() + base_offset
;
3289 cur_offset
= FILE_Pos();
3290 if ( FILE_Seek( new_offset
) ||
3291 ( error
= _HB_OPEN_Load_Coverage( &cpf1
->Coverage
, stream
) ) != HB_Err_Ok
)
3293 (void)FILE_Seek( cur_offset
);
3295 if ( ACCESS_Frame( 2L ) )
3298 count
= cpf1
->PosRuleSetCount
= GET_UShort();
3302 cpf1
->PosRuleSet
= NULL
;
3304 if ( ALLOC_ARRAY( cpf1
->PosRuleSet
, count
, HB_PosRuleSet
) )
3307 prs
= cpf1
->PosRuleSet
;
3309 for ( n
= 0; n
< count
; n
++ )
3311 if ( ACCESS_Frame( 2L ) )
3314 new_offset
= GET_UShort() + base_offset
;
3318 cur_offset
= FILE_Pos();
3319 if ( FILE_Seek( new_offset
) ||
3320 ( error
= Load_PosRuleSet( &prs
[n
], stream
) ) != HB_Err_Ok
)
3322 (void)FILE_Seek( cur_offset
);
3328 for ( m
= 0; m
< n
; m
++ )
3329 Free_PosRuleSet( &prs
[m
] );
3334 _HB_OPEN_Free_Coverage( &cpf1
->Coverage
);
3339 static void Free_ContextPos1( HB_ContextPosFormat1
* cpf1
)
3346 if ( cpf1
->PosRuleSet
)
3348 count
= cpf1
->PosRuleSetCount
;
3349 prs
= cpf1
->PosRuleSet
;
3351 for ( n
= 0; n
< count
; n
++ )
3352 Free_PosRuleSet( &prs
[n
] );
3357 _HB_OPEN_Free_Coverage( &cpf1
->Coverage
);
3363 static HB_Error
Load_PosClassRule( HB_ContextPosFormat2
* cpf2
,
3364 HB_PosClassRule
* pcr
,
3372 HB_PosLookupRecord
* plr
;
3375 if ( ACCESS_Frame( 4L ) )
3378 pcr
->GlyphCount
= GET_UShort();
3379 pcr
->PosCount
= GET_UShort();
3383 if ( pcr
->GlyphCount
> cpf2
->MaxContextLength
)
3384 cpf2
->MaxContextLength
= pcr
->GlyphCount
;
3388 count
= pcr
->GlyphCount
- 1; /* only GlyphCount - 1 elements */
3390 if ( ALLOC_ARRAY( pcr
->Class
, count
, HB_UShort
) )
3395 if ( ACCESS_Frame( count
* 2L ) )
3398 for ( n
= 0; n
< count
; n
++ )
3399 c
[n
] = GET_UShort();
3403 pcr
->PosLookupRecord
= NULL
;
3405 count
= pcr
->PosCount
;
3407 if ( ALLOC_ARRAY( pcr
->PosLookupRecord
, count
, HB_PosLookupRecord
) )
3410 plr
= pcr
->PosLookupRecord
;
3412 if ( ACCESS_Frame( count
* 4L ) )
3415 for ( n
= 0; n
< count
; n
++ )
3417 plr
[n
].SequenceIndex
= GET_UShort();
3418 plr
[n
].LookupListIndex
= GET_UShort();
3434 static void Free_PosClassRule( HB_PosClassRule
* pcr
)
3436 FREE( pcr
->PosLookupRecord
);
3443 static HB_Error
Load_PosClassSet( HB_ContextPosFormat2
* cpf2
,
3444 HB_PosClassSet
* pcs
,
3449 HB_UShort n
, m
, count
;
3450 HB_UInt cur_offset
, new_offset
, base_offset
;
3452 HB_PosClassRule
* pcr
;
3455 base_offset
= FILE_Pos();
3457 if ( ACCESS_Frame( 2L ) )
3460 count
= pcs
->PosClassRuleCount
= GET_UShort();
3464 pcs
->PosClassRule
= NULL
;
3466 if ( ALLOC_ARRAY( pcs
->PosClassRule
, count
, HB_PosClassRule
) )
3469 pcr
= pcs
->PosClassRule
;
3471 for ( n
= 0; n
< count
; n
++ )
3473 if ( ACCESS_Frame( 2L ) )
3476 new_offset
= GET_UShort() + base_offset
;
3480 cur_offset
= FILE_Pos();
3481 if ( FILE_Seek( new_offset
) ||
3482 ( error
= Load_PosClassRule( cpf2
, &pcr
[n
],
3483 stream
) ) != HB_Err_Ok
)
3485 (void)FILE_Seek( cur_offset
);
3491 for ( m
= 0; m
< n
; m
++ )
3492 Free_PosClassRule( &pcr
[m
] );
3499 static void Free_PosClassSet( HB_PosClassSet
* pcs
)
3503 HB_PosClassRule
* pcr
;
3506 if ( pcs
->PosClassRule
)
3508 count
= pcs
->PosClassRuleCount
;
3509 pcr
= pcs
->PosClassRule
;
3511 for ( n
= 0; n
< count
; n
++ )
3512 Free_PosClassRule( &pcr
[n
] );
3519 /* ContextPosFormat2 */
3521 static HB_Error
Load_ContextPos2( HB_ContextPosFormat2
* cpf2
,
3526 HB_UShort n
, m
, count
;
3527 HB_UInt cur_offset
, new_offset
, base_offset
;
3529 HB_PosClassSet
* pcs
;
3532 base_offset
= FILE_Pos() - 2;
3534 if ( ACCESS_Frame( 2L ) )
3537 new_offset
= GET_UShort() + base_offset
;
3541 cur_offset
= FILE_Pos();
3542 if ( FILE_Seek( new_offset
) ||
3543 ( error
= _HB_OPEN_Load_Coverage( &cpf2
->Coverage
, stream
) ) != HB_Err_Ok
)
3545 (void)FILE_Seek( cur_offset
);
3547 if ( ACCESS_Frame( 4L ) )
3550 new_offset
= GET_UShort() + base_offset
;
3552 /* `PosClassSetCount' is the upper limit for class values, thus we
3553 read it now to make an additional safety check. */
3555 count
= cpf2
->PosClassSetCount
= GET_UShort();
3559 cur_offset
= FILE_Pos();
3560 if ( FILE_Seek( new_offset
) ||
3561 ( error
= _HB_OPEN_Load_ClassDefinition( &cpf2
->ClassDef
, count
,
3562 stream
) ) != HB_Err_Ok
)
3564 (void)FILE_Seek( cur_offset
);
3566 cpf2
->PosClassSet
= NULL
;
3567 cpf2
->MaxContextLength
= 0;
3569 if ( ALLOC_ARRAY( cpf2
->PosClassSet
, count
, HB_PosClassSet
) )
3572 pcs
= cpf2
->PosClassSet
;
3574 for ( n
= 0; n
< count
; n
++ )
3576 if ( ACCESS_Frame( 2L ) )
3579 new_offset
= GET_UShort() + base_offset
;
3583 if ( new_offset
!= base_offset
) /* not a NULL offset */
3585 cur_offset
= FILE_Pos();
3586 if ( FILE_Seek( new_offset
) ||
3587 ( error
= Load_PosClassSet( cpf2
, &pcs
[n
],
3588 stream
) ) != HB_Err_Ok
)
3590 (void)FILE_Seek( cur_offset
);
3594 /* we create a PosClassSet table with no entries */
3596 cpf2
->PosClassSet
[n
].PosClassRuleCount
= 0;
3597 cpf2
->PosClassSet
[n
].PosClassRule
= NULL
;
3604 for ( m
= 0; m
< n
; n
++ )
3605 Free_PosClassSet( &pcs
[m
] );
3610 _HB_OPEN_Free_ClassDefinition( &cpf2
->ClassDef
);
3613 _HB_OPEN_Free_Coverage( &cpf2
->Coverage
);
3618 static void Free_ContextPos2( HB_ContextPosFormat2
* cpf2
)
3622 HB_PosClassSet
* pcs
;
3625 if ( cpf2
->PosClassSet
)
3627 count
= cpf2
->PosClassSetCount
;
3628 pcs
= cpf2
->PosClassSet
;
3630 for ( n
= 0; n
< count
; n
++ )
3631 Free_PosClassSet( &pcs
[n
] );
3636 _HB_OPEN_Free_ClassDefinition( &cpf2
->ClassDef
);
3637 _HB_OPEN_Free_Coverage( &cpf2
->Coverage
);
3641 /* ContextPosFormat3 */
3643 static HB_Error
Load_ContextPos3( HB_ContextPosFormat3
* cpf3
,
3649 HB_UInt cur_offset
, new_offset
, base_offset
;
3652 HB_PosLookupRecord
* plr
;
3655 base_offset
= FILE_Pos() - 2L;
3657 if ( ACCESS_Frame( 4L ) )
3660 cpf3
->GlyphCount
= GET_UShort();
3661 cpf3
->PosCount
= GET_UShort();
3665 cpf3
->Coverage
= NULL
;
3667 count
= cpf3
->GlyphCount
;
3669 if ( ALLOC_ARRAY( cpf3
->Coverage
, count
, HB_Coverage
) )
3674 for ( n
= 0; n
< count
; n
++ )
3676 if ( ACCESS_Frame( 2L ) )
3679 new_offset
= GET_UShort() + base_offset
;
3683 cur_offset
= FILE_Pos();
3684 if ( FILE_Seek( new_offset
) ||
3685 ( error
= _HB_OPEN_Load_Coverage( &c
[n
], stream
) ) != HB_Err_Ok
)
3687 (void)FILE_Seek( cur_offset
);
3690 cpf3
->PosLookupRecord
= NULL
;
3692 count
= cpf3
->PosCount
;
3694 if ( ALLOC_ARRAY( cpf3
->PosLookupRecord
, count
, HB_PosLookupRecord
) )
3697 plr
= cpf3
->PosLookupRecord
;
3699 if ( ACCESS_Frame( count
* 4L ) )
3702 for ( n
= 0; n
< count
; n
++ )
3704 plr
[n
].SequenceIndex
= GET_UShort();
3705 plr
[n
].LookupListIndex
= GET_UShort();
3716 for ( n
= 0; n
< count
; n
++ )
3717 _HB_OPEN_Free_Coverage( &c
[n
] );
3724 static void Free_ContextPos3( HB_ContextPosFormat3
* cpf3
)
3731 FREE( cpf3
->PosLookupRecord
);
3733 if ( cpf3
->Coverage
)
3735 count
= cpf3
->GlyphCount
;
3738 for ( n
= 0; n
< count
; n
++ )
3739 _HB_OPEN_Free_Coverage( &c
[n
] );
3748 static HB_Error
Load_ContextPos( HB_GPOS_SubTable
* st
,
3752 HB_ContextPos
* cp
= &st
->context
;
3755 if ( ACCESS_Frame( 2L ) )
3758 cp
->PosFormat
= GET_UShort();
3762 switch ( cp
->PosFormat
)
3765 return Load_ContextPos1( &cp
->cpf
.cpf1
, stream
);
3768 return Load_ContextPos2( &cp
->cpf
.cpf2
, stream
);
3771 return Load_ContextPos3( &cp
->cpf
.cpf3
, stream
);
3774 return ERR(HB_Err_Invalid_SubTable_Format
);
3777 return HB_Err_Ok
; /* never reached */
3781 static void Free_ContextPos( HB_GPOS_SubTable
* st
)
3783 HB_ContextPos
* cp
= &st
->context
;
3785 switch ( cp
->PosFormat
)
3787 case 1: Free_ContextPos1( &cp
->cpf
.cpf1
); break;
3788 case 2: Free_ContextPos2( &cp
->cpf
.cpf2
); break;
3789 case 3: Free_ContextPos3( &cp
->cpf
.cpf3
); break;
3795 static HB_Error
Lookup_ContextPos1( GPOS_Instance
* gpi
,
3796 HB_ContextPosFormat1
* cpf1
,
3799 HB_UShort context_length
,
3802 HB_UShort index
, property
;
3803 HB_UShort i
, j
, k
, numpr
;
3805 HB_GPOSHeader
* gpos
= gpi
->gpos
;
3808 HB_GDEFHeader
* gdef
;
3813 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
3816 error
= _HB_OPEN_Coverage_Index( &cpf1
->Coverage
, IN_CURGLYPH(), &index
);
3820 pr
= cpf1
->PosRuleSet
[index
].PosRule
;
3821 numpr
= cpf1
->PosRuleSet
[index
].PosRuleCount
;
3823 for ( k
= 0; k
< numpr
; k
++ )
3825 if ( context_length
!= 0xFFFF && context_length
< pr
[k
].GlyphCount
)
3828 if ( buffer
->in_pos
+ pr
[k
].GlyphCount
> buffer
->in_length
)
3829 goto next_posrule
; /* context is too long */
3831 for ( i
= 1, j
= buffer
->in_pos
+ 1; i
< pr
[k
].GlyphCount
; i
++, j
++ )
3833 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
3835 if ( error
&& error
!= HB_Err_Not_Covered
)
3838 if ( j
+ pr
[k
].GlyphCount
- i
== (HB_Int
)buffer
->in_length
)
3843 if ( IN_GLYPH( j
) != pr
[k
].Input
[i
- 1] )
3847 return Do_ContextPos( gpi
, pr
[k
].GlyphCount
,
3848 pr
[k
].PosCount
, pr
[k
].PosLookupRecord
,
3856 return HB_Err_Not_Covered
;
3860 static HB_Error
Lookup_ContextPos2( GPOS_Instance
* gpi
,
3861 HB_ContextPosFormat2
* cpf2
,
3864 HB_UShort context_length
,
3867 HB_UShort index
, property
;
3869 HB_UShort i
, j
, k
, known_classes
;
3873 HB_GPOSHeader
* gpos
= gpi
->gpos
;
3875 HB_PosClassSet
* pcs
;
3876 HB_PosClassRule
* pr
;
3877 HB_GDEFHeader
* gdef
;
3882 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
3885 /* Note: The coverage table in format 2 doesn't give an index into
3886 anything. It just lets us know whether or not we need to
3887 do any lookup at all. */
3889 error
= _HB_OPEN_Coverage_Index( &cpf2
->Coverage
, IN_CURGLYPH(), &index
);
3893 if (cpf2
->MaxContextLength
< 1)
3894 return HB_Err_Not_Covered
;
3896 if ( ALLOC_ARRAY( classes
, cpf2
->MaxContextLength
, HB_UShort
) )
3899 error
= _HB_OPEN_Get_Class( &cpf2
->ClassDef
, IN_CURGLYPH(),
3900 &classes
[0], NULL
);
3901 if ( error
&& error
!= HB_Err_Not_Covered
)
3905 pcs
= &cpf2
->PosClassSet
[classes
[0]];
3908 error
= ERR(HB_Err_Invalid_SubTable
);
3912 for ( k
= 0; k
< pcs
->PosClassRuleCount
; k
++ )
3914 pr
= &pcs
->PosClassRule
[k
];
3916 if ( context_length
!= 0xFFFF && context_length
< pr
->GlyphCount
)
3917 goto next_posclassrule
;
3919 if ( buffer
->in_pos
+ pr
->GlyphCount
> buffer
->in_length
)
3920 goto next_posclassrule
; /* context is too long */
3924 /* Start at 1 because [0] is implied */
3926 for ( i
= 1, j
= buffer
->in_pos
+ 1; i
< pr
->GlyphCount
; i
++, j
++ )
3928 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
3930 if ( error
&& error
!= HB_Err_Not_Covered
)
3933 if ( j
+ pr
->GlyphCount
- i
== (HB_Int
)buffer
->in_length
)
3934 goto next_posclassrule
;
3938 if ( i
> known_classes
)
3940 /* Keeps us from having to do this for each rule */
3942 error
= _HB_OPEN_Get_Class( &cpf2
->ClassDef
, IN_GLYPH( j
), &classes
[i
], NULL
);
3943 if ( error
&& error
!= HB_Err_Not_Covered
)
3948 if ( cl
[i
- 1] != classes
[i
] )
3949 goto next_posclassrule
;
3952 error
= Do_ContextPos( gpi
, pr
->GlyphCount
,
3953 pr
->PosCount
, pr
->PosLookupRecord
,
3962 error
= HB_Err_Not_Covered
;
3970 static HB_Error
Lookup_ContextPos3( GPOS_Instance
* gpi
,
3971 HB_ContextPosFormat3
* cpf3
,
3974 HB_UShort context_length
,
3978 HB_UShort index
, i
, j
, property
;
3979 HB_GPOSHeader
* gpos
= gpi
->gpos
;
3982 HB_GDEFHeader
* gdef
;
3987 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
3990 if ( context_length
!= 0xFFFF && context_length
< cpf3
->GlyphCount
)
3991 return HB_Err_Not_Covered
;
3993 if ( buffer
->in_pos
+ cpf3
->GlyphCount
> buffer
->in_length
)
3994 return HB_Err_Not_Covered
; /* context is too long */
3998 for ( i
= 1, j
= 1; i
< cpf3
->GlyphCount
; i
++, j
++ )
4000 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
4002 if ( error
&& error
!= HB_Err_Not_Covered
)
4005 if ( j
+ cpf3
->GlyphCount
- i
== (HB_Int
)buffer
->in_length
)
4006 return HB_Err_Not_Covered
;
4010 error
= _HB_OPEN_Coverage_Index( &c
[i
], IN_GLYPH( j
), &index
);
4015 return Do_ContextPos( gpi
, cpf3
->GlyphCount
,
4016 cpf3
->PosCount
, cpf3
->PosLookupRecord
,
4022 static HB_Error
Lookup_ContextPos( GPOS_Instance
* gpi
,
4023 HB_GPOS_SubTable
* st
,
4026 HB_UShort context_length
,
4029 HB_ContextPos
* cp
= &st
->context
;
4031 switch ( cp
->PosFormat
)
4034 return Lookup_ContextPos1( gpi
, &cp
->cpf
.cpf1
, buffer
,
4035 flags
, context_length
, nesting_level
);
4038 return Lookup_ContextPos2( gpi
, &cp
->cpf
.cpf2
, buffer
,
4039 flags
, context_length
, nesting_level
);
4042 return Lookup_ContextPos3( gpi
, &cp
->cpf
.cpf3
, buffer
,
4043 flags
, context_length
, nesting_level
);
4046 return ERR(HB_Err_Invalid_SubTable_Format
);
4049 return HB_Err_Ok
; /* never reached */
4057 static HB_Error
Load_ChainPosRule( HB_ChainPosRule
* cpr
,
4067 HB_PosLookupRecord
* plr
;
4070 if ( ACCESS_Frame( 2L ) )
4073 cpr
->BacktrackGlyphCount
= GET_UShort();
4077 cpr
->Backtrack
= NULL
;
4079 count
= cpr
->BacktrackGlyphCount
;
4081 if ( ALLOC_ARRAY( cpr
->Backtrack
, count
, HB_UShort
) )
4086 if ( ACCESS_Frame( count
* 2L ) )
4089 for ( n
= 0; n
< count
; n
++ )
4090 b
[n
] = GET_UShort();
4094 if ( ACCESS_Frame( 2L ) )
4097 cpr
->InputGlyphCount
= GET_UShort();
4103 count
= cpr
->InputGlyphCount
- 1; /* only InputGlyphCount - 1 elements */
4105 if ( ALLOC_ARRAY( cpr
->Input
, count
, HB_UShort
) )
4110 if ( ACCESS_Frame( count
* 2L ) )
4113 for ( n
= 0; n
< count
; n
++ )
4114 i
[n
] = GET_UShort();
4118 if ( ACCESS_Frame( 2L ) )
4121 cpr
->LookaheadGlyphCount
= GET_UShort();
4125 cpr
->Lookahead
= NULL
;
4127 count
= cpr
->LookaheadGlyphCount
;
4129 if ( ALLOC_ARRAY( cpr
->Lookahead
, count
, HB_UShort
) )
4134 if ( ACCESS_Frame( count
* 2L ) )
4137 for ( n
= 0; n
< count
; n
++ )
4138 l
[n
] = GET_UShort();
4142 if ( ACCESS_Frame( 2L ) )
4145 cpr
->PosCount
= GET_UShort();
4149 cpr
->PosLookupRecord
= NULL
;
4151 count
= cpr
->PosCount
;
4153 if ( ALLOC_ARRAY( cpr
->PosLookupRecord
, count
, HB_PosLookupRecord
) )
4156 plr
= cpr
->PosLookupRecord
;
4158 if ( ACCESS_Frame( count
* 4L ) )
4161 for ( n
= 0; n
< count
; n
++ )
4163 plr
[n
].SequenceIndex
= GET_UShort();
4164 plr
[n
].LookupListIndex
= GET_UShort();
4186 static void Free_ChainPosRule( HB_ChainPosRule
* cpr
)
4188 FREE( cpr
->PosLookupRecord
);
4189 FREE( cpr
->Lookahead
);
4191 FREE( cpr
->Backtrack
);
4195 /* ChainPosRuleSet */
4197 static HB_Error
Load_ChainPosRuleSet( HB_ChainPosRuleSet
* cprs
,
4202 HB_UShort n
, m
, count
;
4203 HB_UInt cur_offset
, new_offset
, base_offset
;
4205 HB_ChainPosRule
* cpr
;
4208 base_offset
= FILE_Pos();
4210 if ( ACCESS_Frame( 2L ) )
4213 count
= cprs
->ChainPosRuleCount
= GET_UShort();
4217 cprs
->ChainPosRule
= NULL
;
4219 if ( ALLOC_ARRAY( cprs
->ChainPosRule
, count
, HB_ChainPosRule
) )
4222 cpr
= cprs
->ChainPosRule
;
4224 for ( n
= 0; n
< count
; n
++ )
4226 if ( ACCESS_Frame( 2L ) )
4229 new_offset
= GET_UShort() + base_offset
;
4233 cur_offset
= FILE_Pos();
4234 if ( FILE_Seek( new_offset
) ||
4235 ( error
= Load_ChainPosRule( &cpr
[n
], stream
) ) != HB_Err_Ok
)
4237 (void)FILE_Seek( cur_offset
);
4243 for ( m
= 0; m
< n
; m
++ )
4244 Free_ChainPosRule( &cpr
[m
] );
4251 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet
* cprs
)
4255 HB_ChainPosRule
* cpr
;
4258 if ( cprs
->ChainPosRule
)
4260 count
= cprs
->ChainPosRuleCount
;
4261 cpr
= cprs
->ChainPosRule
;
4263 for ( n
= 0; n
< count
; n
++ )
4264 Free_ChainPosRule( &cpr
[n
] );
4271 /* ChainContextPosFormat1 */
4273 static HB_Error
Load_ChainContextPos1( HB_ChainContextPosFormat1
* ccpf1
,
4278 HB_UShort n
, m
, count
;
4279 HB_UInt cur_offset
, new_offset
, base_offset
;
4281 HB_ChainPosRuleSet
* cprs
;
4284 base_offset
= FILE_Pos() - 2L;
4286 if ( ACCESS_Frame( 2L ) )
4289 new_offset
= GET_UShort() + base_offset
;
4293 cur_offset
= FILE_Pos();
4294 if ( FILE_Seek( new_offset
) ||
4295 ( error
= _HB_OPEN_Load_Coverage( &ccpf1
->Coverage
, stream
) ) != HB_Err_Ok
)
4297 (void)FILE_Seek( cur_offset
);
4299 if ( ACCESS_Frame( 2L ) )
4302 count
= ccpf1
->ChainPosRuleSetCount
= GET_UShort();
4306 ccpf1
->ChainPosRuleSet
= NULL
;
4308 if ( ALLOC_ARRAY( ccpf1
->ChainPosRuleSet
, count
, HB_ChainPosRuleSet
) )
4311 cprs
= ccpf1
->ChainPosRuleSet
;
4313 for ( n
= 0; n
< count
; n
++ )
4315 if ( ACCESS_Frame( 2L ) )
4318 new_offset
= GET_UShort() + base_offset
;
4322 cur_offset
= FILE_Pos();
4323 if ( FILE_Seek( new_offset
) ||
4324 ( error
= Load_ChainPosRuleSet( &cprs
[n
], stream
) ) != HB_Err_Ok
)
4326 (void)FILE_Seek( cur_offset
);
4332 for ( m
= 0; m
< n
; m
++ )
4333 Free_ChainPosRuleSet( &cprs
[m
] );
4338 _HB_OPEN_Free_Coverage( &ccpf1
->Coverage
);
4343 static void Free_ChainContextPos1( HB_ChainContextPosFormat1
* ccpf1
)
4347 HB_ChainPosRuleSet
* cprs
;
4350 if ( ccpf1
->ChainPosRuleSet
)
4352 count
= ccpf1
->ChainPosRuleSetCount
;
4353 cprs
= ccpf1
->ChainPosRuleSet
;
4355 for ( n
= 0; n
< count
; n
++ )
4356 Free_ChainPosRuleSet( &cprs
[n
] );
4361 _HB_OPEN_Free_Coverage( &ccpf1
->Coverage
);
4365 /* ChainPosClassRule */
4367 static HB_Error
Load_ChainPosClassRule(
4368 HB_ChainContextPosFormat2
* ccpf2
,
4369 HB_ChainPosClassRule
* cpcr
,
4379 HB_PosLookupRecord
* plr
;
4382 if ( ACCESS_Frame( 2L ) )
4385 cpcr
->BacktrackGlyphCount
= GET_UShort();
4389 if ( cpcr
->BacktrackGlyphCount
> ccpf2
->MaxBacktrackLength
)
4390 ccpf2
->MaxBacktrackLength
= cpcr
->BacktrackGlyphCount
;
4392 cpcr
->Backtrack
= NULL
;
4394 count
= cpcr
->BacktrackGlyphCount
;
4396 if ( ALLOC_ARRAY( cpcr
->Backtrack
, count
, HB_UShort
) )
4399 b
= cpcr
->Backtrack
;
4401 if ( ACCESS_Frame( count
* 2L ) )
4404 for ( n
= 0; n
< count
; n
++ )
4405 b
[n
] = GET_UShort();
4409 if ( ACCESS_Frame( 2L ) )
4412 cpcr
->InputGlyphCount
= GET_UShort();
4414 if ( cpcr
->InputGlyphCount
> ccpf2
->MaxInputLength
)
4415 ccpf2
->MaxInputLength
= cpcr
->InputGlyphCount
;
4421 count
= cpcr
->InputGlyphCount
- 1; /* only InputGlyphCount - 1 elements */
4423 if ( ALLOC_ARRAY( cpcr
->Input
, count
, HB_UShort
) )
4428 if ( ACCESS_Frame( count
* 2L ) )
4431 for ( n
= 0; n
< count
; n
++ )
4432 i
[n
] = GET_UShort();
4436 if ( ACCESS_Frame( 2L ) )
4439 cpcr
->LookaheadGlyphCount
= GET_UShort();
4443 if ( cpcr
->LookaheadGlyphCount
> ccpf2
->MaxLookaheadLength
)
4444 ccpf2
->MaxLookaheadLength
= cpcr
->LookaheadGlyphCount
;
4446 cpcr
->Lookahead
= NULL
;
4448 count
= cpcr
->LookaheadGlyphCount
;
4450 if ( ALLOC_ARRAY( cpcr
->Lookahead
, count
, HB_UShort
) )
4453 l
= cpcr
->Lookahead
;
4455 if ( ACCESS_Frame( count
* 2L ) )
4458 for ( n
= 0; n
< count
; n
++ )
4459 l
[n
] = GET_UShort();
4463 if ( ACCESS_Frame( 2L ) )
4466 cpcr
->PosCount
= GET_UShort();
4470 cpcr
->PosLookupRecord
= NULL
;
4472 count
= cpcr
->PosCount
;
4474 if ( ALLOC_ARRAY( cpcr
->PosLookupRecord
, count
, HB_PosLookupRecord
) )
4477 plr
= cpcr
->PosLookupRecord
;
4479 if ( ACCESS_Frame( count
* 4L ) )
4482 for ( n
= 0; n
< count
; n
++ )
4484 plr
[n
].SequenceIndex
= GET_UShort();
4485 plr
[n
].LookupListIndex
= GET_UShort();
4507 static void Free_ChainPosClassRule( HB_ChainPosClassRule
* cpcr
)
4509 FREE( cpcr
->PosLookupRecord
);
4510 FREE( cpcr
->Lookahead
);
4511 FREE( cpcr
->Input
);
4512 FREE( cpcr
->Backtrack
);
4518 static HB_Error
Load_ChainPosClassSet(
4519 HB_ChainContextPosFormat2
* ccpf2
,
4520 HB_ChainPosClassSet
* cpcs
,
4525 HB_UShort n
, m
, count
;
4526 HB_UInt cur_offset
, new_offset
, base_offset
;
4528 HB_ChainPosClassRule
* cpcr
;
4531 base_offset
= FILE_Pos();
4533 if ( ACCESS_Frame( 2L ) )
4536 count
= cpcs
->ChainPosClassRuleCount
= GET_UShort();
4540 cpcs
->ChainPosClassRule
= NULL
;
4542 if ( ALLOC_ARRAY( cpcs
->ChainPosClassRule
, count
,
4543 HB_ChainPosClassRule
) )
4546 cpcr
= cpcs
->ChainPosClassRule
;
4548 for ( n
= 0; n
< count
; n
++ )
4550 if ( ACCESS_Frame( 2L ) )
4553 new_offset
= GET_UShort() + base_offset
;
4557 cur_offset
= FILE_Pos();
4558 if ( FILE_Seek( new_offset
) ||
4559 ( error
= Load_ChainPosClassRule( ccpf2
, &cpcr
[n
],
4560 stream
) ) != HB_Err_Ok
)
4562 (void)FILE_Seek( cur_offset
);
4568 for ( m
= 0; m
< n
; m
++ )
4569 Free_ChainPosClassRule( &cpcr
[m
] );
4576 static void Free_ChainPosClassSet( HB_ChainPosClassSet
* cpcs
)
4580 HB_ChainPosClassRule
* cpcr
;
4583 if ( cpcs
->ChainPosClassRule
)
4585 count
= cpcs
->ChainPosClassRuleCount
;
4586 cpcr
= cpcs
->ChainPosClassRule
;
4588 for ( n
= 0; n
< count
; n
++ )
4589 Free_ChainPosClassRule( &cpcr
[n
] );
4596 /* ChainContextPosFormat2 */
4598 static HB_Error
Load_ChainContextPos2( HB_ChainContextPosFormat2
* ccpf2
,
4603 HB_UShort n
, m
, count
;
4604 HB_UInt cur_offset
, new_offset
, base_offset
;
4605 HB_UInt backtrack_offset
, input_offset
, lookahead_offset
;
4607 HB_ChainPosClassSet
* cpcs
;
4610 base_offset
= FILE_Pos() - 2;
4612 if ( ACCESS_Frame( 2L ) )
4615 new_offset
= GET_UShort() + base_offset
;
4619 cur_offset
= FILE_Pos();
4620 if ( FILE_Seek( new_offset
) ||
4621 ( error
= _HB_OPEN_Load_Coverage( &ccpf2
->Coverage
, stream
) ) != HB_Err_Ok
)
4623 (void)FILE_Seek( cur_offset
);
4625 if ( ACCESS_Frame( 8L ) )
4628 backtrack_offset
= GET_UShort();
4629 input_offset
= GET_UShort();
4630 lookahead_offset
= GET_UShort();
4632 /* `ChainPosClassSetCount' is the upper limit for input class values,
4633 thus we read it now to make an additional safety check. No limit
4634 is known or needed for the other two class definitions */
4636 count
= ccpf2
->ChainPosClassSetCount
= GET_UShort();
4640 if ( ( error
= _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2
->BacktrackClassDef
, 65535,
4641 backtrack_offset
, base_offset
,
4642 stream
) ) != HB_Err_Ok
)
4644 if ( ( error
= _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2
->InputClassDef
, count
,
4645 input_offset
, base_offset
,
4646 stream
) ) != HB_Err_Ok
)
4648 if ( ( error
= _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2
->LookaheadClassDef
, 65535,
4649 lookahead_offset
, base_offset
,
4650 stream
) ) != HB_Err_Ok
)
4653 ccpf2
->ChainPosClassSet
= NULL
;
4654 ccpf2
->MaxBacktrackLength
= 0;
4655 ccpf2
->MaxInputLength
= 0;
4656 ccpf2
->MaxLookaheadLength
= 0;
4658 if ( ALLOC_ARRAY( ccpf2
->ChainPosClassSet
, count
, HB_ChainPosClassSet
) )
4661 cpcs
= ccpf2
->ChainPosClassSet
;
4663 for ( n
= 0; n
< count
; n
++ )
4665 if ( ACCESS_Frame( 2L ) )
4668 new_offset
= GET_UShort() + base_offset
;
4672 if ( new_offset
!= base_offset
) /* not a NULL offset */
4674 cur_offset
= FILE_Pos();
4675 if ( FILE_Seek( new_offset
) ||
4676 ( error
= Load_ChainPosClassSet( ccpf2
, &cpcs
[n
],
4677 stream
) ) != HB_Err_Ok
)
4679 (void)FILE_Seek( cur_offset
);
4683 /* we create a ChainPosClassSet table with no entries */
4685 ccpf2
->ChainPosClassSet
[n
].ChainPosClassRuleCount
= 0;
4686 ccpf2
->ChainPosClassSet
[n
].ChainPosClassRule
= NULL
;
4693 for ( m
= 0; m
< n
; m
++ )
4694 Free_ChainPosClassSet( &cpcs
[m
] );
4699 _HB_OPEN_Free_ClassDefinition( &ccpf2
->LookaheadClassDef
);
4702 _HB_OPEN_Free_ClassDefinition( &ccpf2
->InputClassDef
);
4705 _HB_OPEN_Free_ClassDefinition( &ccpf2
->BacktrackClassDef
);
4708 _HB_OPEN_Free_Coverage( &ccpf2
->Coverage
);
4713 static void Free_ChainContextPos2( HB_ChainContextPosFormat2
* ccpf2
)
4717 HB_ChainPosClassSet
* cpcs
;
4720 if ( ccpf2
->ChainPosClassSet
)
4722 count
= ccpf2
->ChainPosClassSetCount
;
4723 cpcs
= ccpf2
->ChainPosClassSet
;
4725 for ( n
= 0; n
< count
; n
++ )
4726 Free_ChainPosClassSet( &cpcs
[n
] );
4731 _HB_OPEN_Free_ClassDefinition( &ccpf2
->LookaheadClassDef
);
4732 _HB_OPEN_Free_ClassDefinition( &ccpf2
->InputClassDef
);
4733 _HB_OPEN_Free_ClassDefinition( &ccpf2
->BacktrackClassDef
);
4735 _HB_OPEN_Free_Coverage( &ccpf2
->Coverage
);
4739 /* ChainContextPosFormat3 */
4741 static HB_Error
Load_ChainContextPos3( HB_ChainContextPosFormat3
* ccpf3
,
4746 HB_UShort n
, nb
, ni
, nl
, m
, count
;
4747 HB_UShort backtrack_count
, input_count
, lookahead_count
;
4748 HB_UInt cur_offset
, new_offset
, base_offset
;
4753 HB_PosLookupRecord
* plr
;
4756 base_offset
= FILE_Pos() - 2L;
4758 if ( ACCESS_Frame( 2L ) )
4761 ccpf3
->BacktrackGlyphCount
= GET_UShort();
4765 ccpf3
->BacktrackCoverage
= NULL
;
4767 backtrack_count
= ccpf3
->BacktrackGlyphCount
;
4769 if ( ALLOC_ARRAY( ccpf3
->BacktrackCoverage
, backtrack_count
,
4773 b
= ccpf3
->BacktrackCoverage
;
4775 for ( nb
= 0; nb
< backtrack_count
; nb
++ )
4777 if ( ACCESS_Frame( 2L ) )
4780 new_offset
= GET_UShort() + base_offset
;
4784 cur_offset
= FILE_Pos();
4785 if ( FILE_Seek( new_offset
) ||
4786 ( error
= _HB_OPEN_Load_Coverage( &b
[nb
], stream
) ) != HB_Err_Ok
)
4788 (void)FILE_Seek( cur_offset
);
4791 if ( ACCESS_Frame( 2L ) )
4794 ccpf3
->InputGlyphCount
= GET_UShort();
4798 ccpf3
->InputCoverage
= NULL
;
4800 input_count
= ccpf3
->InputGlyphCount
;
4802 if ( ALLOC_ARRAY( ccpf3
->InputCoverage
, input_count
, HB_Coverage
) )
4805 i
= ccpf3
->InputCoverage
;
4807 for ( ni
= 0; ni
< input_count
; ni
++ )
4809 if ( ACCESS_Frame( 2L ) )
4812 new_offset
= GET_UShort() + base_offset
;
4816 cur_offset
= FILE_Pos();
4817 if ( FILE_Seek( new_offset
) ||
4818 ( error
= _HB_OPEN_Load_Coverage( &i
[ni
], stream
) ) != HB_Err_Ok
)
4820 (void)FILE_Seek( cur_offset
);
4823 if ( ACCESS_Frame( 2L ) )
4826 ccpf3
->LookaheadGlyphCount
= GET_UShort();
4830 ccpf3
->LookaheadCoverage
= NULL
;
4832 lookahead_count
= ccpf3
->LookaheadGlyphCount
;
4834 if ( ALLOC_ARRAY( ccpf3
->LookaheadCoverage
, lookahead_count
,
4838 l
= ccpf3
->LookaheadCoverage
;
4840 for ( nl
= 0; nl
< lookahead_count
; nl
++ )
4842 if ( ACCESS_Frame( 2L ) )
4845 new_offset
= GET_UShort() + base_offset
;
4849 cur_offset
= FILE_Pos();
4850 if ( FILE_Seek( new_offset
) ||
4851 ( error
= _HB_OPEN_Load_Coverage( &l
[nl
], stream
) ) != HB_Err_Ok
)
4853 (void)FILE_Seek( cur_offset
);
4856 if ( ACCESS_Frame( 2L ) )
4859 ccpf3
->PosCount
= GET_UShort();
4863 ccpf3
->PosLookupRecord
= NULL
;
4865 count
= ccpf3
->PosCount
;
4867 if ( ALLOC_ARRAY( ccpf3
->PosLookupRecord
, count
, HB_PosLookupRecord
) )
4870 plr
= ccpf3
->PosLookupRecord
;
4872 if ( ACCESS_Frame( count
* 4L ) )
4875 for ( n
= 0; n
< count
; n
++ )
4877 plr
[n
].SequenceIndex
= GET_UShort();
4878 plr
[n
].LookupListIndex
= GET_UShort();
4889 for ( m
= 0; m
< nl
; m
++ )
4890 _HB_OPEN_Free_Coverage( &l
[m
] );
4895 for ( m
= 0; m
< ni
; m
++ )
4896 _HB_OPEN_Free_Coverage( &i
[m
] );
4901 for ( m
= 0; m
< nb
; m
++ )
4902 _HB_OPEN_Free_Coverage( &b
[m
] );
4909 static void Free_ChainContextPos3( HB_ChainContextPosFormat3
* ccpf3
)
4916 FREE( ccpf3
->PosLookupRecord
);
4918 if ( ccpf3
->LookaheadCoverage
)
4920 count
= ccpf3
->LookaheadGlyphCount
;
4921 c
= ccpf3
->LookaheadCoverage
;
4923 for ( n
= 0; n
< count
; n
++ )
4924 _HB_OPEN_Free_Coverage( &c
[n
] );
4929 if ( ccpf3
->InputCoverage
)
4931 count
= ccpf3
->InputGlyphCount
;
4932 c
= ccpf3
->InputCoverage
;
4934 for ( n
= 0; n
< count
; n
++ )
4935 _HB_OPEN_Free_Coverage( &c
[n
] );
4940 if ( ccpf3
->BacktrackCoverage
)
4942 count
= ccpf3
->BacktrackGlyphCount
;
4943 c
= ccpf3
->BacktrackCoverage
;
4945 for ( n
= 0; n
< count
; n
++ )
4946 _HB_OPEN_Free_Coverage( &c
[n
] );
4953 /* ChainContextPos */
4955 static HB_Error
Load_ChainContextPos( HB_GPOS_SubTable
* st
,
4959 HB_ChainContextPos
* ccp
= &st
->chain
;
4962 if ( ACCESS_Frame( 2L ) )
4965 ccp
->PosFormat
= GET_UShort();
4969 switch ( ccp
->PosFormat
)
4972 return Load_ChainContextPos1( &ccp
->ccpf
.ccpf1
, stream
);
4975 return Load_ChainContextPos2( &ccp
->ccpf
.ccpf2
, stream
);
4978 return Load_ChainContextPos3( &ccp
->ccpf
.ccpf3
, stream
);
4981 return ERR(HB_Err_Invalid_SubTable_Format
);
4984 return HB_Err_Ok
; /* never reached */
4988 static void Free_ChainContextPos( HB_GPOS_SubTable
* st
)
4990 HB_ChainContextPos
* ccp
= &st
->chain
;
4992 switch ( ccp
->PosFormat
)
4994 case 1: Free_ChainContextPos1( &ccp
->ccpf
.ccpf1
); break;
4995 case 2: Free_ChainContextPos2( &ccp
->ccpf
.ccpf2
); break;
4996 case 3: Free_ChainContextPos3( &ccp
->ccpf
.ccpf3
); break;
5002 static HB_Error
Lookup_ChainContextPos1(
5004 HB_ChainContextPosFormat1
* ccpf1
,
5007 HB_UShort context_length
,
5010 HB_UShort index
, property
;
5011 HB_UShort i
, j
, k
, num_cpr
;
5012 HB_UShort bgc
, igc
, lgc
;
5014 HB_GPOSHeader
* gpos
= gpi
->gpos
;
5016 HB_ChainPosRule
* cpr
;
5017 HB_ChainPosRule curr_cpr
;
5018 HB_GDEFHeader
* gdef
;
5023 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
5026 error
= _HB_OPEN_Coverage_Index( &ccpf1
->Coverage
, IN_CURGLYPH(), &index
);
5030 cpr
= ccpf1
->ChainPosRuleSet
[index
].ChainPosRule
;
5031 num_cpr
= ccpf1
->ChainPosRuleSet
[index
].ChainPosRuleCount
;
5033 for ( k
= 0; k
< num_cpr
; k
++ )
5036 bgc
= curr_cpr
.BacktrackGlyphCount
;
5037 igc
= curr_cpr
.InputGlyphCount
;
5038 lgc
= curr_cpr
.LookaheadGlyphCount
;
5040 if ( context_length
!= 0xFFFF && context_length
< igc
)
5041 goto next_chainposrule
;
5043 /* check whether context is too long; it is a first guess only */
5045 if ( bgc
> buffer
->in_pos
|| buffer
->in_pos
+ igc
+ lgc
> buffer
->in_length
)
5046 goto next_chainposrule
;
5050 /* Since we don't know in advance the number of glyphs to inspect,
5051 we search backwards for matches in the backtrack glyph array */
5053 for ( i
= 0, j
= buffer
->in_pos
- 1; i
< bgc
; i
++, j
-- )
5055 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5057 if ( error
&& error
!= HB_Err_Not_Covered
)
5060 if ( j
+ 1 == bgc
- i
)
5061 goto next_chainposrule
;
5065 /* In OpenType 1.3, it is undefined whether the offsets of
5066 backtrack glyphs is in logical order or not. Version 1.4
5069 Logical order - a b c d e f g h i j
5072 Backtrack offsets - 3 2 1 0
5073 Lookahead offsets - 0 1 2 3 */
5075 if ( IN_GLYPH( j
) != curr_cpr
.Backtrack
[i
] )
5076 goto next_chainposrule
;
5080 /* Start at 1 because [0] is implied */
5082 for ( i
= 1, j
= buffer
->in_pos
+ 1; i
< igc
; i
++, j
++ )
5084 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5086 if ( error
&& error
!= HB_Err_Not_Covered
)
5089 if ( j
+ igc
- i
+ lgc
== (HB_Int
)buffer
->in_length
)
5090 goto next_chainposrule
;
5094 if ( IN_GLYPH( j
) != curr_cpr
.Input
[i
- 1] )
5095 goto next_chainposrule
;
5098 /* we are starting to check for lookahead glyphs right after the
5099 last context glyph */
5101 for ( i
= 0; i
< lgc
; i
++, j
++ )
5103 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5105 if ( error
&& error
!= HB_Err_Not_Covered
)
5108 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
5109 goto next_chainposrule
;
5113 if ( IN_GLYPH( j
) != curr_cpr
.Lookahead
[i
] )
5114 goto next_chainposrule
;
5117 return Do_ContextPos( gpi
, igc
,
5119 curr_cpr
.PosLookupRecord
,
5127 return HB_Err_Not_Covered
;
5131 static HB_Error
Lookup_ChainContextPos2(
5133 HB_ChainContextPosFormat2
* ccpf2
,
5136 HB_UShort context_length
,
5139 HB_UShort index
, property
;
5142 HB_UShort bgc
, igc
, lgc
;
5143 HB_UShort known_backtrack_classes
,
5144 known_input_classes
,
5145 known_lookahead_classes
;
5147 HB_UShort
* backtrack_classes
;
5148 HB_UShort
* input_classes
;
5149 HB_UShort
* lookahead_classes
;
5154 HB_GPOSHeader
* gpos
= gpi
->gpos
;
5156 HB_ChainPosClassSet
* cpcs
;
5157 HB_ChainPosClassRule cpcr
;
5158 HB_GDEFHeader
* gdef
;
5163 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
5166 /* Note: The coverage table in format 2 doesn't give an index into
5167 anything. It just lets us know whether or not we need to
5168 do any lookup at all. */
5170 error
= _HB_OPEN_Coverage_Index( &ccpf2
->Coverage
, IN_CURGLYPH(), &index
);
5174 if (ccpf2
->MaxInputLength
< 1)
5175 return HB_Err_Not_Covered
;
5177 if ( ALLOC_ARRAY( backtrack_classes
, ccpf2
->MaxBacktrackLength
, HB_UShort
) )
5179 known_backtrack_classes
= 0;
5181 if ( ALLOC_ARRAY( input_classes
, ccpf2
->MaxInputLength
, HB_UShort
) )
5183 known_input_classes
= 1;
5185 if ( ALLOC_ARRAY( lookahead_classes
, ccpf2
->MaxLookaheadLength
, HB_UShort
) )
5187 known_lookahead_classes
= 0;
5189 error
= _HB_OPEN_Get_Class( &ccpf2
->InputClassDef
, IN_CURGLYPH(),
5190 &input_classes
[0], NULL
);
5191 if ( error
&& error
!= HB_Err_Not_Covered
)
5194 cpcs
= &ccpf2
->ChainPosClassSet
[input_classes
[0]];
5197 error
= ERR(HB_Err_Invalid_SubTable
);
5201 for ( k
= 0; k
< cpcs
->ChainPosClassRuleCount
; k
++ )
5203 cpcr
= cpcs
->ChainPosClassRule
[k
];
5204 bgc
= cpcr
.BacktrackGlyphCount
;
5205 igc
= cpcr
.InputGlyphCount
;
5206 lgc
= cpcr
.LookaheadGlyphCount
;
5208 if ( context_length
!= 0xFFFF && context_length
< igc
)
5209 goto next_chainposclassrule
;
5211 /* check whether context is too long; it is a first guess only */
5213 if ( bgc
> buffer
->in_pos
|| buffer
->in_pos
+ igc
+ lgc
> buffer
->in_length
)
5214 goto next_chainposclassrule
;
5218 /* Since we don't know in advance the number of glyphs to inspect,
5219 we search backwards for matches in the backtrack glyph array.
5220 Note that `known_backtrack_classes' starts at index 0. */
5222 bc
= cpcr
.Backtrack
;
5224 for ( i
= 0, j
= buffer
->in_pos
- 1; i
< bgc
; i
++, j
-- )
5226 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5228 if ( error
&& error
!= HB_Err_Not_Covered
)
5231 if ( j
+ 1 == bgc
- i
)
5232 goto next_chainposclassrule
;
5236 if ( i
>= known_backtrack_classes
)
5238 /* Keeps us from having to do this for each rule */
5240 error
= _HB_OPEN_Get_Class( &ccpf2
->BacktrackClassDef
, IN_GLYPH( j
),
5241 &backtrack_classes
[i
], NULL
);
5242 if ( error
&& error
!= HB_Err_Not_Covered
)
5244 known_backtrack_classes
= i
;
5247 if ( bc
[i
] != backtrack_classes
[i
] )
5248 goto next_chainposclassrule
;
5254 /* Start at 1 because [0] is implied */
5256 for ( i
= 1, j
= buffer
->in_pos
+ 1; i
< igc
; i
++, j
++ )
5258 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5260 if ( error
&& error
!= HB_Err_Not_Covered
)
5263 if ( j
+ igc
- i
+ lgc
== (HB_Int
)buffer
->in_length
)
5264 goto next_chainposclassrule
;
5268 if ( i
>= known_input_classes
)
5270 error
= _HB_OPEN_Get_Class( &ccpf2
->InputClassDef
, IN_GLYPH( j
),
5271 &input_classes
[i
], NULL
);
5272 if ( error
&& error
!= HB_Err_Not_Covered
)
5274 known_input_classes
= i
;
5277 if ( ic
[i
- 1] != input_classes
[i
] )
5278 goto next_chainposclassrule
;
5281 /* we are starting to check for lookahead glyphs right after the
5282 last context glyph */
5284 lc
= cpcr
.Lookahead
;
5286 for ( i
= 0; i
< lgc
; i
++, j
++ )
5288 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5290 if ( error
&& error
!= HB_Err_Not_Covered
)
5293 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
5294 goto next_chainposclassrule
;
5298 if ( i
>= known_lookahead_classes
)
5300 error
= _HB_OPEN_Get_Class( &ccpf2
->LookaheadClassDef
, IN_GLYPH( j
),
5301 &lookahead_classes
[i
], NULL
);
5302 if ( error
&& error
!= HB_Err_Not_Covered
)
5304 known_lookahead_classes
= i
;
5307 if ( lc
[i
] != lookahead_classes
[i
] )
5308 goto next_chainposclassrule
;
5311 error
= Do_ContextPos( gpi
, igc
,
5313 cpcr
.PosLookupRecord
,
5318 next_chainposclassrule
:
5322 error
= HB_Err_Not_Covered
;
5325 FREE( lookahead_classes
);
5328 FREE( input_classes
);
5331 FREE( backtrack_classes
);
5336 static HB_Error
Lookup_ChainContextPos3(
5338 HB_ChainContextPosFormat3
* ccpf3
,
5341 HB_UShort context_length
,
5344 HB_UShort index
, i
, j
, property
;
5345 HB_UShort bgc
, igc
, lgc
;
5347 HB_GPOSHeader
* gpos
= gpi
->gpos
;
5352 HB_GDEFHeader
* gdef
;
5357 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
5360 bgc
= ccpf3
->BacktrackGlyphCount
;
5361 igc
= ccpf3
->InputGlyphCount
;
5362 lgc
= ccpf3
->LookaheadGlyphCount
;
5364 if ( context_length
!= 0xFFFF && context_length
< igc
)
5365 return HB_Err_Not_Covered
;
5367 /* check whether context is too long; it is a first guess only */
5369 if ( bgc
> buffer
->in_pos
|| buffer
->in_pos
+ igc
+ lgc
> buffer
->in_length
)
5370 return HB_Err_Not_Covered
;
5374 /* Since we don't know in advance the number of glyphs to inspect,
5375 we search backwards for matches in the backtrack glyph array */
5377 bc
= ccpf3
->BacktrackCoverage
;
5379 for ( i
= 0, j
= buffer
->in_pos
- 1; i
< bgc
; i
++, j
-- )
5381 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5383 if ( error
&& error
!= HB_Err_Not_Covered
)
5386 if ( j
+ 1 == bgc
- i
)
5387 return HB_Err_Not_Covered
;
5391 error
= _HB_OPEN_Coverage_Index( &bc
[i
], IN_GLYPH( j
), &index
);
5397 ic
= ccpf3
->InputCoverage
;
5399 for ( i
= 0, j
= buffer
->in_pos
; i
< igc
; i
++, j
++ )
5401 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5402 while ( j
> buffer
->in_pos
&& CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5404 if ( error
&& error
!= HB_Err_Not_Covered
)
5407 if ( j
+ igc
- i
+ lgc
== (HB_Int
)buffer
->in_length
)
5408 return HB_Err_Not_Covered
;
5412 error
= _HB_OPEN_Coverage_Index( &ic
[i
], IN_GLYPH( j
), &index
);
5417 /* we are starting to check for lookahead glyphs right after the
5418 last context glyph */
5420 lc
= ccpf3
->LookaheadCoverage
;
5422 for ( i
= 0; i
< lgc
; i
++, j
++ )
5424 while ( CHECK_Property( gdef
, IN_ITEM( j
), flags
, &property
) )
5426 if ( error
&& error
!= HB_Err_Not_Covered
)
5429 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
5430 return HB_Err_Not_Covered
;
5434 error
= _HB_OPEN_Coverage_Index( &lc
[i
], IN_GLYPH( j
), &index
);
5439 return Do_ContextPos( gpi
, igc
,
5441 ccpf3
->PosLookupRecord
,
5447 static HB_Error
Lookup_ChainContextPos(
5449 HB_GPOS_SubTable
* st
,
5452 HB_UShort context_length
,
5455 HB_ChainContextPos
* ccp
= &st
->chain
;
5457 switch ( ccp
->PosFormat
)
5460 return Lookup_ChainContextPos1( gpi
, &ccp
->ccpf
.ccpf1
, buffer
,
5461 flags
, context_length
,
5465 return Lookup_ChainContextPos2( gpi
, &ccp
->ccpf
.ccpf2
, buffer
,
5466 flags
, context_length
,
5470 return Lookup_ChainContextPos3( gpi
, &ccp
->ccpf
.ccpf3
, buffer
,
5471 flags
, context_length
,
5475 return ERR(HB_Err_Invalid_SubTable_Format
);
5478 return HB_Err_Ok
; /* never reached */
5489 HB_Error
HB_GPOS_Select_Script( HB_GPOSHeader
* gpos
,
5491 HB_UShort
* script_index
)
5496 HB_ScriptRecord
* sr
;
5499 if ( !gpos
|| !script_index
)
5500 return ERR(HB_Err_Invalid_Argument
);
5502 sl
= &gpos
->ScriptList
;
5503 sr
= sl
->ScriptRecord
;
5505 for ( n
= 0; n
< sl
->ScriptCount
; n
++ )
5506 if ( script_tag
== sr
[n
].ScriptTag
)
5513 return HB_Err_Not_Covered
;
5518 HB_Error
HB_GPOS_Select_Language( HB_GPOSHeader
* gpos
,
5519 HB_UInt language_tag
,
5520 HB_UShort script_index
,
5521 HB_UShort
* language_index
,
5522 HB_UShort
* req_feature_index
)
5527 HB_ScriptRecord
* sr
;
5529 HB_LangSysRecord
* lsr
;
5532 if ( !gpos
|| !language_index
|| !req_feature_index
)
5533 return ERR(HB_Err_Invalid_Argument
);
5535 sl
= &gpos
->ScriptList
;
5536 sr
= sl
->ScriptRecord
;
5538 if ( script_index
>= sl
->ScriptCount
)
5539 return ERR(HB_Err_Invalid_Argument
);
5541 s
= &sr
[script_index
].Script
;
5542 lsr
= s
->LangSysRecord
;
5544 for ( n
= 0; n
< s
->LangSysCount
; n
++ )
5545 if ( language_tag
== lsr
[n
].LangSysTag
)
5547 *language_index
= n
;
5548 *req_feature_index
= lsr
[n
].LangSys
.ReqFeatureIndex
;
5553 return HB_Err_Not_Covered
;
5557 /* selecting 0xFFFF for language_index asks for the values of the
5558 default language (DefaultLangSys) */
5561 HB_Error
HB_GPOS_Select_Feature( HB_GPOSHeader
* gpos
,
5562 HB_UInt feature_tag
,
5563 HB_UShort script_index
,
5564 HB_UShort language_index
,
5565 HB_UShort
* feature_index
)
5570 HB_ScriptRecord
* sr
;
5572 HB_LangSysRecord
* lsr
;
5577 HB_FeatureRecord
* fr
;
5580 if ( !gpos
|| !feature_index
)
5581 return ERR(HB_Err_Invalid_Argument
);
5583 sl
= &gpos
->ScriptList
;
5584 sr
= sl
->ScriptRecord
;
5586 fl
= &gpos
->FeatureList
;
5587 fr
= fl
->FeatureRecord
;
5589 if ( script_index
>= sl
->ScriptCount
)
5590 return ERR(HB_Err_Invalid_Argument
);
5592 s
= &sr
[script_index
].Script
;
5593 lsr
= s
->LangSysRecord
;
5595 if ( language_index
== 0xFFFF )
5596 ls
= &s
->DefaultLangSys
;
5599 if ( language_index
>= s
->LangSysCount
)
5600 return ERR(HB_Err_Invalid_Argument
);
5602 ls
= &lsr
[language_index
].LangSys
;
5605 fi
= ls
->FeatureIndex
;
5607 for ( n
= 0; n
< ls
->FeatureCount
; n
++ )
5609 if ( fi
[n
] >= fl
->FeatureCount
)
5610 return ERR(HB_Err_Invalid_SubTable_Format
);
5612 if ( feature_tag
== fr
[fi
[n
]].FeatureTag
)
5614 *feature_index
= fi
[n
];
5620 return HB_Err_Not_Covered
;
5624 /* The next three functions return a null-terminated list */
5627 HB_Error
HB_GPOS_Query_Scripts( HB_GPOSHeader
* gpos
,
5628 HB_UInt
** script_tag_list
)
5635 HB_ScriptRecord
* sr
;
5638 if ( !gpos
|| !script_tag_list
)
5639 return ERR(HB_Err_Invalid_Argument
);
5641 sl
= &gpos
->ScriptList
;
5642 sr
= sl
->ScriptRecord
;
5644 if ( ALLOC_ARRAY( stl
, sl
->ScriptCount
+ 1, HB_UInt
) )
5647 for ( n
= 0; n
< sl
->ScriptCount
; n
++ )
5648 stl
[n
] = sr
[n
].ScriptTag
;
5651 *script_tag_list
= stl
;
5658 HB_Error
HB_GPOS_Query_Languages( HB_GPOSHeader
* gpos
,
5659 HB_UShort script_index
,
5660 HB_UInt
** language_tag_list
)
5667 HB_ScriptRecord
* sr
;
5669 HB_LangSysRecord
* lsr
;
5672 if ( !gpos
|| !language_tag_list
)
5673 return ERR(HB_Err_Invalid_Argument
);
5675 sl
= &gpos
->ScriptList
;
5676 sr
= sl
->ScriptRecord
;
5678 if ( script_index
>= sl
->ScriptCount
)
5679 return ERR(HB_Err_Invalid_Argument
);
5681 s
= &sr
[script_index
].Script
;
5682 lsr
= s
->LangSysRecord
;
5684 if ( ALLOC_ARRAY( ltl
, s
->LangSysCount
+ 1, HB_UInt
) )
5687 for ( n
= 0; n
< s
->LangSysCount
; n
++ )
5688 ltl
[n
] = lsr
[n
].LangSysTag
;
5691 *language_tag_list
= ltl
;
5697 /* selecting 0xFFFF for language_index asks for the values of the
5698 default language (DefaultLangSys) */
5701 HB_Error
HB_GPOS_Query_Features( HB_GPOSHeader
* gpos
,
5702 HB_UShort script_index
,
5703 HB_UShort language_index
,
5704 HB_UInt
** feature_tag_list
)
5711 HB_ScriptRecord
* sr
;
5713 HB_LangSysRecord
* lsr
;
5718 HB_FeatureRecord
* fr
;
5721 if ( !gpos
|| !feature_tag_list
)
5722 return ERR(HB_Err_Invalid_Argument
);
5724 sl
= &gpos
->ScriptList
;
5725 sr
= sl
->ScriptRecord
;
5727 fl
= &gpos
->FeatureList
;
5728 fr
= fl
->FeatureRecord
;
5730 if ( script_index
>= sl
->ScriptCount
)
5731 return ERR(HB_Err_Invalid_Argument
);
5733 s
= &sr
[script_index
].Script
;
5734 lsr
= s
->LangSysRecord
;
5736 if ( language_index
== 0xFFFF )
5737 ls
= &s
->DefaultLangSys
;
5740 if ( language_index
>= s
->LangSysCount
)
5741 return ERR(HB_Err_Invalid_Argument
);
5743 ls
= &lsr
[language_index
].LangSys
;
5746 fi
= ls
->FeatureIndex
;
5748 if ( ALLOC_ARRAY( ftl
, ls
->FeatureCount
+ 1, HB_UInt
) )
5751 for ( n
= 0; n
< ls
->FeatureCount
; n
++ )
5753 if ( fi
[n
] >= fl
->FeatureCount
)
5756 return ERR(HB_Err_Invalid_SubTable_Format
);
5758 ftl
[n
] = fr
[fi
[n
]].FeatureTag
;
5762 *feature_tag_list
= ftl
;
5768 /* Do an individual subtable lookup. Returns HB_Err_Ok if positioning
5769 has been done, or HB_Err_Not_Covered if not. */
5770 static HB_Error
GPOS_Do_Glyph_Lookup( GPOS_Instance
* gpi
,
5771 HB_UShort lookup_index
,
5773 HB_UShort context_length
,
5776 HB_Error error
= HB_Err_Not_Covered
;
5777 HB_UShort i
, flags
, lookup_count
;
5778 HB_GPOSHeader
* gpos
= gpi
->gpos
;
5785 if ( nesting_level
> HB_MAX_NESTING_LEVEL
)
5786 return ERR(HB_Err_Not_Covered
); /* ERR() call intended */
5788 lookup_count
= gpos
->LookupList
.LookupCount
;
5789 if (lookup_index
>= lookup_count
)
5792 lo
= &gpos
->LookupList
.Lookup
[lookup_index
];
5793 flags
= lo
->LookupFlag
;
5794 lookup_type
= lo
->LookupType
;
5796 for ( i
= 0; i
< lo
->SubTableCount
; i
++ )
5798 HB_GPOS_SubTable
*st
= &lo
->SubTable
[i
].st
.gpos
;
5800 switch (lookup_type
) {
5801 case HB_GPOS_LOOKUP_SINGLE
:
5802 error
= Lookup_SinglePos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5803 case HB_GPOS_LOOKUP_PAIR
:
5804 error
= Lookup_PairPos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5805 case HB_GPOS_LOOKUP_CURSIVE
:
5806 error
= Lookup_CursivePos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5807 case HB_GPOS_LOOKUP_MARKBASE
:
5808 error
= Lookup_MarkBasePos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5809 case HB_GPOS_LOOKUP_MARKLIG
:
5810 error
= Lookup_MarkLigPos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5811 case HB_GPOS_LOOKUP_MARKMARK
:
5812 error
= Lookup_MarkMarkPos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5813 case HB_GPOS_LOOKUP_CONTEXT
:
5814 error
= Lookup_ContextPos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5815 case HB_GPOS_LOOKUP_CHAIN
:
5816 error
= Lookup_ChainContextPos ( gpi
, st
, buffer
, flags
, context_length
, nesting_level
); break;
5817 /*case HB_GPOS_LOOKUP_EXTENSION:
5818 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5820 error
= HB_Err_Not_Covered
;
5823 /* Check whether we have a successful positioning or an error other
5824 than HB_Err_Not_Covered */
5825 if ( error
!= HB_Err_Not_Covered
)
5829 return HB_Err_Not_Covered
;
5833 HB_INTERNAL HB_Error
5834 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable
* st
,
5836 HB_UShort lookup_type
)
5838 switch ( lookup_type
) {
5839 case HB_GPOS_LOOKUP_SINGLE
: return Load_SinglePos ( st
, stream
);
5840 case HB_GPOS_LOOKUP_PAIR
: return Load_PairPos ( st
, stream
);
5841 case HB_GPOS_LOOKUP_CURSIVE
: return Load_CursivePos ( st
, stream
);
5842 case HB_GPOS_LOOKUP_MARKBASE
: return Load_MarkBasePos ( st
, stream
);
5843 case HB_GPOS_LOOKUP_MARKLIG
: return Load_MarkLigPos ( st
, stream
);
5844 case HB_GPOS_LOOKUP_MARKMARK
: return Load_MarkMarkPos ( st
, stream
);
5845 case HB_GPOS_LOOKUP_CONTEXT
: return Load_ContextPos ( st
, stream
);
5846 case HB_GPOS_LOOKUP_CHAIN
: return Load_ChainContextPos ( st
, stream
);
5847 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/
5848 default: return ERR(HB_Err_Invalid_SubTable_Format
);
5854 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable
* st
,
5855 HB_UShort lookup_type
)
5857 switch ( lookup_type
) {
5858 case HB_GPOS_LOOKUP_SINGLE
: Free_SinglePos ( st
); return;
5859 case HB_GPOS_LOOKUP_PAIR
: Free_PairPos ( st
); return;
5860 case HB_GPOS_LOOKUP_CURSIVE
: Free_CursivePos ( st
); return;
5861 case HB_GPOS_LOOKUP_MARKBASE
: Free_MarkBasePos ( st
); return;
5862 case HB_GPOS_LOOKUP_MARKLIG
: Free_MarkLigPos ( st
); return;
5863 case HB_GPOS_LOOKUP_MARKMARK
: Free_MarkMarkPos ( st
); return;
5864 case HB_GPOS_LOOKUP_CONTEXT
: Free_ContextPos ( st
); return;
5865 case HB_GPOS_LOOKUP_CHAIN
: Free_ChainContextPos ( st
); return;
5866 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/
5872 /* apply one lookup to the input string object */
5874 static HB_Error
GPOS_Do_String_Lookup( GPOS_Instance
* gpi
,
5875 HB_UShort lookup_index
,
5878 HB_Error error
, retError
= HB_Err_Not_Covered
;
5879 HB_GPOSHeader
* gpos
= gpi
->gpos
;
5881 HB_UInt
* properties
= gpos
->LookupList
.Properties
;
5883 const int nesting_level
= 0;
5884 /* 0xFFFF indicates that we don't have a context length yet */
5885 const HB_UShort context_length
= 0xFFFF;
5888 gpi
->last
= 0xFFFF; /* no last valid glyph for cursive pos. */
5891 while ( buffer
->in_pos
< buffer
->in_length
)
5893 if ( ~IN_PROPERTIES( buffer
->in_pos
) & properties
[lookup_index
] )
5895 /* Note that the connection between mark and base glyphs hold
5896 exactly one (string) lookup. For example, it would be possible
5897 that in the first lookup, mark glyph X is attached to base
5898 glyph A, and in the next lookup it is attached to base glyph B.
5899 It is up to the font designer to provide meaningful lookups and
5902 error
= GPOS_Do_Glyph_Lookup( gpi
, lookup_index
, buffer
, context_length
, nesting_level
);
5903 if ( error
&& error
!= HB_Err_Not_Covered
)
5908 /* Contrary to properties defined in GDEF, user-defined properties
5909 will always stop a possible cursive positioning. */
5912 error
= HB_Err_Not_Covered
;
5915 if ( error
== HB_Err_Not_Covered
)
5925 static HB_Error
Position_CursiveChain ( HB_Buffer buffer
)
5928 HB_Position positions
= buffer
->positions
;
5930 /* First handle all left-to-right connections */
5931 for (j
= 0; j
< buffer
->in_length
; j
++)
5933 if (positions
[j
].cursive_chain
> 0)
5934 positions
[j
].y_pos
+= positions
[j
- positions
[j
].cursive_chain
].y_pos
;
5937 /* Then handle all right-to-left connections */
5938 for (i
= buffer
->in_length
; i
> 0; i
--)
5942 if (positions
[j
].cursive_chain
< 0)
5943 positions
[j
].y_pos
+= positions
[j
- positions
[j
].cursive_chain
].y_pos
;
5950 HB_Error
HB_GPOS_Add_Feature( HB_GPOSHeader
* gpos
,
5951 HB_UShort feature_index
,
5957 HB_UInt
* properties
;
5959 HB_UShort lookup_count
;
5961 /* Each feature can only be added once */
5964 feature_index
>= gpos
->FeatureList
.FeatureCount
||
5965 gpos
->FeatureList
.ApplyCount
== gpos
->FeatureList
.FeatureCount
)
5966 return ERR(HB_Err_Invalid_Argument
);
5968 gpos
->FeatureList
.ApplyOrder
[gpos
->FeatureList
.ApplyCount
++] = feature_index
;
5970 properties
= gpos
->LookupList
.Properties
;
5972 feature
= gpos
->FeatureList
.FeatureRecord
[feature_index
].Feature
;
5973 index
= feature
.LookupListIndex
;
5974 lookup_count
= gpos
->LookupList
.LookupCount
;
5976 for ( i
= 0; i
< feature
.LookupListCount
; i
++ )
5978 HB_UShort lookup_index
= index
[i
];
5979 if (lookup_index
< lookup_count
)
5980 properties
[lookup_index
] |= property
;
5988 HB_Error
HB_GPOS_Clear_Features( HB_GPOSHeader
* gpos
)
5992 HB_UInt
* properties
;
5996 return ERR(HB_Err_Invalid_Argument
);
5998 gpos
->FeatureList
.ApplyCount
= 0;
6000 properties
= gpos
->LookupList
.Properties
;
6002 for ( i
= 0; i
< gpos
->LookupList
.LookupCount
; i
++ )
6008 #ifdef HB_SUPPORT_MULTIPLE_MASTER
6009 HB_Error
HB_GPOS_Register_MM_Function( HB_GPOSHeader
* gpos
,
6010 HB_MMFunction mmfunc
,
6014 return ERR(HB_Err_Invalid_Argument
);
6016 gpos
->mmfunc
= mmfunc
;
6023 /* If `dvi' is TRUE, glyph contour points for anchor points and device
6024 tables are ignored -- you will get device independent values. */
6027 HB_Error
HB_GPOS_Apply_String( HB_Font font
,
6028 HB_GPOSHeader
* gpos
,
6029 HB_UShort load_flags
,
6034 HB_Error error
, retError
= HB_Err_Not_Covered
;
6036 int i
, j
, lookup_count
, num_features
;
6038 if ( !font
|| !gpos
|| !buffer
)
6039 return ERR(HB_Err_Invalid_Argument
);
6041 if ( buffer
->in_length
== 0 )
6042 return HB_Err_Not_Covered
;
6046 gpi
.load_flags
= load_flags
;
6050 lookup_count
= gpos
->LookupList
.LookupCount
;
6051 num_features
= gpos
->FeatureList
.ApplyCount
;
6055 error
= _hb_buffer_clear_positions( buffer
);
6060 for ( i
= 0; i
< num_features
; i
++ )
6062 HB_UShort feature_index
= gpos
->FeatureList
.ApplyOrder
[i
];
6063 HB_Feature feature
= gpos
->FeatureList
.FeatureRecord
[feature_index
].Feature
;
6065 for ( j
= 0; j
< feature
.LookupListCount
; j
++ )
6067 HB_UShort lookup_index
= feature
.LookupListIndex
[j
];
6069 /* Skip nonexistant lookups */
6070 if (lookup_index
>= lookup_count
)
6073 error
= GPOS_Do_String_Lookup( &gpi
, lookup_index
, buffer
);
6076 if ( error
!= HB_Err_Not_Covered
)
6086 error
= Position_CursiveChain ( buffer
);