summaryrefslogtreecommitdiff
path: root/src/harfbuzz-gpos.c
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2009-05-24 14:22:22 -0400
committerBehdad Esfahbod <behdad@behdad.org>2009-11-02 14:40:17 -0500
commitda2c52abcd75d46929b34cad55c4fb2c8892bc08 (patch)
treea593461a7b29a1aceda3b09084f7de61c50189b4 /src/harfbuzz-gpos.c
parente5372f1621602dcee4e14a4b22dc182c21502a50 (diff)
[HB] Remove old code!
Goodbye 16 thousand lines of ten-year old code!
Diffstat (limited to 'src/harfbuzz-gpos.c')
-rw-r--r--src/harfbuzz-gpos.c6071
1 files changed, 0 insertions, 6071 deletions
diff --git a/src/harfbuzz-gpos.c b/src/harfbuzz-gpos.c
deleted file mode 100644
index c4e8a786..00000000
--- a/src/harfbuzz-gpos.c
+++ /dev/null
@@ -1,6071 +0,0 @@
1/*
2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
4 * Copyright (C) 2007 Red Hat, Inc.
5 *
6 * This is part of HarfBuzz, an OpenType Layout engine library.
7 *
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.
13 *
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.
19 *
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.
25 *
26 * Red Hat Author(s): Behdad Esfahbod
27 */
28
29#include "harfbuzz-impl.h"
30#include "harfbuzz-gpos-private.h"
31#include "harfbuzz-open-private.h"
32#include "harfbuzz-gdef-private.h"
33
34struct GPOS_Instance_
35{
36 HB_GPOSHeader* gpos;
37 HB_Font font;
38 HB_Bool dvi;
39 HB_UShort load_flags; /* how the glyph should be loaded */
40 HB_Bool r2l;
41
42 HB_UShort last; /* the last valid glyph -- used
43 with cursive positioning */
44 HB_Fixed anchor_x; /* the coordinates of the anchor point */
45 HB_Fixed anchor_y; /* of the last valid glyph */
46};
47
48typedef struct GPOS_Instance_ GPOS_Instance;
49
50
51static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
52 HB_UShort lookup_index,
53 HB_Buffer buffer,
54 HB_UShort context_length,
55 int nesting_level );
56
57
58
59/* the client application must replace this with something more
60 meaningful if multiple master fonts are to be supported. */
61
62static HB_Error default_mmfunc( HB_Font font,
63 HB_UShort metric_id,
64 HB_Fixed* metric_value,
65 void* data )
66{
67 HB_UNUSED(font);
68 HB_UNUSED(metric_id);
69 HB_UNUSED(metric_value);
70 HB_UNUSED(data);
71 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
72}
73
74
75
76HB_Error HB_Load_GPOS_Table( HB_Font font,
77 HB_GPOSHeader** retptr,
78 hb_ot_layout_t *layout )
79{
80 HB_UInt cur_offset, new_offset, base_offset;
81
82 HB_GPOSHeader* gpos;
83
84 HB_Stream stream = font->stream;
85 HB_Error error;
86
87
88 if ( !retptr || !layout )
89 return ERR(HB_Err_Invalid_Argument);
90
91 if ( GOTO_Table( TTAG_GPOS ) )
92 return error;
93
94 base_offset = FILE_Pos();
95
96 if ( ALLOC ( gpos, sizeof( *gpos ) ) )
97 return error;
98
99 gpos->gfunc = (HB_GlyphFunction) FT_Load_Glyph;
100 gpos->mmfunc = default_mmfunc;
101
102 /* skip version */
103
104 if ( FILE_Seek( base_offset + 4L ) ||
105 ACCESS_Frame( 2L ) )
106 goto Fail4;
107
108 new_offset = GET_UShort() + base_offset;
109
110 FORGET_Frame();
111
112 cur_offset = FILE_Pos();
113 if ( FILE_Seek( new_offset ) ||
114 ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
115 stream ) ) != HB_Err_Ok )
116 goto Fail4;
117 (void)FILE_Seek( cur_offset );
118
119 if ( ACCESS_Frame( 2L ) )
120 goto Fail3;
121
122 new_offset = GET_UShort() + base_offset;
123
124 FORGET_Frame();
125
126 cur_offset = FILE_Pos();
127 if ( FILE_Seek( new_offset ) ||
128 ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
129 stream ) ) != HB_Err_Ok )
130 goto Fail3;
131 (void)FILE_Seek( cur_offset );
132
133 if ( ACCESS_Frame( 2L ) )
134 goto Fail2;
135
136 new_offset = GET_UShort() + base_offset;
137
138 FORGET_Frame();
139
140 cur_offset = FILE_Pos();
141 if ( FILE_Seek( new_offset ) ||
142 ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
143 stream, HB_Type_GPOS ) ) != HB_Err_Ok )
144 goto Fail2;
145
146 gpos->layout = layout; /* can be NULL */
147
148 *retptr = gpos;
149
150 return HB_Err_Ok;
151
152Fail2:
153 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
154
155Fail3:
156 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
157
158Fail4:
159 FREE( gpos );
160
161 return error;
162}
163
164
165HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
166{
167 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
168 _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
169 _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
170
171 FREE( gpos );
172
173 return HB_Err_Ok;
174}
175
176
177/*****************************
178 * SubTable related functions
179 *****************************/
180
181/* shared tables */
182
183/* ValueRecord */
184
185/* There is a subtle difference in the specs between a `table' and a
186 `record' -- offsets for device tables in ValueRecords are taken from
187 the parent table and not the parent record. */
188
189static HB_Error Load_ValueRecord( HB_ValueRecord* vr,
190 HB_UShort format,
191 HB_UInt base_offset,
192 HB_Stream stream )
193{
194 HB_Error error;
195
196 HB_UInt cur_offset, new_offset;
197
198
199 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
200 {
201 if ( ACCESS_Frame( 2L ) )
202 return error;
203
204 vr->XPlacement = GET_Short();
205
206 FORGET_Frame();
207 }
208 else
209 vr->XPlacement = 0;
210
211 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
212 {
213 if ( ACCESS_Frame( 2L ) )
214 return error;
215
216 vr->YPlacement = GET_Short();
217
218 FORGET_Frame();
219 }
220 else
221 vr->YPlacement = 0;
222
223 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
224 {
225 if ( ACCESS_Frame( 2L ) )
226 return error;
227
228 vr->XAdvance = GET_Short();
229
230 FORGET_Frame();
231 }
232 else
233 vr->XAdvance = 0;
234
235 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
236 {
237 if ( ACCESS_Frame( 2L ) )
238 return error;
239
240 vr->YAdvance = GET_Short();
241
242 FORGET_Frame();
243 }
244 else
245 vr->YAdvance = 0;
246
247 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
248 {
249 if ( ACCESS_Frame( 2L ) )
250 return error;
251
252 new_offset = GET_UShort();
253
254 FORGET_Frame();
255
256 if ( new_offset )
257 {
258 new_offset += base_offset;
259
260 cur_offset = FILE_Pos();
261 if ( FILE_Seek( new_offset ) ||
262 ( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
263 stream ) ) != HB_Err_Ok )
264 return error;
265 (void)FILE_Seek( cur_offset );
266 }
267 else
268 goto empty1;
269 }
270 else
271 {
272 empty1:
273 vr->XPlacementDevice.StartSize = 0;
274 vr->XPlacementDevice.EndSize = 0;
275 vr->XPlacementDevice.DeltaValue = NULL;
276 }
277
278 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
279 {
280 if ( ACCESS_Frame( 2L ) )
281 goto Fail3;
282
283 new_offset = GET_UShort();
284
285 FORGET_Frame();
286
287 if ( new_offset )
288 {
289 new_offset += base_offset;
290
291 cur_offset = FILE_Pos();
292 if ( FILE_Seek( new_offset ) ||
293 ( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
294 stream ) ) != HB_Err_Ok )
295 goto Fail3;
296 (void)FILE_Seek( cur_offset );
297 }
298 else
299 goto empty2;
300 }
301 else
302 {
303 empty2:
304 vr->YPlacementDevice.StartSize = 0;
305 vr->YPlacementDevice.EndSize = 0;
306 vr->YPlacementDevice.DeltaValue = NULL;
307 }
308
309 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
310 {
311 if ( ACCESS_Frame( 2L ) )
312 goto Fail2;
313
314 new_offset = GET_UShort();
315
316 FORGET_Frame();
317
318 if ( new_offset )
319 {
320 new_offset += base_offset;
321
322 cur_offset = FILE_Pos();
323 if ( FILE_Seek( new_offset ) ||
324 ( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice,
325 stream ) ) != HB_Err_Ok )
326 goto Fail2;
327 (void)FILE_Seek( cur_offset );
328 }
329 else
330 goto empty3;
331 }
332 else
333 {
334 empty3:
335 vr->XAdvanceDevice.StartSize = 0;
336 vr->XAdvanceDevice.EndSize = 0;
337 vr->XAdvanceDevice.DeltaValue = NULL;
338 }
339
340 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
341 {
342 if ( ACCESS_Frame( 2L ) )
343 goto Fail1;
344
345 new_offset = GET_UShort();
346
347 FORGET_Frame();
348
349 if ( new_offset )
350 {
351 new_offset += base_offset;
352
353 cur_offset = FILE_Pos();
354 if ( FILE_Seek( new_offset ) ||
355 ( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
356 stream ) ) != HB_Err_Ok )
357 goto Fail1;
358 (void)FILE_Seek( cur_offset );
359 }
360 else
361 goto empty4;
362 }
363 else
364 {
365 empty4:
366 vr->YAdvanceDevice.StartSize = 0;
367 vr->YAdvanceDevice.EndSize = 0;
368 vr->YAdvanceDevice.DeltaValue = NULL;
369 }
370
371 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
372 {
373 if ( ACCESS_Frame( 2L ) )
374 goto Fail1;
375
376 vr->XIdPlacement = GET_UShort();
377
378 FORGET_Frame();
379 }
380 else
381 vr->XIdPlacement = 0;
382
383 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
384 {
385 if ( ACCESS_Frame( 2L ) )
386 goto Fail1;
387
388 vr->YIdPlacement = GET_UShort();
389
390 FORGET_Frame();
391 }
392 else
393 vr->YIdPlacement = 0;
394
395 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
396 {
397 if ( ACCESS_Frame( 2L ) )
398 goto Fail1;
399
400 vr->XIdAdvance = GET_UShort();
401
402 FORGET_Frame();
403 }
404 else
405 vr->XIdAdvance = 0;
406
407 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
408 {
409 if ( ACCESS_Frame( 2L ) )
410 goto Fail1;
411
412 vr->YIdAdvance = GET_UShort();
413
414 FORGET_Frame();
415 }
416 else
417 vr->YIdAdvance = 0;
418
419 return HB_Err_Ok;
420
421Fail1:
422 _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
423
424Fail2:
425 _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
426
427Fail3:
428 _HB_OPEN_Free_Device( &vr->YPlacementDevice );
429 return error;
430}
431
432
433static void Free_ValueRecord( HB_ValueRecord* vr,
434 HB_UShort format )
435{
436 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
437 _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
438 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
439 _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
440 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
441 _HB_OPEN_Free_Device( &vr->YPlacementDevice );
442 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
443 _HB_OPEN_Free_Device( &vr->XPlacementDevice );
444}
445
446
447static HB_Error Get_ValueRecord( GPOS_Instance* gpi,
448 HB_ValueRecord* vr,
449 HB_UShort format,
450 HB_Position gd )
451{
452 HB_Fixed value;
453 HB_Short pixel_value;
454 HB_Error error = HB_Err_Ok;
455 HB_GPOSHeader* gpos = gpi->gpos;
456
457 HB_UShort x_ppem, y_ppem;
458 HB_16Dot16 x_scale, y_scale;
459
460
461 if ( !format )
462 return HB_Err_Ok;
463
464 x_ppem = gpi->font->size->metrics.x_ppem;
465 y_ppem = gpi->font->size->metrics.y_ppem;
466 x_scale = gpi->font->size->metrics.x_scale;
467 y_scale = gpi->font->size->metrics.y_scale;
468
469 /* design units -> fractional pixel */
470
471 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
472 gd->x_pos += x_scale * vr->XPlacement / 0x10000;
473 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
474 gd->y_pos += y_scale * vr->YPlacement / 0x10000;
475 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
476 gd->x_advance += x_scale * vr->XAdvance / 0x10000;
477 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
478 gd->y_advance += y_scale * vr->YAdvance / 0x10000;
479
480 if ( !gpi->dvi )
481 {
482 /* pixel -> fractional pixel */
483
484 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
485 {
486 _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
487 gd->x_pos += pixel_value << 6;
488 }
489 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
490 {
491 _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
492 gd->y_pos += pixel_value << 6;
493 }
494 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
495 {
496 _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
497 gd->x_advance += pixel_value << 6;
498 }
499 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
500 {
501 _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
502 gd->y_advance += pixel_value << 6;
503 }
504 }
505
506 /* values returned from mmfunc() are already in fractional pixels */
507
508 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
509 {
510 error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
511 &value, gpos->data );
512 if ( error )
513 return error;
514 gd->x_pos += value;
515 }
516 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
517 {
518 error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
519 &value, gpos->data );
520 if ( error )
521 return error;
522 gd->y_pos += value;
523 }
524 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
525 {
526 error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
527 &value, gpos->data );
528 if ( error )
529 return error;
530 gd->x_advance += value;
531 }
532 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
533 {
534 error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
535 &value, gpos->data );
536 if ( error )
537 return error;
538 gd->y_advance += value;
539 }
540
541 return error;
542}
543
544
545/* AnchorFormat1 */
546/* AnchorFormat2 */
547/* AnchorFormat3 */
548/* AnchorFormat4 */
549
550static HB_Error Load_Anchor( HB_Anchor* an,
551 HB_Stream stream )
552{
553 HB_Error error;
554
555 HB_UInt cur_offset, new_offset, base_offset;
556
557
558 base_offset = FILE_Pos();
559
560 if ( ACCESS_Frame( 2L ) )
561 return error;
562
563 an->PosFormat = GET_UShort();
564
565 FORGET_Frame();
566
567 switch ( an->PosFormat )
568 {
569 case 1:
570 if ( ACCESS_Frame( 4L ) )
571 return error;
572
573 an->af.af1.XCoordinate = GET_Short();
574 an->af.af1.YCoordinate = GET_Short();
575
576 FORGET_Frame();
577 break;
578
579 case 2:
580 if ( ACCESS_Frame( 6L ) )
581 return error;
582
583 an->af.af2.XCoordinate = GET_Short();
584 an->af.af2.YCoordinate = GET_Short();
585 an->af.af2.AnchorPoint = GET_UShort();
586
587 FORGET_Frame();
588 break;
589
590 case 3:
591 if ( ACCESS_Frame( 6L ) )
592 return error;
593
594 an->af.af3.XCoordinate = GET_Short();
595 an->af.af3.YCoordinate = GET_Short();
596
597 new_offset = GET_UShort();
598
599 FORGET_Frame();
600
601 if ( new_offset )
602 {
603 new_offset += base_offset;
604
605 cur_offset = FILE_Pos();
606 if ( FILE_Seek( new_offset ) ||
607 ( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
608 stream ) ) != HB_Err_Ok )
609 return error;
610 (void)FILE_Seek( cur_offset );
611 }
612 else
613 {
614 an->af.af3.XDeviceTable.StartSize = 0;
615 an->af.af3.XDeviceTable.EndSize = 0;
616 an->af.af3.XDeviceTable.DeltaValue = NULL;
617 }
618
619 if ( ACCESS_Frame( 2L ) )
620 goto Fail;
621
622 new_offset = GET_UShort();
623
624 FORGET_Frame();
625
626 if ( new_offset )
627 {
628 new_offset += base_offset;
629
630 cur_offset = FILE_Pos();
631 if ( FILE_Seek( new_offset ) ||
632 ( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
633 stream ) ) != HB_Err_Ok )
634 goto Fail;
635 (void)FILE_Seek( cur_offset );
636 }
637 else
638 {
639 an->af.af3.YDeviceTable.StartSize = 0;
640 an->af.af3.YDeviceTable.EndSize = 0;
641 an->af.af3.YDeviceTable.DeltaValue = NULL;
642 }
643 break;
644
645 case 4:
646 if ( ACCESS_Frame( 4L ) )
647 return error;
648
649 an->af.af4.XIdAnchor = GET_UShort();
650 an->af.af4.YIdAnchor = GET_UShort();
651
652 FORGET_Frame();
653 break;
654
655 default:
656 return ERR(HB_Err_Invalid_SubTable_Format);
657 }
658
659 return HB_Err_Ok;
660
661Fail:
662 _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
663 return error;
664}
665
666
667static void Free_Anchor( HB_Anchor* an )
668{
669 if ( an->PosFormat == 3 )
670 {
671 _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable );
672 _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
673 }
674}
675
676
677static HB_Error Get_Anchor( GPOS_Instance* gpi,
678 HB_Anchor* an,
679 HB_UShort glyph_index,
680 HB_Fixed* x_value,
681 HB_Fixed* y_value )
682{
683 HB_Error error = HB_Err_Ok;
684
685 FT_Outline outline;
686 HB_GPOSHeader* gpos = gpi->gpos;
687 HB_UShort ap;
688
689 HB_Short pixel_value;
690 HB_UShort load_flags;
691
692 HB_UShort x_ppem, y_ppem;
693 HB_16Dot16 x_scale, y_scale;
694
695
696 x_ppem = gpi->font->size->metrics.x_ppem;
697 y_ppem = gpi->font->size->metrics.y_ppem;
698 x_scale = gpi->font->size->metrics.x_scale;
699 y_scale = gpi->font->size->metrics.y_scale;
700
701 switch ( an->PosFormat )
702 {
703 case 0:
704 /* The special case of an empty AnchorTable */
705 default:
706
707 return HB_Err_Not_Covered;
708
709 case 1:
710 *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
711 *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
712 break;
713
714 case 2:
715 /* glyphs must be scaled */
716
717 load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE;
718
719 if ( !gpi->dvi )
720 {
721 error = (gpos->gfunc)( gpi->font, glyph_index, load_flags );
722 if ( error )
723 return error;
724
725 if ( gpi->font->glyph->format != ft_glyph_format_outline )
726 return ERR(HB_Err_Invalid_SubTable);
727
728 ap = an->af.af2.AnchorPoint;
729
730 outline = gpi->font->glyph->outline;
731
732 /* if n_points is set to zero, we use the design coordinate value pair.
733 * This can happen e.g. for sbit glyphs. */
734 if ( !outline.n_points )
735 goto no_contour_point;
736
737 if ( ap >= outline.n_points )
738 return ERR(HB_Err_Invalid_SubTable);
739
740 *x_value = outline.points[ap].x;
741 *y_value = outline.points[ap].y;
742 }
743 else
744 {
745 no_contour_point:
746 *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
747 *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
748 }
749 break;
750
751 case 3:
752 if ( !gpi->dvi )
753 {
754 _HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
755 *x_value = pixel_value << 6;
756 _HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
757 *y_value = pixel_value << 6;
758 }
759 else
760 *x_value = *y_value = 0;
761
762 *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
763 *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
764 break;
765
766 case 4:
767 error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
768 x_value, gpos->data );
769 if ( error )
770 return error;
771
772 error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
773 y_value, gpos->data );
774 if ( error )
775 return error;
776 break;
777 }
778
779 return error;
780}
781
782
783/* MarkArray */
784
785static HB_Error Load_MarkArray ( HB_MarkArray* ma,
786 HB_Stream stream )
787{
788 HB_Error error;
789
790 HB_UShort n, m, count;
791 HB_UInt cur_offset, new_offset, base_offset;
792
793 HB_MarkRecord* mr;
794
795
796 base_offset = FILE_Pos();
797
798 if ( ACCESS_Frame( 2L ) )
799 return error;
800
801 count = ma->MarkCount = GET_UShort();
802
803 FORGET_Frame();
804
805 ma->MarkRecord = NULL;
806
807 if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
808 return error;
809
810 mr = ma->MarkRecord;
811
812 for ( n = 0; n < count; n++ )
813 {
814 if ( ACCESS_Frame( 4L ) )
815 goto Fail;
816
817 mr[n].Class = GET_UShort();
818 new_offset = GET_UShort() + base_offset;
819
820 FORGET_Frame();
821
822 cur_offset = FILE_Pos();
823 if ( FILE_Seek( new_offset ) ||
824 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
825 goto Fail;
826 (void)FILE_Seek( cur_offset );
827 }
828
829 return HB_Err_Ok;
830
831Fail:
832 for ( m = 0; m < n; m++ )
833 Free_Anchor( &mr[m].MarkAnchor );
834
835 FREE( mr );
836 return error;
837}
838
839
840static void Free_MarkArray( HB_MarkArray* ma )
841{
842 HB_UShort n, count;
843
844 HB_MarkRecord* mr;
845
846
847 if ( ma->MarkRecord )
848 {
849 count = ma->MarkCount;
850 mr = ma->MarkRecord;
851
852 for ( n = 0; n < count; n++ )
853 Free_Anchor( &mr[n].MarkAnchor );
854
855 FREE( mr );
856 }
857}
858
859
860/* LookupType 1 */
861
862/* SinglePosFormat1 */
863/* SinglePosFormat2 */
864
865static HB_Error Load_SinglePos( HB_GPOS_SubTable* st,
866 HB_Stream stream )
867{
868 HB_Error error;
869 HB_SinglePos* sp = &st->single;
870
871 HB_UShort n, m, count, format;
872 HB_UInt cur_offset, new_offset, base_offset;
873
874 HB_ValueRecord* vr;
875
876
877 base_offset = FILE_Pos();
878
879 if ( ACCESS_Frame( 6L ) )
880 return error;
881
882 sp->PosFormat = GET_UShort();
883 new_offset = GET_UShort() + base_offset;
884
885 format = sp->ValueFormat = GET_UShort();
886
887 FORGET_Frame();
888
889 if ( !format )
890 return ERR(HB_Err_Invalid_SubTable);
891
892 cur_offset = FILE_Pos();
893 if ( FILE_Seek( new_offset ) ||
894 ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
895 return error;
896 (void)FILE_Seek( cur_offset );
897
898 switch ( sp->PosFormat )
899 {
900 case 1:
901 error = Load_ValueRecord( &sp->spf.spf1.Value, format,
902 base_offset, stream );
903 if ( error )
904 goto Fail2;
905 break;
906
907 case 2:
908 if ( ACCESS_Frame( 2L ) )
909 goto Fail2;
910
911 count = sp->spf.spf2.ValueCount = GET_UShort();
912
913 FORGET_Frame();
914
915 sp->spf.spf2.Value = NULL;
916
917 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
918 goto Fail2;
919
920 vr = sp->spf.spf2.Value;
921
922 for ( n = 0; n < count; n++ )
923 {
924 error = Load_ValueRecord( &vr[n], format, base_offset, stream );
925 if ( error )
926 goto Fail1;
927 }
928 break;
929
930 default:
931 return ERR(HB_Err_Invalid_SubTable_Format);
932 }
933
934 return HB_Err_Ok;
935
936Fail1:
937 for ( m = 0; m < n; m++ )
938 Free_ValueRecord( &vr[m], format );
939
940 FREE( vr );
941
942Fail2:
943 _HB_OPEN_Free_Coverage( &sp->Coverage );
944 return error;
945}
946
947
948static void Free_SinglePos( HB_GPOS_SubTable* st )
949{
950 HB_UShort n, count, format;
951 HB_SinglePos* sp = &st->single;
952
953 HB_ValueRecord* v;
954
955
956 format = sp->ValueFormat;
957
958 switch ( sp->PosFormat )
959 {
960 case 1:
961 Free_ValueRecord( &sp->spf.spf1.Value, format );
962 break;
963
964 case 2:
965 if ( sp->spf.spf2.Value )
966 {
967 count = sp->spf.spf2.ValueCount;
968 v = sp->spf.spf2.Value;
969
970 for ( n = 0; n < count; n++ )
971 Free_ValueRecord( &v[n], format );
972
973 FREE( v );
974 }
975 break;
976 default:
977 break;
978 }
979
980 _HB_OPEN_Free_Coverage( &sp->Coverage );
981}
982
983static HB_Error Lookup_SinglePos( GPOS_Instance* gpi,
984 HB_GPOS_SubTable* st,
985 HB_Buffer buffer,
986 HB_UShort flags,
987 HB_UShort context_length,
988 int nesting_level )
989{
990 HB_UShort index, property;
991 HB_Error error;
992 HB_GPOSHeader* gpos = gpi->gpos;
993 HB_SinglePos* sp = &st->single;
994
995 HB_UNUSED(nesting_level);
996
997 if ( context_length != 0xFFFF && context_length < 1 )
998 return HB_Err_Not_Covered;
999
1000 if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
1001 return error;
1002
1003 error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
1004 if ( error )
1005 return error;
1006
1007 switch ( sp->PosFormat )
1008 {
1009 case 1:
1010 error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
1011 sp->ValueFormat, POSITION( buffer->in_pos ) );
1012 if ( error )
1013 return error;
1014 break;
1015
1016 case 2:
1017 if ( index >= sp->spf.spf2.ValueCount )
1018 return ERR(HB_Err_Invalid_SubTable);
1019 error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
1020 sp->ValueFormat, POSITION( buffer->in_pos ) );
1021 if ( error )
1022 return error;
1023 break;
1024
1025 default:
1026 return ERR(HB_Err_Invalid_SubTable);
1027 }
1028
1029 (buffer->in_pos)++;
1030
1031 return HB_Err_Ok;
1032}
1033
1034
1035/* LookupType 2 */
1036
1037/* PairSet */
1038
1039static HB_Error Load_PairSet ( HB_PairSet* ps,
1040 HB_UShort format1,
1041 HB_UShort format2,
1042 HB_Stream stream )
1043{
1044 HB_Error error;
1045
1046 HB_UShort n, m, count;
1047 HB_UInt base_offset;
1048
1049 HB_PairValueRecord* pvr;
1050
1051
1052 base_offset = FILE_Pos();
1053
1054 if ( ACCESS_Frame( 2L ) )
1055 return error;
1056
1057 count = ps->PairValueCount = GET_UShort();
1058
1059 FORGET_Frame();
1060
1061 ps->PairValueRecord = NULL;
1062
1063 if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
1064 return error;
1065
1066 pvr = ps->PairValueRecord;
1067
1068 for ( n = 0; n < count; n++ )
1069 {
1070 if ( ACCESS_Frame( 2L ) )
1071 goto Fail;
1072
1073 pvr[n].SecondGlyph = GET_UShort();
1074
1075 FORGET_Frame();
1076
1077 if ( format1 )
1078 {
1079 error = Load_ValueRecord( &pvr[n].Value1, format1,
1080 base_offset, stream );
1081 if ( error )
1082 goto Fail;
1083 }
1084 if ( format2 )
1085 {
1086 error = Load_ValueRecord( &pvr[n].Value2, format2,
1087 base_offset, stream );
1088 if ( error )
1089 {
1090 if ( format1 )
1091 Free_ValueRecord( &pvr[n].Value1, format1 );
1092 goto Fail;
1093 }
1094 }
1095 }
1096
1097 return HB_Err_Ok;
1098
1099Fail:
1100 for ( m = 0; m < n; m++ )
1101 {
1102 if ( format1 )
1103 Free_ValueRecord( &pvr[m].Value1, format1 );
1104 if ( format2 )
1105 Free_ValueRecord( &pvr[m].Value2, format2 );
1106 }
1107
1108 FREE( pvr );
1109 return error;
1110}
1111
1112
1113static void Free_PairSet( HB_PairSet* ps,
1114 HB_UShort format1,
1115 HB_UShort format2 )
1116{
1117 HB_UShort n, count;
1118
1119 HB_PairValueRecord* pvr;
1120
1121
1122 if ( ps->PairValueRecord )
1123 {
1124 count = ps->PairValueCount;
1125 pvr = ps->PairValueRecord;
1126
1127 for ( n = 0; n < count; n++ )
1128 {
1129 if ( format1 )
1130 Free_ValueRecord( &pvr[n].Value1, format1 );
1131 if ( format2 )
1132 Free_ValueRecord( &pvr[n].Value2, format2 );
1133 }
1134
1135 FREE( pvr );
1136 }
1137}
1138
1139
1140/* PairPosFormat1 */
1141
1142static HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
1143 HB_UShort format1,
1144 HB_UShort format2,
1145 HB_Stream stream )
1146{
1147 HB_Error error;
1148
1149 HB_UShort n, m, count;
1150 HB_UInt cur_offset, new_offset, base_offset;
1151
1152 HB_PairSet* ps;
1153
1154
1155 base_offset = FILE_Pos() - 8L;
1156
1157 if ( ACCESS_Frame( 2L ) )
1158 return error;
1159
1160 count = ppf1->PairSetCount = GET_UShort();
1161
1162 FORGET_Frame();
1163
1164 ppf1->PairSet = NULL;
1165
1166 if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
1167 return error;
1168
1169 ps = ppf1->PairSet;
1170
1171 for ( n = 0; n < count; n++ )
1172 {
1173 if ( ACCESS_Frame( 2L ) )
1174 goto Fail;
1175
1176 new_offset = GET_UShort() + base_offset;
1177
1178 FORGET_Frame();
1179
1180 cur_offset = FILE_Pos();
1181 if ( FILE_Seek( new_offset ) ||
1182 ( error = Load_PairSet( &ps[n], format1,
1183 format2, stream ) ) != HB_Err_Ok )
1184 goto Fail;
1185 (void)FILE_Seek( cur_offset );
1186 }
1187
1188 return HB_Err_Ok;
1189
1190Fail:
1191 for ( m = 0; m < n; m++ )
1192 Free_PairSet( &ps[m], format1, format2 );
1193
1194 FREE( ps );
1195 return error;
1196}
1197
1198
1199static void Free_PairPos1( HB_PairPosFormat1* ppf1,
1200 HB_UShort format1,
1201 HB_UShort format2 )
1202{
1203 HB_UShort n, count;
1204
1205 HB_PairSet* ps;
1206
1207
1208 if ( ppf1->PairSet )
1209 {
1210 count = ppf1->PairSetCount;
1211 ps = ppf1->PairSet;
1212
1213 for ( n = 0; n < count; n++ )
1214 Free_PairSet( &ps[n], format1, format2 );
1215
1216 FREE( ps );
1217 }
1218}
1219
1220
1221/* PairPosFormat2 */
1222
1223static HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
1224 HB_UShort format1,
1225 HB_UShort format2,
1226 HB_Stream stream )
1227{
1228 HB_Error error;
1229
1230 HB_UShort m, n, k, count1, count2;
1231 HB_UInt cur_offset, new_offset1, new_offset2, base_offset;
1232
1233 HB_Class1Record* c1r;
1234 HB_Class2Record* c2r;
1235
1236
1237 base_offset = FILE_Pos() - 8L;
1238
1239 if ( ACCESS_Frame( 8L ) )
1240 return error;
1241
1242 new_offset1 = GET_UShort() + base_offset;
1243 new_offset2 = GET_UShort() + base_offset;
1244
1245 /* `Class1Count' and `Class2Count' are the upper limits for class
1246 values, thus we read it now to make additional safety checks. */
1247
1248 count1 = ppf2->Class1Count = GET_UShort();
1249 count2 = ppf2->Class2Count = GET_UShort();
1250
1251 FORGET_Frame();
1252
1253 cur_offset = FILE_Pos();
1254 if ( FILE_Seek( new_offset1 ) ||
1255 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
1256 stream ) ) != HB_Err_Ok )
1257 return error;
1258 if ( FILE_Seek( new_offset2 ) ||
1259 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
1260 stream ) ) != HB_Err_Ok )
1261 goto Fail3;
1262 (void)FILE_Seek( cur_offset );
1263
1264 ppf2->Class1Record = NULL;
1265
1266 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
1267 goto Fail2;
1268
1269 c1r = ppf2->Class1Record;
1270
1271 for ( m = 0; m < count1; m++ )
1272 {
1273 c1r[m].Class2Record = NULL;
1274
1275 if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
1276 goto Fail1;
1277
1278 c2r = c1r[m].Class2Record;
1279
1280 for ( n = 0; n < count2; n++ )
1281 {
1282 if ( format1 )
1283 {
1284 error = Load_ValueRecord( &c2r[n].Value1, format1,
1285 base_offset, stream );
1286 if ( error )
1287 goto Fail0;
1288 }
1289 if ( format2 )
1290 {
1291 error = Load_ValueRecord( &c2r[n].Value2, format2,
1292 base_offset, stream );
1293 if ( error )
1294 {
1295 if ( format1 )
1296 Free_ValueRecord( &c2r[n].Value1, format1 );
1297 goto Fail0;
1298 }
1299 }
1300 }
1301
1302 continue;
1303
1304 Fail0:
1305 for ( k = 0; k < n; k++ )
1306 {
1307 if ( format1 )
1308 Free_ValueRecord( &c2r[k].Value1, format1 );
1309 if ( format2 )
1310 Free_ValueRecord( &c2r[k].Value2, format2 );
1311 }
1312 goto Fail1;
1313 }
1314
1315 return HB_Err_Ok;
1316
1317Fail1:
1318 for ( k = 0; k < m; k++ )
1319 {
1320 c2r = c1r[k].Class2Record;
1321
1322 for ( n = 0; n < count2; n++ )
1323 {
1324 if ( format1 )
1325 Free_ValueRecord( &c2r[n].Value1, format1 );
1326 if ( format2 )
1327 Free_ValueRecord( &c2r[n].Value2, format2 );
1328 }
1329
1330 FREE( c2r );
1331 }
1332
1333 FREE( c1r );
1334Fail2:
1335
1336 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1337
1338Fail3:
1339 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1340 return error;
1341}
1342
1343
1344static void Free_PairPos2( HB_PairPosFormat2* ppf2,
1345 HB_UShort format1,
1346 HB_UShort format2 )
1347{
1348 HB_UShort m, n, count1, count2;
1349
1350 HB_Class1Record* c1r;
1351 HB_Class2Record* c2r;
1352
1353
1354 if ( ppf2->Class1Record )
1355 {
1356 c1r = ppf2->Class1Record;
1357 count1 = ppf2->Class1Count;
1358 count2 = ppf2->Class2Count;
1359
1360 for ( m = 0; m < count1; m++ )
1361 {
1362 c2r = c1r[m].Class2Record;
1363
1364 for ( n = 0; n < count2; n++ )
1365 {
1366 if ( format1 )
1367 Free_ValueRecord( &c2r[n].Value1, format1 );
1368 if ( format2 )
1369 Free_ValueRecord( &c2r[n].Value2, format2 );
1370 }
1371
1372 FREE( c2r );
1373 }
1374
1375 FREE( c1r );
1376
1377 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
1378 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
1379 }
1380}
1381
1382
1383static HB_Error Load_PairPos( HB_GPOS_SubTable* st,
1384 HB_Stream stream )
1385{
1386 HB_Error error;
1387 HB_PairPos* pp = &st->pair;
1388
1389 HB_UShort format1, format2;
1390 HB_UInt cur_offset, new_offset, base_offset;
1391
1392
1393 base_offset = FILE_Pos();
1394
1395 if ( ACCESS_Frame( 8L ) )
1396 return error;
1397
1398 pp->PosFormat = GET_UShort();
1399 new_offset = GET_UShort() + base_offset;
1400
1401 format1 = pp->ValueFormat1 = GET_UShort();
1402 format2 = pp->ValueFormat2 = GET_UShort();
1403
1404 FORGET_Frame();
1405
1406 cur_offset = FILE_Pos();
1407 if ( FILE_Seek( new_offset ) ||
1408 ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
1409 return error;
1410 (void)FILE_Seek( cur_offset );
1411
1412 switch ( pp->PosFormat )
1413 {
1414 case 1:
1415 error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
1416 if ( error )
1417 goto Fail;
1418 break;
1419
1420 case 2:
1421 error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
1422 if ( error )
1423 goto Fail;
1424 break;
1425
1426 default:
1427 return ERR(HB_Err_Invalid_SubTable_Format);
1428 }
1429
1430 return HB_Err_Ok;
1431
1432Fail:
1433 _HB_OPEN_Free_Coverage( &pp->Coverage );
1434 return error;
1435}
1436
1437
1438static void Free_PairPos( HB_GPOS_SubTable* st )
1439{
1440 HB_UShort format1, format2;
1441 HB_PairPos* pp = &st->pair;
1442
1443
1444 format1 = pp->ValueFormat1;
1445 format2 = pp->ValueFormat2;
1446
1447 switch ( pp->PosFormat )
1448 {
1449 case 1:
1450 Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
1451 break;
1452
1453 case 2:
1454 Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
1455 break;
1456
1457 default:
1458 break;
1459 }
1460
1461 _HB_OPEN_Free_Coverage( &pp->Coverage );
1462}
1463
1464
1465static HB_Error Lookup_PairPos1( GPOS_Instance* gpi,
1466 HB_PairPosFormat1* ppf1,
1467 HB_Buffer buffer,
1468 HB_UInt first_pos,
1469 HB_UShort index,
1470 HB_UShort format1,
1471 HB_UShort format2 )
1472{
1473 HB_Error error;
1474 HB_UShort numpvr, glyph2;
1475
1476 HB_PairValueRecord* pvr;
1477
1478
1479 if ( index >= ppf1->PairSetCount )
1480 return ERR(HB_Err_Invalid_SubTable);
1481
1482 pvr = ppf1->PairSet[index].PairValueRecord;
1483 if ( !pvr )
1484 return ERR(HB_Err_Invalid_SubTable);
1485
1486 glyph2 = IN_CURGLYPH();
1487
1488 for ( numpvr = ppf1->PairSet[index].PairValueCount;
1489 numpvr;
1490 numpvr--, pvr++ )
1491 {
1492 if ( glyph2 == pvr->SecondGlyph )
1493 {
1494 error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1495 POSITION( first_pos ) );
1496 if ( error )
1497 return error;
1498 return Get_ValueRecord( gpi, &pvr->Value2, format2,
1499 POSITION( buffer->in_pos ) );
1500 }
1501 }
1502
1503 return HB_Err_Not_Covered;
1504}
1505
1506
1507static HB_Error Lookup_PairPos2( GPOS_Instance* gpi,
1508 HB_PairPosFormat2* ppf2,
1509 HB_Buffer buffer,
1510 HB_UInt first_pos,
1511 HB_UShort format1,
1512 HB_UShort format2 )
1513{
1514 HB_Error error;
1515 HB_UShort cl1 = 0, cl2 = 0; /* shut compiler up */
1516
1517 HB_Class1Record* c1r;
1518 HB_Class2Record* c2r;
1519
1520
1521 error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
1522 &cl1, NULL );
1523 if ( error && error != HB_Err_Not_Covered )
1524 return error;
1525 error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1526 &cl2, NULL );
1527 if ( error && error != HB_Err_Not_Covered )
1528 return error;
1529
1530 c1r = &ppf2->Class1Record[cl1];
1531 if ( !c1r )
1532 return ERR(HB_Err_Invalid_SubTable);
1533 c2r = &c1r->Class2Record[cl2];
1534
1535 error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1536 if ( error )
1537 return error;
1538 return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
1539}
1540
1541
1542static HB_Error Lookup_PairPos( GPOS_Instance* gpi,
1543 HB_GPOS_SubTable* st,
1544 HB_Buffer buffer,
1545 HB_UShort flags,
1546 HB_UShort context_length,
1547 int nesting_level )
1548{
1549 HB_Error error;
1550 HB_UShort index, property;
1551 HB_UInt first_pos;
1552 HB_GPOSHeader* gpos = gpi->gpos;
1553 HB_PairPos* pp = &st->pair;
1554
1555 HB_UNUSED(nesting_level);
1556
1557 if ( buffer->in_pos >= buffer->in_length - 1 )
1558 return HB_Err_Not_Covered; /* Not enough glyphs in stream */
1559
1560 if ( context_length != 0xFFFF && context_length < 2 )
1561 return HB_Err_Not_Covered;
1562
1563 if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
1564 return error;
1565
1566 error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1567 if ( error )
1568 return error;
1569
1570 /* second glyph */
1571
1572 first_pos = buffer->in_pos;
1573 (buffer->in_pos)++;
1574
1575 while ( CHECK_Property( gpos->layout, IN_CURITEM(),
1576 flags, &property ) )
1577 {
1578 if ( error && error != HB_Err_Not_Covered )
1579 return error;
1580
1581 if ( buffer->in_pos == buffer->in_length )
1582 {
1583 buffer->in_pos = first_pos;
1584 return HB_Err_Not_Covered;
1585 }
1586 (buffer->in_pos)++;
1587
1588 }
1589
1590 switch ( pp->PosFormat )
1591 {
1592 case 1:
1593 error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1594 first_pos, index,
1595 pp->ValueFormat1, pp->ValueFormat2 );
1596 break;
1597
1598 case 2:
1599 error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1600 pp->ValueFormat1, pp->ValueFormat2 );
1601 break;
1602
1603 default:
1604 return ERR(HB_Err_Invalid_SubTable_Format);
1605 }
1606
1607 /* if we don't have coverage for the second glyph don't skip it for
1608 further lookups but reset in_pos back to the first_glyph and let
1609 the caller in Do_String_Lookup increment in_pos */
1610 if ( error == HB_Err_Not_Covered )
1611 buffer->in_pos = first_pos;
1612
1613 /* adjusting the `next' glyph */
1614
1615 if ( pp->ValueFormat2 )
1616 (buffer->in_pos)++;
1617
1618 return error;
1619}
1620
1621
1622/* LookupType 3 */
1623
1624/* CursivePosFormat1 */
1625
1626static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
1627 HB_Stream stream )
1628{
1629 HB_Error error;
1630 HB_CursivePos* cp = &st->cursive;
1631
1632 HB_UShort n, m, count;
1633 HB_UInt cur_offset, new_offset, base_offset;
1634
1635 HB_EntryExitRecord* eer;
1636
1637
1638 base_offset = FILE_Pos();
1639
1640 if ( ACCESS_Frame( 4L ) )
1641 return error;
1642
1643 cp->PosFormat = GET_UShort();
1644 new_offset = GET_UShort() + base_offset;
1645
1646 FORGET_Frame();
1647
1648 cur_offset = FILE_Pos();
1649 if ( FILE_Seek( new_offset ) ||
1650 ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
1651 return error;
1652 (void)FILE_Seek( cur_offset );
1653
1654 if ( ACCESS_Frame( 2L ) )
1655 goto Fail2;
1656
1657 count = cp->EntryExitCount = GET_UShort();
1658
1659 FORGET_Frame();
1660
1661 cp->EntryExitRecord = NULL;
1662
1663 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1664 goto Fail2;
1665
1666 eer = cp->EntryExitRecord;
1667
1668 for ( n = 0; n < count; n++ )
1669 {
1670 HB_UInt entry_offset;
1671
1672 if ( ACCESS_Frame( 2L ) )
1673 return error;
1674
1675 entry_offset = new_offset = GET_UShort();
1676
1677 FORGET_Frame();
1678
1679 if ( new_offset )
1680 {
1681 new_offset += base_offset;
1682
1683 cur_offset = FILE_Pos();
1684 if ( FILE_Seek( new_offset ) ||
1685 ( error = Load_Anchor( &eer[n].EntryAnchor,
1686 stream ) ) != HB_Err_Ok )
1687 goto Fail1;
1688 (void)FILE_Seek( cur_offset );
1689 }
1690 else
1691 eer[n].EntryAnchor.PosFormat = 0;
1692
1693 if ( ACCESS_Frame( 2L ) )
1694 return error;
1695
1696 new_offset = GET_UShort();
1697
1698 FORGET_Frame();
1699
1700 if ( new_offset )
1701 {
1702 new_offset += base_offset;
1703
1704 cur_offset = FILE_Pos();
1705 if ( FILE_Seek( new_offset ) ||
1706 ( error = Load_Anchor( &eer[n].ExitAnchor,
1707 stream ) ) != HB_Err_Ok )
1708 {
1709 if ( entry_offset )
1710 Free_Anchor( &eer[n].EntryAnchor );
1711 goto Fail1;
1712 }
1713 (void)FILE_Seek( cur_offset );
1714 }
1715 else
1716 eer[n].ExitAnchor.PosFormat = 0;
1717 }
1718
1719 return HB_Err_Ok;
1720
1721Fail1:
1722 for ( m = 0; m < n; m++ )
1723 {
1724 Free_Anchor( &eer[m].EntryAnchor );
1725 Free_Anchor( &eer[m].ExitAnchor );
1726 }
1727
1728 FREE( eer );
1729
1730Fail2:
1731 _HB_OPEN_Free_Coverage( &cp->Coverage );
1732 return error;
1733}
1734
1735
1736static void Free_CursivePos( HB_GPOS_SubTable* st )
1737{
1738 HB_UShort n, count;
1739 HB_CursivePos* cp = &st->cursive;
1740
1741 HB_EntryExitRecord* eer;
1742
1743
1744 if ( cp->EntryExitRecord )
1745 {
1746 count = cp->EntryExitCount;
1747 eer = cp->EntryExitRecord;
1748
1749 for ( n = 0; n < count; n++ )
1750 {
1751 Free_Anchor( &eer[n].EntryAnchor );
1752 Free_Anchor( &eer[n].ExitAnchor );
1753 }
1754
1755 FREE( eer );
1756 }
1757
1758 _HB_OPEN_Free_Coverage( &cp->Coverage );
1759}
1760
1761
1762static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
1763 HB_GPOS_SubTable* st,
1764 HB_Buffer buffer,
1765 HB_UShort flags,
1766 HB_UShort context_length,
1767 int nesting_level )
1768{
1769 HB_UShort index, property;
1770 HB_Error error;
1771 HB_GPOSHeader* gpos = gpi->gpos;
1772 HB_CursivePos* cp = &st->cursive;
1773
1774 HB_EntryExitRecord* eer;
1775 HB_Fixed entry_x, entry_y;
1776 HB_Fixed exit_x, exit_y;
1777
1778 HB_UNUSED(nesting_level);
1779
1780 if ( context_length != 0xFFFF && context_length < 1 )
1781 {
1782 gpi->last = 0xFFFF;
1783 return HB_Err_Not_Covered;
1784 }
1785
1786 /* Glyphs not having the right GDEF property will be ignored, i.e.,
1787 gpi->last won't be reset (contrary to user defined properties). */
1788
1789 if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
1790 return error;
1791
1792 /* We don't handle mark glyphs here. According to Andrei, this isn't
1793 possible, but who knows... */
1794
1795 if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK )
1796 {
1797 gpi->last = 0xFFFF;
1798 return HB_Err_Not_Covered;
1799 }
1800
1801 error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1802 if ( error )
1803 {
1804 gpi->last = 0xFFFF;
1805 return error;
1806 }
1807
1808 if ( index >= cp->EntryExitCount )
1809 return ERR(HB_Err_Invalid_SubTable);
1810
1811 eer = &cp->EntryExitRecord[index];
1812
1813 /* Now comes the messiest part of the whole OpenType
1814 specification. At first glance, cursive connections seem easy
1815 to understand, but there are pitfalls! The reason is that
1816 the specs don't mention how to compute the advance values
1817 resp. glyph offsets. I was told it would be an omission, to
1818 be fixed in the next OpenType version... Again many thanks to
1819 Andrei Burago <andreib@microsoft.com> for clarifications.
1820
1821 Consider the following example:
1822
1823 | xadv1 |
1824 +---------+
1825 | |
1826 +-----+--+ 1 |
1827 | | .| |
1828 | 0+--+------+
1829 | 2 |
1830 | |
1831 0+--------+
1832 | xadv2 |
1833
1834 glyph1: advance width = 12
1835 anchor point = (3,1)
1836
1837 glyph2: advance width = 11
1838 anchor point = (9,4)
1839
1840 LSB is 1 for both glyphs (so the boxes drawn above are glyph
1841 bboxes). Writing direction is R2L; `0' denotes the glyph's
1842 coordinate origin.
1843
1844 Now the surprising part: The advance width of the *left* glyph
1845 (resp. of the *bottom* glyph) will be modified, no matter
1846 whether the writing direction is L2R or R2L (resp. T2B or
1847 B2T)! This assymetry is caused by the fact that the glyph's
1848 coordinate origin is always the lower left corner for all
1849 writing directions.
1850
1851 Continuing the above example, we can compute the new
1852 (horizontal) advance width of glyph2 as
1853
1854 9 - 3 = 6 ,
1855
1856 and the new vertical offset of glyph2 as
1857
1858 1 - 4 = -3 .
1859
1860
1861 Vertical writing direction is far more complicated:
1862
1863 a) Assuming that we recompute the advance height of the lower glyph:
1864
1865 --
1866 +---------+
1867 -- | |
1868 +-----+--+ 1 | yadv1
1869 | | .| |
1870 yadv2 | 0+--+------+ -- BSB1 --
1871 | 2 | -- -- y_offset
1872 | |
1873 BSB2 -- 0+--------+ --
1874 -- --
1875
1876 glyph1: advance height = 6
1877 anchor point = (3,1)
1878
1879 glyph2: advance height = 7
1880 anchor point = (9,4)
1881
1882 TSB is 1 for both glyphs; writing direction is T2B.
1883
1884
1885 BSB1 = yadv1 - (TSB1 + ymax1)
1886 BSB2 = yadv2 - (TSB2 + ymax2)
1887 y_offset = y2 - y1
1888
1889 vertical advance width of glyph2
1890 = y_offset + BSB2 - BSB1
1891 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1892 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1893 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1894
1895
1896 b) Assuming that we recompute the advance height of the upper glyph:
1897
1898 -- --
1899 +---------+ -- TSB1
1900 -- -- | |
1901 TSB2 -- +-----+--+ 1 | yadv1 ymax1
1902 | | .| |
1903 yadv2 | 0+--+------+ -- --
1904 ymax2 | 2 | -- y_offset
1905 | |
1906 -- 0+--------+ --
1907 --
1908
1909 glyph1: advance height = 6
1910 anchor point = (3,1)
1911
1912 glyph2: advance height = 7
1913 anchor point = (9,4)
1914
1915 TSB is 1 for both glyphs; writing direction is T2B.
1916
1917 y_offset = y2 - y1
1918
1919 vertical advance width of glyph2
1920 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1921 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1922
1923
1924 Comparing a) with b) shows that b) is easier to compute. I'll wait
1925 for a reply from Andrei to see what should really be implemented...
1926
1927 Since horizontal advance widths or vertical advance heights
1928 can be used alone but not together, no ambiguity occurs. */
1929
1930 if ( gpi->last == 0xFFFF )
1931 goto end;
1932
1933 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1934 table. */
1935
1936 error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1937 &entry_x, &entry_y );
1938 if ( error == HB_Err_Not_Covered )
1939 goto end;
1940 if ( error )
1941 return error;
1942
1943 if ( gpi->r2l )
1944 {
1945 POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
1946 POSITION( buffer->in_pos )->new_advance = TRUE;
1947 }
1948 else
1949 {
1950 POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
1951 POSITION( gpi->last )->new_advance = TRUE;
1952 }
1953
1954 if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
1955 {
1956 POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
1957 POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
1958 }
1959 else
1960 {
1961 POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
1962 POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
1963 }
1964
1965end:
1966 error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
1967 &exit_x, &exit_y );
1968 if ( error == HB_Err_Not_Covered )
1969 gpi->last = 0xFFFF;
1970 else
1971 {
1972 gpi->last = buffer->in_pos;
1973 gpi->anchor_x = exit_x;
1974 gpi->anchor_y = exit_y;
1975 }
1976 if ( error )
1977 return error;
1978
1979 (buffer->in_pos)++;
1980
1981 return HB_Err_Ok;
1982}
1983
1984
1985/* LookupType 4 */
1986
1987/* BaseArray */
1988
1989static HB_Error Load_BaseArray( HB_BaseArray* ba,
1990 HB_UShort num_classes,
1991 HB_Stream stream )
1992{
1993 HB_Error error;
1994
1995 HB_UShort m, n, count;
1996 HB_UInt cur_offset, new_offset, base_offset;
1997
1998 HB_BaseRecord *br;
1999 HB_Anchor *ban, *bans;
2000
2001
2002 base_offset = FILE_Pos();
2003
2004 if ( ACCESS_Frame( 2L ) )
2005 return error;
2006
2007 count = ba->BaseCount = GET_UShort();
2008
2009 FORGET_Frame();
2010
2011 ba->BaseRecord = NULL;
2012
2013 if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2014 return error;
2015
2016 br = ba->BaseRecord;
2017
2018 bans = NULL;
2019
2020 if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
2021 goto Fail;
2022
2023 for ( m = 0; m < count; m++ )
2024 {
2025 br[m].BaseAnchor = NULL;
2026
2027 ban = br[m].BaseAnchor = bans + m * num_classes;
2028
2029 for ( n = 0; n < num_classes; n++ )
2030 {
2031 if ( ACCESS_Frame( 2L ) )
2032 goto Fail;
2033
2034 new_offset = GET_UShort() + base_offset;
2035
2036 FORGET_Frame();
2037
2038 if (new_offset == base_offset) {
2039 /* XXX
2040 * Doulos SIL Regular is buggy and has zero offsets here.
2041 * Skip it
2042 */
2043 ban[n].PosFormat = 0;
2044 continue;
2045 }
2046
2047 cur_offset = FILE_Pos();
2048 if ( FILE_Seek( new_offset ) ||
2049 ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
2050 goto Fail;
2051 (void)FILE_Seek( cur_offset );
2052 }
2053 }
2054
2055 return HB_Err_Ok;
2056
2057Fail:
2058 FREE( bans );
2059 FREE( br );
2060 return error;
2061}
2062
2063
2064static void Free_BaseArray( HB_BaseArray* ba,
2065 HB_UShort num_classes )
2066{
2067 HB_BaseRecord *br;
2068 HB_Anchor *bans;
2069
2070 HB_UNUSED(num_classes);
2071
2072 if ( ba->BaseRecord )
2073 {
2074 br = ba->BaseRecord;
2075
2076 if ( ba->BaseCount )
2077 {
2078 bans = br[0].BaseAnchor;
2079 FREE( bans );
2080 }
2081
2082 FREE( br );
2083 }
2084}
2085
2086
2087/* MarkBasePosFormat1 */
2088
2089static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
2090 HB_Stream stream )
2091{
2092 HB_Error error;
2093 HB_MarkBasePos* mbp = &st->markbase;
2094
2095 HB_UInt cur_offset, new_offset, base_offset;
2096
2097
2098 base_offset = FILE_Pos();
2099
2100 if ( ACCESS_Frame( 4L ) )
2101 return error;
2102
2103 mbp->PosFormat = GET_UShort();
2104 new_offset = GET_UShort() + base_offset;
2105
2106 FORGET_Frame();
2107
2108 if (mbp->PosFormat != 1)
2109 return ERR(HB_Err_Invalid_SubTable_Format);
2110
2111 cur_offset = FILE_Pos();
2112 if ( FILE_Seek( new_offset ) ||
2113 ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
2114 return error;
2115 (void)FILE_Seek( cur_offset );
2116
2117 if ( ACCESS_Frame( 2L ) )
2118 goto Fail3;
2119
2120 new_offset = GET_UShort() + base_offset;
2121
2122 FORGET_Frame();
2123
2124 cur_offset = FILE_Pos();
2125 if ( FILE_Seek( new_offset ) ||
2126 ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
2127 goto Fail3;
2128 (void)FILE_Seek( cur_offset );
2129
2130 if ( ACCESS_Frame( 4L ) )
2131 goto Fail2;
2132
2133 mbp->ClassCount = GET_UShort();
2134 new_offset = GET_UShort() + base_offset;
2135
2136 FORGET_Frame();
2137
2138 cur_offset = FILE_Pos();
2139 if ( FILE_Seek( new_offset ) ||
2140 ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
2141 goto Fail2;
2142 (void)FILE_Seek( cur_offset );
2143
2144 if ( ACCESS_Frame( 2L ) )
2145 goto Fail1;
2146
2147 new_offset = GET_UShort() + base_offset;
2148
2149 FORGET_Frame();
2150
2151 cur_offset = FILE_Pos();
2152 if ( FILE_Seek( new_offset ) ||
2153 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2154 stream ) ) != HB_Err_Ok )
2155 goto Fail1;
2156
2157 return HB_Err_Ok;
2158
2159Fail1:
2160 Free_MarkArray( &mbp->MarkArray );
2161
2162Fail2:
2163 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2164
2165Fail3:
2166 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2167 return error;
2168}
2169
2170
2171static void Free_MarkBasePos( HB_GPOS_SubTable* st )
2172{
2173 HB_MarkBasePos* mbp = &st->markbase;
2174
2175 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
2176 Free_MarkArray( &mbp->MarkArray );
2177 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2178 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2179}
2180
2181
2182static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
2183 HB_GPOS_SubTable* st,
2184 HB_Buffer buffer,
2185 HB_UShort flags,
2186 HB_UShort context_length,
2187 int nesting_level )
2188{
2189 HB_UShort i, j, mark_index, base_index, property, class;
2190 HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value;
2191 HB_Error error;
2192 HB_GPOSHeader* gpos = gpi->gpos;
2193 HB_MarkBasePos* mbp = &st->markbase;
2194
2195 HB_MarkArray* ma;
2196 HB_BaseArray* ba;
2197 HB_BaseRecord* br;
2198 HB_Anchor* mark_anchor;
2199 HB_Anchor* base_anchor;
2200
2201 HB_Position o;
2202
2203 HB_UNUSED(nesting_level);
2204
2205 if ( context_length != 0xFFFF && context_length < 1 )
2206 return HB_Err_Not_Covered;
2207
2208 if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
2209 return HB_Err_Not_Covered;
2210
2211 if ( CHECK_Property( gpos->layout, IN_CURITEM(),
2212 flags, &property ) )
2213 return error;
2214
2215 error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2216 &mark_index );
2217 if ( error )
2218 return error;
2219
2220 /* now we search backwards for a non-mark glyph */
2221
2222 i = 1;
2223 j = buffer->in_pos - 1;
2224
2225 while ( i <= buffer->in_pos )
2226 {
2227 property = _hb_ot_layout_get_glyph_property (gpos->layout, IN_GLYPH(j));
2228 if ( !property )
2229 return HB_Err_Not_Covered;
2230
2231 if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2232 break;
2233
2234 i++;
2235 j--;
2236 }
2237
2238 /* The following assertion is too strong -- at least for mangal.ttf. */
2239#if 0
2240 if ( property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH )
2241 return HB_Err_Not_Covered;
2242#endif
2243
2244 if ( i > buffer->in_pos )
2245 return HB_Err_Not_Covered;
2246
2247 error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2248 &base_index );
2249 if ( error )
2250 return error;
2251
2252 ma = &mbp->MarkArray;
2253
2254 if ( mark_index >= ma->MarkCount )
2255 return ERR(HB_Err_Invalid_SubTable);
2256
2257 class = ma->MarkRecord[mark_index].Class;
2258 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2259
2260 if ( class >= mbp->ClassCount )
2261 return ERR(HB_Err_Invalid_SubTable);
2262
2263 ba = &mbp->BaseArray;
2264
2265 if ( base_index >= ba->BaseCount )
2266 return ERR(HB_Err_Invalid_SubTable);
2267
2268 br = &ba->BaseRecord[base_index];
2269 base_anchor = &br->BaseAnchor[class];
2270
2271 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2272 &x_mark_value, &y_mark_value );
2273 if ( error )
2274 return error;
2275
2276 error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2277 &x_base_value, &y_base_value );
2278 if ( error )
2279 return error;
2280
2281 /* anchor points are not cumulative */
2282
2283 o = POSITION( buffer->in_pos );
2284
2285 o->x_pos = x_base_value - x_mark_value;
2286 o->y_pos = y_base_value - y_mark_value;
2287 o->x_advance = 0;
2288 o->y_advance = 0;
2289 o->back = i;
2290
2291 (buffer->in_pos)++;
2292
2293 return HB_Err_Ok;
2294}
2295
2296
2297/* LookupType 5 */
2298
2299/* LigatureAttach */
2300
2301static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
2302 HB_UShort num_classes,
2303 HB_Stream stream )
2304{
2305 HB_Error error;
2306
2307 HB_UShort m, n, k, count;
2308 HB_UInt cur_offset, new_offset, base_offset;
2309
2310 HB_ComponentRecord* cr;
2311 HB_Anchor* lan;
2312
2313
2314 base_offset = FILE_Pos();
2315
2316 if ( ACCESS_Frame( 2L ) )
2317 return error;
2318
2319 count = lat->ComponentCount = GET_UShort();
2320
2321 FORGET_Frame();
2322
2323 lat->ComponentRecord = NULL;
2324
2325 if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2326 return error;
2327
2328 cr = lat->ComponentRecord;
2329
2330 for ( m = 0; m < count; m++ )
2331 {
2332 cr[m].LigatureAnchor = NULL;
2333
2334 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
2335 goto Fail;
2336
2337 lan = cr[m].LigatureAnchor;
2338
2339 for ( n = 0; n < num_classes; n++ )
2340 {
2341 if ( ACCESS_Frame( 2L ) )
2342 goto Fail0;
2343
2344 new_offset = GET_UShort();
2345
2346 FORGET_Frame();
2347
2348 if ( new_offset )
2349 {
2350 new_offset += base_offset;
2351
2352 cur_offset = FILE_Pos();
2353 if ( FILE_Seek( new_offset ) ||
2354 ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
2355 goto Fail0;
2356 (void)FILE_Seek( cur_offset );
2357 }
2358 else
2359 lan[n].PosFormat = 0;
2360 }
2361
2362 continue;
2363 Fail0:
2364 for ( k = 0; k < n; k++ )
2365 Free_Anchor( &lan[k] );
2366 goto Fail;
2367 }
2368
2369 return HB_Err_Ok;
2370
2371Fail:
2372 for ( k = 0; k < m; k++ )
2373 {
2374 lan = cr[k].LigatureAnchor;
2375
2376 for ( n = 0; n < num_classes; n++ )
2377 Free_Anchor( &lan[n] );
2378
2379 FREE( lan );
2380 }
2381
2382 FREE( cr );
2383 return error;
2384}
2385
2386
2387static void Free_LigatureAttach( HB_LigatureAttach* lat,
2388 HB_UShort num_classes )
2389{
2390 HB_UShort m, n, count;
2391
2392 HB_ComponentRecord* cr;
2393 HB_Anchor* lan;
2394
2395
2396 if ( lat->ComponentRecord )
2397 {
2398 count = lat->ComponentCount;
2399 cr = lat->ComponentRecord;
2400
2401 for ( m = 0; m < count; m++ )
2402 {
2403 lan = cr[m].LigatureAnchor;
2404
2405 for ( n = 0; n < num_classes; n++ )
2406 Free_Anchor( &lan[n] );
2407
2408 FREE( lan );
2409 }
2410
2411 FREE( cr );
2412 }
2413}
2414
2415
2416/* LigatureArray */
2417
2418static HB_Error Load_LigatureArray( HB_LigatureArray* la,
2419 HB_UShort num_classes,
2420 HB_Stream stream )
2421{
2422 HB_Error error;
2423
2424 HB_UShort n, m, count;
2425 HB_UInt cur_offset, new_offset, base_offset;
2426
2427 HB_LigatureAttach* lat;
2428
2429
2430 base_offset = FILE_Pos();
2431
2432 if ( ACCESS_Frame( 2L ) )
2433 return error;
2434
2435 count = la->LigatureCount = GET_UShort();
2436
2437 FORGET_Frame();
2438
2439 la->LigatureAttach = NULL;
2440
2441 if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2442 return error;
2443
2444 lat = la->LigatureAttach;
2445
2446 for ( n = 0; n < count; n++ )
2447 {
2448 if ( ACCESS_Frame( 2L ) )
2449 goto Fail;
2450
2451 new_offset = GET_UShort() + base_offset;
2452
2453 FORGET_Frame();
2454
2455 cur_offset = FILE_Pos();
2456 if ( FILE_Seek( new_offset ) ||
2457 ( error = Load_LigatureAttach( &lat[n], num_classes,
2458 stream ) ) != HB_Err_Ok )
2459 goto Fail;
2460 (void)FILE_Seek( cur_offset );
2461 }
2462
2463 return HB_Err_Ok;
2464
2465Fail:
2466 for ( m = 0; m < n; m++ )
2467 Free_LigatureAttach( &lat[m], num_classes );
2468
2469 FREE( lat );
2470 return error;
2471}
2472
2473
2474static void Free_LigatureArray( HB_LigatureArray* la,
2475 HB_UShort num_classes )
2476{
2477 HB_UShort n, count;
2478
2479 HB_LigatureAttach* lat;
2480
2481
2482 if ( la->LigatureAttach )
2483 {
2484 count = la->LigatureCount;
2485 lat = la->LigatureAttach;
2486
2487 for ( n = 0; n < count; n++ )
2488 Free_LigatureAttach( &lat[n], num_classes );
2489
2490 FREE( lat );
2491 }
2492}
2493
2494
2495/* MarkLigPosFormat1 */
2496
2497static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
2498 HB_Stream stream )
2499{
2500 HB_Error error;
2501 HB_MarkLigPos* mlp = &st->marklig;
2502
2503 HB_UInt cur_offset, new_offset, base_offset;
2504
2505
2506 base_offset = FILE_Pos();
2507
2508 if ( ACCESS_Frame( 4L ) )
2509 return error;
2510
2511 mlp->PosFormat = GET_UShort();
2512 new_offset = GET_UShort() + base_offset;
2513
2514 FORGET_Frame();
2515
2516 cur_offset = FILE_Pos();
2517 if ( FILE_Seek( new_offset ) ||
2518 ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
2519 return error;
2520 (void)FILE_Seek( cur_offset );
2521
2522 if ( ACCESS_Frame( 2L ) )
2523 goto Fail3;
2524
2525 new_offset = GET_UShort() + base_offset;
2526
2527 FORGET_Frame();
2528
2529 cur_offset = FILE_Pos();
2530 if ( FILE_Seek( new_offset ) ||
2531 ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2532 stream ) ) != HB_Err_Ok )
2533 goto Fail3;
2534 (void)FILE_Seek( cur_offset );
2535
2536 if ( ACCESS_Frame( 4L ) )
2537 goto Fail2;
2538
2539 mlp->ClassCount = GET_UShort();
2540 new_offset = GET_UShort() + base_offset;
2541
2542 FORGET_Frame();
2543
2544 cur_offset = FILE_Pos();
2545 if ( FILE_Seek( new_offset ) ||
2546 ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
2547 goto Fail2;
2548 (void)FILE_Seek( cur_offset );
2549
2550 if ( ACCESS_Frame( 2L ) )
2551 goto Fail1;
2552
2553 new_offset = GET_UShort() + base_offset;
2554
2555 FORGET_Frame();
2556
2557 cur_offset = FILE_Pos();
2558 if ( FILE_Seek( new_offset ) ||
2559 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2560 stream ) ) != HB_Err_Ok )
2561 goto Fail1;
2562
2563 return HB_Err_Ok;
2564
2565Fail1:
2566 Free_MarkArray( &mlp->MarkArray );
2567
2568Fail2:
2569 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2570
2571Fail3:
2572 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2573 return error;
2574}
2575
2576
2577static void Free_MarkLigPos( HB_GPOS_SubTable* st )
2578{
2579 HB_MarkLigPos* mlp = &st->marklig;
2580
2581 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
2582 Free_MarkArray( &mlp->MarkArray );
2583 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2584 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2585}
2586
2587
2588static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
2589 HB_GPOS_SubTable* st,
2590 HB_Buffer buffer,
2591 HB_UShort flags,
2592 HB_UShort context_length,
2593 int nesting_level )
2594{
2595 HB_UShort i, j, mark_index, lig_index, property, class;
2596 HB_UShort mark_glyph;
2597 HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2598 HB_Error error;
2599 HB_GPOSHeader* gpos = gpi->gpos;
2600 HB_MarkLigPos* mlp = &st->marklig;
2601
2602 HB_MarkArray* ma;
2603 HB_LigatureArray* la;
2604 HB_LigatureAttach* lat;
2605 HB_ComponentRecord* cr;
2606 HB_UShort comp_index;
2607 HB_Anchor* mark_anchor;
2608 HB_Anchor* lig_anchor;
2609
2610 HB_Position o;
2611
2612 HB_UNUSED(nesting_level);
2613
2614 if ( context_length != 0xFFFF && context_length < 1 )
2615 return HB_Err_Not_Covered;
2616
2617 if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
2618 return HB_Err_Not_Covered;
2619
2620 mark_glyph = IN_CURGLYPH();
2621
2622 if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
2623 return error;
2624
2625 error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2626 if ( error )
2627 return error;
2628
2629 /* now we search backwards for a non-mark glyph */
2630
2631 i = 1;
2632 j = buffer->in_pos - 1;
2633
2634 while ( i <= buffer->in_pos )
2635 {
2636 property = _hb_ot_layout_get_glyph_property (gpos->layout, IN_GLYPH(j));
2637 if ( !property )
2638 return HB_Err_Not_Covered;
2639
2640 if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2641 break;
2642
2643 i++;
2644 j--;
2645 }
2646
2647 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2648 too strong, thus it is commented out. */
2649#if 0
2650 if ( property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
2651 return HB_Err_Not_Covered;
2652#endif
2653
2654 if ( i > buffer->in_pos )
2655 return HB_Err_Not_Covered;
2656
2657 error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2658 &lig_index );
2659 if ( error )
2660 return error;
2661
2662 ma = &mlp->MarkArray;
2663
2664 if ( mark_index >= ma->MarkCount )
2665 return ERR(HB_Err_Invalid_SubTable);
2666
2667 class = ma->MarkRecord[mark_index].Class;
2668 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2669
2670 if ( class >= mlp->ClassCount )
2671 return ERR(HB_Err_Invalid_SubTable);
2672
2673 la = &mlp->LigatureArray;
2674
2675 if ( lig_index >= la->LigatureCount )
2676 return ERR(HB_Err_Invalid_SubTable);
2677
2678 lat = &la->LigatureAttach[lig_index];
2679
2680 /* We must now check whether the ligature ID of the current mark glyph
2681 is identical to the ligature ID of the found ligature. If yes, we
2682 can directly use the component index. If not, we attach the mark
2683 glyph to the last component of the ligature. */
2684
2685 if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
2686 {
2687 comp_index = IN_COMPONENT( buffer->in_pos );
2688 if ( comp_index >= lat->ComponentCount )
2689 return HB_Err_Not_Covered;
2690 }
2691 else
2692 comp_index = lat->ComponentCount - 1;
2693
2694 cr = &lat->ComponentRecord[comp_index];
2695 lig_anchor = &cr->LigatureAnchor[class];
2696
2697 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2698 &x_mark_value, &y_mark_value );
2699 if ( error )
2700 return error;
2701 error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2702 &x_lig_value, &y_lig_value );
2703 if ( error )
2704 return error;
2705
2706 /* anchor points are not cumulative */
2707
2708 o = POSITION( buffer->in_pos );
2709
2710 o->x_pos = x_lig_value - x_mark_value;
2711 o->y_pos = y_lig_value - y_mark_value;
2712 o->x_advance = 0;
2713 o->y_advance = 0;
2714 o->back = i;
2715
2716 (buffer->in_pos)++;
2717
2718 return HB_Err_Ok;
2719}
2720
2721
2722/* LookupType 6 */
2723
2724/* Mark2Array */
2725
2726static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
2727 HB_UShort num_classes,
2728 HB_Stream stream )
2729{
2730 HB_Error error;
2731
2732 HB_UShort k, m, n, count;
2733 HB_UInt cur_offset, new_offset, base_offset;
2734
2735 HB_Mark2Record *m2r;
2736 HB_Anchor *m2an, *m2ans;
2737
2738
2739 base_offset = FILE_Pos();
2740
2741 if ( ACCESS_Frame( 2L ) )
2742 return error;
2743
2744 count = m2a->Mark2Count = GET_UShort();
2745
2746 FORGET_Frame();
2747
2748 m2a->Mark2Record = NULL;
2749
2750 if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2751 return error;
2752
2753 m2r = m2a->Mark2Record;
2754
2755 m2ans = NULL;
2756
2757 if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
2758 goto Fail;
2759
2760 for ( m = 0; m < count; m++ )
2761 {
2762 m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
2763
2764 for ( n = 0; n < num_classes; n++ )
2765 {
2766 if ( ACCESS_Frame( 2L ) )
2767 goto Fail;
2768
2769 new_offset = GET_UShort() + base_offset;
2770
2771 FORGET_Frame();
2772
2773 if (new_offset == base_offset) {
2774 /* Anchor table not provided. Skip loading.
2775 * Some versions of FreeSans hit this. */
2776 m2an[n].PosFormat = 0;
2777 continue;
2778 }
2779
2780 cur_offset = FILE_Pos();
2781 if ( FILE_Seek( new_offset ) ||
2782 ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
2783 goto Fail;
2784 (void)FILE_Seek( cur_offset );
2785 }
2786 }
2787
2788 return HB_Err_Ok;
2789
2790Fail:
2791 FREE( m2ans );
2792 FREE( m2r );
2793 return error;
2794}
2795
2796
2797static void Free_Mark2Array( HB_Mark2Array* m2a,
2798 HB_UShort num_classes )
2799{
2800 HB_Mark2Record *m2r;
2801 HB_Anchor *m2ans;
2802
2803 HB_UNUSED(num_classes);
2804
2805 if ( m2a->Mark2Record )
2806 {
2807 m2r = m2a->Mark2Record;
2808
2809 if ( m2a->Mark2Count )
2810 {
2811 m2ans = m2r[0].Mark2Anchor;
2812 FREE( m2ans );
2813 }
2814
2815 FREE( m2r );
2816 }
2817}
2818
2819
2820/* MarkMarkPosFormat1 */
2821
2822static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
2823 HB_Stream stream )
2824{
2825 HB_Error error;
2826 HB_MarkMarkPos* mmp = &st->markmark;
2827
2828 HB_UInt cur_offset, new_offset, base_offset;
2829
2830
2831 base_offset = FILE_Pos();
2832
2833 if ( ACCESS_Frame( 4L ) )
2834 return error;
2835
2836 mmp->PosFormat = GET_UShort();
2837 new_offset = GET_UShort() + base_offset;
2838
2839 FORGET_Frame();
2840
2841 cur_offset = FILE_Pos();
2842 if ( FILE_Seek( new_offset ) ||
2843 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2844 stream ) ) != HB_Err_Ok )
2845 return error;
2846 (void)FILE_Seek( cur_offset );
2847
2848 if ( ACCESS_Frame( 2L ) )
2849 goto Fail3;
2850
2851 new_offset = GET_UShort() + base_offset;
2852
2853 FORGET_Frame();
2854
2855 cur_offset = FILE_Pos();
2856 if ( FILE_Seek( new_offset ) ||
2857 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2858 stream ) ) != HB_Err_Ok )
2859 goto Fail3;
2860 (void)FILE_Seek( cur_offset );
2861
2862 if ( ACCESS_Frame( 4L ) )
2863 goto Fail2;
2864
2865 mmp->ClassCount = GET_UShort();
2866 new_offset = GET_UShort() + base_offset;
2867
2868 FORGET_Frame();
2869
2870 cur_offset = FILE_Pos();
2871 if ( FILE_Seek( new_offset ) ||
2872 ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
2873 goto Fail2;
2874 (void)FILE_Seek( cur_offset );
2875
2876 if ( ACCESS_Frame( 2L ) )
2877 goto Fail1;
2878
2879 new_offset = GET_UShort() + base_offset;
2880
2881 FORGET_Frame();
2882
2883 cur_offset = FILE_Pos();
2884 if ( FILE_Seek( new_offset ) ||
2885 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2886 stream ) ) != HB_Err_Ok )
2887 goto Fail1;
2888
2889 return HB_Err_Ok;
2890
2891Fail1:
2892 Free_MarkArray( &mmp->Mark1Array );
2893
2894Fail2:
2895 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2896
2897Fail3:
2898 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2899 return error;
2900}
2901
2902
2903static void Free_MarkMarkPos( HB_GPOS_SubTable* st )
2904{
2905 HB_MarkMarkPos* mmp = &st->markmark;
2906
2907 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2908 Free_MarkArray( &mmp->Mark1Array );
2909 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2910 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2911}
2912
2913
2914static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
2915 HB_GPOS_SubTable* st,
2916 HB_Buffer buffer,
2917 HB_UShort flags,
2918 HB_UShort context_length,
2919 int nesting_level )
2920{
2921 HB_UShort i, j, mark1_index, mark2_index, property, class;
2922 HB_Fixed x_mark1_value, y_mark1_value,
2923 x_mark2_value, y_mark2_value;
2924 HB_Error error;
2925 HB_GPOSHeader* gpos = gpi->gpos;
2926 HB_MarkMarkPos* mmp = &st->markmark;
2927
2928 HB_MarkArray* ma1;
2929 HB_Mark2Array* ma2;
2930 HB_Mark2Record* m2r;
2931 HB_Anchor* mark1_anchor;
2932 HB_Anchor* mark2_anchor;
2933
2934 HB_Position o;
2935
2936 HB_UNUSED(nesting_level);
2937
2938 if ( context_length != 0xFFFF && context_length < 1 )
2939 return HB_Err_Not_Covered;
2940
2941 if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
2942 return HB_Err_Not_Covered;
2943
2944 if ( CHECK_Property( gpos->layout, IN_CURITEM(),
2945 flags, &property ) )
2946 return error;
2947
2948 error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
2949 &mark1_index );
2950 if ( error )
2951 return error;
2952
2953 /* now we search backwards for a suitable mark glyph until a non-mark
2954 glyph */
2955
2956 if ( buffer->in_pos == 0 )
2957 return HB_Err_Not_Covered;
2958
2959 i = 1;
2960 j = buffer->in_pos - 1;
2961 while ( i <= buffer->in_pos )
2962 {
2963 property = _hb_ot_layout_get_glyph_property (gpos->layout, IN_GLYPH(j));
2964 if ( !property )
2965 return HB_Err_Not_Covered;
2966
2967 if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2968 return HB_Err_Not_Covered;
2969
2970 if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
2971 {
2972 if ( property == (flags & 0xFF00) )
2973 break;
2974 }
2975 else
2976 break;
2977
2978 i++;
2979 j--;
2980 }
2981
2982 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
2983 &mark2_index );
2984 if ( error )
2985 return error;
2986
2987 ma1 = &mmp->Mark1Array;
2988
2989 if ( mark1_index >= ma1->MarkCount )
2990 return ERR(HB_Err_Invalid_SubTable);
2991
2992 class = ma1->MarkRecord[mark1_index].Class;
2993 mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
2994
2995 if ( class >= mmp->ClassCount )
2996 return ERR(HB_Err_Invalid_SubTable);
2997
2998 ma2 = &mmp->Mark2Array;
2999
3000 if ( mark2_index >= ma2->Mark2Count )
3001 return ERR(HB_Err_Invalid_SubTable);
3002
3003 m2r = &ma2->Mark2Record[mark2_index];
3004 mark2_anchor = &m2r->Mark2Anchor[class];
3005
3006 error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3007 &x_mark1_value, &y_mark1_value );
3008 if ( error )
3009 return error;
3010 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3011 &x_mark2_value, &y_mark2_value );
3012 if ( error )
3013 return error;
3014
3015 /* anchor points are not cumulative */
3016
3017 o = POSITION( buffer->in_pos );
3018
3019 o->x_pos = x_mark2_value - x_mark1_value;
3020 o->y_pos = y_mark2_value - y_mark1_value;
3021 o->x_advance = 0;
3022 o->y_advance = 0;
3023 o->back = 1;
3024
3025 (buffer->in_pos)++;
3026
3027 return HB_Err_Ok;
3028}
3029
3030
3031/* Do the actual positioning for a context positioning (either format
3032 7 or 8). This is only called after we've determined that the stream
3033 matches the subrule. */
3034
3035static HB_Error Do_ContextPos( GPOS_Instance* gpi,
3036 HB_UShort GlyphCount,
3037 HB_UShort PosCount,
3038 HB_PosLookupRecord* pos,
3039 HB_Buffer buffer,
3040 int nesting_level )
3041{
3042 HB_Error error;
3043 HB_UInt i, old_pos;
3044
3045
3046 i = 0;
3047
3048 while ( i < GlyphCount )
3049 {
3050 if ( PosCount && i == pos->SequenceIndex )
3051 {
3052 old_pos = buffer->in_pos;
3053
3054 /* Do a positioning */
3055
3056 error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3057 GlyphCount, nesting_level );
3058
3059 if ( error )
3060 return error;
3061
3062 pos++;
3063 PosCount--;
3064 i += buffer->in_pos - old_pos;
3065 }
3066 else
3067 {
3068 i++;
3069 (buffer->in_pos)++;
3070 }
3071 }
3072
3073 return HB_Err_Ok;
3074}
3075
3076
3077/* LookupType 7 */
3078
3079/* PosRule */
3080
3081static HB_Error Load_PosRule( HB_PosRule* pr,
3082 HB_Stream stream )
3083{
3084 HB_Error error;
3085
3086 HB_UShort n, count;
3087 HB_UShort* i;
3088
3089 HB_PosLookupRecord* plr;
3090
3091
3092 if ( ACCESS_Frame( 4L ) )
3093 return error;
3094
3095 pr->GlyphCount = GET_UShort();
3096 pr->PosCount = GET_UShort();
3097
3098 FORGET_Frame();
3099
3100 pr->Input = NULL;
3101
3102 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3103
3104 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3105 return error;
3106
3107 i = pr->Input;
3108
3109 if ( ACCESS_Frame( count * 2L ) )
3110 goto Fail2;
3111
3112 for ( n = 0; n < count; n++ )
3113 i[n] = GET_UShort();
3114
3115 FORGET_Frame();
3116
3117 pr->PosLookupRecord = NULL;
3118
3119 count = pr->PosCount;
3120
3121 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3122 goto Fail2;
3123
3124 plr = pr->PosLookupRecord;
3125
3126 if ( ACCESS_Frame( count * 4L ) )
3127 goto Fail1;
3128
3129 for ( n = 0; n < count; n++ )
3130 {
3131 plr[n].SequenceIndex = GET_UShort();
3132 plr[n].LookupListIndex = GET_UShort();
3133 }
3134
3135 FORGET_Frame();
3136
3137 return HB_Err_Ok;
3138
3139Fail1:
3140 FREE( plr );
3141
3142Fail2:
3143 FREE( i );
3144 return error;
3145}
3146
3147
3148static void Free_PosRule( HB_PosRule* pr )
3149{
3150 FREE( pr->PosLookupRecord );
3151 FREE( pr->Input );
3152}
3153
3154
3155/* PosRuleSet */
3156
3157static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
3158 HB_Stream stream )
3159{
3160 HB_Error error;
3161
3162 HB_UShort n, m, count;
3163 HB_UInt cur_offset, new_offset, base_offset;
3164
3165 HB_PosRule* pr;
3166
3167
3168 base_offset = FILE_Pos();
3169
3170 if ( ACCESS_Frame( 2L ) )
3171 return error;
3172
3173 count = prs->PosRuleCount = GET_UShort();
3174
3175 FORGET_Frame();
3176
3177 prs->PosRule = NULL;
3178
3179 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3180 return error;
3181
3182 pr = prs->PosRule;
3183
3184 for ( n = 0; n < count; n++ )
3185 {
3186 if ( ACCESS_Frame( 2L ) )
3187 goto Fail;
3188
3189 new_offset = GET_UShort() + base_offset;
3190
3191 FORGET_Frame();
3192
3193 cur_offset = FILE_Pos();
3194 if ( FILE_Seek( new_offset ) ||
3195 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3196 goto Fail;
3197 (void)FILE_Seek( cur_offset );
3198 }
3199
3200 return HB_Err_Ok;
3201
3202Fail:
3203 for ( m = 0; m < n; m++ )
3204 Free_PosRule( &pr[m] );
3205
3206 FREE( pr );
3207 return error;
3208}
3209
3210
3211static void Free_PosRuleSet( HB_PosRuleSet* prs )
3212{
3213 HB_UShort n, count;
3214
3215 HB_PosRule* pr;
3216
3217
3218 if ( prs->PosRule )
3219 {
3220 count = prs->PosRuleCount;
3221 pr = prs->PosRule;
3222
3223 for ( n = 0; n < count; n++ )
3224 Free_PosRule( &pr[n] );
3225
3226 FREE( pr );
3227 }
3228}
3229
3230
3231/* ContextPosFormat1 */
3232
3233static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
3234 HB_Stream stream )
3235{
3236 HB_Error error;
3237
3238 HB_UShort n, m, count;
3239 HB_UInt cur_offset, new_offset, base_offset;
3240
3241 HB_PosRuleSet* prs;
3242
3243
3244 base_offset = FILE_Pos() - 2L;
3245
3246 if ( ACCESS_Frame( 2L ) )
3247 return error;
3248
3249 new_offset = GET_UShort() + base_offset;
3250
3251 FORGET_Frame();
3252
3253 cur_offset = FILE_Pos();
3254 if ( FILE_Seek( new_offset ) ||
3255 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3256 return error;
3257 (void)FILE_Seek( cur_offset );
3258
3259 if ( ACCESS_Frame( 2L ) )
3260 goto Fail2;
3261
3262 count = cpf1->PosRuleSetCount = GET_UShort();
3263
3264 FORGET_Frame();
3265
3266 cpf1->PosRuleSet = NULL;
3267
3268 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3269 goto Fail2;
3270
3271 prs = cpf1->PosRuleSet;
3272
3273 for ( n = 0; n < count; n++ )
3274 {
3275 if ( ACCESS_Frame( 2L ) )
3276 goto Fail1;
3277
3278 new_offset = GET_UShort() + base_offset;
3279
3280 FORGET_Frame();
3281
3282 cur_offset = FILE_Pos();
3283 if ( FILE_Seek( new_offset ) ||
3284 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3285 goto Fail1;
3286 (void)FILE_Seek( cur_offset );
3287 }
3288
3289 return HB_Err_Ok;
3290
3291Fail1:
3292 for ( m = 0; m < n; m++ )
3293 Free_PosRuleSet( &prs[m] );
3294
3295 FREE( prs );
3296
3297Fail2:
3298 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3299 return error;
3300}
3301
3302
3303static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
3304{
3305 HB_UShort n, count;
3306
3307 HB_PosRuleSet* prs;
3308
3309
3310 if ( cpf1->PosRuleSet )
3311 {
3312 count = cpf1->PosRuleSetCount;
3313 prs = cpf1->PosRuleSet;
3314
3315 for ( n = 0; n < count; n++ )
3316 Free_PosRuleSet( &prs[n] );
3317
3318 FREE( prs );
3319 }
3320
3321 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3322}
3323
3324
3325/* PosClassRule */
3326
3327static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
3328 HB_PosClassRule* pcr,
3329 HB_Stream stream )
3330{
3331 HB_Error error;
3332
3333 HB_UShort n, count;
3334
3335 HB_UShort* c;
3336 HB_PosLookupRecord* plr;
3337
3338
3339 if ( ACCESS_Frame( 4L ) )
3340 return error;
3341
3342 pcr->GlyphCount = GET_UShort();
3343 pcr->PosCount = GET_UShort();
3344
3345 FORGET_Frame();
3346
3347 if ( pcr->GlyphCount > cpf2->MaxContextLength )
3348 cpf2->MaxContextLength = pcr->GlyphCount;
3349
3350 pcr->Class = NULL;
3351
3352 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3353
3354 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3355 return error;
3356
3357 c = pcr->Class;
3358
3359 if ( ACCESS_Frame( count * 2L ) )
3360 goto Fail2;
3361
3362 for ( n = 0; n < count; n++ )
3363 c[n] = GET_UShort();
3364
3365 FORGET_Frame();
3366
3367 pcr->PosLookupRecord = NULL;
3368
3369 count = pcr->PosCount;
3370
3371 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3372 goto Fail2;
3373
3374 plr = pcr->PosLookupRecord;
3375
3376 if ( ACCESS_Frame( count * 4L ) )
3377 goto Fail1;
3378
3379 for ( n = 0; n < count; n++ )
3380 {
3381 plr[n].SequenceIndex = GET_UShort();
3382 plr[n].LookupListIndex = GET_UShort();
3383 }
3384
3385 FORGET_Frame();
3386
3387 return HB_Err_Ok;
3388
3389Fail1:
3390 FREE( plr );
3391
3392Fail2:
3393 FREE( c );
3394 return error;
3395}
3396
3397
3398static void Free_PosClassRule( HB_PosClassRule* pcr )
3399{
3400 FREE( pcr->PosLookupRecord );
3401 FREE( pcr->Class );
3402}
3403
3404
3405/* PosClassSet */
3406
3407static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
3408 HB_PosClassSet* pcs,
3409 HB_Stream stream )
3410{
3411 HB_Error error;
3412
3413 HB_UShort n, m, count;
3414 HB_UInt cur_offset, new_offset, base_offset;
3415
3416 HB_PosClassRule* pcr;
3417
3418
3419 base_offset = FILE_Pos();
3420
3421 if ( ACCESS_Frame( 2L ) )
3422 return error;
3423
3424 count = pcs->PosClassRuleCount = GET_UShort();
3425
3426 FORGET_Frame();
3427
3428 pcs->PosClassRule = NULL;
3429
3430 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3431 return error;
3432
3433 pcr = pcs->PosClassRule;
3434
3435 for ( n = 0; n < count; n++ )
3436 {
3437 if ( ACCESS_Frame( 2L ) )
3438 goto Fail;
3439
3440 new_offset = GET_UShort() + base_offset;
3441
3442 FORGET_Frame();
3443
3444 cur_offset = FILE_Pos();
3445 if ( FILE_Seek( new_offset ) ||
3446 ( error = Load_PosClassRule( cpf2, &pcr[n],
3447 stream ) ) != HB_Err_Ok )
3448 goto Fail;
3449 (void)FILE_Seek( cur_offset );
3450 }
3451
3452 return HB_Err_Ok;
3453
3454Fail:
3455 for ( m = 0; m < n; m++ )
3456 Free_PosClassRule( &pcr[m] );
3457
3458 FREE( pcr );
3459 return error;
3460}
3461
3462
3463static void Free_PosClassSet( HB_PosClassSet* pcs )
3464{
3465 HB_UShort n, count;
3466
3467 HB_PosClassRule* pcr;
3468
3469
3470 if ( pcs->PosClassRule )
3471 {
3472 count = pcs->PosClassRuleCount;
3473 pcr = pcs->PosClassRule;
3474
3475 for ( n = 0; n < count; n++ )
3476 Free_PosClassRule( &pcr[n] );
3477
3478 FREE( pcr );
3479 }
3480}
3481
3482
3483/* ContextPosFormat2 */
3484
3485static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
3486 HB_Stream stream )
3487{
3488 HB_Error error;
3489
3490 HB_UShort n, m, count;
3491 HB_UInt cur_offset, new_offset, base_offset;
3492
3493 HB_PosClassSet* pcs;
3494
3495
3496 base_offset = FILE_Pos() - 2;
3497
3498 if ( ACCESS_Frame( 2L ) )
3499 return error;
3500
3501 new_offset = GET_UShort() + base_offset;
3502
3503 FORGET_Frame();
3504
3505 cur_offset = FILE_Pos();
3506 if ( FILE_Seek( new_offset ) ||
3507 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3508 return error;
3509 (void)FILE_Seek( cur_offset );
3510
3511 if ( ACCESS_Frame( 4L ) )
3512 goto Fail3;
3513
3514 new_offset = GET_UShort() + base_offset;
3515
3516 /* `PosClassSetCount' is the upper limit for class values, thus we
3517 read it now to make an additional safety check. */
3518
3519 count = cpf2->PosClassSetCount = GET_UShort();
3520
3521 FORGET_Frame();
3522
3523 cur_offset = FILE_Pos();
3524 if ( FILE_Seek( new_offset ) ||
3525 ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3526 stream ) ) != HB_Err_Ok )
3527 goto Fail3;
3528 (void)FILE_Seek( cur_offset );
3529
3530 cpf2->PosClassSet = NULL;
3531 cpf2->MaxContextLength = 0;
3532
3533 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3534 goto Fail2;
3535
3536 pcs = cpf2->PosClassSet;
3537
3538 for ( n = 0; n < count; n++ )
3539 {
3540 if ( ACCESS_Frame( 2L ) )
3541 goto Fail1;
3542
3543 new_offset = GET_UShort() + base_offset;
3544
3545 FORGET_Frame();
3546
3547 if ( new_offset != base_offset ) /* not a NULL offset */
3548 {
3549 cur_offset = FILE_Pos();
3550 if ( FILE_Seek( new_offset ) ||
3551 ( error = Load_PosClassSet( cpf2, &pcs[n],
3552 stream ) ) != HB_Err_Ok )
3553 goto Fail1;
3554 (void)FILE_Seek( cur_offset );
3555 }
3556 else
3557 {
3558 /* we create a PosClassSet table with no entries */
3559
3560 cpf2->PosClassSet[n].PosClassRuleCount = 0;
3561 cpf2->PosClassSet[n].PosClassRule = NULL;
3562 }
3563 }
3564
3565 return HB_Err_Ok;
3566
3567Fail1:
3568 for ( m = 0; m < n; n++ )
3569 Free_PosClassSet( &pcs[m] );
3570
3571 FREE( pcs );
3572
3573Fail2:
3574 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3575
3576Fail3:
3577 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3578 return error;
3579}
3580
3581
3582static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
3583{
3584 HB_UShort n, count;
3585
3586 HB_PosClassSet* pcs;
3587
3588
3589 if ( cpf2->PosClassSet )
3590 {
3591 count = cpf2->PosClassSetCount;
3592 pcs = cpf2->PosClassSet;
3593
3594 for ( n = 0; n < count; n++ )
3595 Free_PosClassSet( &pcs[n] );
3596
3597 FREE( pcs );
3598 }
3599
3600 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3601 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3602}
3603
3604
3605/* ContextPosFormat3 */
3606
3607static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
3608 HB_Stream stream )
3609{
3610 HB_Error error;
3611
3612 HB_UShort n, count;
3613 HB_UInt cur_offset, new_offset, base_offset;
3614
3615 HB_Coverage* c;
3616 HB_PosLookupRecord* plr;
3617
3618
3619 base_offset = FILE_Pos() - 2L;
3620
3621 if ( ACCESS_Frame( 4L ) )
3622 return error;
3623
3624 cpf3->GlyphCount = GET_UShort();
3625 cpf3->PosCount = GET_UShort();
3626
3627 FORGET_Frame();
3628
3629 cpf3->Coverage = NULL;
3630
3631 count = cpf3->GlyphCount;
3632
3633 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3634 return error;
3635
3636 c = cpf3->Coverage;
3637
3638 for ( n = 0; n < count; n++ )
3639 {
3640 if ( ACCESS_Frame( 2L ) )
3641 goto Fail2;
3642
3643 new_offset = GET_UShort() + base_offset;
3644
3645 FORGET_Frame();
3646
3647 cur_offset = FILE_Pos();
3648 if ( FILE_Seek( new_offset ) ||
3649 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3650 goto Fail2;
3651 (void)FILE_Seek( cur_offset );
3652 }
3653
3654 cpf3->PosLookupRecord = NULL;
3655
3656 count = cpf3->PosCount;
3657
3658 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3659 goto Fail2;
3660
3661 plr = cpf3->PosLookupRecord;
3662
3663 if ( ACCESS_Frame( count * 4L ) )
3664 goto Fail1;
3665
3666 for ( n = 0; n < count; n++ )
3667 {
3668 plr[n].SequenceIndex = GET_UShort();
3669 plr[n].LookupListIndex = GET_UShort();
3670 }
3671
3672 FORGET_Frame();
3673
3674 return HB_Err_Ok;
3675
3676Fail1:
3677 FREE( plr );
3678
3679Fail2:
3680 for ( n = 0; n < count; n++ )
3681 _HB_OPEN_Free_Coverage( &c[n] );
3682
3683 FREE( c );
3684 return error;
3685}
3686
3687
3688static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
3689{
3690 HB_UShort n, count;
3691
3692 HB_Coverage* c;
3693
3694
3695 FREE( cpf3->PosLookupRecord );
3696
3697 if ( cpf3->Coverage )
3698 {
3699 count = cpf3->GlyphCount;
3700 c = cpf3->Coverage;
3701
3702 for ( n = 0; n < count; n++ )
3703 _HB_OPEN_Free_Coverage( &c[n] );
3704
3705 FREE( c );
3706 }
3707}
3708
3709
3710/* ContextPos */
3711
3712static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
3713 HB_Stream stream )
3714{
3715 HB_Error error;
3716 HB_ContextPos* cp = &st->context;
3717
3718
3719 if ( ACCESS_Frame( 2L ) )
3720 return error;
3721
3722 cp->PosFormat = GET_UShort();
3723
3724 FORGET_Frame();
3725
3726 switch ( cp->PosFormat )
3727 {
3728 case 1:
3729 return Load_ContextPos1( &cp->cpf.cpf1, stream );
3730
3731 case 2:
3732 return Load_ContextPos2( &cp->cpf.cpf2, stream );
3733
3734 case 3:
3735 return Load_ContextPos3( &cp->cpf.cpf3, stream );
3736
3737 default:
3738 return ERR(HB_Err_Invalid_SubTable_Format);
3739 }
3740
3741 return HB_Err_Ok; /* never reached */
3742}
3743
3744
3745static void Free_ContextPos( HB_GPOS_SubTable* st )
3746{
3747 HB_ContextPos* cp = &st->context;
3748
3749 switch ( cp->PosFormat )
3750 {
3751 case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break;
3752 case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break;
3753 case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break;
3754 default: break;
3755 }
3756}
3757
3758
3759static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3760 HB_ContextPosFormat1* cpf1,
3761 HB_Buffer buffer,
3762 HB_UShort flags,
3763 HB_UShort context_length,
3764 int nesting_level )
3765{
3766 HB_UShort index, property;
3767 HB_UShort i, j, k, numpr;
3768 HB_Error error;
3769 HB_GPOSHeader* gpos = gpi->gpos;
3770
3771 HB_PosRule* pr;
3772 hb_ot_layout_t* layout;
3773
3774
3775 layout = gpos->layout;
3776
3777 if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
3778 return error;
3779
3780 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3781 if ( error )
3782 return error;
3783
3784 pr = cpf1->PosRuleSet[index].PosRule;
3785 numpr = cpf1->PosRuleSet[index].PosRuleCount;
3786
3787 for ( k = 0; k < numpr; k++ )
3788 {
3789 if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3790 goto next_posrule;
3791
3792 if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3793 goto next_posrule; /* context is too long */
3794
3795 for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3796 {
3797 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
3798 {
3799 if ( error && error != HB_Err_Not_Covered )
3800 return error;
3801
3802 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3803 goto next_posrule;
3804 j++;
3805 }
3806
3807 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3808 goto next_posrule;
3809 }
3810
3811 return Do_ContextPos( gpi, pr[k].GlyphCount,
3812 pr[k].PosCount, pr[k].PosLookupRecord,
3813 buffer,
3814 nesting_level );
3815
3816 next_posrule:
3817 ;
3818 }
3819
3820 return HB_Err_Not_Covered;
3821}
3822
3823
3824static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
3825 HB_ContextPosFormat2* cpf2,
3826 HB_Buffer buffer,
3827 HB_UShort flags,
3828 HB_UShort context_length,
3829 int nesting_level )
3830{
3831 HB_UShort index, property;
3832 HB_Error error;
3833 HB_UShort i, j, k, known_classes;
3834
3835 HB_UShort* classes;
3836 HB_UShort* cl;
3837 HB_GPOSHeader* gpos = gpi->gpos;
3838
3839 HB_PosClassSet* pcs;
3840 HB_PosClassRule* pr;
3841 hb_ot_layout_t* layout;
3842
3843
3844 layout = gpos->layout;
3845
3846 if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
3847 return error;
3848
3849 /* Note: The coverage table in format 2 doesn't give an index into
3850 anything. It just lets us know whether or not we need to
3851 do any lookup at all. */
3852
3853 error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3854 if ( error )
3855 return error;
3856
3857 if (cpf2->MaxContextLength < 1)
3858 return HB_Err_Not_Covered;
3859
3860 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3861 return error;
3862
3863 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3864 &classes[0], NULL );
3865 if ( error && error != HB_Err_Not_Covered )
3866 goto End;
3867 known_classes = 0;
3868
3869 pcs = &cpf2->PosClassSet[classes[0]];
3870 if ( !pcs )
3871 {
3872 error = ERR(HB_Err_Invalid_SubTable);
3873 goto End;
3874 }
3875
3876 for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3877 {
3878 pr = &pcs->PosClassRule[k];
3879
3880 if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
3881 goto next_posclassrule;
3882
3883 if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
3884 goto next_posclassrule; /* context is too long */
3885
3886 cl = pr->Class;
3887
3888 /* Start at 1 because [0] is implied */
3889
3890 for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
3891 {
3892 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
3893 {
3894 if ( error && error != HB_Err_Not_Covered )
3895 goto End;
3896
3897 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3898 goto next_posclassrule;
3899 j++;
3900 }
3901
3902 if ( i > known_classes )
3903 {
3904 /* Keeps us from having to do this for each rule */
3905
3906 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
3907 if ( error && error != HB_Err_Not_Covered )
3908 goto End;
3909 known_classes = i;
3910 }
3911
3912 if ( cl[i - 1] != classes[i] )
3913 goto next_posclassrule;
3914 }
3915
3916 error = Do_ContextPos( gpi, pr->GlyphCount,
3917 pr->PosCount, pr->PosLookupRecord,
3918 buffer,
3919 nesting_level );
3920 goto End;
3921
3922 next_posclassrule:
3923 ;
3924 }
3925
3926 error = HB_Err_Not_Covered;
3927
3928End:
3929 FREE( classes );
3930 return error;
3931}
3932
3933
3934static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
3935 HB_ContextPosFormat3* cpf3,
3936 HB_Buffer buffer,
3937 HB_UShort flags,
3938 HB_UShort context_length,
3939 int nesting_level )
3940{
3941 HB_Error error;
3942 HB_UShort index, i, j, property;
3943 HB_GPOSHeader* gpos = gpi->gpos;
3944
3945 HB_Coverage* c;
3946 hb_ot_layout_t* layout;
3947
3948
3949 layout = gpos->layout;
3950
3951 if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
3952 return error;
3953
3954 if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
3955 return HB_Err_Not_Covered;
3956
3957 if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
3958 return HB_Err_Not_Covered; /* context is too long */
3959
3960 c = cpf3->Coverage;
3961
3962 for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
3963 {
3964 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
3965 {
3966 if ( error && error != HB_Err_Not_Covered )
3967 return error;
3968
3969 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
3970 return HB_Err_Not_Covered;
3971 j++;
3972 }
3973
3974 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
3975 if ( error )
3976 return error;
3977 }
3978
3979 return Do_ContextPos( gpi, cpf3->GlyphCount,
3980 cpf3->PosCount, cpf3->PosLookupRecord,
3981 buffer,
3982 nesting_level );
3983}
3984
3985
3986static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
3987 HB_GPOS_SubTable* st,
3988 HB_Buffer buffer,
3989 HB_UShort flags,
3990 HB_UShort context_length,
3991 int nesting_level )
3992{
3993 HB_ContextPos* cp = &st->context;
3994
3995 switch ( cp->PosFormat )
3996 {
3997 case 1:
3998 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
3999 flags, context_length, nesting_level );
4000
4001 case 2:
4002 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4003 flags, context_length, nesting_level );
4004
4005 case 3:
4006 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4007 flags, context_length, nesting_level );
4008
4009 default:
4010 return ERR(HB_Err_Invalid_SubTable_Format);
4011 }
4012
4013 return HB_Err_Ok; /* never reached */
4014}
4015
4016
4017/* LookupType 8 */
4018
4019/* ChainPosRule */
4020
4021static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
4022 HB_Stream stream )
4023{
4024 HB_Error error;
4025
4026 HB_UShort n, count;
4027 HB_UShort* b;
4028 HB_UShort* i;
4029 HB_UShort* l;
4030
4031 HB_PosLookupRecord* plr;
4032
4033
4034 if ( ACCESS_Frame( 2L ) )
4035 return error;
4036
4037 cpr->BacktrackGlyphCount = GET_UShort();
4038
4039 FORGET_Frame();
4040
4041 cpr->Backtrack = NULL;
4042
4043 count = cpr->BacktrackGlyphCount;
4044
4045 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4046 return error;
4047
4048 b = cpr->Backtrack;
4049
4050 if ( ACCESS_Frame( count * 2L ) )
4051 goto Fail4;
4052
4053 for ( n = 0; n < count; n++ )
4054 b[n] = GET_UShort();
4055
4056 FORGET_Frame();
4057
4058 if ( ACCESS_Frame( 2L ) )
4059 goto Fail4;
4060
4061 cpr->InputGlyphCount = GET_UShort();
4062
4063 FORGET_Frame();
4064
4065 cpr->Input = NULL;
4066
4067 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4068
4069 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4070 goto Fail4;
4071
4072 i = cpr->Input;
4073
4074 if ( ACCESS_Frame( count * 2L ) )
4075 goto Fail3;
4076
4077 for ( n = 0; n < count; n++ )
4078 i[n] = GET_UShort();
4079
4080 FORGET_Frame();
4081
4082 if ( ACCESS_Frame( 2L ) )
4083 goto Fail3;
4084
4085 cpr->LookaheadGlyphCount = GET_UShort();
4086
4087 FORGET_Frame();
4088
4089 cpr->Lookahead = NULL;
4090
4091 count = cpr->LookaheadGlyphCount;
4092
4093 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4094 goto Fail3;
4095
4096 l = cpr->Lookahead;
4097
4098 if ( ACCESS_Frame( count * 2L ) )
4099 goto Fail2;
4100
4101 for ( n = 0; n < count; n++ )
4102 l[n] = GET_UShort();
4103
4104 FORGET_Frame();
4105
4106 if ( ACCESS_Frame( 2L ) )
4107 goto Fail2;
4108
4109 cpr->PosCount = GET_UShort();
4110
4111 FORGET_Frame();
4112
4113 cpr->PosLookupRecord = NULL;
4114
4115 count = cpr->PosCount;
4116
4117 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4118 goto Fail2;
4119
4120 plr = cpr->PosLookupRecord;
4121
4122 if ( ACCESS_Frame( count * 4L ) )
4123 goto Fail1;
4124
4125 for ( n = 0; n < count; n++ )
4126 {
4127 plr[n].SequenceIndex = GET_UShort();
4128 plr[n].LookupListIndex = GET_UShort();
4129 }
4130
4131 FORGET_Frame();
4132
4133 return HB_Err_Ok;
4134
4135Fail1:
4136 FREE( plr );
4137
4138Fail2:
4139 FREE( l );
4140
4141Fail3:
4142 FREE( i );
4143
4144Fail4:
4145 FREE( b );
4146 return error;
4147}
4148
4149
4150static void Free_ChainPosRule( HB_ChainPosRule* cpr )
4151{
4152 FREE( cpr->PosLookupRecord );
4153 FREE( cpr->Lookahead );
4154 FREE( cpr->Input );
4155 FREE( cpr->Backtrack );
4156}
4157
4158
4159/* ChainPosRuleSet */
4160
4161static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4162 HB_Stream stream )
4163{
4164 HB_Error error;
4165
4166 HB_UShort n, m, count;
4167 HB_UInt cur_offset, new_offset, base_offset;
4168
4169 HB_ChainPosRule* cpr;
4170
4171
4172 base_offset = FILE_Pos();
4173
4174 if ( ACCESS_Frame( 2L ) )
4175 return error;
4176
4177 count = cprs->ChainPosRuleCount = GET_UShort();
4178
4179 FORGET_Frame();
4180
4181 cprs->ChainPosRule = NULL;
4182
4183 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4184 return error;
4185
4186 cpr = cprs->ChainPosRule;
4187
4188 for ( n = 0; n < count; n++ )
4189 {
4190 if ( ACCESS_Frame( 2L ) )
4191 goto Fail;
4192
4193 new_offset = GET_UShort() + base_offset;
4194
4195 FORGET_Frame();
4196
4197 cur_offset = FILE_Pos();
4198 if ( FILE_Seek( new_offset ) ||
4199 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4200 goto Fail;
4201 (void)FILE_Seek( cur_offset );
4202 }
4203
4204 return HB_Err_Ok;
4205
4206Fail:
4207 for ( m = 0; m < n; m++ )
4208 Free_ChainPosRule( &cpr[m] );
4209
4210 FREE( cpr );
4211 return error;
4212}
4213
4214
4215static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
4216{
4217 HB_UShort n, count;
4218
4219 HB_ChainPosRule* cpr;
4220
4221
4222 if ( cprs->ChainPosRule )
4223 {
4224 count = cprs->ChainPosRuleCount;
4225 cpr = cprs->ChainPosRule;
4226
4227 for ( n = 0; n < count; n++ )
4228 Free_ChainPosRule( &cpr[n] );
4229
4230 FREE( cpr );
4231 }
4232}
4233
4234
4235/* ChainContextPosFormat1 */
4236
4237static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4238 HB_Stream stream )
4239{
4240 HB_Error error;
4241
4242 HB_UShort n, m, count;
4243 HB_UInt cur_offset, new_offset, base_offset;
4244
4245 HB_ChainPosRuleSet* cprs;
4246
4247
4248 base_offset = FILE_Pos() - 2L;
4249
4250 if ( ACCESS_Frame( 2L ) )
4251 return error;
4252
4253 new_offset = GET_UShort() + base_offset;
4254
4255 FORGET_Frame();
4256
4257 cur_offset = FILE_Pos();
4258 if ( FILE_Seek( new_offset ) ||
4259 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4260 return error;
4261 (void)FILE_Seek( cur_offset );
4262
4263 if ( ACCESS_Frame( 2L ) )
4264 goto Fail2;
4265
4266 count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4267
4268 FORGET_Frame();
4269
4270 ccpf1->ChainPosRuleSet = NULL;
4271
4272 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4273 goto Fail2;
4274
4275 cprs = ccpf1->ChainPosRuleSet;
4276
4277 for ( n = 0; n < count; n++ )
4278 {
4279 if ( ACCESS_Frame( 2L ) )
4280 goto Fail1;
4281
4282 new_offset = GET_UShort() + base_offset;
4283
4284 FORGET_Frame();
4285
4286 cur_offset = FILE_Pos();
4287 if ( FILE_Seek( new_offset ) ||
4288 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4289 goto Fail1;
4290 (void)FILE_Seek( cur_offset );
4291 }
4292
4293 return HB_Err_Ok;
4294
4295Fail1:
4296 for ( m = 0; m < n; m++ )
4297 Free_ChainPosRuleSet( &cprs[m] );
4298
4299 FREE( cprs );
4300
4301Fail2:
4302 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4303 return error;
4304}
4305
4306
4307static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
4308{
4309 HB_UShort n, count;
4310
4311 HB_ChainPosRuleSet* cprs;
4312
4313
4314 if ( ccpf1->ChainPosRuleSet )
4315 {
4316 count = ccpf1->ChainPosRuleSetCount;
4317 cprs = ccpf1->ChainPosRuleSet;
4318
4319 for ( n = 0; n < count; n++ )
4320 Free_ChainPosRuleSet( &cprs[n] );
4321
4322 FREE( cprs );
4323 }
4324
4325 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4326}
4327
4328
4329/* ChainPosClassRule */
4330
4331static HB_Error Load_ChainPosClassRule(
4332 HB_ChainContextPosFormat2* ccpf2,
4333 HB_ChainPosClassRule* cpcr,
4334 HB_Stream stream )
4335{
4336 HB_Error error;
4337
4338 HB_UShort n, count;
4339
4340 HB_UShort* b;
4341 HB_UShort* i;
4342 HB_UShort* l;
4343 HB_PosLookupRecord* plr;
4344
4345
4346 if ( ACCESS_Frame( 2L ) )
4347 return error;
4348
4349 cpcr->BacktrackGlyphCount = GET_UShort();
4350
4351 FORGET_Frame();
4352
4353 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4354 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4355
4356 cpcr->Backtrack = NULL;
4357
4358 count = cpcr->BacktrackGlyphCount;
4359
4360 if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
4361 return error;
4362
4363 b = cpcr->Backtrack;
4364
4365 if ( ACCESS_Frame( count * 2L ) )
4366 goto Fail4;
4367
4368 for ( n = 0; n < count; n++ )
4369 b[n] = GET_UShort();
4370
4371 FORGET_Frame();
4372
4373 if ( ACCESS_Frame( 2L ) )
4374 goto Fail4;
4375
4376 cpcr->InputGlyphCount = GET_UShort();
4377
4378 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4379 ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4380
4381 FORGET_Frame();
4382
4383 cpcr->Input = NULL;
4384
4385 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4386
4387 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4388 goto Fail4;
4389
4390 i = cpcr->Input;
4391
4392 if ( ACCESS_Frame( count * 2L ) )
4393 goto Fail3;
4394
4395 for ( n = 0; n < count; n++ )
4396 i[n] = GET_UShort();
4397
4398 FORGET_Frame();
4399
4400 if ( ACCESS_Frame( 2L ) )
4401 goto Fail3;
4402
4403 cpcr->LookaheadGlyphCount = GET_UShort();
4404
4405 FORGET_Frame();
4406
4407 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4408 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4409
4410 cpcr->Lookahead = NULL;
4411
4412 count = cpcr->LookaheadGlyphCount;
4413
4414 if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
4415 goto Fail3;
4416
4417 l = cpcr->Lookahead;
4418
4419 if ( ACCESS_Frame( count * 2L ) )
4420 goto Fail2;
4421
4422 for ( n = 0; n < count; n++ )
4423 l[n] = GET_UShort();
4424
4425 FORGET_Frame();
4426
4427 if ( ACCESS_Frame( 2L ) )
4428 goto Fail2;
4429
4430 cpcr->PosCount = GET_UShort();
4431
4432 FORGET_Frame();
4433
4434 cpcr->PosLookupRecord = NULL;
4435
4436 count = cpcr->PosCount;
4437
4438 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4439 goto Fail2;
4440
4441 plr = cpcr->PosLookupRecord;
4442
4443 if ( ACCESS_Frame( count * 4L ) )
4444 goto Fail1;
4445
4446 for ( n = 0; n < count; n++ )
4447 {
4448 plr[n].SequenceIndex = GET_UShort();
4449 plr[n].LookupListIndex = GET_UShort();
4450 }
4451
4452 FORGET_Frame();
4453
4454 return HB_Err_Ok;
4455
4456Fail1:
4457 FREE( plr );
4458
4459Fail2:
4460 FREE( l );
4461
4462Fail3:
4463 FREE( i );
4464
4465Fail4:
4466 FREE( b );
4467 return error;
4468}
4469
4470
4471static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
4472{
4473 FREE( cpcr->PosLookupRecord );
4474 FREE( cpcr->Lookahead );
4475 FREE( cpcr->Input );
4476 FREE( cpcr->Backtrack );
4477}
4478
4479
4480/* PosClassSet */
4481
4482static HB_Error Load_ChainPosClassSet(
4483 HB_ChainContextPosFormat2* ccpf2,
4484 HB_ChainPosClassSet* cpcs,
4485 HB_Stream stream )
4486{
4487 HB_Error error;
4488
4489 HB_UShort n, m, count;
4490 HB_UInt cur_offset, new_offset, base_offset;
4491
4492 HB_ChainPosClassRule* cpcr;
4493
4494
4495 base_offset = FILE_Pos();
4496
4497 if ( ACCESS_Frame( 2L ) )
4498 return error;
4499
4500 count = cpcs->ChainPosClassRuleCount = GET_UShort();
4501
4502 FORGET_Frame();
4503
4504 cpcs->ChainPosClassRule = NULL;
4505
4506 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4507 HB_ChainPosClassRule ) )
4508 return error;
4509
4510 cpcr = cpcs->ChainPosClassRule;
4511
4512 for ( n = 0; n < count; n++ )
4513 {
4514 if ( ACCESS_Frame( 2L ) )
4515 goto Fail;
4516
4517 new_offset = GET_UShort() + base_offset;
4518
4519 FORGET_Frame();
4520
4521 cur_offset = FILE_Pos();
4522 if ( FILE_Seek( new_offset ) ||
4523 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4524 stream ) ) != HB_Err_Ok )
4525 goto Fail;
4526 (void)FILE_Seek( cur_offset );
4527 }
4528
4529 return HB_Err_Ok;
4530
4531Fail:
4532 for ( m = 0; m < n; m++ )
4533 Free_ChainPosClassRule( &cpcr[m] );
4534
4535 FREE( cpcr );
4536 return error;
4537}
4538
4539
4540static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
4541{
4542 HB_UShort n, count;
4543
4544 HB_ChainPosClassRule* cpcr;
4545
4546
4547 if ( cpcs->ChainPosClassRule )
4548 {
4549 count = cpcs->ChainPosClassRuleCount;
4550 cpcr = cpcs->ChainPosClassRule;
4551
4552 for ( n = 0; n < count; n++ )
4553 Free_ChainPosClassRule( &cpcr[n] );
4554
4555 FREE( cpcr );
4556 }
4557}
4558
4559
4560/* ChainContextPosFormat2 */
4561
4562static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4563 HB_Stream stream )
4564{
4565 HB_Error error;
4566
4567 HB_UShort n, m, count;
4568 HB_UInt cur_offset, new_offset, base_offset;
4569 HB_UInt backtrack_offset, input_offset, lookahead_offset;
4570
4571 HB_ChainPosClassSet* cpcs;
4572
4573
4574 base_offset = FILE_Pos() - 2;
4575
4576 if ( ACCESS_Frame( 2L ) )
4577 return error;
4578
4579 new_offset = GET_UShort() + base_offset;
4580
4581 FORGET_Frame();
4582
4583 cur_offset = FILE_Pos();
4584 if ( FILE_Seek( new_offset ) ||
4585 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4586 return error;
4587 (void)FILE_Seek( cur_offset );
4588
4589 if ( ACCESS_Frame( 8L ) )
4590 goto Fail5;
4591
4592 backtrack_offset = GET_UShort();
4593 input_offset = GET_UShort();
4594 lookahead_offset = GET_UShort();
4595
4596 /* `ChainPosClassSetCount' is the upper limit for input class values,
4597 thus we read it now to make an additional safety check. No limit
4598 is known or needed for the other two class definitions */
4599
4600 count = ccpf2->ChainPosClassSetCount = GET_UShort();
4601
4602 FORGET_Frame();
4603
4604 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4605 backtrack_offset, base_offset,
4606 stream ) ) != HB_Err_Ok )
4607 goto Fail5;
4608 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4609 input_offset, base_offset,
4610 stream ) ) != HB_Err_Ok )
4611 goto Fail4;
4612 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4613 lookahead_offset, base_offset,
4614 stream ) ) != HB_Err_Ok )
4615 goto Fail3;
4616
4617 ccpf2->ChainPosClassSet = NULL;
4618 ccpf2->MaxBacktrackLength = 0;
4619 ccpf2->MaxInputLength = 0;
4620 ccpf2->MaxLookaheadLength = 0;
4621
4622 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4623 goto Fail2;
4624
4625 cpcs = ccpf2->ChainPosClassSet;
4626
4627 for ( n = 0; n < count; n++ )
4628 {
4629 if ( ACCESS_Frame( 2L ) )
4630 goto Fail1;
4631
4632 new_offset = GET_UShort() + base_offset;
4633
4634 FORGET_Frame();
4635
4636 if ( new_offset != base_offset ) /* not a NULL offset */
4637 {
4638 cur_offset = FILE_Pos();
4639 if ( FILE_Seek( new_offset ) ||
4640 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4641 stream ) ) != HB_Err_Ok )
4642 goto Fail1;
4643 (void)FILE_Seek( cur_offset );
4644 }
4645 else
4646 {
4647 /* we create a ChainPosClassSet table with no entries */
4648
4649 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4650 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4651 }
4652 }
4653
4654 return HB_Err_Ok;
4655
4656Fail1:
4657 for ( m = 0; m < n; m++ )
4658 Free_ChainPosClassSet( &cpcs[m] );
4659
4660 FREE( cpcs );
4661
4662Fail2:
4663 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4664
4665Fail3:
4666 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4667
4668Fail4:
4669 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4670
4671Fail5:
4672 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4673 return error;
4674}
4675
4676
4677static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
4678{
4679 HB_UShort n, count;
4680
4681 HB_ChainPosClassSet* cpcs;
4682
4683
4684 if ( ccpf2->ChainPosClassSet )
4685 {
4686 count = ccpf2->ChainPosClassSetCount;
4687 cpcs = ccpf2->ChainPosClassSet;
4688
4689 for ( n = 0; n < count; n++ )
4690 Free_ChainPosClassSet( &cpcs[n] );
4691
4692 FREE( cpcs );
4693 }
4694
4695 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4696 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4697 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4698
4699 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4700}
4701
4702
4703/* ChainContextPosFormat3 */
4704
4705static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
4706 HB_Stream stream )
4707{
4708 HB_Error error;
4709
4710 HB_UShort n, nb, ni, nl, m, count;
4711 HB_UShort backtrack_count, input_count, lookahead_count;
4712 HB_UInt cur_offset, new_offset, base_offset;
4713
4714 HB_Coverage* b;
4715 HB_Coverage* i;
4716 HB_Coverage* l;
4717 HB_PosLookupRecord* plr;
4718
4719
4720 base_offset = FILE_Pos() - 2L;
4721
4722 if ( ACCESS_Frame( 2L ) )
4723 return error;
4724
4725 ccpf3->BacktrackGlyphCount = GET_UShort();
4726
4727 FORGET_Frame();
4728
4729 ccpf3->BacktrackCoverage = NULL;
4730
4731 backtrack_count = ccpf3->BacktrackGlyphCount;
4732
4733 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4734 HB_Coverage ) )
4735 return error;
4736
4737 b = ccpf3->BacktrackCoverage;
4738
4739 for ( nb = 0; nb < backtrack_count; nb++ )
4740 {
4741 if ( ACCESS_Frame( 2L ) )
4742 goto Fail4;
4743
4744 new_offset = GET_UShort() + base_offset;
4745
4746 FORGET_Frame();
4747
4748 cur_offset = FILE_Pos();
4749 if ( FILE_Seek( new_offset ) ||
4750 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4751 goto Fail4;
4752 (void)FILE_Seek( cur_offset );
4753 }
4754
4755 if ( ACCESS_Frame( 2L ) )
4756 goto Fail4;
4757
4758 ccpf3->InputGlyphCount = GET_UShort();
4759
4760 FORGET_Frame();
4761
4762 ccpf3->InputCoverage = NULL;
4763
4764 input_count = ccpf3->InputGlyphCount;
4765
4766 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4767 goto Fail4;
4768
4769 i = ccpf3->InputCoverage;
4770
4771 for ( ni = 0; ni < input_count; ni++ )
4772 {
4773 if ( ACCESS_Frame( 2L ) )
4774 goto Fail3;
4775
4776 new_offset = GET_UShort() + base_offset;
4777
4778 FORGET_Frame();
4779
4780 cur_offset = FILE_Pos();
4781 if ( FILE_Seek( new_offset ) ||
4782 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4783 goto Fail3;
4784 (void)FILE_Seek( cur_offset );
4785 }
4786
4787 if ( ACCESS_Frame( 2L ) )
4788 goto Fail3;
4789
4790 ccpf3->LookaheadGlyphCount = GET_UShort();
4791
4792 FORGET_Frame();
4793
4794 ccpf3->LookaheadCoverage = NULL;
4795
4796 lookahead_count = ccpf3->LookaheadGlyphCount;
4797
4798 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4799 HB_Coverage ) )
4800 goto Fail3;
4801
4802 l = ccpf3->LookaheadCoverage;
4803
4804 for ( nl = 0; nl < lookahead_count; nl++ )
4805 {
4806 if ( ACCESS_Frame( 2L ) )
4807 goto Fail2;
4808
4809 new_offset = GET_UShort() + base_offset;
4810
4811 FORGET_Frame();
4812
4813 cur_offset = FILE_Pos();
4814 if ( FILE_Seek( new_offset ) ||
4815 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4816 goto Fail2;
4817 (void)FILE_Seek( cur_offset );
4818 }
4819
4820 if ( ACCESS_Frame( 2L ) )
4821 goto Fail2;
4822
4823 ccpf3->PosCount = GET_UShort();
4824
4825 FORGET_Frame();
4826
4827 ccpf3->PosLookupRecord = NULL;
4828
4829 count = ccpf3->PosCount;
4830
4831 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4832 goto Fail2;
4833
4834 plr = ccpf3->PosLookupRecord;
4835
4836 if ( ACCESS_Frame( count * 4L ) )
4837 goto Fail1;
4838
4839 for ( n = 0; n < count; n++ )
4840 {
4841 plr[n].SequenceIndex = GET_UShort();
4842 plr[n].LookupListIndex = GET_UShort();
4843 }
4844
4845 FORGET_Frame();
4846
4847 return HB_Err_Ok;
4848
4849Fail1:
4850 FREE( plr );
4851
4852Fail2:
4853 for ( m = 0; m < nl; m++ )
4854 _HB_OPEN_Free_Coverage( &l[m] );
4855
4856 FREE( l );
4857
4858Fail3:
4859 for ( m = 0; m < ni; m++ )
4860 _HB_OPEN_Free_Coverage( &i[m] );
4861
4862 FREE( i );
4863
4864Fail4:
4865 for ( m = 0; m < nb; m++ )
4866 _HB_OPEN_Free_Coverage( &b[m] );
4867
4868 FREE( b );
4869 return error;
4870}
4871
4872
4873static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
4874{
4875 HB_UShort n, count;
4876
4877 HB_Coverage* c;
4878
4879
4880 FREE( ccpf3->PosLookupRecord );
4881
4882 if ( ccpf3->LookaheadCoverage )
4883 {
4884 count = ccpf3->LookaheadGlyphCount;
4885 c = ccpf3->LookaheadCoverage;
4886
4887 for ( n = 0; n < count; n++ )
4888 _HB_OPEN_Free_Coverage( &c[n] );
4889
4890 FREE( c );
4891 }
4892
4893 if ( ccpf3->InputCoverage )
4894 {
4895 count = ccpf3->InputGlyphCount;
4896 c = ccpf3->InputCoverage;
4897
4898 for ( n = 0; n < count; n++ )
4899 _HB_OPEN_Free_Coverage( &c[n] );
4900
4901 FREE( c );
4902 }
4903
4904 if ( ccpf3->BacktrackCoverage )
4905 {
4906 count = ccpf3->BacktrackGlyphCount;
4907 c = ccpf3->BacktrackCoverage;
4908
4909 for ( n = 0; n < count; n++ )
4910 _HB_OPEN_Free_Coverage( &c[n] );
4911
4912 FREE( c );
4913 }
4914}
4915
4916
4917/* ChainContextPos */
4918
4919static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
4920 HB_Stream stream )
4921{
4922 HB_Error error;
4923 HB_ChainContextPos* ccp = &st->chain;
4924
4925
4926 if ( ACCESS_Frame( 2L ) )
4927 return error;
4928
4929 ccp->PosFormat = GET_UShort();
4930
4931 FORGET_Frame();
4932
4933 switch ( ccp->PosFormat )
4934 {
4935 case 1:
4936 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
4937
4938 case 2:
4939 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
4940
4941 case 3:
4942 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
4943
4944 default:
4945 return ERR(HB_Err_Invalid_SubTable_Format);
4946 }
4947
4948 return HB_Err_Ok; /* never reached */
4949}
4950
4951
4952static void Free_ChainContextPos( HB_GPOS_SubTable* st )
4953{
4954 HB_ChainContextPos* ccp = &st->chain;
4955
4956 switch ( ccp->PosFormat )
4957 {
4958 case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
4959 case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
4960 case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
4961 default: break;
4962 }
4963}
4964
4965
4966static HB_Error Lookup_ChainContextPos1(
4967 GPOS_Instance* gpi,
4968 HB_ChainContextPosFormat1* ccpf1,
4969 HB_Buffer buffer,
4970 HB_UShort flags,
4971 HB_UShort context_length,
4972 int nesting_level )
4973{
4974 HB_UShort index, property;
4975 HB_UShort i, j, k, num_cpr;
4976 HB_UShort bgc, igc, lgc;
4977 HB_Error error;
4978 HB_GPOSHeader* gpos = gpi->gpos;
4979
4980 HB_ChainPosRule* cpr;
4981 HB_ChainPosRule curr_cpr;
4982 hb_ot_layout_t* layout;
4983
4984
4985 layout = gpos->layout;
4986
4987 if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
4988 return error;
4989
4990 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
4991 if ( error )
4992 return error;
4993
4994 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
4995 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
4996
4997 for ( k = 0; k < num_cpr; k++ )
4998 {
4999 curr_cpr = cpr[k];
5000 bgc = curr_cpr.BacktrackGlyphCount;
5001 igc = curr_cpr.InputGlyphCount;
5002 lgc = curr_cpr.LookaheadGlyphCount;
5003
5004 if ( context_length != 0xFFFF && context_length < igc )
5005 goto next_chainposrule;
5006
5007 /* check whether context is too long; it is a first guess only */
5008
5009 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5010 goto next_chainposrule;
5011
5012 if ( bgc )
5013 {
5014 /* Since we don't know in advance the number of glyphs to inspect,
5015 we search backwards for matches in the backtrack glyph array */
5016
5017 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5018 {
5019 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5020 {
5021 if ( error && error != HB_Err_Not_Covered )
5022 return error;
5023
5024 if ( j + 1 == bgc - i )
5025 goto next_chainposrule;
5026 j--;
5027 }
5028
5029 /* In OpenType 1.3, it is undefined whether the offsets of
5030 backtrack glyphs is in logical order or not. Version 1.4
5031 will clarify this:
5032
5033 Logical order - a b c d e f g h i j
5034 i
5035 Input offsets - 0 1
5036 Backtrack offsets - 3 2 1 0
5037 Lookahead offsets - 0 1 2 3 */
5038
5039 if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5040 goto next_chainposrule;
5041 }
5042 }
5043
5044 /* Start at 1 because [0] is implied */
5045
5046 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5047 {
5048 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5049 {
5050 if ( error && error != HB_Err_Not_Covered )
5051 return error;
5052
5053 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5054 goto next_chainposrule;
5055 j++;
5056 }
5057
5058 if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5059 goto next_chainposrule;
5060 }
5061
5062 /* we are starting to check for lookahead glyphs right after the
5063 last context glyph */
5064
5065 for ( i = 0; i < lgc; i++, j++ )
5066 {
5067 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5068 {
5069 if ( error && error != HB_Err_Not_Covered )
5070 return error;
5071
5072 if ( j + lgc - i == (HB_Int)buffer->in_length )
5073 goto next_chainposrule;
5074 j++;
5075 }
5076
5077 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5078 goto next_chainposrule;
5079 }
5080
5081 return Do_ContextPos( gpi, igc,
5082 curr_cpr.PosCount,
5083 curr_cpr.PosLookupRecord,
5084 buffer,
5085 nesting_level );
5086
5087 next_chainposrule:
5088 ;
5089 }
5090
5091 return HB_Err_Not_Covered;
5092}
5093
5094
5095static HB_Error Lookup_ChainContextPos2(
5096 GPOS_Instance* gpi,
5097 HB_ChainContextPosFormat2* ccpf2,
5098 HB_Buffer buffer,
5099 HB_UShort flags,
5100 HB_UShort context_length,
5101 int nesting_level )
5102{
5103 HB_UShort index, property;
5104 HB_Error error;
5105 HB_UShort i, j, k;
5106 HB_UShort bgc, igc, lgc;
5107 HB_UShort known_backtrack_classes,
5108 known_input_classes,
5109 known_lookahead_classes;
5110
5111 HB_UShort* backtrack_classes;
5112 HB_UShort* input_classes;
5113 HB_UShort* lookahead_classes;
5114
5115 HB_UShort* bc;
5116 HB_UShort* ic;
5117 HB_UShort* lc;
5118 HB_GPOSHeader* gpos = gpi->gpos;
5119
5120 HB_ChainPosClassSet* cpcs;
5121 HB_ChainPosClassRule cpcr;
5122 hb_ot_layout_t* layout;
5123
5124
5125 layout = gpos->layout;
5126
5127 if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
5128 return error;
5129
5130 /* Note: The coverage table in format 2 doesn't give an index into
5131 anything. It just lets us know whether or not we need to
5132 do any lookup at all. */
5133
5134 error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5135 if ( error )
5136 return error;
5137
5138 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5139 return error;
5140 known_backtrack_classes = 0;
5141
5142 if (ccpf2->MaxInputLength < 1)
5143 return HB_Err_Not_Covered;
5144
5145 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5146 goto End3;
5147 known_input_classes = 1;
5148
5149 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5150 goto End2;
5151 known_lookahead_classes = 0;
5152
5153 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5154 &input_classes[0], NULL );
5155 if ( error && error != HB_Err_Not_Covered )
5156 goto End1;
5157
5158 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5159 if ( !cpcs )
5160 {
5161 error = ERR(HB_Err_Invalid_SubTable);
5162 goto End1;
5163 }
5164
5165 for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5166 {
5167 cpcr = cpcs->ChainPosClassRule[k];
5168 bgc = cpcr.BacktrackGlyphCount;
5169 igc = cpcr.InputGlyphCount;
5170 lgc = cpcr.LookaheadGlyphCount;
5171
5172 if ( context_length != 0xFFFF && context_length < igc )
5173 goto next_chainposclassrule;
5174
5175 /* check whether context is too long; it is a first guess only */
5176
5177 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5178 goto next_chainposclassrule;
5179
5180 if ( bgc )
5181 {
5182 /* Since we don't know in advance the number of glyphs to inspect,
5183 we search backwards for matches in the backtrack glyph array.
5184 Note that `known_backtrack_classes' starts at index 0. */
5185
5186 bc = cpcr.Backtrack;
5187
5188 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5189 {
5190 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5191 {
5192 if ( error && error != HB_Err_Not_Covered )
5193 goto End1;
5194
5195 if ( j + 1 == bgc - i )
5196 goto next_chainposclassrule;
5197 j++;
5198 }
5199
5200 if ( i >= known_backtrack_classes )
5201 {
5202 /* Keeps us from having to do this for each rule */
5203
5204 error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5205 &backtrack_classes[i], NULL );
5206 if ( error && error != HB_Err_Not_Covered )
5207 goto End1;
5208 known_backtrack_classes = i;
5209 }
5210
5211 if ( bc[i] != backtrack_classes[i] )
5212 goto next_chainposclassrule;
5213 }
5214 }
5215
5216 ic = cpcr.Input;
5217
5218 /* Start at 1 because [0] is implied */
5219
5220 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5221 {
5222 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5223 {
5224 if ( error && error != HB_Err_Not_Covered )
5225 goto End1;
5226
5227 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5228 goto next_chainposclassrule;
5229 j++;
5230 }
5231
5232 if ( i >= known_input_classes )
5233 {
5234 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5235 &input_classes[i], NULL );
5236 if ( error && error != HB_Err_Not_Covered )
5237 goto End1;
5238 known_input_classes = i;
5239 }
5240
5241 if ( ic[i - 1] != input_classes[i] )
5242 goto next_chainposclassrule;
5243 }
5244
5245 /* we are starting to check for lookahead glyphs right after the
5246 last context glyph */
5247
5248 lc = cpcr.Lookahead;
5249
5250 for ( i = 0; i < lgc; i++, j++ )
5251 {
5252 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5253 {
5254 if ( error && error != HB_Err_Not_Covered )
5255 goto End1;
5256
5257 if ( j + lgc - i == (HB_Int)buffer->in_length )
5258 goto next_chainposclassrule;
5259 j++;
5260 }
5261
5262 if ( i >= known_lookahead_classes )
5263 {
5264 error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5265 &lookahead_classes[i], NULL );
5266 if ( error && error != HB_Err_Not_Covered )
5267 goto End1;
5268 known_lookahead_classes = i;
5269 }
5270
5271 if ( lc[i] != lookahead_classes[i] )
5272 goto next_chainposclassrule;
5273 }
5274
5275 error = Do_ContextPos( gpi, igc,
5276 cpcr.PosCount,
5277 cpcr.PosLookupRecord,
5278 buffer,
5279 nesting_level );
5280 goto End1;
5281
5282 next_chainposclassrule:
5283 ;
5284 }
5285
5286 error = HB_Err_Not_Covered;
5287
5288End1:
5289 FREE( lookahead_classes );
5290
5291End2:
5292 FREE( input_classes );
5293
5294End3:
5295 FREE( backtrack_classes );
5296 return error;
5297}
5298
5299
5300static HB_Error Lookup_ChainContextPos3(
5301 GPOS_Instance* gpi,
5302 HB_ChainContextPosFormat3* ccpf3,
5303 HB_Buffer buffer,
5304 HB_UShort flags,
5305 HB_UShort context_length,
5306 int nesting_level )
5307{
5308 HB_UShort index, i, j, property;
5309 HB_UShort bgc, igc, lgc;
5310 HB_Error error;
5311 HB_GPOSHeader* gpos = gpi->gpos;
5312
5313 HB_Coverage* bc;
5314 HB_Coverage* ic;
5315 HB_Coverage* lc;
5316 hb_ot_layout_t* layout;
5317
5318
5319 layout = gpos->layout;
5320
5321 if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
5322 return error;
5323
5324 bgc = ccpf3->BacktrackGlyphCount;
5325 igc = ccpf3->InputGlyphCount;
5326 lgc = ccpf3->LookaheadGlyphCount;
5327
5328 if ( context_length != 0xFFFF && context_length < igc )
5329 return HB_Err_Not_Covered;
5330
5331 /* check whether context is too long; it is a first guess only */
5332
5333 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5334 return HB_Err_Not_Covered;
5335
5336 if ( bgc )
5337 {
5338 /* Since we don't know in advance the number of glyphs to inspect,
5339 we search backwards for matches in the backtrack glyph array */
5340
5341 bc = ccpf3->BacktrackCoverage;
5342
5343 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5344 {
5345 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5346 {
5347 if ( error && error != HB_Err_Not_Covered )
5348 return error;
5349
5350 if ( j + 1 == bgc - i )
5351 return HB_Err_Not_Covered;
5352 j--;
5353 }
5354
5355 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5356 if ( error )
5357 return error;
5358 }
5359 }
5360
5361 ic = ccpf3->InputCoverage;
5362
5363 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5364 {
5365 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5366 while ( j > buffer->in_pos && CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5367 {
5368 if ( error && error != HB_Err_Not_Covered )
5369 return error;
5370
5371 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5372 return HB_Err_Not_Covered;
5373 j++;
5374 }
5375
5376 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5377 if ( error )
5378 return error;
5379 }
5380
5381 /* we are starting to check for lookahead glyphs right after the
5382 last context glyph */
5383
5384 lc = ccpf3->LookaheadCoverage;
5385
5386 for ( i = 0; i < lgc; i++, j++ )
5387 {
5388 while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
5389 {
5390 if ( error && error != HB_Err_Not_Covered )
5391 return error;
5392
5393 if ( j + lgc - i == (HB_Int)buffer->in_length )
5394 return HB_Err_Not_Covered;
5395 j++;
5396 }
5397
5398 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5399 if ( error )
5400 return error;
5401 }
5402
5403 return Do_ContextPos( gpi, igc,
5404 ccpf3->PosCount,
5405 ccpf3->PosLookupRecord,
5406 buffer,
5407 nesting_level );
5408}
5409
5410
5411static HB_Error Lookup_ChainContextPos(
5412 GPOS_Instance* gpi,
5413 HB_GPOS_SubTable* st,
5414 HB_Buffer buffer,
5415 HB_UShort flags,
5416 HB_UShort context_length,
5417 int nesting_level )
5418{
5419 HB_ChainContextPos* ccp = &st->chain;
5420
5421 switch ( ccp->PosFormat )
5422 {
5423 case 1:
5424 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5425 flags, context_length,
5426 nesting_level );
5427
5428 case 2:
5429 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5430 flags, context_length,
5431 nesting_level );
5432
5433 case 3:
5434 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5435 flags, context_length,
5436 nesting_level );
5437
5438 default:
5439 return ERR(HB_Err_Invalid_SubTable_Format);
5440 }
5441
5442 return HB_Err_Ok; /* never reached */
5443}
5444
5445
5446
5447/***********
5448 * GPOS API
5449 ***********/
5450
5451
5452
5453HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
5454 HB_UInt script_tag,
5455 HB_UShort* script_index )
5456{
5457 HB_UShort n;
5458
5459 HB_ScriptList* sl;
5460 HB_ScriptRecord* sr;
5461
5462
5463 if ( !gpos || !script_index )
5464 return ERR(HB_Err_Invalid_Argument);
5465
5466 sl = &gpos->ScriptList;
5467 sr = sl->ScriptRecord;
5468
5469 for ( n = 0; n < sl->ScriptCount; n++ )
5470 if ( script_tag == sr[n].ScriptTag )
5471 {
5472 *script_index = n;
5473
5474 return HB_Err_Ok;
5475 }
5476
5477 return HB_Err_Not_Covered;
5478}
5479
5480
5481
5482HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
5483 HB_UInt language_tag,
5484 HB_UShort script_index,
5485 HB_UShort* language_index,
5486 HB_UShort* req_feature_index )
5487{
5488 HB_UShort n;
5489
5490 HB_ScriptList* sl;
5491 HB_ScriptRecord* sr;
5492 HB_ScriptTable* s;
5493 HB_LangSysRecord* lsr;
5494
5495
5496 if ( !gpos || !language_index || !req_feature_index )
5497 return ERR(HB_Err_Invalid_Argument);
5498
5499 sl = &gpos->ScriptList;
5500 sr = sl->ScriptRecord;
5501
5502 if ( script_index >= sl->ScriptCount )
5503 return ERR(HB_Err_Invalid_Argument);
5504
5505 s = &sr[script_index].Script;
5506 lsr = s->LangSysRecord;
5507
5508 for ( n = 0; n < s->LangSysCount; n++ )
5509 if ( language_tag == lsr[n].LangSysTag )
5510 {
5511 *language_index = n;
5512 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5513
5514 return HB_Err_Ok;
5515 }
5516
5517 return HB_Err_Not_Covered;
5518}
5519
5520
5521/* selecting 0xFFFF for language_index asks for the values of the
5522 default language (DefaultLangSys) */
5523
5524
5525HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
5526 HB_UInt feature_tag,
5527 HB_UShort script_index,
5528 HB_UShort language_index,
5529 HB_UShort* feature_index )
5530{
5531 HB_UShort n;
5532
5533 HB_ScriptList* sl;
5534 HB_ScriptRecord* sr;
5535 HB_ScriptTable* s;
5536 HB_LangSysRecord* lsr;
5537 HB_LangSys* ls;
5538 HB_UShort* fi;
5539
5540 HB_FeatureList* fl;
5541 HB_FeatureRecord* fr;
5542
5543
5544 if ( !gpos || !feature_index )
5545 return ERR(HB_Err_Invalid_Argument);
5546
5547 sl = &gpos->ScriptList;
5548 sr = sl->ScriptRecord;
5549
5550 fl = &gpos->FeatureList;
5551 fr = fl->FeatureRecord;
5552
5553 if ( script_index >= sl->ScriptCount )
5554 return ERR(HB_Err_Invalid_Argument);
5555
5556 s = &sr[script_index].Script;
5557 lsr = s->LangSysRecord;
5558
5559 if ( language_index == 0xFFFF )
5560 ls = &s->DefaultLangSys;
5561 else
5562 {
5563 if ( language_index >= s->LangSysCount )
5564 return ERR(HB_Err_Invalid_Argument);
5565
5566 ls = &lsr[language_index].LangSys;
5567 }
5568
5569 fi = ls->FeatureIndex;
5570
5571 for ( n = 0; n < ls->FeatureCount; n++ )
5572 {
5573 if ( fi[n] >= fl->FeatureCount )
5574 return ERR(HB_Err_Invalid_SubTable_Format);
5575
5576 if ( feature_tag == fr[fi[n]].FeatureTag )
5577 {
5578 *feature_index = fi[n];
5579
5580 return HB_Err_Ok;
5581 }
5582 }
5583
5584 return HB_Err_Not_Covered;
5585}
5586
5587
5588/* The next three functions return a null-terminated list */
5589
5590
5591HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
5592 HB_UInt** script_tag_list )
5593{
5594 HB_Error error;
5595 HB_UShort n;
5596 HB_UInt* stl;
5597
5598 HB_ScriptList* sl;
5599 HB_ScriptRecord* sr;
5600
5601
5602 if ( !gpos || !script_tag_list )
5603 return ERR(HB_Err_Invalid_Argument);
5604
5605 sl = &gpos->ScriptList;
5606 sr = sl->ScriptRecord;
5607
5608 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
5609 return error;
5610
5611 for ( n = 0; n < sl->ScriptCount; n++ )
5612 stl[n] = sr[n].ScriptTag;
5613 stl[n] = 0;
5614
5615 *script_tag_list = stl;
5616
5617 return HB_Err_Ok;
5618}
5619
5620
5621
5622HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
5623 HB_UShort script_index,
5624 HB_UInt** language_tag_list )
5625{
5626 HB_Error error;
5627 HB_UShort n;
5628 HB_UInt* ltl;
5629
5630 HB_ScriptList* sl;
5631 HB_ScriptRecord* sr;
5632 HB_ScriptTable* s;
5633 HB_LangSysRecord* lsr;
5634
5635
5636 if ( !gpos || !language_tag_list )
5637 return ERR(HB_Err_Invalid_Argument);
5638
5639 sl = &gpos->ScriptList;
5640 sr = sl->ScriptRecord;
5641
5642 if ( script_index >= sl->ScriptCount )
5643 return ERR(HB_Err_Invalid_Argument);
5644
5645 s = &sr[script_index].Script;
5646 lsr = s->LangSysRecord;
5647
5648 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
5649 return error;
5650
5651 for ( n = 0; n < s->LangSysCount; n++ )
5652 ltl[n] = lsr[n].LangSysTag;
5653 ltl[n] = 0;
5654
5655 *language_tag_list = ltl;
5656
5657 return HB_Err_Ok;
5658}
5659
5660
5661/* selecting 0xFFFF for language_index asks for the values of the
5662 default language (DefaultLangSys) */
5663
5664
5665HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
5666 HB_UShort script_index,
5667 HB_UShort language_index,
5668 HB_UInt** feature_tag_list )
5669{
5670 HB_UShort n;
5671 HB_Error error;
5672 HB_UInt* ftl;
5673
5674 HB_ScriptList* sl;
5675 HB_ScriptRecord* sr;
5676 HB_ScriptTable* s;
5677 HB_LangSysRecord* lsr;
5678 HB_LangSys* ls;
5679 HB_UShort* fi;
5680
5681 HB_FeatureList* fl;
5682 HB_FeatureRecord* fr;
5683
5684
5685 if ( !gpos || !feature_tag_list )
5686 return ERR(HB_Err_Invalid_Argument);
5687
5688 sl = &gpos->ScriptList;
5689 sr = sl->ScriptRecord;
5690
5691 fl = &gpos->FeatureList;
5692 fr = fl->FeatureRecord;
5693
5694 if ( script_index >= sl->ScriptCount )
5695 return ERR(HB_Err_Invalid_Argument);
5696
5697 s = &sr[script_index].Script;
5698 lsr = s->LangSysRecord;
5699
5700 if ( language_index == 0xFFFF )
5701 ls = &s->DefaultLangSys;
5702 else
5703 {
5704 if ( language_index >= s->LangSysCount )
5705 return ERR(HB_Err_Invalid_Argument);
5706
5707 ls = &lsr[language_index].LangSys;
5708 }
5709
5710 fi = ls->FeatureIndex;
5711
5712 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
5713 return error;
5714
5715 for ( n = 0; n < ls->FeatureCount; n++ )
5716 {
5717 if ( fi[n] >= fl->FeatureCount )
5718 {
5719 FREE( ftl );
5720 return ERR(HB_Err_Invalid_SubTable_Format);
5721 }
5722 ftl[n] = fr[fi[n]].FeatureTag;
5723 }
5724 ftl[n] = 0;
5725
5726 *feature_tag_list = ftl;
5727
5728 return HB_Err_Ok;
5729}
5730
5731
5732/* Do an individual subtable lookup. Returns HB_Err_Ok if positioning
5733 has been done, or HB_Err_Not_Covered if not. */
5734static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
5735 HB_UShort lookup_index,
5736 HB_Buffer buffer,
5737 HB_UShort context_length,
5738 int nesting_level )
5739{
5740 HB_Error error = HB_Err_Not_Covered;
5741 HB_UShort i, flags, lookup_count;
5742 HB_GPOSHeader* gpos = gpi->gpos;
5743 HB_Lookup* lo;
5744 int lookup_type;
5745
5746
5747 nesting_level++;
5748
5749 if ( nesting_level > HB_MAX_NESTING_LEVEL )
5750 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
5751
5752 lookup_count = gpos->LookupList.LookupCount;
5753 if (lookup_index >= lookup_count)
5754 return error;
5755
5756 lo = &gpos->LookupList.Lookup[lookup_index];
5757 flags = lo->LookupFlag;
5758 lookup_type = lo->LookupType;
5759
5760 for ( i = 0; i < lo->SubTableCount; i++ )
5761 {
5762 HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
5763
5764 switch (lookup_type) {
5765 case HB_GPOS_LOOKUP_SINGLE:
5766 error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5767 case HB_GPOS_LOOKUP_PAIR:
5768 error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5769 case HB_GPOS_LOOKUP_CURSIVE:
5770 error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5771 case HB_GPOS_LOOKUP_MARKBASE:
5772 error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5773 case HB_GPOS_LOOKUP_MARKLIG:
5774 error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5775 case HB_GPOS_LOOKUP_MARKMARK:
5776 error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5777 case HB_GPOS_LOOKUP_CONTEXT:
5778 error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5779 case HB_GPOS_LOOKUP_CHAIN:
5780 error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5781 /*case HB_GPOS_LOOKUP_EXTENSION:
5782 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5783 default:
5784 error = HB_Err_Not_Covered;
5785 }
5786
5787 /* Check whether we have a successful positioning or an error other
5788 than HB_Err_Not_Covered */
5789 if ( error != HB_Err_Not_Covered )
5790 return error;
5791 }
5792
5793 return HB_Err_Not_Covered;
5794}
5795
5796
5797HB_INTERNAL HB_Error
5798_HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5799 HB_Stream stream,
5800 HB_UShort lookup_type )
5801{
5802 switch ( lookup_type ) {
5803 case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream );
5804 case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream );
5805 case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream );
5806 case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream );
5807 case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream );
5808 case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream );
5809 case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream );
5810 case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream );
5811 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/
5812 default: return ERR(HB_Err_Invalid_SubTable_Format);
5813 }
5814}
5815
5816
5817HB_INTERNAL void
5818_HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
5819 HB_UShort lookup_type )
5820{
5821 switch ( lookup_type ) {
5822 case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return;
5823 case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return;
5824 case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return;
5825 case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return;
5826 case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return;
5827 case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return;
5828 case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return;
5829 case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return;
5830 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/
5831 default: return;
5832 }
5833}
5834
5835
5836/* apply one lookup to the input string object */
5837
5838static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
5839 HB_UShort lookup_index,
5840 HB_Buffer buffer )
5841{
5842 HB_Error error, retError = HB_Err_Not_Covered;
5843 HB_GPOSHeader* gpos = gpi->gpos;
5844
5845 HB_UInt* properties = gpos->LookupList.Properties;
5846
5847 const int nesting_level = 0;
5848 /* 0xFFFF indicates that we don't have a context length yet */
5849 const HB_UShort context_length = 0xFFFF;
5850
5851
5852 gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
5853
5854 buffer->in_pos = 0;
5855 while ( buffer->in_pos < buffer->in_length )
5856 {
5857 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
5858 {
5859 /* Note that the connection between mark and base glyphs hold
5860 exactly one (string) lookup. For example, it would be possible
5861 that in the first lookup, mark glyph X is attached to base
5862 glyph A, and in the next lookup it is attached to base glyph B.
5863 It is up to the font designer to provide meaningful lookups and
5864 lookup order. */
5865
5866 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5867 if ( error && error != HB_Err_Not_Covered )
5868 return error;
5869 }
5870 else
5871 {
5872 /* Contrary to properties defined in GDEF, user-defined properties
5873 will always stop a possible cursive positioning. */
5874 gpi->last = 0xFFFF;
5875
5876 error = HB_Err_Not_Covered;
5877 }
5878
5879 if ( error == HB_Err_Not_Covered )
5880 (buffer->in_pos)++;
5881 else
5882 retError = error;
5883 }
5884
5885 return retError;
5886}
5887
5888
5889static HB_Error Position_CursiveChain ( HB_Buffer buffer )
5890{
5891 HB_UInt i, j;
5892 HB_Position positions = buffer->positions;
5893
5894 /* First handle all left-to-right connections */
5895 for (j = 0; j < buffer->in_length; j++)
5896 {
5897 if (positions[j].cursive_chain > 0)
5898 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5899 }
5900
5901 /* Then handle all right-to-left connections */
5902 for (i = buffer->in_length; i > 0; i--)
5903 {
5904 j = i - 1;
5905
5906 if (positions[j].cursive_chain < 0)
5907 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5908 }
5909
5910 return HB_Err_Ok;
5911}
5912
5913
5914HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
5915 HB_UShort feature_index,
5916 HB_UInt property )
5917{
5918 HB_UShort i;
5919
5920 HB_Feature feature;
5921 HB_UInt* properties;
5922 HB_UShort* index;
5923 HB_UShort lookup_count;
5924
5925 /* Each feature can only be added once */
5926
5927 if ( !gpos ||
5928 feature_index >= gpos->FeatureList.FeatureCount ||
5929 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
5930 return ERR(HB_Err_Invalid_Argument);
5931
5932 gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
5933
5934 properties = gpos->LookupList.Properties;
5935
5936 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
5937 index = feature.LookupListIndex;
5938 lookup_count = gpos->LookupList.LookupCount;
5939
5940 for ( i = 0; i < feature.LookupListCount; i++ )
5941 {
5942 HB_UShort lookup_index = index[i];
5943 if (lookup_index < lookup_count)
5944 properties[lookup_index] |= property;
5945 }
5946
5947 return HB_Err_Ok;
5948}
5949
5950
5951
5952HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
5953{
5954 HB_UShort i;
5955
5956 HB_UInt* properties;
5957
5958
5959 if ( !gpos )
5960 return ERR(HB_Err_Invalid_Argument);
5961
5962 gpos->FeatureList.ApplyCount = 0;
5963
5964 properties = gpos->LookupList.Properties;
5965
5966 for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
5967 properties[i] = 0;
5968
5969 return HB_Err_Ok;
5970}
5971
5972
5973
5974HB_Error HB_GPOS_Register_Glyph_Function( HB_GPOSHeader* gpos,
5975 HB_GlyphFunction gfunc )
5976{
5977 if ( !gpos )
5978 return ERR(HB_Err_Invalid_Argument);
5979
5980 gpos->gfunc = gfunc;
5981
5982 return HB_Err_Ok;
5983}
5984
5985
5986
5987HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
5988 HB_MMFunction mmfunc,
5989 void* data )
5990{
5991 if ( !gpos )
5992 return ERR(HB_Err_Invalid_Argument);
5993
5994 gpos->mmfunc = mmfunc;
5995 gpos->data = data;
5996
5997 return HB_Err_Ok;
5998}
5999
6000/* If `dvi' is TRUE, glyph contour points for anchor points and device
6001 tables are ignored -- you will get device independent values. */
6002
6003
6004HB_Error HB_GPOS_Apply_String( HB_Font font,
6005 HB_GPOSHeader* gpos,
6006 HB_UShort load_flags,
6007 HB_Buffer buffer,
6008 HB_Bool dvi,
6009 HB_Bool r2l )
6010{
6011 HB_Error error, retError = HB_Err_Not_Covered;
6012 GPOS_Instance gpi;
6013 int i, j, lookup_count, num_features;
6014
6015 if ( !font || !gpos || !buffer )
6016 return ERR(HB_Err_Invalid_Argument);
6017
6018 if ( buffer->in_length == 0 )
6019 return HB_Err_Not_Covered;
6020
6021 gpi.font = font;
6022 gpi.gpos = gpos;
6023 gpi.load_flags = load_flags;
6024 gpi.r2l = r2l;
6025 gpi.dvi = dvi;
6026
6027 lookup_count = gpos->LookupList.LookupCount;
6028 num_features = gpos->FeatureList.ApplyCount;
6029
6030 if ( num_features )
6031 {
6032 error = _hb_buffer_clear_positions( buffer );
6033 if ( error )
6034 return error;
6035 }
6036
6037 for ( i = 0; i < num_features; i++ )
6038 {
6039 HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i];
6040 HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6041
6042 for ( j = 0; j < feature.LookupListCount; j++ )
6043 {
6044 HB_UShort lookup_index = feature.LookupListIndex[j];
6045
6046 /* Skip nonexistant lookups */
6047 if (lookup_index >= lookup_count)
6048 continue;
6049
6050 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6051 if ( error )
6052 {
6053 if ( error != HB_Err_Not_Covered )
6054 return error;
6055 }
6056 else
6057 retError = error;
6058 }
6059 }
6060
6061 if ( num_features )
6062 {
6063 error = Position_CursiveChain ( buffer );
6064 if ( error )
6065 return error;
6066 }
6067
6068 return retError;
6069}
6070
6071/* END */