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