Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: third_party/harfbuzz/src/harfbuzz-gpos.c

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

Powered by Google App Engine
This is Rietveld 408576698