Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / third_party / harfbuzz / src / harfbuzz-gpos.c
blobe969a0130985fcf29e279a150813c7dca1e8365c
1 /*
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
18 * DAMAGE.
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"
35 struct GPOS_Instance_
37 HB_GPOSHeader* gpos;
38 HB_Font font;
39 HB_Bool dvi;
40 HB_UShort load_flags; /* how the glyph should be loaded */
41 HB_Bool r2l;
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,
54 HB_Buffer buffer,
55 HB_UShort context_length,
56 int nesting_level );
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,
65 HB_UShort metric_id,
66 HB_Fixed* metric_value,
67 void* data )
69 HB_UNUSED(font);
70 HB_UNUSED(metric_id);
71 HB_UNUSED(metric_value);
72 HB_UNUSED(data);
73 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
75 #endif
79 HB_Error HB_Load_GPOS_Table( HB_Stream stream,
80 HB_GPOSHeader** retptr,
81 HB_GDEFHeader* gdef,
82 HB_Stream gdefStream )
84 HB_UInt cur_offset, new_offset, base_offset;
86 HB_GPOSHeader* gpos;
88 HB_Error error;
91 if ( !retptr )
92 return ERR(HB_Err_Invalid_Argument);
94 if ( GOTO_Table( TTAG_GPOS ) )
95 return error;
97 base_offset = FILE_Pos();
99 if ( ALLOC ( gpos, sizeof( *gpos ) ) )
100 return error;
102 #ifdef HB_SUPPORT_MULTIPLE_MASTER
103 gpos->mmfunc = default_mmfunc;
104 #endif
106 /* skip version */
108 if ( FILE_Seek( base_offset + 4L ) ||
109 ACCESS_Frame( 2L ) )
110 goto Fail4;
112 new_offset = GET_UShort() + base_offset;
114 FORGET_Frame();
116 cur_offset = FILE_Pos();
117 if ( FILE_Seek( new_offset ) ||
118 ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
119 stream ) ) != HB_Err_Ok )
120 goto Fail4;
121 (void)FILE_Seek( cur_offset );
123 if ( ACCESS_Frame( 2L ) )
124 goto Fail3;
126 new_offset = GET_UShort() + base_offset;
128 FORGET_Frame();
130 cur_offset = FILE_Pos();
131 if ( FILE_Seek( new_offset ) ||
132 ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
133 stream ) ) != HB_Err_Ok )
134 goto Fail3;
135 (void)FILE_Seek( cur_offset );
137 if ( ACCESS_Frame( 2L ) )
138 goto Fail2;
140 new_offset = GET_UShort() + base_offset;
142 FORGET_Frame();
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 )
148 goto Fail2;
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 ) ) )
155 goto Fail1;
157 *retptr = gpos;
159 return HB_Err_Ok;
161 Fail1:
162 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
164 Fail2:
165 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
167 Fail3:
168 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
170 Fail4:
171 FREE( gpos );
173 return error;
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 );
183 FREE( gpos );
185 return HB_Err_Ok;
189 /*****************************
190 * SubTable related functions
191 *****************************/
193 /* shared tables */
195 /* ValueRecord */
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,
202 HB_UShort format,
203 HB_UInt base_offset,
204 HB_Stream stream )
206 HB_Error error;
208 HB_UInt cur_offset, new_offset;
211 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
213 if ( ACCESS_Frame( 2L ) )
214 return error;
216 vr->XPlacement = GET_Short();
218 FORGET_Frame();
220 else
221 vr->XPlacement = 0;
223 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
225 if ( ACCESS_Frame( 2L ) )
226 return error;
228 vr->YPlacement = GET_Short();
230 FORGET_Frame();
232 else
233 vr->YPlacement = 0;
235 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
237 if ( ACCESS_Frame( 2L ) )
238 return error;
240 vr->XAdvance = GET_Short();
242 FORGET_Frame();
244 else
245 vr->XAdvance = 0;
247 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
249 if ( ACCESS_Frame( 2L ) )
250 return error;
252 vr->YAdvance = GET_Short();
254 FORGET_Frame();
256 else
257 vr->YAdvance = 0;
259 if ( format & HB_GPOS_FORMAT_HAVE_DEVICE_TABLES )
261 if ( ALLOC_ARRAY( vr->DeviceTables, 4, HB_Device ) )
262 return error;
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;
268 else
270 vr->DeviceTables = 0;
273 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
275 if ( ACCESS_Frame( 2L ) )
276 goto Fail4;
278 new_offset = GET_UShort();
280 FORGET_Frame();
282 if ( new_offset )
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 )
290 goto Fail4;
291 (void)FILE_Seek( cur_offset );
295 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
297 if ( ACCESS_Frame( 2L ) )
298 goto Fail3;
300 new_offset = GET_UShort();
302 FORGET_Frame();
304 if ( new_offset )
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 )
312 goto Fail3;
313 (void)FILE_Seek( cur_offset );
317 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
319 if ( ACCESS_Frame( 2L ) )
320 goto Fail2;
322 new_offset = GET_UShort();
324 FORGET_Frame();
326 if ( new_offset )
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 )
334 goto Fail2;
335 (void)FILE_Seek( cur_offset );
339 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
341 if ( ACCESS_Frame( 2L ) )
342 goto Fail1;
344 new_offset = GET_UShort();
346 FORGET_Frame();
348 if ( new_offset )
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 )
356 goto Fail1;
357 (void)FILE_Seek( cur_offset );
361 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
363 if ( ACCESS_Frame( 2L ) )
364 goto Fail1;
366 #ifdef HB_SUPPORT_MULTIPLE_MASTER
367 vr->XIdPlacement = GET_UShort();
368 #else
369 (void) GET_UShort();
370 #endif
372 FORGET_Frame();
374 #ifdef HB_SUPPORT_MULTIPLE_MASTER
375 else
376 vr->XIdPlacement = 0;
377 #endif
379 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
381 if ( ACCESS_Frame( 2L ) )
382 goto Fail1;
384 #ifdef HB_SUPPORT_MULTIPLE_MASTER
385 vr->YIdPlacement = GET_UShort();
386 #else
387 (void) GET_UShort();
388 #endif
390 FORGET_Frame();
392 #ifdef HB_SUPPORT_MULTIPLE_MASTER
393 else
394 vr->YIdPlacement = 0;
395 #endif
397 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
399 if ( ACCESS_Frame( 2L ) )
400 goto Fail1;
402 #ifdef HB_SUPPORT_MULTIPLE_MASTER
403 vr->XIdAdvance = GET_UShort();
404 #else
405 (void) GET_UShort();
406 #endif
408 FORGET_Frame();
410 #ifdef HB_SUPPORT_MULTIPLE_MASTER
411 else
412 vr->XIdAdvance = 0;
413 #endif
415 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
417 if ( ACCESS_Frame( 2L ) )
418 goto Fail1;
420 #ifdef HB_SUPPORT_MULTIPLE_MASTER
421 vr->YIdAdvance = GET_UShort();
422 #else
423 (void) GET_UShort();
424 #endif
426 FORGET_Frame();
428 #ifdef HB_SUPPORT_MULTIPLE_MASTER
429 else
430 vr->YIdAdvance = 0;
431 #endif
433 return HB_Err_Ok;
435 Fail1:
436 if ( vr->DeviceTables )
437 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] );
439 Fail2:
440 if ( vr->DeviceTables )
441 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] );
443 Fail3:
444 if ( vr->DeviceTables )
445 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] );
447 Fail4:
448 FREE( vr->DeviceTables );
449 return error;
453 static void Free_ValueRecord( HB_ValueRecord* vr,
454 HB_UShort format )
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,
469 HB_ValueRecord* vr,
470 HB_UShort format,
471 HB_Position gd )
473 HB_Short pixel_value;
474 HB_Error error = HB_Err_Ok;
475 #ifdef HB_SUPPORT_MULTIPLE_MASTER
476 HB_GPOSHeader* gpos = gpi->gpos;
477 HB_Fixed value;
478 #endif
480 HB_UShort x_ppem, y_ppem;
481 HB_16Dot16 x_scale, y_scale;
484 if ( !format )
485 return HB_Err_Ok;
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;
503 if ( !gpi->dvi )
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 );
536 if ( error )
537 return error;
538 gd->x_pos += value;
540 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
542 error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
543 &value, gpos->data );
544 if ( error )
545 return error;
546 gd->y_pos += value;
548 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
550 error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
551 &value, gpos->data );
552 if ( error )
553 return error;
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 );
560 if ( error )
561 return error;
562 gd->y_advance += value;
564 #endif
566 return error;
570 /* AnchorFormat1 */
571 /* AnchorFormat2 */
572 /* AnchorFormat3 */
573 /* AnchorFormat4 */
575 static HB_Error Load_Anchor( HB_Anchor* an,
576 HB_Stream stream )
578 HB_Error error;
580 HB_UInt cur_offset, new_offset, base_offset;
583 base_offset = FILE_Pos();
585 if ( ACCESS_Frame( 2L ) )
586 return error;
588 an->PosFormat = GET_UShort();
590 FORGET_Frame();
592 switch ( an->PosFormat )
594 case 1:
595 if ( ACCESS_Frame( 4L ) )
596 return error;
598 an->af.af1.XCoordinate = GET_Short();
599 an->af.af1.YCoordinate = GET_Short();
601 FORGET_Frame();
602 break;
604 case 2:
605 if ( ACCESS_Frame( 6L ) )
606 return error;
608 an->af.af2.XCoordinate = GET_Short();
609 an->af.af2.YCoordinate = GET_Short();
610 an->af.af2.AnchorPoint = GET_UShort();
612 FORGET_Frame();
613 break;
615 case 3:
616 if ( ACCESS_Frame( 6L ) )
617 return error;
619 an->af.af3.XCoordinate = GET_Short();
620 an->af.af3.YCoordinate = GET_Short();
622 new_offset = GET_UShort();
624 FORGET_Frame();
626 if ( new_offset )
628 if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) )
629 return error;
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 )
640 goto Fail2;
641 (void)FILE_Seek( cur_offset );
644 if ( ACCESS_Frame( 2L ) )
645 goto Fail;
647 new_offset = GET_UShort();
649 FORGET_Frame();
651 if ( new_offset )
653 if ( !an->af.af3.DeviceTables )
655 if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) )
656 return error;
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 )
668 goto Fail;
669 (void)FILE_Seek( cur_offset );
671 break;
673 case 4:
674 if ( ACCESS_Frame( 4L ) )
675 return error;
677 #ifdef HB_SUPPORT_MULTIPLE_MASTER
678 an->af.af4.XIdAnchor = GET_UShort();
679 an->af.af4.YIdAnchor = GET_UShort();
680 #else
681 (void) GET_UShort();
682 (void) GET_UShort();
683 #endif
685 FORGET_Frame();
686 break;
688 default:
689 return ERR(HB_Err_Invalid_SubTable_Format);
692 return HB_Err_Ok;
694 Fail:
695 if ( an->af.af3.DeviceTables )
696 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] );
698 Fail2:
699 FREE( an->af.af3.DeviceTables );
700 return error;
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,
716 HB_Anchor* an,
717 HB_UShort glyph_index,
718 HB_Fixed* x_value,
719 HB_Fixed* y_value )
721 HB_Error error = HB_Err_Ok;
723 #ifdef HB_SUPPORT_MULTIPLE_MASTER
724 HB_GPOSHeader* gpos = gpi->gpos;
725 #endif
726 HB_UShort ap;
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 )
741 case 0:
742 /* The special case of an empty AnchorTable */
743 default:
745 return HB_Err_Not_Covered;
747 case 1:
748 *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
749 *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
750 break;
752 case 2:
753 if ( !gpi->dvi )
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);
760 if (error)
761 return error;
762 /* if n_points is set to zero, we use the design coordinate value pair.
763 * This can happen e.g. for sbit glyphs. */
764 if (!n_points)
765 goto no_contour_point;
767 else
769 no_contour_point:
770 *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
771 *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
773 break;
775 case 3:
776 if ( !gpi->dvi )
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;
783 else
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;
788 break;
790 case 4:
791 #ifdef HB_SUPPORT_MULTIPLE_MASTER
792 error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
793 x_value, gpos->data );
794 if ( error )
795 return error;
797 error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
798 y_value, gpos->data );
799 if ( error )
800 return error;
801 break;
802 #else
803 return ERR(HB_Err_Not_Covered);
804 #endif
807 return error;
811 /* MarkArray */
813 static HB_Error Load_MarkArray ( HB_MarkArray* ma,
814 HB_Stream stream )
816 HB_Error error;
818 HB_UShort n, m, count;
819 HB_UInt cur_offset, new_offset, base_offset;
821 HB_MarkRecord* mr;
824 base_offset = FILE_Pos();
826 if ( ACCESS_Frame( 2L ) )
827 return error;
829 count = ma->MarkCount = GET_UShort();
831 FORGET_Frame();
833 ma->MarkRecord = NULL;
835 if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
836 return error;
838 mr = ma->MarkRecord;
840 for ( n = 0; n < count; n++ )
842 if ( ACCESS_Frame( 4L ) )
843 goto Fail;
845 mr[n].Class = GET_UShort();
846 new_offset = GET_UShort() + base_offset;
848 FORGET_Frame();
850 cur_offset = FILE_Pos();
851 if ( FILE_Seek( new_offset ) ||
852 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
853 goto Fail;
854 (void)FILE_Seek( cur_offset );
857 return HB_Err_Ok;
859 Fail:
860 for ( m = 0; m < n; m++ )
861 Free_Anchor( &mr[m].MarkAnchor );
863 FREE( mr );
864 return error;
868 static void Free_MarkArray( HB_MarkArray* ma )
870 HB_UShort n, count;
872 HB_MarkRecord* mr;
875 if ( ma->MarkRecord )
877 count = ma->MarkCount;
878 mr = ma->MarkRecord;
880 for ( n = 0; n < count; n++ )
881 Free_Anchor( &mr[n].MarkAnchor );
883 FREE( mr );
888 /* LookupType 1 */
890 /* SinglePosFormat1 */
891 /* SinglePosFormat2 */
893 static HB_Error Load_SinglePos( HB_GPOS_SubTable* st,
894 HB_Stream stream )
896 HB_Error error;
897 HB_SinglePos* sp = &st->single;
899 HB_UShort n, m, count, format;
900 HB_UInt cur_offset, new_offset, base_offset;
902 HB_ValueRecord* vr;
905 base_offset = FILE_Pos();
907 if ( ACCESS_Frame( 6L ) )
908 return error;
910 sp->PosFormat = GET_UShort();
911 new_offset = GET_UShort() + base_offset;
913 format = sp->ValueFormat = GET_UShort();
915 FORGET_Frame();
917 if ( !format )
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 )
923 return error;
924 (void)FILE_Seek( cur_offset );
926 switch ( sp->PosFormat )
928 case 1:
929 error = Load_ValueRecord( &sp->spf.spf1.Value, format,
930 base_offset, stream );
931 if ( error )
932 goto Fail2;
933 break;
935 case 2:
936 if ( ACCESS_Frame( 2L ) )
937 goto Fail2;
939 count = sp->spf.spf2.ValueCount = GET_UShort();
941 FORGET_Frame();
943 sp->spf.spf2.Value = NULL;
945 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
946 goto Fail2;
948 vr = sp->spf.spf2.Value;
950 for ( n = 0; n < count; n++ )
952 error = Load_ValueRecord( &vr[n], format, base_offset, stream );
953 if ( error )
954 goto Fail1;
956 break;
958 default:
959 return ERR(HB_Err_Invalid_SubTable_Format);
962 return HB_Err_Ok;
964 Fail1:
965 for ( m = 0; m < n; m++ )
966 Free_ValueRecord( &vr[m], format );
968 FREE( vr );
970 Fail2:
971 _HB_OPEN_Free_Coverage( &sp->Coverage );
972 return error;
976 static void Free_SinglePos( HB_GPOS_SubTable* st )
978 HB_UShort n, count, format;
979 HB_SinglePos* sp = &st->single;
981 HB_ValueRecord* v;
984 format = sp->ValueFormat;
986 switch ( sp->PosFormat )
988 case 1:
989 Free_ValueRecord( &sp->spf.spf1.Value, format );
990 break;
992 case 2:
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 );
1001 FREE( v );
1003 break;
1004 default:
1005 break;
1008 _HB_OPEN_Free_Coverage( &sp->Coverage );
1011 static HB_Error Lookup_SinglePos( GPOS_Instance* gpi,
1012 HB_GPOS_SubTable* st,
1013 HB_Buffer buffer,
1014 HB_UShort flags,
1015 HB_UShort context_length,
1016 int nesting_level )
1018 HB_UShort index, property;
1019 HB_Error error;
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 ) )
1029 return error;
1031 error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
1032 if ( error )
1033 return error;
1035 switch ( sp->PosFormat )
1037 case 1:
1038 error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
1039 sp->ValueFormat, POSITION( buffer->in_pos ) );
1040 if ( error )
1041 return error;
1042 break;
1044 case 2:
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 ) );
1049 if ( error )
1050 return error;
1051 break;
1053 default:
1054 return ERR(HB_Err_Invalid_SubTable);
1057 (buffer->in_pos)++;
1059 return HB_Err_Ok;
1063 /* LookupType 2 */
1065 /* PairSet */
1067 static HB_Error Load_PairSet ( HB_PairSet* ps,
1068 HB_UShort format1,
1069 HB_UShort format2,
1070 HB_Stream stream )
1072 HB_Error error;
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 ) )
1083 return error;
1085 count = ps->PairValueCount = GET_UShort();
1087 FORGET_Frame();
1089 ps->PairValueRecord = NULL;
1091 if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
1092 return error;
1094 pvr = ps->PairValueRecord;
1096 for ( n = 0; n < count; n++ )
1098 if ( ACCESS_Frame( 2L ) )
1099 goto Fail;
1101 pvr[n].SecondGlyph = GET_UShort();
1103 FORGET_Frame();
1105 if ( format1 )
1107 error = Load_ValueRecord( &pvr[n].Value1, format1,
1108 base_offset, stream );
1109 if ( error )
1110 goto Fail;
1112 if ( format2 )
1114 error = Load_ValueRecord( &pvr[n].Value2, format2,
1115 base_offset, stream );
1116 if ( error )
1118 if ( format1 )
1119 Free_ValueRecord( &pvr[n].Value1, format1 );
1120 goto Fail;
1125 return HB_Err_Ok;
1127 Fail:
1128 for ( m = 0; m < n; m++ )
1130 if ( format1 )
1131 Free_ValueRecord( &pvr[m].Value1, format1 );
1132 if ( format2 )
1133 Free_ValueRecord( &pvr[m].Value2, format2 );
1136 FREE( pvr );
1137 return error;
1141 static void Free_PairSet( HB_PairSet* ps,
1142 HB_UShort format1,
1143 HB_UShort format2 )
1145 HB_UShort n, count;
1147 HB_PairValueRecord* pvr;
1150 if ( ps->PairValueRecord )
1152 count = ps->PairValueCount;
1153 pvr = ps->PairValueRecord;
1155 for ( n = 0; n < count; n++ )
1157 if ( format1 )
1158 Free_ValueRecord( &pvr[n].Value1, format1 );
1159 if ( format2 )
1160 Free_ValueRecord( &pvr[n].Value2, format2 );
1163 FREE( pvr );
1168 /* PairPosFormat1 */
1170 static HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
1171 HB_UShort format1,
1172 HB_UShort format2,
1173 HB_Stream stream )
1175 HB_Error error;
1177 HB_UShort n, m, count;
1178 HB_UInt cur_offset, new_offset, base_offset;
1180 HB_PairSet* ps;
1183 base_offset = FILE_Pos() - 8L;
1185 if ( ACCESS_Frame( 2L ) )
1186 return error;
1188 count = ppf1->PairSetCount = GET_UShort();
1190 FORGET_Frame();
1192 ppf1->PairSet = NULL;
1194 if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
1195 return error;
1197 ps = ppf1->PairSet;
1199 for ( n = 0; n < count; n++ )
1201 if ( ACCESS_Frame( 2L ) )
1202 goto Fail;
1204 new_offset = GET_UShort() + base_offset;
1206 FORGET_Frame();
1208 cur_offset = FILE_Pos();
1209 if ( FILE_Seek( new_offset ) ||
1210 ( error = Load_PairSet( &ps[n], format1,
1211 format2, stream ) ) != HB_Err_Ok )
1212 goto Fail;
1213 (void)FILE_Seek( cur_offset );
1216 return HB_Err_Ok;
1218 Fail:
1219 for ( m = 0; m < n; m++ )
1220 Free_PairSet( &ps[m], format1, format2 );
1222 FREE( ps );
1223 return error;
1227 static void Free_PairPos1( HB_PairPosFormat1* ppf1,
1228 HB_UShort format1,
1229 HB_UShort format2 )
1231 HB_UShort n, count;
1233 HB_PairSet* ps;
1236 if ( ppf1->PairSet )
1238 count = ppf1->PairSetCount;
1239 ps = ppf1->PairSet;
1241 for ( n = 0; n < count; n++ )
1242 Free_PairSet( &ps[n], format1, format2 );
1244 FREE( ps );
1249 /* PairPosFormat2 */
1251 static HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
1252 HB_UShort format1,
1253 HB_UShort format2,
1254 HB_Stream stream )
1256 HB_Error error;
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 ) )
1268 return error;
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();
1279 FORGET_Frame();
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 )
1285 return error;
1286 if ( FILE_Seek( new_offset2 ) ||
1287 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
1288 stream ) ) != HB_Err_Ok )
1289 goto Fail3;
1290 (void)FILE_Seek( cur_offset );
1292 ppf2->Class1Record = NULL;
1294 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
1295 goto Fail2;
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 ) )
1304 goto Fail1;
1306 c2r = c1r[m].Class2Record;
1308 for ( n = 0; n < count2; n++ )
1310 if ( format1 )
1312 error = Load_ValueRecord( &c2r[n].Value1, format1,
1313 base_offset, stream );
1314 if ( error )
1315 goto Fail0;
1317 if ( format2 )
1319 error = Load_ValueRecord( &c2r[n].Value2, format2,
1320 base_offset, stream );
1321 if ( error )
1323 if ( format1 )
1324 Free_ValueRecord( &c2r[n].Value1, format1 );
1325 goto Fail0;
1330 continue;
1332 Fail0:
1333 for ( k = 0; k < n; k++ )
1335 if ( format1 )
1336 Free_ValueRecord( &c2r[k].Value1, format1 );
1337 if ( format2 )
1338 Free_ValueRecord( &c2r[k].Value2, format2 );
1340 goto Fail1;
1343 return HB_Err_Ok;
1345 Fail1:
1346 for ( k = 0; k < m; k++ )
1348 c2r = c1r[k].Class2Record;
1350 for ( n = 0; n < count2; n++ )
1352 if ( format1 )
1353 Free_ValueRecord( &c2r[n].Value1, format1 );
1354 if ( format2 )
1355 Free_ValueRecord( &c2r[n].Value2, format2 );
1358 FREE( c2r );
1361 FREE( c1r );
1362 Fail2:
1364 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1366 Fail3:
1367 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1368 return error;
1372 static void Free_PairPos2( HB_PairPosFormat2* ppf2,
1373 HB_UShort format1,
1374 HB_UShort format2)
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++ )
1394 if ( format1 )
1395 Free_ValueRecord( &c2r[n].Value1, format1 );
1396 if ( format2 )
1397 Free_ValueRecord( &c2r[n].Value2, format2 );
1400 FREE( c2r );
1403 FREE( c1r );
1405 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1406 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1411 static HB_Error Load_PairPos( HB_GPOS_SubTable* st,
1412 HB_Stream stream )
1414 HB_Error error;
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 ) )
1424 return error;
1426 pp->PosFormat = GET_UShort();
1427 new_offset = GET_UShort() + base_offset;
1429 format1 = pp->ValueFormat1 = GET_UShort();
1430 format2 = pp->ValueFormat2 = GET_UShort();
1432 FORGET_Frame();
1434 cur_offset = FILE_Pos();
1435 if ( FILE_Seek( new_offset ) ||
1436 ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
1437 return error;
1438 (void)FILE_Seek( cur_offset );
1440 switch ( pp->PosFormat )
1442 case 1:
1443 error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
1444 if ( error )
1445 goto Fail;
1446 break;
1448 case 2:
1449 error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
1450 if ( error )
1451 goto Fail;
1452 break;
1454 default:
1455 return ERR(HB_Err_Invalid_SubTable_Format);
1458 return HB_Err_Ok;
1460 Fail:
1461 _HB_OPEN_Free_Coverage( &pp->Coverage );
1462 return error;
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 )
1477 case 1:
1478 Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
1479 break;
1481 case 2:
1482 Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
1483 break;
1485 default:
1486 break;
1489 _HB_OPEN_Free_Coverage( &pp->Coverage );
1493 static HB_Error Lookup_PairPos1( GPOS_Instance* gpi,
1494 HB_PairPosFormat1* ppf1,
1495 HB_Buffer buffer,
1496 HB_UInt first_pos,
1497 HB_UShort index,
1498 HB_UShort format1,
1499 HB_UShort format2 )
1501 HB_Error error;
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;
1511 if ( !pvr )
1512 return ERR(HB_Err_Invalid_SubTable);
1514 glyph2 = IN_CURGLYPH();
1516 for ( numpvr = ppf1->PairSet[index].PairValueCount;
1517 numpvr;
1518 numpvr--, pvr++ )
1520 if ( glyph2 == pvr->SecondGlyph )
1522 error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1523 POSITION( first_pos ) );
1524 if ( error )
1525 return error;
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,
1537 HB_Buffer buffer,
1538 HB_UInt first_pos,
1539 HB_UShort format1,
1540 HB_UShort format2 )
1542 HB_Error error;
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 ),
1550 &cl1, NULL );
1551 if ( error && error != HB_Err_Not_Covered )
1552 return error;
1553 error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1554 &cl2, NULL );
1555 if ( error && error != HB_Err_Not_Covered )
1556 return error;
1558 c1r = &ppf2->Class1Record[cl1];
1559 if ( !c1r )
1560 return ERR(HB_Err_Invalid_SubTable);
1561 c2r = &c1r->Class2Record[cl2];
1563 error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1564 if ( error )
1565 return error;
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,
1572 HB_Buffer buffer,
1573 HB_UShort flags,
1574 HB_UShort context_length,
1575 int nesting_level )
1577 HB_Error error;
1578 HB_UShort index, property;
1579 HB_UInt first_pos;
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 ) )
1592 return error;
1594 error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1595 if ( error )
1596 return error;
1598 /* second glyph */
1600 first_pos = buffer->in_pos;
1601 (buffer->in_pos)++;
1603 while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
1604 flags, &property ) )
1606 if ( error && error != HB_Err_Not_Covered )
1607 return error;
1609 if ( buffer->in_pos == buffer->in_length )
1611 buffer->in_pos = first_pos;
1612 return HB_Err_Not_Covered;
1614 (buffer->in_pos)++;
1618 switch ( pp->PosFormat )
1620 case 1:
1621 error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1622 first_pos, index,
1623 pp->ValueFormat1, pp->ValueFormat2 );
1624 break;
1626 case 2:
1627 error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1628 pp->ValueFormat1, pp->ValueFormat2 );
1629 break;
1631 default:
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 )
1644 (buffer->in_pos)++;
1646 return error;
1650 /* LookupType 3 */
1652 /* CursivePosFormat1 */
1654 static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
1655 HB_Stream stream )
1657 HB_Error error;
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 ) )
1669 return error;
1671 cp->PosFormat = GET_UShort();
1672 new_offset = GET_UShort() + base_offset;
1674 FORGET_Frame();
1676 cur_offset = FILE_Pos();
1677 if ( FILE_Seek( new_offset ) ||
1678 ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
1679 return error;
1680 (void)FILE_Seek( cur_offset );
1682 if ( ACCESS_Frame( 2L ) )
1683 goto Fail2;
1685 count = cp->EntryExitCount = GET_UShort();
1687 FORGET_Frame();
1689 cp->EntryExitRecord = NULL;
1691 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1692 goto Fail2;
1694 eer = cp->EntryExitRecord;
1696 for ( n = 0; n < count; n++ )
1698 HB_UInt entry_offset;
1700 if ( ACCESS_Frame( 2L ) )
1701 return error;
1703 entry_offset = new_offset = GET_UShort();
1705 FORGET_Frame();
1707 if ( new_offset )
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 )
1715 goto Fail1;
1716 (void)FILE_Seek( cur_offset );
1718 else
1719 eer[n].EntryAnchor.PosFormat = 0;
1721 if ( ACCESS_Frame( 2L ) )
1722 return error;
1724 new_offset = GET_UShort();
1726 FORGET_Frame();
1728 if ( new_offset )
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 )
1737 if ( entry_offset )
1738 Free_Anchor( &eer[n].EntryAnchor );
1739 goto Fail1;
1741 (void)FILE_Seek( cur_offset );
1743 else
1744 eer[n].ExitAnchor.PosFormat = 0;
1747 return HB_Err_Ok;
1749 Fail1:
1750 for ( m = 0; m < n; m++ )
1752 Free_Anchor( &eer[m].EntryAnchor );
1753 Free_Anchor( &eer[m].ExitAnchor );
1756 FREE( eer );
1758 Fail2:
1759 _HB_OPEN_Free_Coverage( &cp->Coverage );
1760 return error;
1764 static void Free_CursivePos( HB_GPOS_SubTable* st )
1766 HB_UShort n, count;
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 );
1783 FREE( eer );
1786 _HB_OPEN_Free_Coverage( &cp->Coverage );
1790 static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
1791 HB_GPOS_SubTable* st,
1792 HB_Buffer buffer,
1793 HB_UShort flags,
1794 HB_UShort context_length,
1795 int nesting_level )
1797 HB_UShort index, property;
1798 HB_Error error;
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 )
1810 gpi->last = 0xFFFF;
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 ) )
1818 return error;
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 )
1825 gpi->last = 0xFFFF;
1826 return HB_Err_Not_Covered;
1829 error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1830 if ( error )
1832 gpi->last = 0xFFFF;
1833 return error;
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:
1851 | xadv1 |
1852 +---------+
1854 +-----+--+ 1 |
1855 | | .| |
1856 | 0+--+------+
1857 | 2 |
1859 0+--------+
1860 | xadv2 |
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
1870 coordinate origin.
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
1877 writing directions.
1879 Continuing the above example, we can compute the new
1880 (horizontal) advance width of glyph2 as
1882 9 - 3 = 6 ,
1884 and the new vertical offset of glyph2 as
1886 1 - 4 = -3 .
1889 Vertical writing direction is far more complicated:
1891 a) Assuming that we recompute the advance height of the lower glyph:
1894 +---------+
1895 -- | |
1896 +-----+--+ 1 | yadv1
1897 | | .| |
1898 yadv2 | 0+--+------+ -- BSB1 --
1899 | 2 | -- -- y_offset
1901 BSB2 -- 0+--------+ --
1902 -- --
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)
1915 y_offset = y2 - y1
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:
1926 -- --
1927 +---------+ -- TSB1
1928 -- -- | |
1929 TSB2 -- +-----+--+ 1 | yadv1 ymax1
1930 | | .| |
1931 yadv2 | 0+--+------+ -- --
1932 ymax2 | 2 | -- y_offset
1934 -- 0+--------+ --
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.
1945 y_offset = y2 - y1
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 )
1959 goto end;
1961 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1962 table. */
1964 error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1965 &entry_x, &entry_y );
1966 if ( error == HB_Err_Not_Covered )
1967 goto end;
1968 if ( error )
1969 return error;
1971 if ( gpi->r2l )
1973 POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
1974 POSITION( buffer->in_pos )->new_advance = TRUE;
1976 else
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;
1987 else
1989 POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
1990 POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
1993 end:
1994 error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
1995 &exit_x, &exit_y );
1996 if ( error == HB_Err_Not_Covered )
1997 gpi->last = 0xFFFF;
1998 else
2000 gpi->last = buffer->in_pos;
2001 gpi->anchor_x = exit_x;
2002 gpi->anchor_y = exit_y;
2004 if ( error )
2005 return error;
2007 (buffer->in_pos)++;
2009 return HB_Err_Ok;
2013 /* LookupType 4 */
2015 /* BaseArray */
2017 static HB_Error Load_BaseArray( HB_BaseArray* ba,
2018 HB_UShort num_classes,
2019 HB_Stream stream )
2021 HB_Error error;
2023 HB_UShort m, n, count;
2024 HB_UInt cur_offset, new_offset, base_offset;
2026 HB_BaseRecord *br;
2027 HB_Anchor *ban, *bans;
2030 base_offset = FILE_Pos();
2032 if ( ACCESS_Frame( 2L ) )
2033 return error;
2035 count = ba->BaseCount = GET_UShort();
2037 FORGET_Frame();
2039 ba->BaseRecord = NULL;
2041 if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2042 return error;
2044 br = ba->BaseRecord;
2046 bans = NULL;
2048 if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
2049 goto Fail;
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 ) )
2060 goto Fail;
2062 new_offset = GET_UShort() + base_offset;
2064 FORGET_Frame();
2066 if (new_offset == base_offset) {
2067 /* XXX
2068 * Doulos SIL Regular is buggy and has zero offsets here.
2069 * Skip it
2071 ban[n].PosFormat = 0;
2072 continue;
2075 cur_offset = FILE_Pos();
2076 if ( FILE_Seek( new_offset ) ||
2077 ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
2078 goto Fail;
2079 (void)FILE_Seek( cur_offset );
2083 return HB_Err_Ok;
2085 Fail:
2086 FREE( bans );
2087 FREE( br );
2088 return error;
2092 static void Free_BaseArray( HB_BaseArray* ba,
2093 HB_UShort num_classes )
2095 HB_BaseRecord *br;
2096 HB_Anchor *bans;
2098 if ( ba->BaseRecord )
2100 br = ba->BaseRecord;
2102 if ( ba->BaseCount )
2104 HB_UShort i, count;
2105 count = num_classes * ba->BaseCount;
2106 bans = br[0].BaseAnchor;
2107 for (i = 0; i < count; i++)
2108 Free_Anchor (&bans[i]);
2109 FREE( bans );
2112 FREE( br );
2117 /* MarkBasePosFormat1 */
2119 static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
2120 HB_Stream stream )
2122 HB_Error error;
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 ) )
2131 return error;
2133 mbp->PosFormat = GET_UShort();
2134 new_offset = GET_UShort() + base_offset;
2136 FORGET_Frame();
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 )
2144 return error;
2145 (void)FILE_Seek( cur_offset );
2147 if ( ACCESS_Frame( 2L ) )
2148 goto Fail3;
2150 new_offset = GET_UShort() + base_offset;
2152 FORGET_Frame();
2154 cur_offset = FILE_Pos();
2155 if ( FILE_Seek( new_offset ) ||
2156 ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
2157 goto Fail3;
2158 (void)FILE_Seek( cur_offset );
2160 if ( ACCESS_Frame( 4L ) )
2161 goto Fail2;
2163 mbp->ClassCount = GET_UShort();
2164 new_offset = GET_UShort() + base_offset;
2166 FORGET_Frame();
2168 cur_offset = FILE_Pos();
2169 if ( FILE_Seek( new_offset ) ||
2170 ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
2171 goto Fail2;
2172 (void)FILE_Seek( cur_offset );
2174 if ( ACCESS_Frame( 2L ) )
2175 goto Fail1;
2177 new_offset = GET_UShort() + base_offset;
2179 FORGET_Frame();
2181 cur_offset = FILE_Pos();
2182 if ( FILE_Seek( new_offset ) ||
2183 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2184 stream ) ) != HB_Err_Ok )
2185 goto Fail1;
2187 return HB_Err_Ok;
2189 Fail1:
2190 Free_MarkArray( &mbp->MarkArray );
2192 Fail2:
2193 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2195 Fail3:
2196 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2197 return error;
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,
2214 HB_Buffer buffer,
2215 HB_UShort flags,
2216 HB_UShort context_length,
2217 int nesting_level )
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;
2221 HB_Error error;
2222 HB_GPOSHeader* gpos = gpi->gpos;
2223 HB_MarkBasePos* mbp = &st->markbase;
2225 HB_MarkArray* ma;
2226 HB_BaseArray* ba;
2227 HB_BaseRecord* br;
2228 HB_Anchor* mark_anchor;
2229 HB_Anchor* base_anchor;
2231 HB_Position o;
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 ) )
2243 return error;
2245 error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2246 &mark_index );
2247 if ( error )
2248 return error;
2250 /* now we search backwards for a non-mark glyph */
2252 i = 1;
2253 j = buffer->in_pos - 1;
2255 while ( i <= buffer->in_pos )
2257 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2258 &property );
2259 if ( error )
2260 return error;
2262 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2263 break;
2265 i++;
2266 j--;
2269 /* The following assertion is too strong -- at least for mangal.ttf. */
2270 #if 0
2271 if ( property != HB_GDEF_BASE_GLYPH )
2272 return HB_Err_Not_Covered;
2273 #endif
2275 if ( i > buffer->in_pos )
2276 return HB_Err_Not_Covered;
2278 error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2279 &base_index );
2280 if ( error )
2281 return error;
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 );
2304 if ( error )
2305 return error;
2307 error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2308 &x_base_value, &y_base_value );
2309 if ( error )
2310 return error;
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;
2318 o->x_advance = 0;
2319 o->y_advance = 0;
2320 o->back = i;
2322 (buffer->in_pos)++;
2324 return HB_Err_Ok;
2328 /* LookupType 5 */
2330 /* LigatureAttach */
2332 static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
2333 HB_UShort num_classes,
2334 HB_Stream stream )
2336 HB_Error error;
2338 HB_UShort m, n, k, count;
2339 HB_UInt cur_offset, new_offset, base_offset;
2341 HB_ComponentRecord* cr;
2342 HB_Anchor* lan;
2345 base_offset = FILE_Pos();
2347 if ( ACCESS_Frame( 2L ) )
2348 return error;
2350 count = lat->ComponentCount = GET_UShort();
2352 FORGET_Frame();
2354 lat->ComponentRecord = NULL;
2356 if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2357 return error;
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 ) )
2366 goto Fail;
2368 lan = cr[m].LigatureAnchor;
2370 for ( n = 0; n < num_classes; n++ )
2372 if ( ACCESS_Frame( 2L ) )
2373 goto Fail0;
2375 new_offset = GET_UShort();
2377 FORGET_Frame();
2379 if ( new_offset )
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 )
2386 goto Fail0;
2387 (void)FILE_Seek( cur_offset );
2389 else
2390 lan[n].PosFormat = 0;
2393 continue;
2394 Fail0:
2395 for ( k = 0; k < n; k++ )
2396 Free_Anchor( &lan[k] );
2397 goto Fail;
2400 return HB_Err_Ok;
2402 Fail:
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] );
2410 FREE( lan );
2413 FREE( cr );
2414 return error;
2418 static void Free_LigatureAttach( HB_LigatureAttach* lat,
2419 HB_UShort num_classes )
2421 HB_UShort m, n, count;
2423 HB_ComponentRecord* cr;
2424 HB_Anchor* lan;
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] );
2439 FREE( lan );
2442 FREE( cr );
2447 /* LigatureArray */
2449 static HB_Error Load_LigatureArray( HB_LigatureArray* la,
2450 HB_UShort num_classes,
2451 HB_Stream stream )
2453 HB_Error error;
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 ) )
2464 return error;
2466 count = la->LigatureCount = GET_UShort();
2468 FORGET_Frame();
2470 la->LigatureAttach = NULL;
2472 if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2473 return error;
2475 lat = la->LigatureAttach;
2477 for ( n = 0; n < count; n++ )
2479 if ( ACCESS_Frame( 2L ) )
2480 goto Fail;
2482 new_offset = GET_UShort() + base_offset;
2484 FORGET_Frame();
2486 cur_offset = FILE_Pos();
2487 if ( FILE_Seek( new_offset ) ||
2488 ( error = Load_LigatureAttach( &lat[n], num_classes,
2489 stream ) ) != HB_Err_Ok )
2490 goto Fail;
2491 (void)FILE_Seek( cur_offset );
2494 return HB_Err_Ok;
2496 Fail:
2497 for ( m = 0; m < n; m++ )
2498 Free_LigatureAttach( &lat[m], num_classes );
2500 FREE( lat );
2501 return error;
2505 static void Free_LigatureArray( HB_LigatureArray* la,
2506 HB_UShort num_classes )
2508 HB_UShort n, count;
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 );
2521 FREE( lat );
2526 /* MarkLigPosFormat1 */
2528 static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
2529 HB_Stream stream )
2531 HB_Error error;
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 ) )
2540 return error;
2542 mlp->PosFormat = GET_UShort();
2543 new_offset = GET_UShort() + base_offset;
2545 FORGET_Frame();
2547 cur_offset = FILE_Pos();
2548 if ( FILE_Seek( new_offset ) ||
2549 ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
2550 return error;
2551 (void)FILE_Seek( cur_offset );
2553 if ( ACCESS_Frame( 2L ) )
2554 goto Fail3;
2556 new_offset = GET_UShort() + base_offset;
2558 FORGET_Frame();
2560 cur_offset = FILE_Pos();
2561 if ( FILE_Seek( new_offset ) ||
2562 ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2563 stream ) ) != HB_Err_Ok )
2564 goto Fail3;
2565 (void)FILE_Seek( cur_offset );
2567 if ( ACCESS_Frame( 4L ) )
2568 goto Fail2;
2570 mlp->ClassCount = GET_UShort();
2571 new_offset = GET_UShort() + base_offset;
2573 FORGET_Frame();
2575 cur_offset = FILE_Pos();
2576 if ( FILE_Seek( new_offset ) ||
2577 ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
2578 goto Fail2;
2579 (void)FILE_Seek( cur_offset );
2581 if ( ACCESS_Frame( 2L ) )
2582 goto Fail1;
2584 new_offset = GET_UShort() + base_offset;
2586 FORGET_Frame();
2588 cur_offset = FILE_Pos();
2589 if ( FILE_Seek( new_offset ) ||
2590 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2591 stream ) ) != HB_Err_Ok )
2592 goto Fail1;
2594 return HB_Err_Ok;
2596 Fail1:
2597 Free_MarkArray( &mlp->MarkArray );
2599 Fail2:
2600 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2602 Fail3:
2603 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2604 return error;
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,
2621 HB_Buffer buffer,
2622 HB_UShort flags,
2623 HB_UShort context_length,
2624 int nesting_level )
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;
2629 HB_Error error;
2630 HB_GPOSHeader* gpos = gpi->gpos;
2631 HB_MarkLigPos* mlp = &st->marklig;
2633 HB_MarkArray* ma;
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;
2641 HB_Position o;
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 ) )
2654 return error;
2656 error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2657 if ( error )
2658 return error;
2660 /* now we search backwards for a non-mark glyph */
2662 i = 1;
2663 j = buffer->in_pos - 1;
2665 while ( i <= buffer->in_pos )
2667 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2668 &property );
2669 if ( error )
2670 return error;
2672 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2673 break;
2675 i++;
2676 j--;
2679 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2680 too strong, thus it is commented out. */
2681 #if 0
2682 if ( property != HB_GDEF_LIGATURE )
2683 return HB_Err_Not_Covered;
2684 #endif
2686 if ( i > buffer->in_pos )
2687 return HB_Err_Not_Covered;
2689 error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2690 &lig_index );
2691 if ( error )
2692 return error;
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;
2723 else
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 );
2731 if ( error )
2732 return error;
2733 error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2734 &x_lig_value, &y_lig_value );
2735 if ( error )
2736 return error;
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;
2744 o->x_advance = 0;
2745 o->y_advance = 0;
2746 o->back = i;
2748 (buffer->in_pos)++;
2750 return HB_Err_Ok;
2754 /* LookupType 6 */
2756 /* Mark2Array */
2758 static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
2759 HB_UShort num_classes,
2760 HB_Stream stream )
2762 HB_Error error;
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 ) )
2774 return error;
2776 count = m2a->Mark2Count = GET_UShort();
2778 FORGET_Frame();
2780 m2a->Mark2Record = NULL;
2782 if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2783 return error;
2785 m2r = m2a->Mark2Record;
2787 m2ans = NULL;
2789 if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
2790 goto Fail;
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 ) )
2799 goto Fail;
2801 new_offset = GET_UShort() + base_offset;
2803 FORGET_Frame();
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;
2809 continue;
2812 cur_offset = FILE_Pos();
2813 if ( FILE_Seek( new_offset ) ||
2814 ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
2815 goto Fail;
2816 (void)FILE_Seek( cur_offset );
2820 return HB_Err_Ok;
2822 Fail:
2823 FREE( m2ans );
2824 FREE( m2r );
2825 return error;
2829 static void Free_Mark2Array( HB_Mark2Array* m2a,
2830 HB_UShort num_classes )
2832 HB_Mark2Record *m2r;
2833 HB_Anchor *m2ans;
2835 HB_UNUSED(num_classes);
2837 if ( m2a->Mark2Record )
2839 m2r = m2a->Mark2Record;
2841 if ( m2a->Mark2Count )
2843 m2ans = m2r[0].Mark2Anchor;
2844 FREE( m2ans );
2847 FREE( m2r );
2852 /* MarkMarkPosFormat1 */
2854 static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
2855 HB_Stream stream )
2857 HB_Error error;
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 ) )
2866 return error;
2868 mmp->PosFormat = GET_UShort();
2869 new_offset = GET_UShort() + base_offset;
2871 FORGET_Frame();
2873 cur_offset = FILE_Pos();
2874 if ( FILE_Seek( new_offset ) ||
2875 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2876 stream ) ) != HB_Err_Ok )
2877 return error;
2878 (void)FILE_Seek( cur_offset );
2880 if ( ACCESS_Frame( 2L ) )
2881 goto Fail3;
2883 new_offset = GET_UShort() + base_offset;
2885 FORGET_Frame();
2887 cur_offset = FILE_Pos();
2888 if ( FILE_Seek( new_offset ) ||
2889 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2890 stream ) ) != HB_Err_Ok )
2891 goto Fail3;
2892 (void)FILE_Seek( cur_offset );
2894 if ( ACCESS_Frame( 4L ) )
2895 goto Fail2;
2897 mmp->ClassCount = GET_UShort();
2898 new_offset = GET_UShort() + base_offset;
2900 FORGET_Frame();
2902 cur_offset = FILE_Pos();
2903 if ( FILE_Seek( new_offset ) ||
2904 ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
2905 goto Fail2;
2906 (void)FILE_Seek( cur_offset );
2908 if ( ACCESS_Frame( 2L ) )
2909 goto Fail1;
2911 new_offset = GET_UShort() + base_offset;
2913 FORGET_Frame();
2915 cur_offset = FILE_Pos();
2916 if ( FILE_Seek( new_offset ) ||
2917 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2918 stream ) ) != HB_Err_Ok )
2919 goto Fail1;
2921 return HB_Err_Ok;
2923 Fail1:
2924 Free_MarkArray( &mmp->Mark1Array );
2926 Fail2:
2927 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2929 Fail3:
2930 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2931 return error;
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,
2948 HB_Buffer buffer,
2949 HB_UShort flags,
2950 HB_UShort context_length,
2951 int nesting_level )
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;
2956 HB_Error error;
2957 HB_GPOSHeader* gpos = gpi->gpos;
2958 HB_MarkMarkPos* mmp = &st->markmark;
2960 HB_MarkArray* ma1;
2961 HB_Mark2Array* ma2;
2962 HB_Mark2Record* m2r;
2963 HB_Anchor* mark1_anchor;
2964 HB_Anchor* mark2_anchor;
2966 HB_Position o;
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 ) )
2978 return error;
2980 error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
2981 &mark1_index );
2982 if ( error )
2983 return error;
2985 /* now we search backwards for a suitable mark glyph until a non-mark
2986 glyph */
2988 if ( buffer->in_pos == 0 )
2989 return HB_Err_Not_Covered;
2991 i = 1;
2992 j = buffer->in_pos - 1;
2993 while ( i <= buffer->in_pos )
2995 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2996 &property );
2997 if ( error )
2998 return error;
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) )
3006 break;
3008 else
3009 break;
3011 i++;
3012 j--;
3015 if ( i > buffer->in_pos )
3016 return HB_Err_Not_Covered;
3018 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3019 &mark2_index );
3020 if ( error )
3021 return error;
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 );
3044 if ( error )
3045 return error;
3046 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3047 &x_mark2_value, &y_mark2_value );
3048 if ( error )
3049 return error;
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;
3057 o->x_advance = 0;
3058 o->y_advance = 0;
3059 o->back = 1;
3061 (buffer->in_pos)++;
3063 return HB_Err_Ok;
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,
3073 HB_UShort PosCount,
3074 HB_PosLookupRecord* pos,
3075 HB_Buffer buffer,
3076 int nesting_level )
3078 HB_Error error;
3079 HB_UInt i, old_pos;
3082 i = 0;
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 );
3095 if ( error )
3096 return error;
3098 pos++;
3099 PosCount--;
3100 i += buffer->in_pos - old_pos;
3102 else
3104 i++;
3105 (buffer->in_pos)++;
3109 return HB_Err_Ok;
3113 /* LookupType 7 */
3115 /* PosRule */
3117 static HB_Error Load_PosRule( HB_PosRule* pr,
3118 HB_Stream stream )
3120 HB_Error error;
3122 HB_UShort n, count;
3123 HB_UShort* i;
3125 HB_PosLookupRecord* plr;
3128 if ( ACCESS_Frame( 4L ) )
3129 return error;
3131 pr->GlyphCount = GET_UShort();
3132 pr->PosCount = GET_UShort();
3134 FORGET_Frame();
3136 pr->Input = NULL;
3138 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3140 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3141 return error;
3143 i = pr->Input;
3145 if ( ACCESS_Frame( count * 2L ) )
3146 goto Fail2;
3148 for ( n = 0; n < count; n++ )
3149 i[n] = GET_UShort();
3151 FORGET_Frame();
3153 pr->PosLookupRecord = NULL;
3155 count = pr->PosCount;
3157 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3158 goto Fail2;
3160 plr = pr->PosLookupRecord;
3162 if ( ACCESS_Frame( count * 4L ) )
3163 goto Fail1;
3165 for ( n = 0; n < count; n++ )
3167 plr[n].SequenceIndex = GET_UShort();
3168 plr[n].LookupListIndex = GET_UShort();
3171 FORGET_Frame();
3173 return HB_Err_Ok;
3175 Fail1:
3176 FREE( plr );
3178 Fail2:
3179 FREE( i );
3180 return error;
3184 static void Free_PosRule( HB_PosRule* pr )
3186 FREE( pr->PosLookupRecord );
3187 FREE( pr->Input );
3191 /* PosRuleSet */
3193 static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
3194 HB_Stream stream )
3196 HB_Error error;
3198 HB_UShort n, m, count;
3199 HB_UInt cur_offset, new_offset, base_offset;
3201 HB_PosRule* pr;
3204 base_offset = FILE_Pos();
3206 if ( ACCESS_Frame( 2L ) )
3207 return error;
3209 count = prs->PosRuleCount = GET_UShort();
3211 FORGET_Frame();
3213 prs->PosRule = NULL;
3215 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3216 return error;
3218 pr = prs->PosRule;
3220 for ( n = 0; n < count; n++ )
3222 if ( ACCESS_Frame( 2L ) )
3223 goto Fail;
3225 new_offset = GET_UShort() + base_offset;
3227 FORGET_Frame();
3229 cur_offset = FILE_Pos();
3230 if ( FILE_Seek( new_offset ) ||
3231 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3232 goto Fail;
3233 (void)FILE_Seek( cur_offset );
3236 return HB_Err_Ok;
3238 Fail:
3239 for ( m = 0; m < n; m++ )
3240 Free_PosRule( &pr[m] );
3242 FREE( pr );
3243 return error;
3247 static void Free_PosRuleSet( HB_PosRuleSet* prs )
3249 HB_UShort n, count;
3251 HB_PosRule* pr;
3254 if ( prs->PosRule )
3256 count = prs->PosRuleCount;
3257 pr = prs->PosRule;
3259 for ( n = 0; n < count; n++ )
3260 Free_PosRule( &pr[n] );
3262 FREE( pr );
3267 /* ContextPosFormat1 */
3269 static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
3270 HB_Stream stream )
3272 HB_Error error;
3274 HB_UShort n, m, count;
3275 HB_UInt cur_offset, new_offset, base_offset;
3277 HB_PosRuleSet* prs;
3280 base_offset = FILE_Pos() - 2L;
3282 if ( ACCESS_Frame( 2L ) )
3283 return error;
3285 new_offset = GET_UShort() + base_offset;
3287 FORGET_Frame();
3289 cur_offset = FILE_Pos();
3290 if ( FILE_Seek( new_offset ) ||
3291 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3292 return error;
3293 (void)FILE_Seek( cur_offset );
3295 if ( ACCESS_Frame( 2L ) )
3296 goto Fail2;
3298 count = cpf1->PosRuleSetCount = GET_UShort();
3300 FORGET_Frame();
3302 cpf1->PosRuleSet = NULL;
3304 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3305 goto Fail2;
3307 prs = cpf1->PosRuleSet;
3309 for ( n = 0; n < count; n++ )
3311 if ( ACCESS_Frame( 2L ) )
3312 goto Fail1;
3314 new_offset = GET_UShort() + base_offset;
3316 FORGET_Frame();
3318 cur_offset = FILE_Pos();
3319 if ( FILE_Seek( new_offset ) ||
3320 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3321 goto Fail1;
3322 (void)FILE_Seek( cur_offset );
3325 return HB_Err_Ok;
3327 Fail1:
3328 for ( m = 0; m < n; m++ )
3329 Free_PosRuleSet( &prs[m] );
3331 FREE( prs );
3333 Fail2:
3334 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3335 return error;
3339 static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
3341 HB_UShort n, count;
3343 HB_PosRuleSet* prs;
3346 if ( cpf1->PosRuleSet )
3348 count = cpf1->PosRuleSetCount;
3349 prs = cpf1->PosRuleSet;
3351 for ( n = 0; n < count; n++ )
3352 Free_PosRuleSet( &prs[n] );
3354 FREE( prs );
3357 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3361 /* PosClassRule */
3363 static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
3364 HB_PosClassRule* pcr,
3365 HB_Stream stream )
3367 HB_Error error;
3369 HB_UShort n, count;
3371 HB_UShort* c;
3372 HB_PosLookupRecord* plr;
3375 if ( ACCESS_Frame( 4L ) )
3376 return error;
3378 pcr->GlyphCount = GET_UShort();
3379 pcr->PosCount = GET_UShort();
3381 FORGET_Frame();
3383 if ( pcr->GlyphCount > cpf2->MaxContextLength )
3384 cpf2->MaxContextLength = pcr->GlyphCount;
3386 pcr->Class = NULL;
3388 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3390 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3391 return error;
3393 c = pcr->Class;
3395 if ( ACCESS_Frame( count * 2L ) )
3396 goto Fail2;
3398 for ( n = 0; n < count; n++ )
3399 c[n] = GET_UShort();
3401 FORGET_Frame();
3403 pcr->PosLookupRecord = NULL;
3405 count = pcr->PosCount;
3407 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3408 goto Fail2;
3410 plr = pcr->PosLookupRecord;
3412 if ( ACCESS_Frame( count * 4L ) )
3413 goto Fail1;
3415 for ( n = 0; n < count; n++ )
3417 plr[n].SequenceIndex = GET_UShort();
3418 plr[n].LookupListIndex = GET_UShort();
3421 FORGET_Frame();
3423 return HB_Err_Ok;
3425 Fail1:
3426 FREE( plr );
3428 Fail2:
3429 FREE( c );
3430 return error;
3434 static void Free_PosClassRule( HB_PosClassRule* pcr )
3436 FREE( pcr->PosLookupRecord );
3437 FREE( pcr->Class );
3441 /* PosClassSet */
3443 static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
3444 HB_PosClassSet* pcs,
3445 HB_Stream stream )
3447 HB_Error error;
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 ) )
3458 return error;
3460 count = pcs->PosClassRuleCount = GET_UShort();
3462 FORGET_Frame();
3464 pcs->PosClassRule = NULL;
3466 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3467 return error;
3469 pcr = pcs->PosClassRule;
3471 for ( n = 0; n < count; n++ )
3473 if ( ACCESS_Frame( 2L ) )
3474 goto Fail;
3476 new_offset = GET_UShort() + base_offset;
3478 FORGET_Frame();
3480 cur_offset = FILE_Pos();
3481 if ( FILE_Seek( new_offset ) ||
3482 ( error = Load_PosClassRule( cpf2, &pcr[n],
3483 stream ) ) != HB_Err_Ok )
3484 goto Fail;
3485 (void)FILE_Seek( cur_offset );
3488 return HB_Err_Ok;
3490 Fail:
3491 for ( m = 0; m < n; m++ )
3492 Free_PosClassRule( &pcr[m] );
3494 FREE( pcr );
3495 return error;
3499 static void Free_PosClassSet( HB_PosClassSet* pcs )
3501 HB_UShort n, count;
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] );
3514 FREE( pcr );
3519 /* ContextPosFormat2 */
3521 static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
3522 HB_Stream stream )
3524 HB_Error error;
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 ) )
3535 return error;
3537 new_offset = GET_UShort() + base_offset;
3539 FORGET_Frame();
3541 cur_offset = FILE_Pos();
3542 if ( FILE_Seek( new_offset ) ||
3543 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3544 return error;
3545 (void)FILE_Seek( cur_offset );
3547 if ( ACCESS_Frame( 4L ) )
3548 goto Fail3;
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();
3557 FORGET_Frame();
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 )
3563 goto Fail3;
3564 (void)FILE_Seek( cur_offset );
3566 cpf2->PosClassSet = NULL;
3567 cpf2->MaxContextLength = 0;
3569 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3570 goto Fail2;
3572 pcs = cpf2->PosClassSet;
3574 for ( n = 0; n < count; n++ )
3576 if ( ACCESS_Frame( 2L ) )
3577 goto Fail1;
3579 new_offset = GET_UShort() + base_offset;
3581 FORGET_Frame();
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 )
3589 goto Fail1;
3590 (void)FILE_Seek( cur_offset );
3592 else
3594 /* we create a PosClassSet table with no entries */
3596 cpf2->PosClassSet[n].PosClassRuleCount = 0;
3597 cpf2->PosClassSet[n].PosClassRule = NULL;
3601 return HB_Err_Ok;
3603 Fail1:
3604 for ( m = 0; m < n; n++ )
3605 Free_PosClassSet( &pcs[m] );
3607 FREE( pcs );
3609 Fail2:
3610 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3612 Fail3:
3613 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3614 return error;
3618 static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
3620 HB_UShort n, count;
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] );
3633 FREE( pcs );
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,
3644 HB_Stream stream )
3646 HB_Error error;
3648 HB_UShort n, count;
3649 HB_UInt cur_offset, new_offset, base_offset;
3651 HB_Coverage* c;
3652 HB_PosLookupRecord* plr;
3655 base_offset = FILE_Pos() - 2L;
3657 if ( ACCESS_Frame( 4L ) )
3658 return error;
3660 cpf3->GlyphCount = GET_UShort();
3661 cpf3->PosCount = GET_UShort();
3663 FORGET_Frame();
3665 cpf3->Coverage = NULL;
3667 count = cpf3->GlyphCount;
3669 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3670 return error;
3672 c = cpf3->Coverage;
3674 for ( n = 0; n < count; n++ )
3676 if ( ACCESS_Frame( 2L ) )
3677 goto Fail2;
3679 new_offset = GET_UShort() + base_offset;
3681 FORGET_Frame();
3683 cur_offset = FILE_Pos();
3684 if ( FILE_Seek( new_offset ) ||
3685 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3686 goto Fail2;
3687 (void)FILE_Seek( cur_offset );
3690 cpf3->PosLookupRecord = NULL;
3692 count = cpf3->PosCount;
3694 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3695 goto Fail2;
3697 plr = cpf3->PosLookupRecord;
3699 if ( ACCESS_Frame( count * 4L ) )
3700 goto Fail1;
3702 for ( n = 0; n < count; n++ )
3704 plr[n].SequenceIndex = GET_UShort();
3705 plr[n].LookupListIndex = GET_UShort();
3708 FORGET_Frame();
3710 return HB_Err_Ok;
3712 Fail1:
3713 FREE( plr );
3715 Fail2:
3716 for ( n = 0; n < count; n++ )
3717 _HB_OPEN_Free_Coverage( &c[n] );
3719 FREE( c );
3720 return error;
3724 static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
3726 HB_UShort n, count;
3728 HB_Coverage* c;
3731 FREE( cpf3->PosLookupRecord );
3733 if ( cpf3->Coverage )
3735 count = cpf3->GlyphCount;
3736 c = cpf3->Coverage;
3738 for ( n = 0; n < count; n++ )
3739 _HB_OPEN_Free_Coverage( &c[n] );
3741 FREE( c );
3746 /* ContextPos */
3748 static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
3749 HB_Stream stream )
3751 HB_Error error;
3752 HB_ContextPos* cp = &st->context;
3755 if ( ACCESS_Frame( 2L ) )
3756 return error;
3758 cp->PosFormat = GET_UShort();
3760 FORGET_Frame();
3762 switch ( cp->PosFormat )
3764 case 1:
3765 return Load_ContextPos1( &cp->cpf.cpf1, stream );
3767 case 2:
3768 return Load_ContextPos2( &cp->cpf.cpf2, stream );
3770 case 3:
3771 return Load_ContextPos3( &cp->cpf.cpf3, stream );
3773 default:
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;
3790 default: break;
3795 static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3796 HB_ContextPosFormat1* cpf1,
3797 HB_Buffer buffer,
3798 HB_UShort flags,
3799 HB_UShort context_length,
3800 int nesting_level )
3802 HB_UShort index, property;
3803 HB_UShort i, j, k, numpr;
3804 HB_Error error;
3805 HB_GPOSHeader* gpos = gpi->gpos;
3807 HB_PosRule* pr;
3808 HB_GDEFHeader* gdef;
3811 gdef = gpos->gdef;
3813 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3814 return error;
3816 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3817 if ( error )
3818 return error;
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 )
3826 goto next_posrule;
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 )
3836 return error;
3838 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3839 goto next_posrule;
3840 j++;
3843 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3844 goto next_posrule;
3847 return Do_ContextPos( gpi, pr[k].GlyphCount,
3848 pr[k].PosCount, pr[k].PosLookupRecord,
3849 buffer,
3850 nesting_level );
3852 next_posrule:
3856 return HB_Err_Not_Covered;
3860 static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
3861 HB_ContextPosFormat2* cpf2,
3862 HB_Buffer buffer,
3863 HB_UShort flags,
3864 HB_UShort context_length,
3865 int nesting_level )
3867 HB_UShort index, property;
3868 HB_Error error;
3869 HB_UShort i, j, k, known_classes;
3871 HB_UShort* classes;
3872 HB_UShort* cl;
3873 HB_GPOSHeader* gpos = gpi->gpos;
3875 HB_PosClassSet* pcs;
3876 HB_PosClassRule* pr;
3877 HB_GDEFHeader* gdef;
3880 gdef = gpos->gdef;
3882 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3883 return error;
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 );
3890 if ( error )
3891 return error;
3893 if (cpf2->MaxContextLength < 1)
3894 return HB_Err_Not_Covered;
3896 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3897 return error;
3899 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3900 &classes[0], NULL );
3901 if ( error && error != HB_Err_Not_Covered )
3902 goto End;
3903 known_classes = 0;
3905 pcs = &cpf2->PosClassSet[classes[0]];
3906 if ( !pcs )
3908 error = ERR(HB_Err_Invalid_SubTable);
3909 goto End;
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 */
3922 cl = pr->Class;
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 )
3931 goto End;
3933 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3934 goto next_posclassrule;
3935 j++;
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 )
3944 goto End;
3945 known_classes = i;
3948 if ( cl[i - 1] != classes[i] )
3949 goto next_posclassrule;
3952 error = Do_ContextPos( gpi, pr->GlyphCount,
3953 pr->PosCount, pr->PosLookupRecord,
3954 buffer,
3955 nesting_level );
3956 goto End;
3958 next_posclassrule:
3962 error = HB_Err_Not_Covered;
3964 End:
3965 FREE( classes );
3966 return error;
3970 static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
3971 HB_ContextPosFormat3* cpf3,
3972 HB_Buffer buffer,
3973 HB_UShort flags,
3974 HB_UShort context_length,
3975 int nesting_level )
3977 HB_Error error;
3978 HB_UShort index, i, j, property;
3979 HB_GPOSHeader* gpos = gpi->gpos;
3981 HB_Coverage* c;
3982 HB_GDEFHeader* gdef;
3985 gdef = gpos->gdef;
3987 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3988 return error;
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 */
3996 c = cpf3->Coverage;
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 )
4003 return error;
4005 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
4006 return HB_Err_Not_Covered;
4007 j++;
4010 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4011 if ( error )
4012 return error;
4015 return Do_ContextPos( gpi, cpf3->GlyphCount,
4016 cpf3->PosCount, cpf3->PosLookupRecord,
4017 buffer,
4018 nesting_level );
4022 static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
4023 HB_GPOS_SubTable* st,
4024 HB_Buffer buffer,
4025 HB_UShort flags,
4026 HB_UShort context_length,
4027 int nesting_level )
4029 HB_ContextPos* cp = &st->context;
4031 switch ( cp->PosFormat )
4033 case 1:
4034 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4035 flags, context_length, nesting_level );
4037 case 2:
4038 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4039 flags, context_length, nesting_level );
4041 case 3:
4042 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4043 flags, context_length, nesting_level );
4045 default:
4046 return ERR(HB_Err_Invalid_SubTable_Format);
4049 return HB_Err_Ok; /* never reached */
4053 /* LookupType 8 */
4055 /* ChainPosRule */
4057 static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
4058 HB_Stream stream )
4060 HB_Error error;
4062 HB_UShort n, count;
4063 HB_UShort* b;
4064 HB_UShort* i;
4065 HB_UShort* l;
4067 HB_PosLookupRecord* plr;
4070 if ( ACCESS_Frame( 2L ) )
4071 return error;
4073 cpr->BacktrackGlyphCount = GET_UShort();
4075 FORGET_Frame();
4077 cpr->Backtrack = NULL;
4079 count = cpr->BacktrackGlyphCount;
4081 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4082 return error;
4084 b = cpr->Backtrack;
4086 if ( ACCESS_Frame( count * 2L ) )
4087 goto Fail4;
4089 for ( n = 0; n < count; n++ )
4090 b[n] = GET_UShort();
4092 FORGET_Frame();
4094 if ( ACCESS_Frame( 2L ) )
4095 goto Fail4;
4097 cpr->InputGlyphCount = GET_UShort();
4099 FORGET_Frame();
4101 cpr->Input = NULL;
4103 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4105 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4106 goto Fail4;
4108 i = cpr->Input;
4110 if ( ACCESS_Frame( count * 2L ) )
4111 goto Fail3;
4113 for ( n = 0; n < count; n++ )
4114 i[n] = GET_UShort();
4116 FORGET_Frame();
4118 if ( ACCESS_Frame( 2L ) )
4119 goto Fail3;
4121 cpr->LookaheadGlyphCount = GET_UShort();
4123 FORGET_Frame();
4125 cpr->Lookahead = NULL;
4127 count = cpr->LookaheadGlyphCount;
4129 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4130 goto Fail3;
4132 l = cpr->Lookahead;
4134 if ( ACCESS_Frame( count * 2L ) )
4135 goto Fail2;
4137 for ( n = 0; n < count; n++ )
4138 l[n] = GET_UShort();
4140 FORGET_Frame();
4142 if ( ACCESS_Frame( 2L ) )
4143 goto Fail2;
4145 cpr->PosCount = GET_UShort();
4147 FORGET_Frame();
4149 cpr->PosLookupRecord = NULL;
4151 count = cpr->PosCount;
4153 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4154 goto Fail2;
4156 plr = cpr->PosLookupRecord;
4158 if ( ACCESS_Frame( count * 4L ) )
4159 goto Fail1;
4161 for ( n = 0; n < count; n++ )
4163 plr[n].SequenceIndex = GET_UShort();
4164 plr[n].LookupListIndex = GET_UShort();
4167 FORGET_Frame();
4169 return HB_Err_Ok;
4171 Fail1:
4172 FREE( plr );
4174 Fail2:
4175 FREE( l );
4177 Fail3:
4178 FREE( i );
4180 Fail4:
4181 FREE( b );
4182 return error;
4186 static void Free_ChainPosRule( HB_ChainPosRule* cpr )
4188 FREE( cpr->PosLookupRecord );
4189 FREE( cpr->Lookahead );
4190 FREE( cpr->Input );
4191 FREE( cpr->Backtrack );
4195 /* ChainPosRuleSet */
4197 static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4198 HB_Stream stream )
4200 HB_Error error;
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 ) )
4211 return error;
4213 count = cprs->ChainPosRuleCount = GET_UShort();
4215 FORGET_Frame();
4217 cprs->ChainPosRule = NULL;
4219 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4220 return error;
4222 cpr = cprs->ChainPosRule;
4224 for ( n = 0; n < count; n++ )
4226 if ( ACCESS_Frame( 2L ) )
4227 goto Fail;
4229 new_offset = GET_UShort() + base_offset;
4231 FORGET_Frame();
4233 cur_offset = FILE_Pos();
4234 if ( FILE_Seek( new_offset ) ||
4235 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4236 goto Fail;
4237 (void)FILE_Seek( cur_offset );
4240 return HB_Err_Ok;
4242 Fail:
4243 for ( m = 0; m < n; m++ )
4244 Free_ChainPosRule( &cpr[m] );
4246 FREE( cpr );
4247 return error;
4251 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
4253 HB_UShort n, count;
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] );
4266 FREE( cpr );
4271 /* ChainContextPosFormat1 */
4273 static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4274 HB_Stream stream )
4276 HB_Error error;
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 ) )
4287 return error;
4289 new_offset = GET_UShort() + base_offset;
4291 FORGET_Frame();
4293 cur_offset = FILE_Pos();
4294 if ( FILE_Seek( new_offset ) ||
4295 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4296 return error;
4297 (void)FILE_Seek( cur_offset );
4299 if ( ACCESS_Frame( 2L ) )
4300 goto Fail2;
4302 count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4304 FORGET_Frame();
4306 ccpf1->ChainPosRuleSet = NULL;
4308 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4309 goto Fail2;
4311 cprs = ccpf1->ChainPosRuleSet;
4313 for ( n = 0; n < count; n++ )
4315 if ( ACCESS_Frame( 2L ) )
4316 goto Fail1;
4318 new_offset = GET_UShort() + base_offset;
4320 FORGET_Frame();
4322 cur_offset = FILE_Pos();
4323 if ( FILE_Seek( new_offset ) ||
4324 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4325 goto Fail1;
4326 (void)FILE_Seek( cur_offset );
4329 return HB_Err_Ok;
4331 Fail1:
4332 for ( m = 0; m < n; m++ )
4333 Free_ChainPosRuleSet( &cprs[m] );
4335 FREE( cprs );
4337 Fail2:
4338 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4339 return error;
4343 static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
4345 HB_UShort n, count;
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] );
4358 FREE( cprs );
4361 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4365 /* ChainPosClassRule */
4367 static HB_Error Load_ChainPosClassRule(
4368 HB_ChainContextPosFormat2* ccpf2,
4369 HB_ChainPosClassRule* cpcr,
4370 HB_Stream stream )
4372 HB_Error error;
4374 HB_UShort n, count;
4376 HB_UShort* b;
4377 HB_UShort* i;
4378 HB_UShort* l;
4379 HB_PosLookupRecord* plr;
4382 if ( ACCESS_Frame( 2L ) )
4383 return error;
4385 cpcr->BacktrackGlyphCount = GET_UShort();
4387 FORGET_Frame();
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 ) )
4397 return error;
4399 b = cpcr->Backtrack;
4401 if ( ACCESS_Frame( count * 2L ) )
4402 goto Fail4;
4404 for ( n = 0; n < count; n++ )
4405 b[n] = GET_UShort();
4407 FORGET_Frame();
4409 if ( ACCESS_Frame( 2L ) )
4410 goto Fail4;
4412 cpcr->InputGlyphCount = GET_UShort();
4414 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4415 ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4417 FORGET_Frame();
4419 cpcr->Input = NULL;
4421 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4423 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4424 goto Fail4;
4426 i = cpcr->Input;
4428 if ( ACCESS_Frame( count * 2L ) )
4429 goto Fail3;
4431 for ( n = 0; n < count; n++ )
4432 i[n] = GET_UShort();
4434 FORGET_Frame();
4436 if ( ACCESS_Frame( 2L ) )
4437 goto Fail3;
4439 cpcr->LookaheadGlyphCount = GET_UShort();
4441 FORGET_Frame();
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 ) )
4451 goto Fail3;
4453 l = cpcr->Lookahead;
4455 if ( ACCESS_Frame( count * 2L ) )
4456 goto Fail2;
4458 for ( n = 0; n < count; n++ )
4459 l[n] = GET_UShort();
4461 FORGET_Frame();
4463 if ( ACCESS_Frame( 2L ) )
4464 goto Fail2;
4466 cpcr->PosCount = GET_UShort();
4468 FORGET_Frame();
4470 cpcr->PosLookupRecord = NULL;
4472 count = cpcr->PosCount;
4474 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4475 goto Fail2;
4477 plr = cpcr->PosLookupRecord;
4479 if ( ACCESS_Frame( count * 4L ) )
4480 goto Fail1;
4482 for ( n = 0; n < count; n++ )
4484 plr[n].SequenceIndex = GET_UShort();
4485 plr[n].LookupListIndex = GET_UShort();
4488 FORGET_Frame();
4490 return HB_Err_Ok;
4492 Fail1:
4493 FREE( plr );
4495 Fail2:
4496 FREE( l );
4498 Fail3:
4499 FREE( i );
4501 Fail4:
4502 FREE( b );
4503 return error;
4507 static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
4509 FREE( cpcr->PosLookupRecord );
4510 FREE( cpcr->Lookahead );
4511 FREE( cpcr->Input );
4512 FREE( cpcr->Backtrack );
4516 /* PosClassSet */
4518 static HB_Error Load_ChainPosClassSet(
4519 HB_ChainContextPosFormat2* ccpf2,
4520 HB_ChainPosClassSet* cpcs,
4521 HB_Stream stream )
4523 HB_Error error;
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 ) )
4534 return error;
4536 count = cpcs->ChainPosClassRuleCount = GET_UShort();
4538 FORGET_Frame();
4540 cpcs->ChainPosClassRule = NULL;
4542 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4543 HB_ChainPosClassRule ) )
4544 return error;
4546 cpcr = cpcs->ChainPosClassRule;
4548 for ( n = 0; n < count; n++ )
4550 if ( ACCESS_Frame( 2L ) )
4551 goto Fail;
4553 new_offset = GET_UShort() + base_offset;
4555 FORGET_Frame();
4557 cur_offset = FILE_Pos();
4558 if ( FILE_Seek( new_offset ) ||
4559 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4560 stream ) ) != HB_Err_Ok )
4561 goto Fail;
4562 (void)FILE_Seek( cur_offset );
4565 return HB_Err_Ok;
4567 Fail:
4568 for ( m = 0; m < n; m++ )
4569 Free_ChainPosClassRule( &cpcr[m] );
4571 FREE( cpcr );
4572 return error;
4576 static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
4578 HB_UShort n, count;
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] );
4591 FREE( cpcr );
4596 /* ChainContextPosFormat2 */
4598 static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4599 HB_Stream stream )
4601 HB_Error error;
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 ) )
4613 return error;
4615 new_offset = GET_UShort() + base_offset;
4617 FORGET_Frame();
4619 cur_offset = FILE_Pos();
4620 if ( FILE_Seek( new_offset ) ||
4621 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4622 return error;
4623 (void)FILE_Seek( cur_offset );
4625 if ( ACCESS_Frame( 8L ) )
4626 goto Fail5;
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();
4638 FORGET_Frame();
4640 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4641 backtrack_offset, base_offset,
4642 stream ) ) != HB_Err_Ok )
4643 goto Fail5;
4644 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4645 input_offset, base_offset,
4646 stream ) ) != HB_Err_Ok )
4647 goto Fail4;
4648 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4649 lookahead_offset, base_offset,
4650 stream ) ) != HB_Err_Ok )
4651 goto Fail3;
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 ) )
4659 goto Fail2;
4661 cpcs = ccpf2->ChainPosClassSet;
4663 for ( n = 0; n < count; n++ )
4665 if ( ACCESS_Frame( 2L ) )
4666 goto Fail1;
4668 new_offset = GET_UShort() + base_offset;
4670 FORGET_Frame();
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 )
4678 goto Fail1;
4679 (void)FILE_Seek( cur_offset );
4681 else
4683 /* we create a ChainPosClassSet table with no entries */
4685 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4686 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4690 return HB_Err_Ok;
4692 Fail1:
4693 for ( m = 0; m < n; m++ )
4694 Free_ChainPosClassSet( &cpcs[m] );
4696 FREE( cpcs );
4698 Fail2:
4699 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4701 Fail3:
4702 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4704 Fail4:
4705 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4707 Fail5:
4708 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4709 return error;
4713 static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
4715 HB_UShort n, count;
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] );
4728 FREE( cpcs );
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,
4742 HB_Stream stream )
4744 HB_Error error;
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;
4750 HB_Coverage* b;
4751 HB_Coverage* i;
4752 HB_Coverage* l;
4753 HB_PosLookupRecord* plr;
4756 base_offset = FILE_Pos() - 2L;
4758 if ( ACCESS_Frame( 2L ) )
4759 return error;
4761 ccpf3->BacktrackGlyphCount = GET_UShort();
4763 FORGET_Frame();
4765 ccpf3->BacktrackCoverage = NULL;
4767 backtrack_count = ccpf3->BacktrackGlyphCount;
4769 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4770 HB_Coverage ) )
4771 return error;
4773 b = ccpf3->BacktrackCoverage;
4775 for ( nb = 0; nb < backtrack_count; nb++ )
4777 if ( ACCESS_Frame( 2L ) )
4778 goto Fail4;
4780 new_offset = GET_UShort() + base_offset;
4782 FORGET_Frame();
4784 cur_offset = FILE_Pos();
4785 if ( FILE_Seek( new_offset ) ||
4786 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4787 goto Fail4;
4788 (void)FILE_Seek( cur_offset );
4791 if ( ACCESS_Frame( 2L ) )
4792 goto Fail4;
4794 ccpf3->InputGlyphCount = GET_UShort();
4796 FORGET_Frame();
4798 ccpf3->InputCoverage = NULL;
4800 input_count = ccpf3->InputGlyphCount;
4802 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4803 goto Fail4;
4805 i = ccpf3->InputCoverage;
4807 for ( ni = 0; ni < input_count; ni++ )
4809 if ( ACCESS_Frame( 2L ) )
4810 goto Fail3;
4812 new_offset = GET_UShort() + base_offset;
4814 FORGET_Frame();
4816 cur_offset = FILE_Pos();
4817 if ( FILE_Seek( new_offset ) ||
4818 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4819 goto Fail3;
4820 (void)FILE_Seek( cur_offset );
4823 if ( ACCESS_Frame( 2L ) )
4824 goto Fail3;
4826 ccpf3->LookaheadGlyphCount = GET_UShort();
4828 FORGET_Frame();
4830 ccpf3->LookaheadCoverage = NULL;
4832 lookahead_count = ccpf3->LookaheadGlyphCount;
4834 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4835 HB_Coverage ) )
4836 goto Fail3;
4838 l = ccpf3->LookaheadCoverage;
4840 for ( nl = 0; nl < lookahead_count; nl++ )
4842 if ( ACCESS_Frame( 2L ) )
4843 goto Fail2;
4845 new_offset = GET_UShort() + base_offset;
4847 FORGET_Frame();
4849 cur_offset = FILE_Pos();
4850 if ( FILE_Seek( new_offset ) ||
4851 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4852 goto Fail2;
4853 (void)FILE_Seek( cur_offset );
4856 if ( ACCESS_Frame( 2L ) )
4857 goto Fail2;
4859 ccpf3->PosCount = GET_UShort();
4861 FORGET_Frame();
4863 ccpf3->PosLookupRecord = NULL;
4865 count = ccpf3->PosCount;
4867 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4868 goto Fail2;
4870 plr = ccpf3->PosLookupRecord;
4872 if ( ACCESS_Frame( count * 4L ) )
4873 goto Fail1;
4875 for ( n = 0; n < count; n++ )
4877 plr[n].SequenceIndex = GET_UShort();
4878 plr[n].LookupListIndex = GET_UShort();
4881 FORGET_Frame();
4883 return HB_Err_Ok;
4885 Fail1:
4886 FREE( plr );
4888 Fail2:
4889 for ( m = 0; m < nl; m++ )
4890 _HB_OPEN_Free_Coverage( &l[m] );
4892 FREE( l );
4894 Fail3:
4895 for ( m = 0; m < ni; m++ )
4896 _HB_OPEN_Free_Coverage( &i[m] );
4898 FREE( i );
4900 Fail4:
4901 for ( m = 0; m < nb; m++ )
4902 _HB_OPEN_Free_Coverage( &b[m] );
4904 FREE( b );
4905 return error;
4909 static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
4911 HB_UShort n, count;
4913 HB_Coverage* c;
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] );
4926 FREE( c );
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] );
4937 FREE( c );
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] );
4948 FREE( c );
4953 /* ChainContextPos */
4955 static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
4956 HB_Stream stream )
4958 HB_Error error;
4959 HB_ChainContextPos* ccp = &st->chain;
4962 if ( ACCESS_Frame( 2L ) )
4963 return error;
4965 ccp->PosFormat = GET_UShort();
4967 FORGET_Frame();
4969 switch ( ccp->PosFormat )
4971 case 1:
4972 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
4974 case 2:
4975 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
4977 case 3:
4978 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
4980 default:
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;
4997 default: break;
5002 static HB_Error Lookup_ChainContextPos1(
5003 GPOS_Instance* gpi,
5004 HB_ChainContextPosFormat1* ccpf1,
5005 HB_Buffer buffer,
5006 HB_UShort flags,
5007 HB_UShort context_length,
5008 int nesting_level )
5010 HB_UShort index, property;
5011 HB_UShort i, j, k, num_cpr;
5012 HB_UShort bgc, igc, lgc;
5013 HB_Error error;
5014 HB_GPOSHeader* gpos = gpi->gpos;
5016 HB_ChainPosRule* cpr;
5017 HB_ChainPosRule curr_cpr;
5018 HB_GDEFHeader* gdef;
5021 gdef = gpos->gdef;
5023 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5024 return error;
5026 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5027 if ( error )
5028 return error;
5030 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5031 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5033 for ( k = 0; k < num_cpr; k++ )
5035 curr_cpr = 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;
5048 if ( bgc )
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 )
5058 return error;
5060 if ( j + 1 == bgc - i )
5061 goto next_chainposrule;
5062 j--;
5065 /* In OpenType 1.3, it is undefined whether the offsets of
5066 backtrack glyphs is in logical order or not. Version 1.4
5067 will clarify this:
5069 Logical order - a b c d e f g h i j
5071 Input offsets - 0 1
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 )
5087 return error;
5089 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5090 goto next_chainposrule;
5091 j++;
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 )
5106 return error;
5108 if ( j + lgc - i == (HB_Int)buffer->in_length )
5109 goto next_chainposrule;
5110 j++;
5113 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5114 goto next_chainposrule;
5117 return Do_ContextPos( gpi, igc,
5118 curr_cpr.PosCount,
5119 curr_cpr.PosLookupRecord,
5120 buffer,
5121 nesting_level );
5123 next_chainposrule:
5127 return HB_Err_Not_Covered;
5131 static HB_Error Lookup_ChainContextPos2(
5132 GPOS_Instance* gpi,
5133 HB_ChainContextPosFormat2* ccpf2,
5134 HB_Buffer buffer,
5135 HB_UShort flags,
5136 HB_UShort context_length,
5137 int nesting_level )
5139 HB_UShort index, property;
5140 HB_Error error;
5141 HB_UShort i, j, k;
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;
5151 HB_UShort* bc;
5152 HB_UShort* ic;
5153 HB_UShort* lc;
5154 HB_GPOSHeader* gpos = gpi->gpos;
5156 HB_ChainPosClassSet* cpcs;
5157 HB_ChainPosClassRule cpcr;
5158 HB_GDEFHeader* gdef;
5161 gdef = gpos->gdef;
5163 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5164 return error;
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 );
5171 if ( error )
5172 return error;
5174 if (ccpf2->MaxInputLength < 1)
5175 return HB_Err_Not_Covered;
5177 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5178 return error;
5179 known_backtrack_classes = 0;
5181 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5182 goto End3;
5183 known_input_classes = 1;
5185 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5186 goto End2;
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 )
5192 goto End1;
5194 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5195 if ( !cpcs )
5197 error = ERR(HB_Err_Invalid_SubTable);
5198 goto End1;
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;
5216 if ( bgc )
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 )
5229 goto End1;
5231 if ( j + 1 == bgc - i )
5232 goto next_chainposclassrule;
5233 j++;
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 )
5243 goto End1;
5244 known_backtrack_classes = i;
5247 if ( bc[i] != backtrack_classes[i] )
5248 goto next_chainposclassrule;
5252 ic = cpcr.Input;
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 )
5261 goto End1;
5263 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5264 goto next_chainposclassrule;
5265 j++;
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 )
5273 goto End1;
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 )
5291 goto End1;
5293 if ( j + lgc - i == (HB_Int)buffer->in_length )
5294 goto next_chainposclassrule;
5295 j++;
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 )
5303 goto End1;
5304 known_lookahead_classes = i;
5307 if ( lc[i] != lookahead_classes[i] )
5308 goto next_chainposclassrule;
5311 error = Do_ContextPos( gpi, igc,
5312 cpcr.PosCount,
5313 cpcr.PosLookupRecord,
5314 buffer,
5315 nesting_level );
5316 goto End1;
5318 next_chainposclassrule:
5322 error = HB_Err_Not_Covered;
5324 End1:
5325 FREE( lookahead_classes );
5327 End2:
5328 FREE( input_classes );
5330 End3:
5331 FREE( backtrack_classes );
5332 return error;
5336 static HB_Error Lookup_ChainContextPos3(
5337 GPOS_Instance* gpi,
5338 HB_ChainContextPosFormat3* ccpf3,
5339 HB_Buffer buffer,
5340 HB_UShort flags,
5341 HB_UShort context_length,
5342 int nesting_level )
5344 HB_UShort index, i, j, property;
5345 HB_UShort bgc, igc, lgc;
5346 HB_Error error;
5347 HB_GPOSHeader* gpos = gpi->gpos;
5349 HB_Coverage* bc;
5350 HB_Coverage* ic;
5351 HB_Coverage* lc;
5352 HB_GDEFHeader* gdef;
5355 gdef = gpos->gdef;
5357 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5358 return error;
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;
5372 if ( bgc )
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 )
5384 return error;
5386 if ( j + 1 == bgc - i )
5387 return HB_Err_Not_Covered;
5388 j--;
5391 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5392 if ( error )
5393 return error;
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 )
5405 return error;
5407 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5408 return HB_Err_Not_Covered;
5409 j++;
5412 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5413 if ( error )
5414 return error;
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 )
5427 return error;
5429 if ( j + lgc - i == (HB_Int)buffer->in_length )
5430 return HB_Err_Not_Covered;
5431 j++;
5434 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5435 if ( error )
5436 return error;
5439 return Do_ContextPos( gpi, igc,
5440 ccpf3->PosCount,
5441 ccpf3->PosLookupRecord,
5442 buffer,
5443 nesting_level );
5447 static HB_Error Lookup_ChainContextPos(
5448 GPOS_Instance* gpi,
5449 HB_GPOS_SubTable* st,
5450 HB_Buffer buffer,
5451 HB_UShort flags,
5452 HB_UShort context_length,
5453 int nesting_level )
5455 HB_ChainContextPos* ccp = &st->chain;
5457 switch ( ccp->PosFormat )
5459 case 1:
5460 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5461 flags, context_length,
5462 nesting_level );
5464 case 2:
5465 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5466 flags, context_length,
5467 nesting_level );
5469 case 3:
5470 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5471 flags, context_length,
5472 nesting_level );
5474 default:
5475 return ERR(HB_Err_Invalid_SubTable_Format);
5478 return HB_Err_Ok; /* never reached */
5483 /***********
5484 * GPOS API
5485 ***********/
5489 HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
5490 HB_UInt script_tag,
5491 HB_UShort* script_index )
5493 HB_UShort n;
5495 HB_ScriptList* sl;
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 )
5508 *script_index = n;
5510 return HB_Err_Ok;
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 )
5524 HB_UShort n;
5526 HB_ScriptList* sl;
5527 HB_ScriptRecord* sr;
5528 HB_ScriptTable* s;
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;
5550 return HB_Err_Ok;
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 )
5567 HB_UShort n;
5569 HB_ScriptList* sl;
5570 HB_ScriptRecord* sr;
5571 HB_ScriptTable* s;
5572 HB_LangSysRecord* lsr;
5573 HB_LangSys* ls;
5574 HB_UShort* fi;
5576 HB_FeatureList* fl;
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;
5597 else
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];
5616 return HB_Err_Ok;
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 )
5630 HB_Error error;
5631 HB_UShort n;
5632 HB_UInt* stl;
5634 HB_ScriptList* sl;
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 ) )
5645 return error;
5647 for ( n = 0; n < sl->ScriptCount; n++ )
5648 stl[n] = sr[n].ScriptTag;
5649 stl[n] = 0;
5651 *script_tag_list = stl;
5653 return HB_Err_Ok;
5658 HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
5659 HB_UShort script_index,
5660 HB_UInt** language_tag_list )
5662 HB_Error error;
5663 HB_UShort n;
5664 HB_UInt* ltl;
5666 HB_ScriptList* sl;
5667 HB_ScriptRecord* sr;
5668 HB_ScriptTable* s;
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 ) )
5685 return error;
5687 for ( n = 0; n < s->LangSysCount; n++ )
5688 ltl[n] = lsr[n].LangSysTag;
5689 ltl[n] = 0;
5691 *language_tag_list = ltl;
5693 return HB_Err_Ok;
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 )
5706 HB_UShort n;
5707 HB_Error error;
5708 HB_UInt* ftl;
5710 HB_ScriptList* sl;
5711 HB_ScriptRecord* sr;
5712 HB_ScriptTable* s;
5713 HB_LangSysRecord* lsr;
5714 HB_LangSys* ls;
5715 HB_UShort* fi;
5717 HB_FeatureList* fl;
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;
5738 else
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 ) )
5749 return error;
5751 for ( n = 0; n < ls->FeatureCount; n++ )
5753 if ( fi[n] >= fl->FeatureCount )
5755 FREE( ftl );
5756 return ERR(HB_Err_Invalid_SubTable_Format);
5758 ftl[n] = fr[fi[n]].FeatureTag;
5760 ftl[n] = 0;
5762 *feature_tag_list = ftl;
5764 return HB_Err_Ok;
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,
5772 HB_Buffer buffer,
5773 HB_UShort context_length,
5774 int nesting_level )
5776 HB_Error error = HB_Err_Not_Covered;
5777 HB_UShort i, flags, lookup_count;
5778 HB_GPOSHeader* gpos = gpi->gpos;
5779 HB_Lookup* lo;
5780 int lookup_type;
5783 nesting_level++;
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)
5790 return error;
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;*/
5819 default:
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 )
5826 return error;
5829 return HB_Err_Not_Covered;
5833 HB_INTERNAL HB_Error
5834 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5835 HB_Stream stream,
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);
5853 HB_INTERNAL void
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;*/
5867 default: 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,
5876 HB_Buffer buffer )
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. */
5890 buffer->in_pos = 0;
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
5900 lookup order. */
5902 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5903 if ( error && error != HB_Err_Not_Covered )
5904 return error;
5906 else
5908 /* Contrary to properties defined in GDEF, user-defined properties
5909 will always stop a possible cursive positioning. */
5910 gpi->last = 0xFFFF;
5912 error = HB_Err_Not_Covered;
5915 if ( error == HB_Err_Not_Covered )
5916 (buffer->in_pos)++;
5917 else
5918 retError = error;
5921 return retError;
5925 static HB_Error Position_CursiveChain ( HB_Buffer buffer )
5927 HB_UInt i, j;
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--)
5940 j = i - 1;
5942 if (positions[j].cursive_chain < 0)
5943 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5946 return HB_Err_Ok;
5950 HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
5951 HB_UShort feature_index,
5952 HB_UInt property )
5954 HB_UShort i;
5956 HB_Feature feature;
5957 HB_UInt* properties;
5958 HB_UShort* index;
5959 HB_UShort lookup_count;
5961 /* Each feature can only be added once */
5963 if ( !gpos ||
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;
5983 return HB_Err_Ok;
5988 HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
5990 HB_UShort i;
5992 HB_UInt* properties;
5995 if ( !gpos )
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++ )
6003 properties[i] = 0;
6005 return HB_Err_Ok;
6008 #ifdef HB_SUPPORT_MULTIPLE_MASTER
6009 HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
6010 HB_MMFunction mmfunc,
6011 void* data )
6013 if ( !gpos )
6014 return ERR(HB_Err_Invalid_Argument);
6016 gpos->mmfunc = mmfunc;
6017 gpos->data = data;
6019 return HB_Err_Ok;
6021 #endif
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,
6030 HB_Buffer buffer,
6031 HB_Bool dvi,
6032 HB_Bool r2l )
6034 HB_Error error, retError = HB_Err_Not_Covered;
6035 GPOS_Instance gpi;
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;
6044 gpi.font = font;
6045 gpi.gpos = gpos;
6046 gpi.load_flags = load_flags;
6047 gpi.r2l = r2l;
6048 gpi.dvi = dvi;
6050 lookup_count = gpos->LookupList.LookupCount;
6051 num_features = gpos->FeatureList.ApplyCount;
6053 if ( num_features )
6055 error = _hb_buffer_clear_positions( buffer );
6056 if ( error )
6057 return error;
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)
6071 continue;
6073 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6074 if ( error )
6076 if ( error != HB_Err_Not_Covered )
6077 return error;
6079 else
6080 retError = error;
6084 if ( num_features )
6086 error = Position_CursiveChain ( buffer );
6087 if ( error )
6088 return error;
6091 return retError;
6094 /* END */