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 if (!ppf1->PairSet[index].PairValueCount)
1511 return HB_Err_Not_Covered;
1512
1513 pvr = ppf1->PairSet[index].PairValueRecord;
1514 if ( !pvr )
1515 return ERR(HB_Err_Invalid_SubTable);
1516
1517 glyph2 = IN_CURGLYPH();
1518
1519 for ( numpvr = ppf1->PairSet[index].PairValueCount;
1520 numpvr;
1521 numpvr--, pvr++ )
1522 {
1523 if ( glyph2 == pvr->SecondGlyph )
1524 {
1525 error = Get_ValueRecord( gpi, &pvr->Value1, format1,
1526 POSITION( first_pos ) );
1527 if ( error )
1528 return error;
1529 return Get_ValueRecord( gpi, &pvr->Value2, format2,
1530 POSITION( buffer->in_pos ) );
1531 }
1532 }
1533
1534 return HB_Err_Not_Covered;
1535 }
1536
1537
Lookup_PairPos2(GPOS_Instance * gpi,HB_PairPosFormat2 * ppf2,HB_Buffer buffer,HB_UInt first_pos,HB_UShort format1,HB_UShort format2)1538 static HB_Error Lookup_PairPos2( GPOS_Instance* gpi,
1539 HB_PairPosFormat2* ppf2,
1540 HB_Buffer buffer,
1541 HB_UInt first_pos,
1542 HB_UShort format1,
1543 HB_UShort format2 )
1544 {
1545 HB_Error error;
1546 HB_UShort cl1 = 0, cl2 = 0; /* shut compiler up */
1547
1548 HB_Class1Record* c1r;
1549 HB_Class2Record* c2r;
1550
1551
1552 error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
1553 &cl1, NULL );
1554 if ( error && error != HB_Err_Not_Covered )
1555 return error;
1556 error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
1557 &cl2, NULL );
1558 if ( error && error != HB_Err_Not_Covered )
1559 return error;
1560
1561 c1r = &ppf2->Class1Record[cl1];
1562 if ( !c1r )
1563 return ERR(HB_Err_Invalid_SubTable);
1564 c2r = &c1r->Class2Record[cl2];
1565
1566 error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
1567 if ( error )
1568 return error;
1569 return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
1570 }
1571
1572
Lookup_PairPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1573 static HB_Error Lookup_PairPos( GPOS_Instance* gpi,
1574 HB_GPOS_SubTable* st,
1575 HB_Buffer buffer,
1576 HB_UShort flags,
1577 HB_UShort context_length,
1578 int nesting_level )
1579 {
1580 HB_Error error;
1581 HB_UShort index, property;
1582 HB_UInt first_pos;
1583 HB_GPOSHeader* gpos = gpi->gpos;
1584 HB_PairPos* pp = &st->pair;
1585
1586 HB_UNUSED(nesting_level);
1587
1588 if ( buffer->in_pos >= buffer->in_length - 1 )
1589 return HB_Err_Not_Covered; /* Not enough glyphs in stream */
1590
1591 if ( context_length != 0xFFFF && context_length < 2 )
1592 return HB_Err_Not_Covered;
1593
1594 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1595 return error;
1596
1597 error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
1598 if ( error )
1599 return error;
1600
1601 /* second glyph */
1602
1603 first_pos = buffer->in_pos;
1604 (buffer->in_pos)++;
1605
1606 while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
1607 flags, &property ) )
1608 {
1609 if ( error && error != HB_Err_Not_Covered )
1610 return error;
1611
1612 if ( buffer->in_pos == buffer->in_length )
1613 {
1614 buffer->in_pos = first_pos;
1615 return HB_Err_Not_Covered;
1616 }
1617 (buffer->in_pos)++;
1618
1619 }
1620
1621 switch ( pp->PosFormat )
1622 {
1623 case 1:
1624 error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
1625 first_pos, index,
1626 pp->ValueFormat1, pp->ValueFormat2 );
1627 break;
1628
1629 case 2:
1630 error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
1631 pp->ValueFormat1, pp->ValueFormat2 );
1632 break;
1633
1634 default:
1635 return ERR(HB_Err_Invalid_SubTable_Format);
1636 }
1637
1638 /* if we don't have coverage for the second glyph don't skip it for
1639 further lookups but reset in_pos back to the first_glyph and let
1640 the caller in Do_String_Lookup increment in_pos */
1641 if ( error == HB_Err_Not_Covered )
1642 buffer->in_pos = first_pos;
1643
1644 /* adjusting the `next' glyph */
1645
1646 if ( pp->ValueFormat2 )
1647 (buffer->in_pos)++;
1648
1649 return error;
1650 }
1651
1652
1653 /* LookupType 3 */
1654
1655 /* CursivePosFormat1 */
1656
Load_CursivePos(HB_GPOS_SubTable * st,HB_Stream stream)1657 static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
1658 HB_Stream stream )
1659 {
1660 HB_Error error;
1661 HB_CursivePos* cp = &st->cursive;
1662
1663 HB_UShort n, m, count;
1664 HB_UInt cur_offset, new_offset, base_offset;
1665
1666 HB_EntryExitRecord* eer;
1667
1668
1669 base_offset = FILE_Pos();
1670
1671 if ( ACCESS_Frame( 4L ) )
1672 return error;
1673
1674 cp->PosFormat = GET_UShort();
1675 new_offset = GET_UShort() + base_offset;
1676
1677 FORGET_Frame();
1678
1679 cur_offset = FILE_Pos();
1680 if ( FILE_Seek( new_offset ) ||
1681 ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
1682 return error;
1683 (void)FILE_Seek( cur_offset );
1684
1685 if ( ACCESS_Frame( 2L ) )
1686 goto Fail2;
1687
1688 count = cp->EntryExitCount = GET_UShort();
1689
1690 FORGET_Frame();
1691
1692 cp->EntryExitRecord = NULL;
1693
1694 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
1695 goto Fail2;
1696
1697 eer = cp->EntryExitRecord;
1698
1699 for ( n = 0; n < count; n++ )
1700 {
1701 HB_UInt entry_offset;
1702
1703 if ( ACCESS_Frame( 2L ) )
1704 return error;
1705
1706 entry_offset = new_offset = GET_UShort();
1707
1708 FORGET_Frame();
1709
1710 if ( new_offset )
1711 {
1712 new_offset += base_offset;
1713
1714 cur_offset = FILE_Pos();
1715 if ( FILE_Seek( new_offset ) ||
1716 ( error = Load_Anchor( &eer[n].EntryAnchor,
1717 stream ) ) != HB_Err_Ok )
1718 goto Fail1;
1719 (void)FILE_Seek( cur_offset );
1720 }
1721 else
1722 eer[n].EntryAnchor.PosFormat = 0;
1723
1724 if ( ACCESS_Frame( 2L ) )
1725 return error;
1726
1727 new_offset = GET_UShort();
1728
1729 FORGET_Frame();
1730
1731 if ( new_offset )
1732 {
1733 new_offset += base_offset;
1734
1735 cur_offset = FILE_Pos();
1736 if ( FILE_Seek( new_offset ) ||
1737 ( error = Load_Anchor( &eer[n].ExitAnchor,
1738 stream ) ) != HB_Err_Ok )
1739 {
1740 if ( entry_offset )
1741 Free_Anchor( &eer[n].EntryAnchor );
1742 goto Fail1;
1743 }
1744 (void)FILE_Seek( cur_offset );
1745 }
1746 else
1747 eer[n].ExitAnchor.PosFormat = 0;
1748 }
1749
1750 return HB_Err_Ok;
1751
1752 Fail1:
1753 for ( m = 0; m < n; m++ )
1754 {
1755 Free_Anchor( &eer[m].EntryAnchor );
1756 Free_Anchor( &eer[m].ExitAnchor );
1757 }
1758
1759 FREE( eer );
1760
1761 Fail2:
1762 _HB_OPEN_Free_Coverage( &cp->Coverage );
1763 return error;
1764 }
1765
1766
Free_CursivePos(HB_GPOS_SubTable * st)1767 static void Free_CursivePos( HB_GPOS_SubTable* st )
1768 {
1769 HB_UShort n, count;
1770 HB_CursivePos* cp = &st->cursive;
1771
1772 HB_EntryExitRecord* eer;
1773
1774
1775 if ( cp->EntryExitRecord )
1776 {
1777 count = cp->EntryExitCount;
1778 eer = cp->EntryExitRecord;
1779
1780 for ( n = 0; n < count; n++ )
1781 {
1782 Free_Anchor( &eer[n].EntryAnchor );
1783 Free_Anchor( &eer[n].ExitAnchor );
1784 }
1785
1786 FREE( eer );
1787 }
1788
1789 _HB_OPEN_Free_Coverage( &cp->Coverage );
1790 }
1791
1792
Lookup_CursivePos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1793 static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
1794 HB_GPOS_SubTable* st,
1795 HB_Buffer buffer,
1796 HB_UShort flags,
1797 HB_UShort context_length,
1798 int nesting_level )
1799 {
1800 HB_UShort index, property;
1801 HB_Error error;
1802 HB_GPOSHeader* gpos = gpi->gpos;
1803 HB_CursivePos* cp = &st->cursive;
1804
1805 HB_EntryExitRecord* eer;
1806 HB_Fixed entry_x, entry_y;
1807 HB_Fixed exit_x, exit_y;
1808
1809 HB_UNUSED(nesting_level);
1810
1811 if ( context_length != 0xFFFF && context_length < 1 )
1812 {
1813 gpi->last = 0xFFFF;
1814 return HB_Err_Not_Covered;
1815 }
1816
1817 /* Glyphs not having the right GDEF properties will be ignored, i.e.,
1818 gpi->last won't be reset (contrary to user defined properties). */
1819
1820 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
1821 return error;
1822
1823 /* We don't handle mark glyphs here. According to Andrei, this isn't
1824 possible, but who knows... */
1825
1826 if ( property == HB_GDEF_MARK )
1827 {
1828 gpi->last = 0xFFFF;
1829 return HB_Err_Not_Covered;
1830 }
1831
1832 error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
1833 if ( error )
1834 {
1835 gpi->last = 0xFFFF;
1836 return error;
1837 }
1838
1839 if ( index >= cp->EntryExitCount )
1840 return ERR(HB_Err_Invalid_SubTable);
1841
1842 eer = &cp->EntryExitRecord[index];
1843
1844 /* Now comes the messiest part of the whole OpenType
1845 specification. At first glance, cursive connections seem easy
1846 to understand, but there are pitfalls! The reason is that
1847 the specs don't mention how to compute the advance values
1848 resp. glyph offsets. I was told it would be an omission, to
1849 be fixed in the next OpenType version... Again many thanks to
1850 Andrei Burago <andreib@microsoft.com> for clarifications.
1851
1852 Consider the following example:
1853
1854 | xadv1 |
1855 +---------+
1856 | |
1857 +-----+--+ 1 |
1858 | | .| |
1859 | 0+--+------+
1860 | 2 |
1861 | |
1862 0+--------+
1863 | xadv2 |
1864
1865 glyph1: advance width = 12
1866 anchor point = (3,1)
1867
1868 glyph2: advance width = 11
1869 anchor point = (9,4)
1870
1871 LSB is 1 for both glyphs (so the boxes drawn above are glyph
1872 bboxes). Writing direction is R2L; `0' denotes the glyph's
1873 coordinate origin.
1874
1875 Now the surprising part: The advance width of the *left* glyph
1876 (resp. of the *bottom* glyph) will be modified, no matter
1877 whether the writing direction is L2R or R2L (resp. T2B or
1878 B2T)! This assymetry is caused by the fact that the glyph's
1879 coordinate origin is always the lower left corner for all
1880 writing directions.
1881
1882 Continuing the above example, we can compute the new
1883 (horizontal) advance width of glyph2 as
1884
1885 9 - 3 = 6 ,
1886
1887 and the new vertical offset of glyph2 as
1888
1889 1 - 4 = -3 .
1890
1891
1892 Vertical writing direction is far more complicated:
1893
1894 a) Assuming that we recompute the advance height of the lower glyph:
1895
1896 --
1897 +---------+
1898 -- | |
1899 +-----+--+ 1 | yadv1
1900 | | .| |
1901 yadv2 | 0+--+------+ -- BSB1 --
1902 | 2 | -- -- y_offset
1903 | |
1904 BSB2 -- 0+--------+ --
1905 -- --
1906
1907 glyph1: advance height = 6
1908 anchor point = (3,1)
1909
1910 glyph2: advance height = 7
1911 anchor point = (9,4)
1912
1913 TSB is 1 for both glyphs; writing direction is T2B.
1914
1915
1916 BSB1 = yadv1 - (TSB1 + ymax1)
1917 BSB2 = yadv2 - (TSB2 + ymax2)
1918 y_offset = y2 - y1
1919
1920 vertical advance width of glyph2
1921 = y_offset + BSB2 - BSB1
1922 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
1923 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
1924 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
1925
1926
1927 b) Assuming that we recompute the advance height of the upper glyph:
1928
1929 -- --
1930 +---------+ -- TSB1
1931 -- -- | |
1932 TSB2 -- +-----+--+ 1 | yadv1 ymax1
1933 | | .| |
1934 yadv2 | 0+--+------+ -- --
1935 ymax2 | 2 | -- y_offset
1936 | |
1937 -- 0+--------+ --
1938 --
1939
1940 glyph1: advance height = 6
1941 anchor point = (3,1)
1942
1943 glyph2: advance height = 7
1944 anchor point = (9,4)
1945
1946 TSB is 1 for both glyphs; writing direction is T2B.
1947
1948 y_offset = y2 - y1
1949
1950 vertical advance width of glyph2
1951 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
1952 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
1953
1954
1955 Comparing a) with b) shows that b) is easier to compute. I'll wait
1956 for a reply from Andrei to see what should really be implemented...
1957
1958 Since horizontal advance widths or vertical advance heights
1959 can be used alone but not together, no ambiguity occurs. */
1960
1961 if ( gpi->last == 0xFFFF )
1962 goto end;
1963
1964 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
1965 table. */
1966
1967 error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
1968 &entry_x, &entry_y );
1969 if ( error == HB_Err_Not_Covered )
1970 goto end;
1971 if ( error )
1972 return error;
1973
1974 if ( gpi->r2l )
1975 {
1976 POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
1977 POSITION( buffer->in_pos )->new_advance = TRUE;
1978 }
1979 else
1980 {
1981 POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
1982 POSITION( gpi->last )->new_advance = TRUE;
1983 }
1984
1985 if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
1986 {
1987 POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
1988 POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
1989 }
1990 else
1991 {
1992 POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
1993 POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
1994 }
1995
1996 end:
1997 error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
1998 &exit_x, &exit_y );
1999 if ( error == HB_Err_Not_Covered )
2000 gpi->last = 0xFFFF;
2001 else
2002 {
2003 gpi->last = buffer->in_pos;
2004 gpi->anchor_x = exit_x;
2005 gpi->anchor_y = exit_y;
2006 }
2007 if ( error )
2008 return error;
2009
2010 (buffer->in_pos)++;
2011
2012 return HB_Err_Ok;
2013 }
2014
2015
2016 /* LookupType 4 */
2017
2018 /* BaseArray */
2019
Load_BaseArray(HB_BaseArray * ba,HB_UShort num_classes,HB_Stream stream)2020 static HB_Error Load_BaseArray( HB_BaseArray* ba,
2021 HB_UShort num_classes,
2022 HB_Stream stream )
2023 {
2024 HB_Error error;
2025
2026 HB_UShort m, n, count;
2027 HB_UInt cur_offset, new_offset, base_offset;
2028
2029 HB_BaseRecord *br;
2030 HB_Anchor *ban, *bans;
2031
2032
2033 base_offset = FILE_Pos();
2034
2035 if ( ACCESS_Frame( 2L ) )
2036 return error;
2037
2038 count = ba->BaseCount = GET_UShort();
2039
2040 FORGET_Frame();
2041
2042 ba->BaseRecord = NULL;
2043
2044 if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
2045 return error;
2046
2047 br = ba->BaseRecord;
2048
2049 bans = NULL;
2050
2051 if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
2052 goto Fail;
2053
2054 for ( m = 0; m < count; m++ )
2055 {
2056 br[m].BaseAnchor = NULL;
2057
2058 ban = br[m].BaseAnchor = bans + m * num_classes;
2059
2060 for ( n = 0; n < num_classes; n++ )
2061 {
2062 if ( ACCESS_Frame( 2L ) )
2063 goto Fail;
2064
2065 new_offset = GET_UShort() + base_offset;
2066
2067 FORGET_Frame();
2068
2069 if (new_offset == base_offset) {
2070 /* XXX
2071 * Doulos SIL Regular is buggy and has zero offsets here.
2072 * Skip it
2073 */
2074 ban[n].PosFormat = 0;
2075 continue;
2076 }
2077
2078 cur_offset = FILE_Pos();
2079 if ( FILE_Seek( new_offset ) ||
2080 ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
2081 goto Fail;
2082 (void)FILE_Seek( cur_offset );
2083 }
2084 }
2085
2086 return HB_Err_Ok;
2087
2088 Fail:
2089 FREE( bans );
2090 FREE( br );
2091 return error;
2092 }
2093
2094
Free_BaseArray(HB_BaseArray * ba,HB_UShort num_classes)2095 static void Free_BaseArray( HB_BaseArray* ba,
2096 HB_UShort num_classes )
2097 {
2098 HB_BaseRecord *br;
2099 HB_Anchor *bans;
2100
2101 if ( ba->BaseRecord )
2102 {
2103 br = ba->BaseRecord;
2104
2105 if ( ba->BaseCount )
2106 {
2107 HB_UShort i, count;
2108 count = num_classes * ba->BaseCount;
2109 bans = br[0].BaseAnchor;
2110 for (i = 0; i < count; i++)
2111 Free_Anchor (&bans[i]);
2112 FREE( bans );
2113 }
2114
2115 FREE( br );
2116 }
2117 }
2118
2119
2120 /* MarkBasePosFormat1 */
2121
Load_MarkBasePos(HB_GPOS_SubTable * st,HB_Stream stream)2122 static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
2123 HB_Stream stream )
2124 {
2125 HB_Error error;
2126 HB_MarkBasePos* mbp = &st->markbase;
2127
2128 HB_UInt cur_offset, new_offset, base_offset;
2129
2130
2131 base_offset = FILE_Pos();
2132
2133 if ( ACCESS_Frame( 4L ) )
2134 return error;
2135
2136 mbp->PosFormat = GET_UShort();
2137 new_offset = GET_UShort() + base_offset;
2138
2139 FORGET_Frame();
2140
2141 if (mbp->PosFormat != 1)
2142 return ERR(HB_Err_Invalid_SubTable_Format);
2143
2144 cur_offset = FILE_Pos();
2145 if ( FILE_Seek( new_offset ) ||
2146 ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
2147 return error;
2148 (void)FILE_Seek( cur_offset );
2149
2150 if ( ACCESS_Frame( 2L ) )
2151 goto Fail3;
2152
2153 new_offset = GET_UShort() + base_offset;
2154
2155 FORGET_Frame();
2156
2157 cur_offset = FILE_Pos();
2158 if ( FILE_Seek( new_offset ) ||
2159 ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
2160 goto Fail3;
2161 (void)FILE_Seek( cur_offset );
2162
2163 if ( ACCESS_Frame( 4L ) )
2164 goto Fail2;
2165
2166 mbp->ClassCount = GET_UShort();
2167 new_offset = GET_UShort() + base_offset;
2168
2169 FORGET_Frame();
2170
2171 cur_offset = FILE_Pos();
2172 if ( FILE_Seek( new_offset ) ||
2173 ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
2174 goto Fail2;
2175 (void)FILE_Seek( cur_offset );
2176
2177 if ( ACCESS_Frame( 2L ) )
2178 goto Fail1;
2179
2180 new_offset = GET_UShort() + base_offset;
2181
2182 FORGET_Frame();
2183
2184 cur_offset = FILE_Pos();
2185 if ( FILE_Seek( new_offset ) ||
2186 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
2187 stream ) ) != HB_Err_Ok )
2188 goto Fail1;
2189
2190 return HB_Err_Ok;
2191
2192 Fail1:
2193 Free_MarkArray( &mbp->MarkArray );
2194
2195 Fail2:
2196 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2197
2198 Fail3:
2199 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2200 return error;
2201 }
2202
2203
Free_MarkBasePos(HB_GPOS_SubTable * st)2204 static void Free_MarkBasePos( HB_GPOS_SubTable* st )
2205 {
2206 HB_MarkBasePos* mbp = &st->markbase;
2207
2208 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
2209 Free_MarkArray( &mbp->MarkArray );
2210 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
2211 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
2212 }
2213
2214
Lookup_MarkBasePos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2215 static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
2216 HB_GPOS_SubTable* st,
2217 HB_Buffer buffer,
2218 HB_UShort flags,
2219 HB_UShort context_length,
2220 int nesting_level )
2221 {
2222 HB_UShort i, j, mark_index, base_index, property, class;
2223 HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value;
2224 HB_Error error;
2225 HB_GPOSHeader* gpos = gpi->gpos;
2226 HB_MarkBasePos* mbp = &st->markbase;
2227
2228 HB_MarkArray* ma;
2229 HB_BaseArray* ba;
2230 HB_BaseRecord* br;
2231 HB_Anchor* mark_anchor;
2232 HB_Anchor* base_anchor;
2233
2234 HB_Position o;
2235
2236 HB_UNUSED(nesting_level);
2237
2238 if ( context_length != 0xFFFF && context_length < 1 )
2239 return HB_Err_Not_Covered;
2240
2241 if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
2242 return HB_Err_Not_Covered;
2243
2244 if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2245 flags, &property ) )
2246 return error;
2247
2248 error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
2249 &mark_index );
2250 if ( error )
2251 return error;
2252
2253 /* now we search backwards for a non-mark glyph */
2254
2255 i = 1;
2256 j = buffer->in_pos - 1;
2257
2258 while ( i <= buffer->in_pos )
2259 {
2260 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2261 &property );
2262 if ( error )
2263 return error;
2264
2265 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2266 break;
2267
2268 i++;
2269 j--;
2270 }
2271
2272 /* The following assertion is too strong -- at least for mangal.ttf. */
2273 #if 0
2274 if ( property != HB_GDEF_BASE_GLYPH )
2275 return HB_Err_Not_Covered;
2276 #endif
2277
2278 if ( i > buffer->in_pos )
2279 return HB_Err_Not_Covered;
2280
2281 error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
2282 &base_index );
2283 if ( error )
2284 return error;
2285
2286 ma = &mbp->MarkArray;
2287
2288 if ( mark_index >= ma->MarkCount )
2289 return ERR(HB_Err_Invalid_SubTable);
2290
2291 class = ma->MarkRecord[mark_index].Class;
2292 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2293
2294 if ( class >= mbp->ClassCount )
2295 return ERR(HB_Err_Invalid_SubTable);
2296
2297 ba = &mbp->BaseArray;
2298
2299 if ( base_index >= ba->BaseCount )
2300 return ERR(HB_Err_Invalid_SubTable);
2301
2302 br = &ba->BaseRecord[base_index];
2303 base_anchor = &br->BaseAnchor[class];
2304
2305 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2306 &x_mark_value, &y_mark_value );
2307 if ( error )
2308 return error;
2309
2310 error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
2311 &x_base_value, &y_base_value );
2312 if ( error )
2313 return error;
2314
2315 /* anchor points are not cumulative */
2316
2317 o = POSITION( buffer->in_pos );
2318
2319 o->x_pos = x_base_value - x_mark_value;
2320 o->y_pos = y_base_value - y_mark_value;
2321 o->x_advance = 0;
2322 o->y_advance = 0;
2323 o->back = i;
2324
2325 (buffer->in_pos)++;
2326
2327 return HB_Err_Ok;
2328 }
2329
2330
2331 /* LookupType 5 */
2332
2333 /* LigatureAttach */
2334
Load_LigatureAttach(HB_LigatureAttach * lat,HB_UShort num_classes,HB_Stream stream)2335 static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
2336 HB_UShort num_classes,
2337 HB_Stream stream )
2338 {
2339 HB_Error error;
2340
2341 HB_UShort m, n, k, count;
2342 HB_UInt cur_offset, new_offset, base_offset;
2343
2344 HB_ComponentRecord* cr;
2345 HB_Anchor* lan;
2346
2347
2348 base_offset = FILE_Pos();
2349
2350 if ( ACCESS_Frame( 2L ) )
2351 return error;
2352
2353 count = lat->ComponentCount = GET_UShort();
2354
2355 FORGET_Frame();
2356
2357 lat->ComponentRecord = NULL;
2358
2359 if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
2360 return error;
2361
2362 cr = lat->ComponentRecord;
2363
2364 for ( m = 0; m < count; m++ )
2365 {
2366 cr[m].LigatureAnchor = NULL;
2367
2368 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
2369 goto Fail;
2370
2371 lan = cr[m].LigatureAnchor;
2372
2373 for ( n = 0; n < num_classes; n++ )
2374 {
2375 if ( ACCESS_Frame( 2L ) )
2376 goto Fail0;
2377
2378 new_offset = GET_UShort();
2379
2380 FORGET_Frame();
2381
2382 if ( new_offset )
2383 {
2384 new_offset += base_offset;
2385
2386 cur_offset = FILE_Pos();
2387 if ( FILE_Seek( new_offset ) ||
2388 ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
2389 goto Fail0;
2390 (void)FILE_Seek( cur_offset );
2391 }
2392 else
2393 lan[n].PosFormat = 0;
2394 }
2395
2396 continue;
2397 Fail0:
2398 for ( k = 0; k < n; k++ )
2399 Free_Anchor( &lan[k] );
2400 goto Fail;
2401 }
2402
2403 return HB_Err_Ok;
2404
2405 Fail:
2406 for ( k = 0; k < m; k++ )
2407 {
2408 lan = cr[k].LigatureAnchor;
2409
2410 for ( n = 0; n < num_classes; n++ )
2411 Free_Anchor( &lan[n] );
2412
2413 FREE( lan );
2414 }
2415
2416 FREE( cr );
2417 return error;
2418 }
2419
2420
Free_LigatureAttach(HB_LigatureAttach * lat,HB_UShort num_classes)2421 static void Free_LigatureAttach( HB_LigatureAttach* lat,
2422 HB_UShort num_classes )
2423 {
2424 HB_UShort m, n, count;
2425
2426 HB_ComponentRecord* cr;
2427 HB_Anchor* lan;
2428
2429
2430 if ( lat->ComponentRecord )
2431 {
2432 count = lat->ComponentCount;
2433 cr = lat->ComponentRecord;
2434
2435 for ( m = 0; m < count; m++ )
2436 {
2437 lan = cr[m].LigatureAnchor;
2438
2439 for ( n = 0; n < num_classes; n++ )
2440 Free_Anchor( &lan[n] );
2441
2442 FREE( lan );
2443 }
2444
2445 FREE( cr );
2446 }
2447 }
2448
2449
2450 /* LigatureArray */
2451
Load_LigatureArray(HB_LigatureArray * la,HB_UShort num_classes,HB_Stream stream)2452 static HB_Error Load_LigatureArray( HB_LigatureArray* la,
2453 HB_UShort num_classes,
2454 HB_Stream stream )
2455 {
2456 HB_Error error;
2457
2458 HB_UShort n, m, count;
2459 HB_UInt cur_offset, new_offset, base_offset;
2460
2461 HB_LigatureAttach* lat;
2462
2463
2464 base_offset = FILE_Pos();
2465
2466 if ( ACCESS_Frame( 2L ) )
2467 return error;
2468
2469 count = la->LigatureCount = GET_UShort();
2470
2471 FORGET_Frame();
2472
2473 la->LigatureAttach = NULL;
2474
2475 if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
2476 return error;
2477
2478 lat = la->LigatureAttach;
2479
2480 for ( n = 0; n < count; n++ )
2481 {
2482 if ( ACCESS_Frame( 2L ) )
2483 goto Fail;
2484
2485 new_offset = GET_UShort() + base_offset;
2486
2487 FORGET_Frame();
2488
2489 cur_offset = FILE_Pos();
2490 if ( FILE_Seek( new_offset ) ||
2491 ( error = Load_LigatureAttach( &lat[n], num_classes,
2492 stream ) ) != HB_Err_Ok )
2493 goto Fail;
2494 (void)FILE_Seek( cur_offset );
2495 }
2496
2497 return HB_Err_Ok;
2498
2499 Fail:
2500 for ( m = 0; m < n; m++ )
2501 Free_LigatureAttach( &lat[m], num_classes );
2502
2503 FREE( lat );
2504 return error;
2505 }
2506
2507
Free_LigatureArray(HB_LigatureArray * la,HB_UShort num_classes)2508 static void Free_LigatureArray( HB_LigatureArray* la,
2509 HB_UShort num_classes )
2510 {
2511 HB_UShort n, count;
2512
2513 HB_LigatureAttach* lat;
2514
2515
2516 if ( la->LigatureAttach )
2517 {
2518 count = la->LigatureCount;
2519 lat = la->LigatureAttach;
2520
2521 for ( n = 0; n < count; n++ )
2522 Free_LigatureAttach( &lat[n], num_classes );
2523
2524 FREE( lat );
2525 }
2526 }
2527
2528
2529 /* MarkLigPosFormat1 */
2530
Load_MarkLigPos(HB_GPOS_SubTable * st,HB_Stream stream)2531 static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
2532 HB_Stream stream )
2533 {
2534 HB_Error error;
2535 HB_MarkLigPos* mlp = &st->marklig;
2536
2537 HB_UInt cur_offset, new_offset, base_offset;
2538
2539
2540 base_offset = FILE_Pos();
2541
2542 if ( ACCESS_Frame( 4L ) )
2543 return error;
2544
2545 mlp->PosFormat = GET_UShort();
2546 new_offset = GET_UShort() + base_offset;
2547
2548 FORGET_Frame();
2549
2550 cur_offset = FILE_Pos();
2551 if ( FILE_Seek( new_offset ) ||
2552 ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
2553 return error;
2554 (void)FILE_Seek( cur_offset );
2555
2556 if ( ACCESS_Frame( 2L ) )
2557 goto Fail3;
2558
2559 new_offset = GET_UShort() + base_offset;
2560
2561 FORGET_Frame();
2562
2563 cur_offset = FILE_Pos();
2564 if ( FILE_Seek( new_offset ) ||
2565 ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
2566 stream ) ) != HB_Err_Ok )
2567 goto Fail3;
2568 (void)FILE_Seek( cur_offset );
2569
2570 if ( ACCESS_Frame( 4L ) )
2571 goto Fail2;
2572
2573 mlp->ClassCount = GET_UShort();
2574 new_offset = GET_UShort() + base_offset;
2575
2576 FORGET_Frame();
2577
2578 cur_offset = FILE_Pos();
2579 if ( FILE_Seek( new_offset ) ||
2580 ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
2581 goto Fail2;
2582 (void)FILE_Seek( cur_offset );
2583
2584 if ( ACCESS_Frame( 2L ) )
2585 goto Fail1;
2586
2587 new_offset = GET_UShort() + base_offset;
2588
2589 FORGET_Frame();
2590
2591 cur_offset = FILE_Pos();
2592 if ( FILE_Seek( new_offset ) ||
2593 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
2594 stream ) ) != HB_Err_Ok )
2595 goto Fail1;
2596
2597 return HB_Err_Ok;
2598
2599 Fail1:
2600 Free_MarkArray( &mlp->MarkArray );
2601
2602 Fail2:
2603 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2604
2605 Fail3:
2606 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2607 return error;
2608 }
2609
2610
Free_MarkLigPos(HB_GPOS_SubTable * st)2611 static void Free_MarkLigPos( HB_GPOS_SubTable* st)
2612 {
2613 HB_MarkLigPos* mlp = &st->marklig;
2614
2615 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
2616 Free_MarkArray( &mlp->MarkArray );
2617 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
2618 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
2619 }
2620
2621
Lookup_MarkLigPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2622 static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
2623 HB_GPOS_SubTable* st,
2624 HB_Buffer buffer,
2625 HB_UShort flags,
2626 HB_UShort context_length,
2627 int nesting_level )
2628 {
2629 HB_UShort i, j, mark_index, lig_index, property, class;
2630 HB_UShort mark_glyph;
2631 HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value;
2632 HB_Error error;
2633 HB_GPOSHeader* gpos = gpi->gpos;
2634 HB_MarkLigPos* mlp = &st->marklig;
2635
2636 HB_MarkArray* ma;
2637 HB_LigatureArray* la;
2638 HB_LigatureAttach* lat;
2639 HB_ComponentRecord* cr;
2640 HB_UShort comp_index;
2641 HB_Anchor* mark_anchor;
2642 HB_Anchor* lig_anchor;
2643
2644 HB_Position o;
2645
2646 HB_UNUSED(nesting_level);
2647
2648 if ( context_length != 0xFFFF && context_length < 1 )
2649 return HB_Err_Not_Covered;
2650
2651 if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
2652 return HB_Err_Not_Covered;
2653
2654 mark_glyph = IN_CURGLYPH();
2655
2656 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
2657 return error;
2658
2659 error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
2660 if ( error )
2661 return error;
2662
2663 /* now we search backwards for a non-mark glyph */
2664
2665 i = 1;
2666 j = buffer->in_pos - 1;
2667
2668 while ( i <= buffer->in_pos )
2669 {
2670 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2671 &property );
2672 if ( error )
2673 return error;
2674
2675 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
2676 break;
2677
2678 i++;
2679 j--;
2680 }
2681
2682 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
2683 too strong, thus it is commented out. */
2684 #if 0
2685 if ( property != HB_GDEF_LIGATURE )
2686 return HB_Err_Not_Covered;
2687 #endif
2688
2689 if ( i > buffer->in_pos )
2690 return HB_Err_Not_Covered;
2691
2692 error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
2693 &lig_index );
2694 if ( error )
2695 return error;
2696
2697 ma = &mlp->MarkArray;
2698
2699 if ( mark_index >= ma->MarkCount )
2700 return ERR(HB_Err_Invalid_SubTable);
2701
2702 class = ma->MarkRecord[mark_index].Class;
2703 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
2704
2705 if ( class >= mlp->ClassCount )
2706 return ERR(HB_Err_Invalid_SubTable);
2707
2708 la = &mlp->LigatureArray;
2709
2710 if ( lig_index >= la->LigatureCount )
2711 return ERR(HB_Err_Invalid_SubTable);
2712
2713 lat = &la->LigatureAttach[lig_index];
2714
2715 /* We must now check whether the ligature ID of the current mark glyph
2716 is identical to the ligature ID of the found ligature. If yes, we
2717 can directly use the component index. If not, we attach the mark
2718 glyph to the last component of the ligature. */
2719
2720 if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
2721 {
2722 comp_index = IN_COMPONENT( buffer->in_pos );
2723 if ( comp_index >= lat->ComponentCount )
2724 return HB_Err_Not_Covered;
2725 }
2726 else
2727 comp_index = lat->ComponentCount - 1;
2728
2729 cr = &lat->ComponentRecord[comp_index];
2730 lig_anchor = &cr->LigatureAnchor[class];
2731
2732 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
2733 &x_mark_value, &y_mark_value );
2734 if ( error )
2735 return error;
2736 error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
2737 &x_lig_value, &y_lig_value );
2738 if ( error )
2739 return error;
2740
2741 /* anchor points are not cumulative */
2742
2743 o = POSITION( buffer->in_pos );
2744
2745 o->x_pos = x_lig_value - x_mark_value;
2746 o->y_pos = y_lig_value - y_mark_value;
2747 o->x_advance = 0;
2748 o->y_advance = 0;
2749 o->back = i;
2750
2751 (buffer->in_pos)++;
2752
2753 return HB_Err_Ok;
2754 }
2755
2756
2757 /* LookupType 6 */
2758
2759 /* Mark2Array */
2760
Load_Mark2Array(HB_Mark2Array * m2a,HB_UShort num_classes,HB_Stream stream)2761 static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
2762 HB_UShort num_classes,
2763 HB_Stream stream )
2764 {
2765 HB_Error error;
2766
2767 HB_UShort m, n, count;
2768 HB_UInt cur_offset, new_offset, base_offset;
2769
2770 HB_Mark2Record *m2r;
2771 HB_Anchor *m2an, *m2ans;
2772
2773
2774 base_offset = FILE_Pos();
2775
2776 if ( ACCESS_Frame( 2L ) )
2777 return error;
2778
2779 count = m2a->Mark2Count = GET_UShort();
2780
2781 FORGET_Frame();
2782
2783 m2a->Mark2Record = NULL;
2784
2785 if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
2786 return error;
2787
2788 m2r = m2a->Mark2Record;
2789
2790 m2ans = NULL;
2791
2792 if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
2793 goto Fail;
2794
2795 for ( m = 0; m < count; m++ )
2796 {
2797 m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
2798
2799 for ( n = 0; n < num_classes; n++ )
2800 {
2801 if ( ACCESS_Frame( 2L ) )
2802 goto Fail;
2803
2804 new_offset = GET_UShort() + base_offset;
2805
2806 FORGET_Frame();
2807
2808 if (new_offset == base_offset) {
2809 /* Anchor table not provided. Skip loading.
2810 * Some versions of FreeSans hit this. */
2811 m2an[n].PosFormat = 0;
2812 continue;
2813 }
2814
2815 cur_offset = FILE_Pos();
2816 if ( FILE_Seek( new_offset ) ||
2817 ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
2818 goto Fail;
2819 (void)FILE_Seek( cur_offset );
2820 }
2821 }
2822
2823 return HB_Err_Ok;
2824
2825 Fail:
2826 FREE( m2ans );
2827 FREE( m2r );
2828 return error;
2829 }
2830
2831
Free_Mark2Array(HB_Mark2Array * m2a,HB_UShort num_classes)2832 static void Free_Mark2Array( HB_Mark2Array* m2a,
2833 HB_UShort num_classes )
2834 {
2835 HB_Mark2Record *m2r;
2836 HB_Anchor *m2ans;
2837
2838 HB_UNUSED(num_classes);
2839
2840 if ( m2a->Mark2Record )
2841 {
2842 m2r = m2a->Mark2Record;
2843
2844 if ( m2a->Mark2Count )
2845 {
2846 m2ans = m2r[0].Mark2Anchor;
2847 FREE( m2ans );
2848 }
2849
2850 FREE( m2r );
2851 }
2852 }
2853
2854
2855 /* MarkMarkPosFormat1 */
2856
Load_MarkMarkPos(HB_GPOS_SubTable * st,HB_Stream stream)2857 static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
2858 HB_Stream stream )
2859 {
2860 HB_Error error;
2861 HB_MarkMarkPos* mmp = &st->markmark;
2862
2863 HB_UInt cur_offset, new_offset, base_offset;
2864
2865
2866 base_offset = FILE_Pos();
2867
2868 if ( ACCESS_Frame( 4L ) )
2869 return error;
2870
2871 mmp->PosFormat = GET_UShort();
2872 new_offset = GET_UShort() + base_offset;
2873
2874 FORGET_Frame();
2875
2876 cur_offset = FILE_Pos();
2877 if ( FILE_Seek( new_offset ) ||
2878 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
2879 stream ) ) != HB_Err_Ok )
2880 return error;
2881 (void)FILE_Seek( cur_offset );
2882
2883 if ( ACCESS_Frame( 2L ) )
2884 goto Fail3;
2885
2886 new_offset = GET_UShort() + base_offset;
2887
2888 FORGET_Frame();
2889
2890 cur_offset = FILE_Pos();
2891 if ( FILE_Seek( new_offset ) ||
2892 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
2893 stream ) ) != HB_Err_Ok )
2894 goto Fail3;
2895 (void)FILE_Seek( cur_offset );
2896
2897 if ( ACCESS_Frame( 4L ) )
2898 goto Fail2;
2899
2900 mmp->ClassCount = GET_UShort();
2901 new_offset = GET_UShort() + base_offset;
2902
2903 FORGET_Frame();
2904
2905 cur_offset = FILE_Pos();
2906 if ( FILE_Seek( new_offset ) ||
2907 ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
2908 goto Fail2;
2909 (void)FILE_Seek( cur_offset );
2910
2911 if ( ACCESS_Frame( 2L ) )
2912 goto Fail1;
2913
2914 new_offset = GET_UShort() + base_offset;
2915
2916 FORGET_Frame();
2917
2918 cur_offset = FILE_Pos();
2919 if ( FILE_Seek( new_offset ) ||
2920 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2921 stream ) ) != HB_Err_Ok )
2922 goto Fail1;
2923
2924 return HB_Err_Ok;
2925
2926 Fail1:
2927 Free_MarkArray( &mmp->Mark1Array );
2928
2929 Fail2:
2930 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2931
2932 Fail3:
2933 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2934 return error;
2935 }
2936
2937
Free_MarkMarkPos(HB_GPOS_SubTable * st)2938 static void Free_MarkMarkPos( HB_GPOS_SubTable* st)
2939 {
2940 HB_MarkMarkPos* mmp = &st->markmark;
2941
2942 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2943 Free_MarkArray( &mmp->Mark1Array );
2944 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
2945 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
2946 }
2947
2948
Lookup_MarkMarkPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2949 static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
2950 HB_GPOS_SubTable* st,
2951 HB_Buffer buffer,
2952 HB_UShort flags,
2953 HB_UShort context_length,
2954 int nesting_level )
2955 {
2956 HB_UShort i, j, mark1_index, mark2_index, property, class;
2957 HB_Fixed x_mark1_value, y_mark1_value,
2958 x_mark2_value, y_mark2_value;
2959 HB_Error error;
2960 HB_GPOSHeader* gpos = gpi->gpos;
2961 HB_MarkMarkPos* mmp = &st->markmark;
2962
2963 HB_MarkArray* ma1;
2964 HB_Mark2Array* ma2;
2965 HB_Mark2Record* m2r;
2966 HB_Anchor* mark1_anchor;
2967 HB_Anchor* mark2_anchor;
2968
2969 HB_Position o;
2970
2971 HB_UNUSED(nesting_level);
2972
2973 if ( context_length != 0xFFFF && context_length < 1 )
2974 return HB_Err_Not_Covered;
2975
2976 if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
2977 return HB_Err_Not_Covered;
2978
2979 if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
2980 flags, &property ) )
2981 return error;
2982
2983 error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
2984 &mark1_index );
2985 if ( error )
2986 return error;
2987
2988 /* now we search backwards for a suitable mark glyph until a non-mark
2989 glyph */
2990
2991 if ( buffer->in_pos == 0 )
2992 return HB_Err_Not_Covered;
2993
2994 i = 1;
2995 j = buffer->in_pos - 1;
2996 while ( i <= buffer->in_pos )
2997 {
2998 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
2999 &property );
3000 if ( error )
3001 return error;
3002
3003 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
3004 return HB_Err_Not_Covered;
3005
3006 if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
3007 {
3008 if ( property == (flags & 0xFF00) )
3009 break;
3010 }
3011 else
3012 break;
3013
3014 i++;
3015 j--;
3016 }
3017
3018 if ( i > buffer->in_pos )
3019 return HB_Err_Not_Covered;
3020
3021 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
3022 &mark2_index );
3023 if ( error )
3024 return error;
3025
3026 ma1 = &mmp->Mark1Array;
3027
3028 if ( mark1_index >= ma1->MarkCount )
3029 return ERR(HB_Err_Invalid_SubTable);
3030
3031 class = ma1->MarkRecord[mark1_index].Class;
3032 mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
3033
3034 if ( class >= mmp->ClassCount )
3035 return ERR(HB_Err_Invalid_SubTable);
3036
3037 ma2 = &mmp->Mark2Array;
3038
3039 if ( mark2_index >= ma2->Mark2Count )
3040 return ERR(HB_Err_Invalid_SubTable);
3041
3042 m2r = &ma2->Mark2Record[mark2_index];
3043 mark2_anchor = &m2r->Mark2Anchor[class];
3044
3045 error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
3046 &x_mark1_value, &y_mark1_value );
3047 if ( error )
3048 return error;
3049 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
3050 &x_mark2_value, &y_mark2_value );
3051 if ( error )
3052 return error;
3053
3054 /* anchor points are not cumulative */
3055
3056 o = POSITION( buffer->in_pos );
3057
3058 o->x_pos = x_mark2_value - x_mark1_value;
3059 o->y_pos = y_mark2_value - y_mark1_value;
3060 o->x_advance = 0;
3061 o->y_advance = 0;
3062 o->back = 1;
3063
3064 (buffer->in_pos)++;
3065
3066 return HB_Err_Ok;
3067 }
3068
3069
3070 /* Do the actual positioning for a context positioning (either format
3071 7 or 8). This is only called after we've determined that the stream
3072 matches the subrule. */
3073
Do_ContextPos(GPOS_Instance * gpi,HB_UShort GlyphCount,HB_UShort PosCount,HB_PosLookupRecord * pos,HB_Buffer buffer,int nesting_level)3074 static HB_Error Do_ContextPos( GPOS_Instance* gpi,
3075 HB_UShort GlyphCount,
3076 HB_UShort PosCount,
3077 HB_PosLookupRecord* pos,
3078 HB_Buffer buffer,
3079 int nesting_level )
3080 {
3081 HB_Error error;
3082 HB_UInt i, old_pos;
3083
3084
3085 i = 0;
3086
3087 while ( i < GlyphCount )
3088 {
3089 if ( PosCount && i == pos->SequenceIndex )
3090 {
3091 old_pos = buffer->in_pos;
3092
3093 /* Do a positioning */
3094
3095 error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
3096 GlyphCount, nesting_level );
3097
3098 if ( error )
3099 return error;
3100
3101 pos++;
3102 PosCount--;
3103 i += buffer->in_pos - old_pos;
3104 }
3105 else
3106 {
3107 i++;
3108 (buffer->in_pos)++;
3109 }
3110 }
3111
3112 return HB_Err_Ok;
3113 }
3114
3115
3116 /* LookupType 7 */
3117
3118 /* PosRule */
3119
Load_PosRule(HB_PosRule * pr,HB_Stream stream)3120 static HB_Error Load_PosRule( HB_PosRule* pr,
3121 HB_Stream stream )
3122 {
3123 HB_Error error;
3124
3125 HB_UShort n, count;
3126 HB_UShort* i;
3127
3128 HB_PosLookupRecord* plr;
3129
3130
3131 if ( ACCESS_Frame( 4L ) )
3132 return error;
3133
3134 pr->GlyphCount = GET_UShort();
3135 pr->PosCount = GET_UShort();
3136
3137 FORGET_Frame();
3138
3139 pr->Input = NULL;
3140
3141 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3142
3143 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
3144 return error;
3145
3146 i = pr->Input;
3147
3148 if ( ACCESS_Frame( count * 2L ) )
3149 goto Fail2;
3150
3151 for ( n = 0; n < count; n++ )
3152 i[n] = GET_UShort();
3153
3154 FORGET_Frame();
3155
3156 pr->PosLookupRecord = NULL;
3157
3158 count = pr->PosCount;
3159
3160 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
3161 goto Fail2;
3162
3163 plr = pr->PosLookupRecord;
3164
3165 if ( ACCESS_Frame( count * 4L ) )
3166 goto Fail1;
3167
3168 for ( n = 0; n < count; n++ )
3169 {
3170 plr[n].SequenceIndex = GET_UShort();
3171 plr[n].LookupListIndex = GET_UShort();
3172 }
3173
3174 FORGET_Frame();
3175
3176 return HB_Err_Ok;
3177
3178 Fail1:
3179 FREE( plr );
3180
3181 Fail2:
3182 FREE( i );
3183 return error;
3184 }
3185
3186
Free_PosRule(HB_PosRule * pr)3187 static void Free_PosRule( HB_PosRule* pr )
3188 {
3189 FREE( pr->PosLookupRecord );
3190 FREE( pr->Input );
3191 }
3192
3193
3194 /* PosRuleSet */
3195
Load_PosRuleSet(HB_PosRuleSet * prs,HB_Stream stream)3196 static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
3197 HB_Stream stream )
3198 {
3199 HB_Error error;
3200
3201 HB_UShort n, m, count;
3202 HB_UInt cur_offset, new_offset, base_offset;
3203
3204 HB_PosRule* pr;
3205
3206
3207 base_offset = FILE_Pos();
3208
3209 if ( ACCESS_Frame( 2L ) )
3210 return error;
3211
3212 count = prs->PosRuleCount = GET_UShort();
3213
3214 FORGET_Frame();
3215
3216 prs->PosRule = NULL;
3217
3218 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
3219 return error;
3220
3221 pr = prs->PosRule;
3222
3223 for ( n = 0; n < count; n++ )
3224 {
3225 if ( ACCESS_Frame( 2L ) )
3226 goto Fail;
3227
3228 new_offset = GET_UShort() + base_offset;
3229
3230 FORGET_Frame();
3231
3232 cur_offset = FILE_Pos();
3233 if ( FILE_Seek( new_offset ) ||
3234 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
3235 goto Fail;
3236 (void)FILE_Seek( cur_offset );
3237 }
3238
3239 return HB_Err_Ok;
3240
3241 Fail:
3242 for ( m = 0; m < n; m++ )
3243 Free_PosRule( &pr[m] );
3244
3245 FREE( pr );
3246 return error;
3247 }
3248
3249
Free_PosRuleSet(HB_PosRuleSet * prs)3250 static void Free_PosRuleSet( HB_PosRuleSet* prs )
3251 {
3252 HB_UShort n, count;
3253
3254 HB_PosRule* pr;
3255
3256
3257 if ( prs->PosRule )
3258 {
3259 count = prs->PosRuleCount;
3260 pr = prs->PosRule;
3261
3262 for ( n = 0; n < count; n++ )
3263 Free_PosRule( &pr[n] );
3264
3265 FREE( pr );
3266 }
3267 }
3268
3269
3270 /* ContextPosFormat1 */
3271
Load_ContextPos1(HB_ContextPosFormat1 * cpf1,HB_Stream stream)3272 static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
3273 HB_Stream stream )
3274 {
3275 HB_Error error;
3276
3277 HB_UShort n, m, count;
3278 HB_UInt cur_offset, new_offset, base_offset;
3279
3280 HB_PosRuleSet* prs;
3281
3282
3283 base_offset = FILE_Pos() - 2L;
3284
3285 if ( ACCESS_Frame( 2L ) )
3286 return error;
3287
3288 new_offset = GET_UShort() + base_offset;
3289
3290 FORGET_Frame();
3291
3292 cur_offset = FILE_Pos();
3293 if ( FILE_Seek( new_offset ) ||
3294 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
3295 return error;
3296 (void)FILE_Seek( cur_offset );
3297
3298 if ( ACCESS_Frame( 2L ) )
3299 goto Fail2;
3300
3301 count = cpf1->PosRuleSetCount = GET_UShort();
3302
3303 FORGET_Frame();
3304
3305 cpf1->PosRuleSet = NULL;
3306
3307 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
3308 goto Fail2;
3309
3310 prs = cpf1->PosRuleSet;
3311
3312 for ( n = 0; n < count; n++ )
3313 {
3314 if ( ACCESS_Frame( 2L ) )
3315 goto Fail1;
3316
3317 new_offset = GET_UShort() + base_offset;
3318
3319 FORGET_Frame();
3320
3321 cur_offset = FILE_Pos();
3322 if ( FILE_Seek( new_offset ) ||
3323 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
3324 goto Fail1;
3325 (void)FILE_Seek( cur_offset );
3326 }
3327
3328 return HB_Err_Ok;
3329
3330 Fail1:
3331 for ( m = 0; m < n; m++ )
3332 Free_PosRuleSet( &prs[m] );
3333
3334 FREE( prs );
3335
3336 Fail2:
3337 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3338 return error;
3339 }
3340
3341
Free_ContextPos1(HB_ContextPosFormat1 * cpf1)3342 static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
3343 {
3344 HB_UShort n, count;
3345
3346 HB_PosRuleSet* prs;
3347
3348
3349 if ( cpf1->PosRuleSet )
3350 {
3351 count = cpf1->PosRuleSetCount;
3352 prs = cpf1->PosRuleSet;
3353
3354 for ( n = 0; n < count; n++ )
3355 Free_PosRuleSet( &prs[n] );
3356
3357 FREE( prs );
3358 }
3359
3360 _HB_OPEN_Free_Coverage( &cpf1->Coverage );
3361 }
3362
3363
3364 /* PosClassRule */
3365
Load_PosClassRule(HB_ContextPosFormat2 * cpf2,HB_PosClassRule * pcr,HB_Stream stream)3366 static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
3367 HB_PosClassRule* pcr,
3368 HB_Stream stream )
3369 {
3370 HB_Error error;
3371
3372 HB_UShort n, count;
3373
3374 HB_UShort* c;
3375 HB_PosLookupRecord* plr;
3376
3377
3378 if ( ACCESS_Frame( 4L ) )
3379 return error;
3380
3381 pcr->GlyphCount = GET_UShort();
3382 pcr->PosCount = GET_UShort();
3383
3384 FORGET_Frame();
3385
3386 if ( pcr->GlyphCount > cpf2->MaxContextLength )
3387 cpf2->MaxContextLength = pcr->GlyphCount;
3388
3389 pcr->Class = NULL;
3390
3391 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
3392
3393 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
3394 return error;
3395
3396 c = pcr->Class;
3397
3398 if ( ACCESS_Frame( count * 2L ) )
3399 goto Fail2;
3400
3401 for ( n = 0; n < count; n++ )
3402 c[n] = GET_UShort();
3403
3404 FORGET_Frame();
3405
3406 pcr->PosLookupRecord = NULL;
3407
3408 count = pcr->PosCount;
3409
3410 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
3411 goto Fail2;
3412
3413 plr = pcr->PosLookupRecord;
3414
3415 if ( ACCESS_Frame( count * 4L ) )
3416 goto Fail1;
3417
3418 for ( n = 0; n < count; n++ )
3419 {
3420 plr[n].SequenceIndex = GET_UShort();
3421 plr[n].LookupListIndex = GET_UShort();
3422 }
3423
3424 FORGET_Frame();
3425
3426 return HB_Err_Ok;
3427
3428 Fail1:
3429 FREE( plr );
3430
3431 Fail2:
3432 FREE( c );
3433 return error;
3434 }
3435
3436
Free_PosClassRule(HB_PosClassRule * pcr)3437 static void Free_PosClassRule( HB_PosClassRule* pcr )
3438 {
3439 FREE( pcr->PosLookupRecord );
3440 FREE( pcr->Class );
3441 }
3442
3443
3444 /* PosClassSet */
3445
Load_PosClassSet(HB_ContextPosFormat2 * cpf2,HB_PosClassSet * pcs,HB_Stream stream)3446 static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
3447 HB_PosClassSet* pcs,
3448 HB_Stream stream )
3449 {
3450 HB_Error error;
3451
3452 HB_UShort n, m, count;
3453 HB_UInt cur_offset, new_offset, base_offset;
3454
3455 HB_PosClassRule* pcr;
3456
3457
3458 base_offset = FILE_Pos();
3459
3460 if ( ACCESS_Frame( 2L ) )
3461 return error;
3462
3463 count = pcs->PosClassRuleCount = GET_UShort();
3464
3465 FORGET_Frame();
3466
3467 pcs->PosClassRule = NULL;
3468
3469 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
3470 return error;
3471
3472 pcr = pcs->PosClassRule;
3473
3474 for ( n = 0; n < count; n++ )
3475 {
3476 if ( ACCESS_Frame( 2L ) )
3477 goto Fail;
3478
3479 new_offset = GET_UShort() + base_offset;
3480
3481 FORGET_Frame();
3482
3483 cur_offset = FILE_Pos();
3484 if ( FILE_Seek( new_offset ) ||
3485 ( error = Load_PosClassRule( cpf2, &pcr[n],
3486 stream ) ) != HB_Err_Ok )
3487 goto Fail;
3488 (void)FILE_Seek( cur_offset );
3489 }
3490
3491 return HB_Err_Ok;
3492
3493 Fail:
3494 for ( m = 0; m < n; m++ )
3495 Free_PosClassRule( &pcr[m] );
3496
3497 FREE( pcr );
3498 return error;
3499 }
3500
3501
Free_PosClassSet(HB_PosClassSet * pcs)3502 static void Free_PosClassSet( HB_PosClassSet* pcs )
3503 {
3504 HB_UShort n, count;
3505
3506 HB_PosClassRule* pcr;
3507
3508
3509 if ( pcs->PosClassRule )
3510 {
3511 count = pcs->PosClassRuleCount;
3512 pcr = pcs->PosClassRule;
3513
3514 for ( n = 0; n < count; n++ )
3515 Free_PosClassRule( &pcr[n] );
3516
3517 FREE( pcr );
3518 }
3519 }
3520
3521
3522 /* ContextPosFormat2 */
3523
Load_ContextPos2(HB_ContextPosFormat2 * cpf2,HB_Stream stream)3524 static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
3525 HB_Stream stream )
3526 {
3527 HB_Error error;
3528
3529 HB_UShort n, m, count;
3530 HB_UInt cur_offset, new_offset, base_offset;
3531
3532 HB_PosClassSet* pcs;
3533
3534
3535 base_offset = FILE_Pos() - 2;
3536
3537 if ( ACCESS_Frame( 2L ) )
3538 return error;
3539
3540 new_offset = GET_UShort() + base_offset;
3541
3542 FORGET_Frame();
3543
3544 cur_offset = FILE_Pos();
3545 if ( FILE_Seek( new_offset ) ||
3546 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
3547 return error;
3548 (void)FILE_Seek( cur_offset );
3549
3550 if ( ACCESS_Frame( 4L ) )
3551 goto Fail3;
3552
3553 new_offset = GET_UShort() + base_offset;
3554
3555 /* `PosClassSetCount' is the upper limit for class values, thus we
3556 read it now to make an additional safety check. */
3557
3558 count = cpf2->PosClassSetCount = GET_UShort();
3559
3560 FORGET_Frame();
3561
3562 cur_offset = FILE_Pos();
3563 if ( FILE_Seek( new_offset ) ||
3564 ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
3565 stream ) ) != HB_Err_Ok )
3566 goto Fail3;
3567 (void)FILE_Seek( cur_offset );
3568
3569 cpf2->PosClassSet = NULL;
3570 cpf2->MaxContextLength = 0;
3571
3572 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
3573 goto Fail2;
3574
3575 pcs = cpf2->PosClassSet;
3576
3577 for ( n = 0; n < count; n++ )
3578 {
3579 if ( ACCESS_Frame( 2L ) )
3580 goto Fail1;
3581
3582 new_offset = GET_UShort() + base_offset;
3583
3584 FORGET_Frame();
3585
3586 if ( new_offset != base_offset ) /* not a NULL offset */
3587 {
3588 cur_offset = FILE_Pos();
3589 if ( FILE_Seek( new_offset ) ||
3590 ( error = Load_PosClassSet( cpf2, &pcs[n],
3591 stream ) ) != HB_Err_Ok )
3592 goto Fail1;
3593 (void)FILE_Seek( cur_offset );
3594 }
3595 else
3596 {
3597 /* we create a PosClassSet table with no entries */
3598
3599 cpf2->PosClassSet[n].PosClassRuleCount = 0;
3600 cpf2->PosClassSet[n].PosClassRule = NULL;
3601 }
3602 }
3603
3604 return HB_Err_Ok;
3605
3606 Fail1:
3607 for ( m = 0; m < n; n++ )
3608 Free_PosClassSet( &pcs[m] );
3609
3610 FREE( pcs );
3611
3612 Fail2:
3613 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3614
3615 Fail3:
3616 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3617 return error;
3618 }
3619
3620
Free_ContextPos2(HB_ContextPosFormat2 * cpf2)3621 static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
3622 {
3623 HB_UShort n, count;
3624
3625 HB_PosClassSet* pcs;
3626
3627
3628 if ( cpf2->PosClassSet )
3629 {
3630 count = cpf2->PosClassSetCount;
3631 pcs = cpf2->PosClassSet;
3632
3633 for ( n = 0; n < count; n++ )
3634 Free_PosClassSet( &pcs[n] );
3635
3636 FREE( pcs );
3637 }
3638
3639 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
3640 _HB_OPEN_Free_Coverage( &cpf2->Coverage );
3641 }
3642
3643
3644 /* ContextPosFormat3 */
3645
Load_ContextPos3(HB_ContextPosFormat3 * cpf3,HB_Stream stream)3646 static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
3647 HB_Stream stream )
3648 {
3649 HB_Error error;
3650
3651 HB_UShort n, count;
3652 HB_UInt cur_offset, new_offset, base_offset;
3653
3654 HB_Coverage* c;
3655 HB_PosLookupRecord* plr;
3656
3657
3658 base_offset = FILE_Pos() - 2L;
3659
3660 if ( ACCESS_Frame( 4L ) )
3661 return error;
3662
3663 cpf3->GlyphCount = GET_UShort();
3664 cpf3->PosCount = GET_UShort();
3665
3666 FORGET_Frame();
3667
3668 cpf3->Coverage = NULL;
3669
3670 count = cpf3->GlyphCount;
3671
3672 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
3673 return error;
3674
3675 c = cpf3->Coverage;
3676
3677 for ( n = 0; n < count; n++ )
3678 {
3679 if ( ACCESS_Frame( 2L ) )
3680 goto Fail2;
3681
3682 new_offset = GET_UShort() + base_offset;
3683
3684 FORGET_Frame();
3685
3686 cur_offset = FILE_Pos();
3687 if ( FILE_Seek( new_offset ) ||
3688 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
3689 goto Fail2;
3690 (void)FILE_Seek( cur_offset );
3691 }
3692
3693 cpf3->PosLookupRecord = NULL;
3694
3695 count = cpf3->PosCount;
3696
3697 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
3698 goto Fail2;
3699
3700 plr = cpf3->PosLookupRecord;
3701
3702 if ( ACCESS_Frame( count * 4L ) )
3703 goto Fail1;
3704
3705 for ( n = 0; n < count; n++ )
3706 {
3707 plr[n].SequenceIndex = GET_UShort();
3708 plr[n].LookupListIndex = GET_UShort();
3709 }
3710
3711 FORGET_Frame();
3712
3713 return HB_Err_Ok;
3714
3715 Fail1:
3716 FREE( plr );
3717
3718 Fail2:
3719 for ( n = 0; n < count; n++ )
3720 _HB_OPEN_Free_Coverage( &c[n] );
3721
3722 FREE( c );
3723 return error;
3724 }
3725
3726
Free_ContextPos3(HB_ContextPosFormat3 * cpf3)3727 static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
3728 {
3729 HB_UShort n, count;
3730
3731 HB_Coverage* c;
3732
3733
3734 FREE( cpf3->PosLookupRecord );
3735
3736 if ( cpf3->Coverage )
3737 {
3738 count = cpf3->GlyphCount;
3739 c = cpf3->Coverage;
3740
3741 for ( n = 0; n < count; n++ )
3742 _HB_OPEN_Free_Coverage( &c[n] );
3743
3744 FREE( c );
3745 }
3746 }
3747
3748
3749 /* ContextPos */
3750
Load_ContextPos(HB_GPOS_SubTable * st,HB_Stream stream)3751 static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
3752 HB_Stream stream )
3753 {
3754 HB_Error error;
3755 HB_ContextPos* cp = &st->context;
3756
3757
3758 if ( ACCESS_Frame( 2L ) )
3759 return error;
3760
3761 cp->PosFormat = GET_UShort();
3762
3763 FORGET_Frame();
3764
3765 switch ( cp->PosFormat )
3766 {
3767 case 1:
3768 return Load_ContextPos1( &cp->cpf.cpf1, stream );
3769
3770 case 2:
3771 return Load_ContextPos2( &cp->cpf.cpf2, stream );
3772
3773 case 3:
3774 return Load_ContextPos3( &cp->cpf.cpf3, stream );
3775
3776 default:
3777 return ERR(HB_Err_Invalid_SubTable_Format);
3778 }
3779
3780 return HB_Err_Ok; /* never reached */
3781 }
3782
3783
Free_ContextPos(HB_GPOS_SubTable * st)3784 static void Free_ContextPos( HB_GPOS_SubTable* st )
3785 {
3786 HB_ContextPos* cp = &st->context;
3787
3788 switch ( cp->PosFormat )
3789 {
3790 case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break;
3791 case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break;
3792 case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break;
3793 default: break;
3794 }
3795 }
3796
3797
Lookup_ContextPos1(GPOS_Instance * gpi,HB_ContextPosFormat1 * cpf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3798 static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
3799 HB_ContextPosFormat1* cpf1,
3800 HB_Buffer buffer,
3801 HB_UShort flags,
3802 HB_UShort context_length,
3803 int nesting_level )
3804 {
3805 HB_UShort index, property;
3806 HB_UShort i, j, k, numpr;
3807 HB_Error error;
3808 HB_GPOSHeader* gpos = gpi->gpos;
3809
3810 HB_PosRule* pr;
3811 HB_GDEFHeader* gdef;
3812
3813
3814 gdef = gpos->gdef;
3815
3816 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3817 return error;
3818
3819 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
3820 if ( error )
3821 return error;
3822
3823 pr = cpf1->PosRuleSet[index].PosRule;
3824 numpr = cpf1->PosRuleSet[index].PosRuleCount;
3825
3826 for ( k = 0; k < numpr; k++ )
3827 {
3828 if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
3829 goto next_posrule;
3830
3831 if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
3832 goto next_posrule; /* context is too long */
3833
3834 for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
3835 {
3836 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3837 {
3838 if ( error && error != HB_Err_Not_Covered )
3839 return error;
3840
3841 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
3842 goto next_posrule;
3843 j++;
3844 }
3845
3846 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
3847 goto next_posrule;
3848 }
3849
3850 return Do_ContextPos( gpi, pr[k].GlyphCount,
3851 pr[k].PosCount, pr[k].PosLookupRecord,
3852 buffer,
3853 nesting_level );
3854
3855 next_posrule:
3856 ;
3857 }
3858
3859 return HB_Err_Not_Covered;
3860 }
3861
3862
Lookup_ContextPos2(GPOS_Instance * gpi,HB_ContextPosFormat2 * cpf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3863 static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
3864 HB_ContextPosFormat2* cpf2,
3865 HB_Buffer buffer,
3866 HB_UShort flags,
3867 HB_UShort context_length,
3868 int nesting_level )
3869 {
3870 HB_UShort index, property;
3871 HB_Error error;
3872 HB_UShort i, j, k, known_classes;
3873
3874 HB_UShort* classes;
3875 HB_UShort* cl;
3876 HB_GPOSHeader* gpos = gpi->gpos;
3877
3878 HB_PosClassSet* pcs;
3879 HB_PosClassRule* pr;
3880 HB_GDEFHeader* gdef;
3881
3882
3883 gdef = gpos->gdef;
3884
3885 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3886 return error;
3887
3888 /* Note: The coverage table in format 2 doesn't give an index into
3889 anything. It just lets us know whether or not we need to
3890 do any lookup at all. */
3891
3892 error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
3893 if ( error )
3894 return error;
3895
3896 if (cpf2->MaxContextLength < 1)
3897 return HB_Err_Not_Covered;
3898
3899 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
3900 return error;
3901
3902 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
3903 &classes[0], NULL );
3904 if ( error && error != HB_Err_Not_Covered )
3905 goto End;
3906 known_classes = 0;
3907
3908 pcs = &cpf2->PosClassSet[classes[0]];
3909 if ( !pcs )
3910 {
3911 error = ERR(HB_Err_Invalid_SubTable);
3912 goto End;
3913 }
3914
3915 for ( k = 0; k < pcs->PosClassRuleCount; k++ )
3916 {
3917 pr = &pcs->PosClassRule[k];
3918
3919 if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
3920 goto next_posclassrule;
3921
3922 if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
3923 goto next_posclassrule; /* context is too long */
3924
3925 cl = pr->Class;
3926
3927 /* Start at 1 because [0] is implied */
3928
3929 for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
3930 {
3931 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3932 {
3933 if ( error && error != HB_Err_Not_Covered )
3934 goto End;
3935
3936 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
3937 goto next_posclassrule;
3938 j++;
3939 }
3940
3941 if ( i > known_classes )
3942 {
3943 /* Keeps us from having to do this for each rule */
3944
3945 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
3946 if ( error && error != HB_Err_Not_Covered )
3947 goto End;
3948 known_classes = i;
3949 }
3950
3951 if ( cl[i - 1] != classes[i] )
3952 goto next_posclassrule;
3953 }
3954
3955 error = Do_ContextPos( gpi, pr->GlyphCount,
3956 pr->PosCount, pr->PosLookupRecord,
3957 buffer,
3958 nesting_level );
3959 goto End;
3960
3961 next_posclassrule:
3962 ;
3963 }
3964
3965 error = HB_Err_Not_Covered;
3966
3967 End:
3968 FREE( classes );
3969 return error;
3970 }
3971
3972
Lookup_ContextPos3(GPOS_Instance * gpi,HB_ContextPosFormat3 * cpf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3973 static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
3974 HB_ContextPosFormat3* cpf3,
3975 HB_Buffer buffer,
3976 HB_UShort flags,
3977 HB_UShort context_length,
3978 int nesting_level )
3979 {
3980 HB_Error error;
3981 HB_UShort index, i, j, property;
3982 HB_GPOSHeader* gpos = gpi->gpos;
3983
3984 HB_Coverage* c;
3985 HB_GDEFHeader* gdef;
3986
3987
3988 gdef = gpos->gdef;
3989
3990 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3991 return error;
3992
3993 if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
3994 return HB_Err_Not_Covered;
3995
3996 if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
3997 return HB_Err_Not_Covered; /* context is too long */
3998
3999 c = cpf3->Coverage;
4000
4001 for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
4002 {
4003 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
4004 {
4005 if ( error && error != HB_Err_Not_Covered )
4006 return error;
4007
4008 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
4009 return HB_Err_Not_Covered;
4010 j++;
4011 }
4012
4013 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
4014 if ( error )
4015 return error;
4016 }
4017
4018 return Do_ContextPos( gpi, cpf3->GlyphCount,
4019 cpf3->PosCount, cpf3->PosLookupRecord,
4020 buffer,
4021 nesting_level );
4022 }
4023
4024
Lookup_ContextPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)4025 static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
4026 HB_GPOS_SubTable* st,
4027 HB_Buffer buffer,
4028 HB_UShort flags,
4029 HB_UShort context_length,
4030 int nesting_level )
4031 {
4032 HB_ContextPos* cp = &st->context;
4033
4034 switch ( cp->PosFormat )
4035 {
4036 case 1:
4037 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
4038 flags, context_length, nesting_level );
4039
4040 case 2:
4041 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
4042 flags, context_length, nesting_level );
4043
4044 case 3:
4045 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
4046 flags, context_length, nesting_level );
4047
4048 default:
4049 return ERR(HB_Err_Invalid_SubTable_Format);
4050 }
4051
4052 return HB_Err_Ok; /* never reached */
4053 }
4054
4055
4056 /* LookupType 8 */
4057
4058 /* ChainPosRule */
4059
Load_ChainPosRule(HB_ChainPosRule * cpr,HB_Stream stream)4060 static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
4061 HB_Stream stream )
4062 {
4063 HB_Error error;
4064
4065 HB_UShort n, count;
4066 HB_UShort* b;
4067 HB_UShort* i;
4068 HB_UShort* l;
4069
4070 HB_PosLookupRecord* plr;
4071
4072
4073 if ( ACCESS_Frame( 2L ) )
4074 return error;
4075
4076 cpr->BacktrackGlyphCount = GET_UShort();
4077
4078 FORGET_Frame();
4079
4080 cpr->Backtrack = NULL;
4081
4082 count = cpr->BacktrackGlyphCount;
4083
4084 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
4085 return error;
4086
4087 b = cpr->Backtrack;
4088
4089 if ( ACCESS_Frame( count * 2L ) )
4090 goto Fail4;
4091
4092 for ( n = 0; n < count; n++ )
4093 b[n] = GET_UShort();
4094
4095 FORGET_Frame();
4096
4097 if ( ACCESS_Frame( 2L ) )
4098 goto Fail4;
4099
4100 cpr->InputGlyphCount = GET_UShort();
4101
4102 FORGET_Frame();
4103
4104 cpr->Input = NULL;
4105
4106 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4107
4108 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
4109 goto Fail4;
4110
4111 i = cpr->Input;
4112
4113 if ( ACCESS_Frame( count * 2L ) )
4114 goto Fail3;
4115
4116 for ( n = 0; n < count; n++ )
4117 i[n] = GET_UShort();
4118
4119 FORGET_Frame();
4120
4121 if ( ACCESS_Frame( 2L ) )
4122 goto Fail3;
4123
4124 cpr->LookaheadGlyphCount = GET_UShort();
4125
4126 FORGET_Frame();
4127
4128 cpr->Lookahead = NULL;
4129
4130 count = cpr->LookaheadGlyphCount;
4131
4132 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
4133 goto Fail3;
4134
4135 l = cpr->Lookahead;
4136
4137 if ( ACCESS_Frame( count * 2L ) )
4138 goto Fail2;
4139
4140 for ( n = 0; n < count; n++ )
4141 l[n] = GET_UShort();
4142
4143 FORGET_Frame();
4144
4145 if ( ACCESS_Frame( 2L ) )
4146 goto Fail2;
4147
4148 cpr->PosCount = GET_UShort();
4149
4150 FORGET_Frame();
4151
4152 cpr->PosLookupRecord = NULL;
4153
4154 count = cpr->PosCount;
4155
4156 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
4157 goto Fail2;
4158
4159 plr = cpr->PosLookupRecord;
4160
4161 if ( ACCESS_Frame( count * 4L ) )
4162 goto Fail1;
4163
4164 for ( n = 0; n < count; n++ )
4165 {
4166 plr[n].SequenceIndex = GET_UShort();
4167 plr[n].LookupListIndex = GET_UShort();
4168 }
4169
4170 FORGET_Frame();
4171
4172 return HB_Err_Ok;
4173
4174 Fail1:
4175 FREE( plr );
4176
4177 Fail2:
4178 FREE( l );
4179
4180 Fail3:
4181 FREE( i );
4182
4183 Fail4:
4184 FREE( b );
4185 return error;
4186 }
4187
4188
Free_ChainPosRule(HB_ChainPosRule * cpr)4189 static void Free_ChainPosRule( HB_ChainPosRule* cpr )
4190 {
4191 FREE( cpr->PosLookupRecord );
4192 FREE( cpr->Lookahead );
4193 FREE( cpr->Input );
4194 FREE( cpr->Backtrack );
4195 }
4196
4197
4198 /* ChainPosRuleSet */
4199
Load_ChainPosRuleSet(HB_ChainPosRuleSet * cprs,HB_Stream stream)4200 static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
4201 HB_Stream stream )
4202 {
4203 HB_Error error;
4204
4205 HB_UShort n, m, count;
4206 HB_UInt cur_offset, new_offset, base_offset;
4207
4208 HB_ChainPosRule* cpr;
4209
4210
4211 base_offset = FILE_Pos();
4212
4213 if ( ACCESS_Frame( 2L ) )
4214 return error;
4215
4216 count = cprs->ChainPosRuleCount = GET_UShort();
4217
4218 FORGET_Frame();
4219
4220 cprs->ChainPosRule = NULL;
4221
4222 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
4223 return error;
4224
4225 cpr = cprs->ChainPosRule;
4226
4227 for ( n = 0; n < count; n++ )
4228 {
4229 if ( ACCESS_Frame( 2L ) )
4230 goto Fail;
4231
4232 new_offset = GET_UShort() + base_offset;
4233
4234 FORGET_Frame();
4235
4236 cur_offset = FILE_Pos();
4237 if ( FILE_Seek( new_offset ) ||
4238 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
4239 goto Fail;
4240 (void)FILE_Seek( cur_offset );
4241 }
4242
4243 return HB_Err_Ok;
4244
4245 Fail:
4246 for ( m = 0; m < n; m++ )
4247 Free_ChainPosRule( &cpr[m] );
4248
4249 FREE( cpr );
4250 return error;
4251 }
4252
4253
Free_ChainPosRuleSet(HB_ChainPosRuleSet * cprs)4254 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
4255 {
4256 HB_UShort n, count;
4257
4258 HB_ChainPosRule* cpr;
4259
4260
4261 if ( cprs->ChainPosRule )
4262 {
4263 count = cprs->ChainPosRuleCount;
4264 cpr = cprs->ChainPosRule;
4265
4266 for ( n = 0; n < count; n++ )
4267 Free_ChainPosRule( &cpr[n] );
4268
4269 FREE( cpr );
4270 }
4271 }
4272
4273
4274 /* ChainContextPosFormat1 */
4275
Load_ChainContextPos1(HB_ChainContextPosFormat1 * ccpf1,HB_Stream stream)4276 static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
4277 HB_Stream stream )
4278 {
4279 HB_Error error;
4280
4281 HB_UShort n, m, count;
4282 HB_UInt cur_offset, new_offset, base_offset;
4283
4284 HB_ChainPosRuleSet* cprs;
4285
4286
4287 base_offset = FILE_Pos() - 2L;
4288
4289 if ( ACCESS_Frame( 2L ) )
4290 return error;
4291
4292 new_offset = GET_UShort() + base_offset;
4293
4294 FORGET_Frame();
4295
4296 cur_offset = FILE_Pos();
4297 if ( FILE_Seek( new_offset ) ||
4298 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
4299 return error;
4300 (void)FILE_Seek( cur_offset );
4301
4302 if ( ACCESS_Frame( 2L ) )
4303 goto Fail2;
4304
4305 count = ccpf1->ChainPosRuleSetCount = GET_UShort();
4306
4307 FORGET_Frame();
4308
4309 ccpf1->ChainPosRuleSet = NULL;
4310
4311 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
4312 goto Fail2;
4313
4314 cprs = ccpf1->ChainPosRuleSet;
4315
4316 for ( n = 0; n < count; n++ )
4317 {
4318 if ( ACCESS_Frame( 2L ) )
4319 goto Fail1;
4320
4321 new_offset = GET_UShort() + base_offset;
4322
4323 FORGET_Frame();
4324
4325 cur_offset = FILE_Pos();
4326 if ( FILE_Seek( new_offset ) ||
4327 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
4328 goto Fail1;
4329 (void)FILE_Seek( cur_offset );
4330 }
4331
4332 return HB_Err_Ok;
4333
4334 Fail1:
4335 for ( m = 0; m < n; m++ )
4336 Free_ChainPosRuleSet( &cprs[m] );
4337
4338 FREE( cprs );
4339
4340 Fail2:
4341 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4342 return error;
4343 }
4344
4345
Free_ChainContextPos1(HB_ChainContextPosFormat1 * ccpf1)4346 static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
4347 {
4348 HB_UShort n, count;
4349
4350 HB_ChainPosRuleSet* cprs;
4351
4352
4353 if ( ccpf1->ChainPosRuleSet )
4354 {
4355 count = ccpf1->ChainPosRuleSetCount;
4356 cprs = ccpf1->ChainPosRuleSet;
4357
4358 for ( n = 0; n < count; n++ )
4359 Free_ChainPosRuleSet( &cprs[n] );
4360
4361 FREE( cprs );
4362 }
4363
4364 _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
4365 }
4366
4367
4368 /* ChainPosClassRule */
4369
Load_ChainPosClassRule(HB_ChainContextPosFormat2 * ccpf2,HB_ChainPosClassRule * cpcr,HB_Stream stream)4370 static HB_Error Load_ChainPosClassRule(
4371 HB_ChainContextPosFormat2* ccpf2,
4372 HB_ChainPosClassRule* cpcr,
4373 HB_Stream stream )
4374 {
4375 HB_Error error;
4376
4377 HB_UShort n, count;
4378
4379 HB_UShort* b;
4380 HB_UShort* i;
4381 HB_UShort* l;
4382 HB_PosLookupRecord* plr;
4383
4384
4385 if ( ACCESS_Frame( 2L ) )
4386 return error;
4387
4388 cpcr->BacktrackGlyphCount = GET_UShort();
4389
4390 FORGET_Frame();
4391
4392 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
4393 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
4394
4395 cpcr->Backtrack = NULL;
4396
4397 count = cpcr->BacktrackGlyphCount;
4398
4399 if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
4400 return error;
4401
4402 b = cpcr->Backtrack;
4403
4404 if ( ACCESS_Frame( count * 2L ) )
4405 goto Fail4;
4406
4407 for ( n = 0; n < count; n++ )
4408 b[n] = GET_UShort();
4409
4410 FORGET_Frame();
4411
4412 if ( ACCESS_Frame( 2L ) )
4413 goto Fail4;
4414
4415 cpcr->InputGlyphCount = GET_UShort();
4416
4417 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
4418 ccpf2->MaxInputLength = cpcr->InputGlyphCount;
4419
4420 FORGET_Frame();
4421
4422 cpcr->Input = NULL;
4423
4424 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
4425
4426 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
4427 goto Fail4;
4428
4429 i = cpcr->Input;
4430
4431 if ( ACCESS_Frame( count * 2L ) )
4432 goto Fail3;
4433
4434 for ( n = 0; n < count; n++ )
4435 i[n] = GET_UShort();
4436
4437 FORGET_Frame();
4438
4439 if ( ACCESS_Frame( 2L ) )
4440 goto Fail3;
4441
4442 cpcr->LookaheadGlyphCount = GET_UShort();
4443
4444 FORGET_Frame();
4445
4446 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
4447 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
4448
4449 cpcr->Lookahead = NULL;
4450
4451 count = cpcr->LookaheadGlyphCount;
4452
4453 if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
4454 goto Fail3;
4455
4456 l = cpcr->Lookahead;
4457
4458 if ( ACCESS_Frame( count * 2L ) )
4459 goto Fail2;
4460
4461 for ( n = 0; n < count; n++ )
4462 l[n] = GET_UShort();
4463
4464 FORGET_Frame();
4465
4466 if ( ACCESS_Frame( 2L ) )
4467 goto Fail2;
4468
4469 cpcr->PosCount = GET_UShort();
4470
4471 FORGET_Frame();
4472
4473 cpcr->PosLookupRecord = NULL;
4474
4475 count = cpcr->PosCount;
4476
4477 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
4478 goto Fail2;
4479
4480 plr = cpcr->PosLookupRecord;
4481
4482 if ( ACCESS_Frame( count * 4L ) )
4483 goto Fail1;
4484
4485 for ( n = 0; n < count; n++ )
4486 {
4487 plr[n].SequenceIndex = GET_UShort();
4488 plr[n].LookupListIndex = GET_UShort();
4489 }
4490
4491 FORGET_Frame();
4492
4493 return HB_Err_Ok;
4494
4495 Fail1:
4496 FREE( plr );
4497
4498 Fail2:
4499 FREE( l );
4500
4501 Fail3:
4502 FREE( i );
4503
4504 Fail4:
4505 FREE( b );
4506 return error;
4507 }
4508
4509
Free_ChainPosClassRule(HB_ChainPosClassRule * cpcr)4510 static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
4511 {
4512 FREE( cpcr->PosLookupRecord );
4513 FREE( cpcr->Lookahead );
4514 FREE( cpcr->Input );
4515 FREE( cpcr->Backtrack );
4516 }
4517
4518
4519 /* PosClassSet */
4520
Load_ChainPosClassSet(HB_ChainContextPosFormat2 * ccpf2,HB_ChainPosClassSet * cpcs,HB_Stream stream)4521 static HB_Error Load_ChainPosClassSet(
4522 HB_ChainContextPosFormat2* ccpf2,
4523 HB_ChainPosClassSet* cpcs,
4524 HB_Stream stream )
4525 {
4526 HB_Error error;
4527
4528 HB_UShort n, m, count;
4529 HB_UInt cur_offset, new_offset, base_offset;
4530
4531 HB_ChainPosClassRule* cpcr;
4532
4533
4534 base_offset = FILE_Pos();
4535
4536 if ( ACCESS_Frame( 2L ) )
4537 return error;
4538
4539 count = cpcs->ChainPosClassRuleCount = GET_UShort();
4540
4541 FORGET_Frame();
4542
4543 cpcs->ChainPosClassRule = NULL;
4544
4545 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
4546 HB_ChainPosClassRule ) )
4547 return error;
4548
4549 cpcr = cpcs->ChainPosClassRule;
4550
4551 for ( n = 0; n < count; n++ )
4552 {
4553 if ( ACCESS_Frame( 2L ) )
4554 goto Fail;
4555
4556 new_offset = GET_UShort() + base_offset;
4557
4558 FORGET_Frame();
4559
4560 cur_offset = FILE_Pos();
4561 if ( FILE_Seek( new_offset ) ||
4562 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
4563 stream ) ) != HB_Err_Ok )
4564 goto Fail;
4565 (void)FILE_Seek( cur_offset );
4566 }
4567
4568 return HB_Err_Ok;
4569
4570 Fail:
4571 for ( m = 0; m < n; m++ )
4572 Free_ChainPosClassRule( &cpcr[m] );
4573
4574 FREE( cpcr );
4575 return error;
4576 }
4577
4578
Free_ChainPosClassSet(HB_ChainPosClassSet * cpcs)4579 static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
4580 {
4581 HB_UShort n, count;
4582
4583 HB_ChainPosClassRule* cpcr;
4584
4585
4586 if ( cpcs->ChainPosClassRule )
4587 {
4588 count = cpcs->ChainPosClassRuleCount;
4589 cpcr = cpcs->ChainPosClassRule;
4590
4591 for ( n = 0; n < count; n++ )
4592 Free_ChainPosClassRule( &cpcr[n] );
4593
4594 FREE( cpcr );
4595 }
4596 }
4597
4598
4599 /* ChainContextPosFormat2 */
4600
Load_ChainContextPos2(HB_ChainContextPosFormat2 * ccpf2,HB_Stream stream)4601 static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
4602 HB_Stream stream )
4603 {
4604 HB_Error error;
4605
4606 HB_UShort n, m, count;
4607 HB_UInt cur_offset, new_offset, base_offset;
4608 HB_UInt backtrack_offset, input_offset, lookahead_offset;
4609
4610 HB_ChainPosClassSet* cpcs;
4611
4612
4613 base_offset = FILE_Pos() - 2;
4614
4615 if ( ACCESS_Frame( 2L ) )
4616 return error;
4617
4618 new_offset = GET_UShort() + base_offset;
4619
4620 FORGET_Frame();
4621
4622 cur_offset = FILE_Pos();
4623 if ( FILE_Seek( new_offset ) ||
4624 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
4625 return error;
4626 (void)FILE_Seek( cur_offset );
4627
4628 if ( ACCESS_Frame( 8L ) )
4629 goto Fail5;
4630
4631 backtrack_offset = GET_UShort();
4632 input_offset = GET_UShort();
4633 lookahead_offset = GET_UShort();
4634
4635 /* `ChainPosClassSetCount' is the upper limit for input class values,
4636 thus we read it now to make an additional safety check. No limit
4637 is known or needed for the other two class definitions */
4638
4639 count = ccpf2->ChainPosClassSetCount = GET_UShort();
4640
4641 FORGET_Frame();
4642
4643 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
4644 backtrack_offset, base_offset,
4645 stream ) ) != HB_Err_Ok )
4646 goto Fail5;
4647 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
4648 input_offset, base_offset,
4649 stream ) ) != HB_Err_Ok )
4650 goto Fail4;
4651 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
4652 lookahead_offset, base_offset,
4653 stream ) ) != HB_Err_Ok )
4654 goto Fail3;
4655
4656 ccpf2->ChainPosClassSet = NULL;
4657 ccpf2->MaxBacktrackLength = 0;
4658 ccpf2->MaxInputLength = 0;
4659 ccpf2->MaxLookaheadLength = 0;
4660
4661 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
4662 goto Fail2;
4663
4664 cpcs = ccpf2->ChainPosClassSet;
4665
4666 for ( n = 0; n < count; n++ )
4667 {
4668 if ( ACCESS_Frame( 2L ) )
4669 goto Fail1;
4670
4671 new_offset = GET_UShort() + base_offset;
4672
4673 FORGET_Frame();
4674
4675 if ( new_offset != base_offset ) /* not a NULL offset */
4676 {
4677 cur_offset = FILE_Pos();
4678 if ( FILE_Seek( new_offset ) ||
4679 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
4680 stream ) ) != HB_Err_Ok )
4681 goto Fail1;
4682 (void)FILE_Seek( cur_offset );
4683 }
4684 else
4685 {
4686 /* we create a ChainPosClassSet table with no entries */
4687
4688 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
4689 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
4690 }
4691 }
4692
4693 return HB_Err_Ok;
4694
4695 Fail1:
4696 for ( m = 0; m < n; m++ )
4697 Free_ChainPosClassSet( &cpcs[m] );
4698
4699 FREE( cpcs );
4700
4701 Fail2:
4702 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4703
4704 Fail3:
4705 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4706
4707 Fail4:
4708 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4709
4710 Fail5:
4711 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4712 return error;
4713 }
4714
4715
Free_ChainContextPos2(HB_ChainContextPosFormat2 * ccpf2)4716 static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
4717 {
4718 HB_UShort n, count;
4719
4720 HB_ChainPosClassSet* cpcs;
4721
4722
4723 if ( ccpf2->ChainPosClassSet )
4724 {
4725 count = ccpf2->ChainPosClassSetCount;
4726 cpcs = ccpf2->ChainPosClassSet;
4727
4728 for ( n = 0; n < count; n++ )
4729 Free_ChainPosClassSet( &cpcs[n] );
4730
4731 FREE( cpcs );
4732 }
4733
4734 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
4735 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
4736 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
4737
4738 _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
4739 }
4740
4741
4742 /* ChainContextPosFormat3 */
4743
Load_ChainContextPos3(HB_ChainContextPosFormat3 * ccpf3,HB_Stream stream)4744 static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
4745 HB_Stream stream )
4746 {
4747 HB_Error error;
4748
4749 HB_UShort n, nb, ni, nl, m, count;
4750 HB_UShort backtrack_count, input_count, lookahead_count;
4751 HB_UInt cur_offset, new_offset, base_offset;
4752
4753 HB_Coverage* b;
4754 HB_Coverage* i;
4755 HB_Coverage* l;
4756 HB_PosLookupRecord* plr;
4757
4758
4759 base_offset = FILE_Pos() - 2L;
4760
4761 if ( ACCESS_Frame( 2L ) )
4762 return error;
4763
4764 ccpf3->BacktrackGlyphCount = GET_UShort();
4765
4766 FORGET_Frame();
4767
4768 ccpf3->BacktrackCoverage = NULL;
4769
4770 backtrack_count = ccpf3->BacktrackGlyphCount;
4771
4772 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
4773 HB_Coverage ) )
4774 return error;
4775
4776 b = ccpf3->BacktrackCoverage;
4777
4778 for ( nb = 0; nb < backtrack_count; nb++ )
4779 {
4780 if ( ACCESS_Frame( 2L ) )
4781 goto Fail4;
4782
4783 new_offset = GET_UShort() + base_offset;
4784
4785 FORGET_Frame();
4786
4787 cur_offset = FILE_Pos();
4788 if ( FILE_Seek( new_offset ) ||
4789 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
4790 goto Fail4;
4791 (void)FILE_Seek( cur_offset );
4792 }
4793
4794 if ( ACCESS_Frame( 2L ) )
4795 goto Fail4;
4796
4797 ccpf3->InputGlyphCount = GET_UShort();
4798
4799 FORGET_Frame();
4800
4801 ccpf3->InputCoverage = NULL;
4802
4803 input_count = ccpf3->InputGlyphCount;
4804
4805 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
4806 goto Fail4;
4807
4808 i = ccpf3->InputCoverage;
4809
4810 for ( ni = 0; ni < input_count; ni++ )
4811 {
4812 if ( ACCESS_Frame( 2L ) )
4813 goto Fail3;
4814
4815 new_offset = GET_UShort() + base_offset;
4816
4817 FORGET_Frame();
4818
4819 cur_offset = FILE_Pos();
4820 if ( FILE_Seek( new_offset ) ||
4821 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
4822 goto Fail3;
4823 (void)FILE_Seek( cur_offset );
4824 }
4825
4826 if ( ACCESS_Frame( 2L ) )
4827 goto Fail3;
4828
4829 ccpf3->LookaheadGlyphCount = GET_UShort();
4830
4831 FORGET_Frame();
4832
4833 ccpf3->LookaheadCoverage = NULL;
4834
4835 lookahead_count = ccpf3->LookaheadGlyphCount;
4836
4837 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
4838 HB_Coverage ) )
4839 goto Fail3;
4840
4841 l = ccpf3->LookaheadCoverage;
4842
4843 for ( nl = 0; nl < lookahead_count; nl++ )
4844 {
4845 if ( ACCESS_Frame( 2L ) )
4846 goto Fail2;
4847
4848 new_offset = GET_UShort() + base_offset;
4849
4850 FORGET_Frame();
4851
4852 cur_offset = FILE_Pos();
4853 if ( FILE_Seek( new_offset ) ||
4854 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
4855 goto Fail2;
4856 (void)FILE_Seek( cur_offset );
4857 }
4858
4859 if ( ACCESS_Frame( 2L ) )
4860 goto Fail2;
4861
4862 ccpf3->PosCount = GET_UShort();
4863
4864 FORGET_Frame();
4865
4866 ccpf3->PosLookupRecord = NULL;
4867
4868 count = ccpf3->PosCount;
4869
4870 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
4871 goto Fail2;
4872
4873 plr = ccpf3->PosLookupRecord;
4874
4875 if ( ACCESS_Frame( count * 4L ) )
4876 goto Fail1;
4877
4878 for ( n = 0; n < count; n++ )
4879 {
4880 plr[n].SequenceIndex = GET_UShort();
4881 plr[n].LookupListIndex = GET_UShort();
4882 }
4883
4884 FORGET_Frame();
4885
4886 return HB_Err_Ok;
4887
4888 Fail1:
4889 FREE( plr );
4890
4891 Fail2:
4892 for ( m = 0; m < nl; m++ )
4893 _HB_OPEN_Free_Coverage( &l[m] );
4894
4895 FREE( l );
4896
4897 Fail3:
4898 for ( m = 0; m < ni; m++ )
4899 _HB_OPEN_Free_Coverage( &i[m] );
4900
4901 FREE( i );
4902
4903 Fail4:
4904 for ( m = 0; m < nb; m++ )
4905 _HB_OPEN_Free_Coverage( &b[m] );
4906
4907 FREE( b );
4908 return error;
4909 }
4910
4911
Free_ChainContextPos3(HB_ChainContextPosFormat3 * ccpf3)4912 static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
4913 {
4914 HB_UShort n, count;
4915
4916 HB_Coverage* c;
4917
4918
4919 FREE( ccpf3->PosLookupRecord );
4920
4921 if ( ccpf3->LookaheadCoverage )
4922 {
4923 count = ccpf3->LookaheadGlyphCount;
4924 c = ccpf3->LookaheadCoverage;
4925
4926 for ( n = 0; n < count; n++ )
4927 _HB_OPEN_Free_Coverage( &c[n] );
4928
4929 FREE( c );
4930 }
4931
4932 if ( ccpf3->InputCoverage )
4933 {
4934 count = ccpf3->InputGlyphCount;
4935 c = ccpf3->InputCoverage;
4936
4937 for ( n = 0; n < count; n++ )
4938 _HB_OPEN_Free_Coverage( &c[n] );
4939
4940 FREE( c );
4941 }
4942
4943 if ( ccpf3->BacktrackCoverage )
4944 {
4945 count = ccpf3->BacktrackGlyphCount;
4946 c = ccpf3->BacktrackCoverage;
4947
4948 for ( n = 0; n < count; n++ )
4949 _HB_OPEN_Free_Coverage( &c[n] );
4950
4951 FREE( c );
4952 }
4953 }
4954
4955
4956 /* ChainContextPos */
4957
Load_ChainContextPos(HB_GPOS_SubTable * st,HB_Stream stream)4958 static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
4959 HB_Stream stream )
4960 {
4961 HB_Error error;
4962 HB_ChainContextPos* ccp = &st->chain;
4963
4964
4965 if ( ACCESS_Frame( 2L ) )
4966 return error;
4967
4968 ccp->PosFormat = GET_UShort();
4969
4970 FORGET_Frame();
4971
4972 switch ( ccp->PosFormat )
4973 {
4974 case 1:
4975 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
4976
4977 case 2:
4978 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
4979
4980 case 3:
4981 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
4982
4983 default:
4984 return ERR(HB_Err_Invalid_SubTable_Format);
4985 }
4986
4987 return HB_Err_Ok; /* never reached */
4988 }
4989
4990
Free_ChainContextPos(HB_GPOS_SubTable * st)4991 static void Free_ChainContextPos( HB_GPOS_SubTable* st )
4992 {
4993 HB_ChainContextPos* ccp = &st->chain;
4994
4995 switch ( ccp->PosFormat )
4996 {
4997 case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
4998 case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
4999 case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
5000 default: break;
5001 }
5002 }
5003
5004
Lookup_ChainContextPos1(GPOS_Instance * gpi,HB_ChainContextPosFormat1 * ccpf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5005 static HB_Error Lookup_ChainContextPos1(
5006 GPOS_Instance* gpi,
5007 HB_ChainContextPosFormat1* ccpf1,
5008 HB_Buffer buffer,
5009 HB_UShort flags,
5010 HB_UShort context_length,
5011 int nesting_level )
5012 {
5013 HB_UShort index, property;
5014 HB_UShort i, j, k, num_cpr;
5015 HB_UShort bgc, igc, lgc;
5016 HB_Error error;
5017 HB_GPOSHeader* gpos = gpi->gpos;
5018
5019 HB_ChainPosRule* cpr;
5020 HB_ChainPosRule curr_cpr;
5021 HB_GDEFHeader* gdef;
5022
5023
5024 gdef = gpos->gdef;
5025
5026 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5027 return error;
5028
5029 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
5030 if ( error )
5031 return error;
5032
5033 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
5034 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
5035
5036 for ( k = 0; k < num_cpr; k++ )
5037 {
5038 curr_cpr = cpr[k];
5039 bgc = curr_cpr.BacktrackGlyphCount;
5040 igc = curr_cpr.InputGlyphCount;
5041 lgc = curr_cpr.LookaheadGlyphCount;
5042
5043 if ( context_length != 0xFFFF && context_length < igc )
5044 goto next_chainposrule;
5045
5046 /* check whether context is too long; it is a first guess only */
5047
5048 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5049 goto next_chainposrule;
5050
5051 if ( bgc )
5052 {
5053 /* Since we don't know in advance the number of glyphs to inspect,
5054 we search backwards for matches in the backtrack glyph array */
5055
5056 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5057 {
5058 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5059 {
5060 if ( error && error != HB_Err_Not_Covered )
5061 return error;
5062
5063 if ( j + 1 == bgc - i )
5064 goto next_chainposrule;
5065 j--;
5066 }
5067
5068 /* In OpenType 1.3, it is undefined whether the offsets of
5069 backtrack glyphs is in logical order or not. Version 1.4
5070 will clarify this:
5071
5072 Logical order - a b c d e f g h i j
5073 i
5074 Input offsets - 0 1
5075 Backtrack offsets - 3 2 1 0
5076 Lookahead offsets - 0 1 2 3 */
5077
5078 if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
5079 goto next_chainposrule;
5080 }
5081 }
5082
5083 /* Start at 1 because [0] is implied */
5084
5085 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5086 {
5087 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5088 {
5089 if ( error && error != HB_Err_Not_Covered )
5090 return error;
5091
5092 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5093 goto next_chainposrule;
5094 j++;
5095 }
5096
5097 if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
5098 goto next_chainposrule;
5099 }
5100
5101 /* we are starting to check for lookahead glyphs right after the
5102 last context glyph */
5103
5104 for ( i = 0; i < lgc; i++, j++ )
5105 {
5106 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5107 {
5108 if ( error && error != HB_Err_Not_Covered )
5109 return error;
5110
5111 if ( j + lgc - i == (HB_Int)buffer->in_length )
5112 goto next_chainposrule;
5113 j++;
5114 }
5115
5116 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
5117 goto next_chainposrule;
5118 }
5119
5120 return Do_ContextPos( gpi, igc,
5121 curr_cpr.PosCount,
5122 curr_cpr.PosLookupRecord,
5123 buffer,
5124 nesting_level );
5125
5126 next_chainposrule:
5127 ;
5128 }
5129
5130 return HB_Err_Not_Covered;
5131 }
5132
5133
Lookup_ChainContextPos2(GPOS_Instance * gpi,HB_ChainContextPosFormat2 * ccpf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5134 static HB_Error Lookup_ChainContextPos2(
5135 GPOS_Instance* gpi,
5136 HB_ChainContextPosFormat2* ccpf2,
5137 HB_Buffer buffer,
5138 HB_UShort flags,
5139 HB_UShort context_length,
5140 int nesting_level )
5141 {
5142 HB_UShort index, property;
5143 HB_Error error;
5144 HB_UShort i, j, k;
5145 HB_UShort bgc, igc, lgc;
5146 HB_UShort known_backtrack_classes,
5147 known_input_classes,
5148 known_lookahead_classes;
5149
5150 HB_UShort* backtrack_classes;
5151 HB_UShort* input_classes;
5152 HB_UShort* lookahead_classes;
5153
5154 HB_UShort* bc;
5155 HB_UShort* ic;
5156 HB_UShort* lc;
5157 HB_GPOSHeader* gpos = gpi->gpos;
5158
5159 HB_ChainPosClassSet* cpcs;
5160 HB_ChainPosClassRule cpcr;
5161 HB_GDEFHeader* gdef;
5162
5163
5164 gdef = gpos->gdef;
5165
5166 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5167 return error;
5168
5169 /* Note: The coverage table in format 2 doesn't give an index into
5170 anything. It just lets us know whether or not we need to
5171 do any lookup at all. */
5172
5173 error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
5174 if ( error )
5175 return error;
5176
5177 if (ccpf2->MaxInputLength < 1)
5178 return HB_Err_Not_Covered;
5179
5180 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
5181 return error;
5182 known_backtrack_classes = 0;
5183
5184 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
5185 goto End3;
5186 known_input_classes = 1;
5187
5188 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
5189 goto End2;
5190 known_lookahead_classes = 0;
5191
5192 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
5193 &input_classes[0], NULL );
5194 if ( error && error != HB_Err_Not_Covered )
5195 goto End1;
5196
5197 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
5198 if ( !cpcs )
5199 {
5200 error = ERR(HB_Err_Invalid_SubTable);
5201 goto End1;
5202 }
5203
5204 for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
5205 {
5206 cpcr = cpcs->ChainPosClassRule[k];
5207 bgc = cpcr.BacktrackGlyphCount;
5208 igc = cpcr.InputGlyphCount;
5209 lgc = cpcr.LookaheadGlyphCount;
5210
5211 if ( context_length != 0xFFFF && context_length < igc )
5212 goto next_chainposclassrule;
5213
5214 /* check whether context is too long; it is a first guess only */
5215
5216 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5217 goto next_chainposclassrule;
5218
5219 if ( bgc )
5220 {
5221 /* Since we don't know in advance the number of glyphs to inspect,
5222 we search backwards for matches in the backtrack glyph array.
5223 Note that `known_backtrack_classes' starts at index 0. */
5224
5225 bc = cpcr.Backtrack;
5226
5227 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5228 {
5229 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5230 {
5231 if ( error && error != HB_Err_Not_Covered )
5232 goto End1;
5233
5234 if ( j + 1 == bgc - i )
5235 goto next_chainposclassrule;
5236 j++;
5237 }
5238
5239 if ( i >= known_backtrack_classes )
5240 {
5241 /* Keeps us from having to do this for each rule */
5242
5243 error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
5244 &backtrack_classes[i], NULL );
5245 if ( error && error != HB_Err_Not_Covered )
5246 goto End1;
5247 known_backtrack_classes = i;
5248 }
5249
5250 if ( bc[i] != backtrack_classes[i] )
5251 goto next_chainposclassrule;
5252 }
5253 }
5254
5255 ic = cpcr.Input;
5256
5257 /* Start at 1 because [0] is implied */
5258
5259 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
5260 {
5261 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5262 {
5263 if ( error && error != HB_Err_Not_Covered )
5264 goto End1;
5265
5266 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5267 goto next_chainposclassrule;
5268 j++;
5269 }
5270
5271 if ( i >= known_input_classes )
5272 {
5273 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
5274 &input_classes[i], NULL );
5275 if ( error && error != HB_Err_Not_Covered )
5276 goto End1;
5277 known_input_classes = i;
5278 }
5279
5280 if ( ic[i - 1] != input_classes[i] )
5281 goto next_chainposclassrule;
5282 }
5283
5284 /* we are starting to check for lookahead glyphs right after the
5285 last context glyph */
5286
5287 lc = cpcr.Lookahead;
5288
5289 for ( i = 0; i < lgc; i++, j++ )
5290 {
5291 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5292 {
5293 if ( error && error != HB_Err_Not_Covered )
5294 goto End1;
5295
5296 if ( j + lgc - i == (HB_Int)buffer->in_length )
5297 goto next_chainposclassrule;
5298 j++;
5299 }
5300
5301 if ( i >= known_lookahead_classes )
5302 {
5303 error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
5304 &lookahead_classes[i], NULL );
5305 if ( error && error != HB_Err_Not_Covered )
5306 goto End1;
5307 known_lookahead_classes = i;
5308 }
5309
5310 if ( lc[i] != lookahead_classes[i] )
5311 goto next_chainposclassrule;
5312 }
5313
5314 error = Do_ContextPos( gpi, igc,
5315 cpcr.PosCount,
5316 cpcr.PosLookupRecord,
5317 buffer,
5318 nesting_level );
5319 goto End1;
5320
5321 next_chainposclassrule:
5322 ;
5323 }
5324
5325 error = HB_Err_Not_Covered;
5326
5327 End1:
5328 FREE( lookahead_classes );
5329
5330 End2:
5331 FREE( input_classes );
5332
5333 End3:
5334 FREE( backtrack_classes );
5335 return error;
5336 }
5337
5338
Lookup_ChainContextPos3(GPOS_Instance * gpi,HB_ChainContextPosFormat3 * ccpf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5339 static HB_Error Lookup_ChainContextPos3(
5340 GPOS_Instance* gpi,
5341 HB_ChainContextPosFormat3* ccpf3,
5342 HB_Buffer buffer,
5343 HB_UShort flags,
5344 HB_UShort context_length,
5345 int nesting_level )
5346 {
5347 HB_UShort index, i, j, property;
5348 HB_UShort bgc, igc, lgc;
5349 HB_Error error;
5350 HB_GPOSHeader* gpos = gpi->gpos;
5351
5352 HB_Coverage* bc;
5353 HB_Coverage* ic;
5354 HB_Coverage* lc;
5355 HB_GDEFHeader* gdef;
5356
5357
5358 gdef = gpos->gdef;
5359
5360 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
5361 return error;
5362
5363 bgc = ccpf3->BacktrackGlyphCount;
5364 igc = ccpf3->InputGlyphCount;
5365 lgc = ccpf3->LookaheadGlyphCount;
5366
5367 if ( context_length != 0xFFFF && context_length < igc )
5368 return HB_Err_Not_Covered;
5369
5370 /* check whether context is too long; it is a first guess only */
5371
5372 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
5373 return HB_Err_Not_Covered;
5374
5375 if ( bgc )
5376 {
5377 /* Since we don't know in advance the number of glyphs to inspect,
5378 we search backwards for matches in the backtrack glyph array */
5379
5380 bc = ccpf3->BacktrackCoverage;
5381
5382 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
5383 {
5384 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5385 {
5386 if ( error && error != HB_Err_Not_Covered )
5387 return error;
5388
5389 if ( j + 1 == bgc - i )
5390 return HB_Err_Not_Covered;
5391 j--;
5392 }
5393
5394 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
5395 if ( error )
5396 return error;
5397 }
5398 }
5399
5400 ic = ccpf3->InputCoverage;
5401
5402 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
5403 {
5404 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
5405 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5406 {
5407 if ( error && error != HB_Err_Not_Covered )
5408 return error;
5409
5410 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
5411 return HB_Err_Not_Covered;
5412 j++;
5413 }
5414
5415 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
5416 if ( error )
5417 return error;
5418 }
5419
5420 /* we are starting to check for lookahead glyphs right after the
5421 last context glyph */
5422
5423 lc = ccpf3->LookaheadCoverage;
5424
5425 for ( i = 0; i < lgc; i++, j++ )
5426 {
5427 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
5428 {
5429 if ( error && error != HB_Err_Not_Covered )
5430 return error;
5431
5432 if ( j + lgc - i == (HB_Int)buffer->in_length )
5433 return HB_Err_Not_Covered;
5434 j++;
5435 }
5436
5437 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
5438 if ( error )
5439 return error;
5440 }
5441
5442 return Do_ContextPos( gpi, igc,
5443 ccpf3->PosCount,
5444 ccpf3->PosLookupRecord,
5445 buffer,
5446 nesting_level );
5447 }
5448
5449
Lookup_ChainContextPos(GPOS_Instance * gpi,HB_GPOS_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)5450 static HB_Error Lookup_ChainContextPos(
5451 GPOS_Instance* gpi,
5452 HB_GPOS_SubTable* st,
5453 HB_Buffer buffer,
5454 HB_UShort flags,
5455 HB_UShort context_length,
5456 int nesting_level )
5457 {
5458 HB_ChainContextPos* ccp = &st->chain;
5459
5460 switch ( ccp->PosFormat )
5461 {
5462 case 1:
5463 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
5464 flags, context_length,
5465 nesting_level );
5466
5467 case 2:
5468 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
5469 flags, context_length,
5470 nesting_level );
5471
5472 case 3:
5473 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
5474 flags, context_length,
5475 nesting_level );
5476
5477 default:
5478 return ERR(HB_Err_Invalid_SubTable_Format);
5479 }
5480
5481 return HB_Err_Ok; /* never reached */
5482 }
5483
5484
5485
5486 /***********
5487 * GPOS API
5488 ***********/
5489
5490
5491
HB_GPOS_Select_Script(HB_GPOSHeader * gpos,HB_UInt script_tag,HB_UShort * script_index)5492 HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
5493 HB_UInt script_tag,
5494 HB_UShort* script_index )
5495 {
5496 HB_UShort n;
5497
5498 HB_ScriptList* sl;
5499 HB_ScriptRecord* sr;
5500
5501
5502 if ( !gpos || !script_index )
5503 return ERR(HB_Err_Invalid_Argument);
5504
5505 sl = &gpos->ScriptList;
5506 sr = sl->ScriptRecord;
5507
5508 for ( n = 0; n < sl->ScriptCount; n++ )
5509 if ( script_tag == sr[n].ScriptTag )
5510 {
5511 *script_index = n;
5512
5513 return HB_Err_Ok;
5514 }
5515
5516 return HB_Err_Not_Covered;
5517 }
5518
5519
5520
HB_GPOS_Select_Language(HB_GPOSHeader * gpos,HB_UInt language_tag,HB_UShort script_index,HB_UShort * language_index,HB_UShort * req_feature_index)5521 HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
5522 HB_UInt language_tag,
5523 HB_UShort script_index,
5524 HB_UShort* language_index,
5525 HB_UShort* req_feature_index )
5526 {
5527 HB_UShort n;
5528
5529 HB_ScriptList* sl;
5530 HB_ScriptRecord* sr;
5531 HB_ScriptTable* s;
5532 HB_LangSysRecord* lsr;
5533
5534
5535 if ( !gpos || !language_index || !req_feature_index )
5536 return ERR(HB_Err_Invalid_Argument);
5537
5538 sl = &gpos->ScriptList;
5539 sr = sl->ScriptRecord;
5540
5541 if ( script_index >= sl->ScriptCount )
5542 return ERR(HB_Err_Invalid_Argument);
5543
5544 s = &sr[script_index].Script;
5545 lsr = s->LangSysRecord;
5546
5547 for ( n = 0; n < s->LangSysCount; n++ )
5548 if ( language_tag == lsr[n].LangSysTag )
5549 {
5550 *language_index = n;
5551 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
5552
5553 return HB_Err_Ok;
5554 }
5555
5556 return HB_Err_Not_Covered;
5557 }
5558
5559
5560 /* selecting 0xFFFF for language_index asks for the values of the
5561 default language (DefaultLangSys) */
5562
5563
HB_GPOS_Select_Feature(HB_GPOSHeader * gpos,HB_UInt feature_tag,HB_UShort script_index,HB_UShort language_index,HB_UShort * feature_index)5564 HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
5565 HB_UInt feature_tag,
5566 HB_UShort script_index,
5567 HB_UShort language_index,
5568 HB_UShort* feature_index )
5569 {
5570 HB_UShort n;
5571
5572 HB_ScriptList* sl;
5573 HB_ScriptRecord* sr;
5574 HB_ScriptTable* s;
5575 HB_LangSysRecord* lsr;
5576 HB_LangSys* ls;
5577 HB_UShort* fi;
5578
5579 HB_FeatureList* fl;
5580 HB_FeatureRecord* fr;
5581
5582
5583 if ( !gpos || !feature_index )
5584 return ERR(HB_Err_Invalid_Argument);
5585
5586 sl = &gpos->ScriptList;
5587 sr = sl->ScriptRecord;
5588
5589 fl = &gpos->FeatureList;
5590 fr = fl->FeatureRecord;
5591
5592 if ( script_index >= sl->ScriptCount )
5593 return ERR(HB_Err_Invalid_Argument);
5594
5595 s = &sr[script_index].Script;
5596 lsr = s->LangSysRecord;
5597
5598 if ( language_index == 0xFFFF )
5599 ls = &s->DefaultLangSys;
5600 else
5601 {
5602 if ( language_index >= s->LangSysCount )
5603 return ERR(HB_Err_Invalid_Argument);
5604
5605 ls = &lsr[language_index].LangSys;
5606 }
5607
5608 fi = ls->FeatureIndex;
5609
5610 for ( n = 0; n < ls->FeatureCount; n++ )
5611 {
5612 if ( fi[n] >= fl->FeatureCount )
5613 return ERR(HB_Err_Invalid_SubTable_Format);
5614
5615 if ( feature_tag == fr[fi[n]].FeatureTag )
5616 {
5617 *feature_index = fi[n];
5618
5619 return HB_Err_Ok;
5620 }
5621 }
5622
5623 return HB_Err_Not_Covered;
5624 }
5625
5626
5627 /* The next three functions return a null-terminated list */
5628
5629
HB_GPOS_Query_Scripts(HB_GPOSHeader * gpos,HB_UInt ** script_tag_list)5630 HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
5631 HB_UInt** script_tag_list )
5632 {
5633 HB_Error error;
5634 HB_UShort n;
5635 HB_UInt* stl;
5636
5637 HB_ScriptList* sl;
5638 HB_ScriptRecord* sr;
5639
5640
5641 if ( !gpos || !script_tag_list )
5642 return ERR(HB_Err_Invalid_Argument);
5643
5644 sl = &gpos->ScriptList;
5645 sr = sl->ScriptRecord;
5646
5647 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
5648 return error;
5649
5650 for ( n = 0; n < sl->ScriptCount; n++ )
5651 stl[n] = sr[n].ScriptTag;
5652 stl[n] = 0;
5653
5654 *script_tag_list = stl;
5655
5656 return HB_Err_Ok;
5657 }
5658
5659
5660
HB_GPOS_Query_Languages(HB_GPOSHeader * gpos,HB_UShort script_index,HB_UInt ** language_tag_list)5661 HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
5662 HB_UShort script_index,
5663 HB_UInt** language_tag_list )
5664 {
5665 HB_Error error;
5666 HB_UShort n;
5667 HB_UInt* ltl;
5668
5669 HB_ScriptList* sl;
5670 HB_ScriptRecord* sr;
5671 HB_ScriptTable* s;
5672 HB_LangSysRecord* lsr;
5673
5674
5675 if ( !gpos || !language_tag_list )
5676 return ERR(HB_Err_Invalid_Argument);
5677
5678 sl = &gpos->ScriptList;
5679 sr = sl->ScriptRecord;
5680
5681 if ( script_index >= sl->ScriptCount )
5682 return ERR(HB_Err_Invalid_Argument);
5683
5684 s = &sr[script_index].Script;
5685 lsr = s->LangSysRecord;
5686
5687 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
5688 return error;
5689
5690 for ( n = 0; n < s->LangSysCount; n++ )
5691 ltl[n] = lsr[n].LangSysTag;
5692 ltl[n] = 0;
5693
5694 *language_tag_list = ltl;
5695
5696 return HB_Err_Ok;
5697 }
5698
5699
5700 /* selecting 0xFFFF for language_index asks for the values of the
5701 default language (DefaultLangSys) */
5702
5703
HB_GPOS_Query_Features(HB_GPOSHeader * gpos,HB_UShort script_index,HB_UShort language_index,HB_UInt ** feature_tag_list)5704 HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
5705 HB_UShort script_index,
5706 HB_UShort language_index,
5707 HB_UInt** feature_tag_list )
5708 {
5709 HB_UShort n;
5710 HB_Error error;
5711 HB_UInt* ftl;
5712
5713 HB_ScriptList* sl;
5714 HB_ScriptRecord* sr;
5715 HB_ScriptTable* s;
5716 HB_LangSysRecord* lsr;
5717 HB_LangSys* ls;
5718 HB_UShort* fi;
5719
5720 HB_FeatureList* fl;
5721 HB_FeatureRecord* fr;
5722
5723
5724 if ( !gpos || !feature_tag_list )
5725 return ERR(HB_Err_Invalid_Argument);
5726
5727 sl = &gpos->ScriptList;
5728 sr = sl->ScriptRecord;
5729
5730 fl = &gpos->FeatureList;
5731 fr = fl->FeatureRecord;
5732
5733 if ( script_index >= sl->ScriptCount )
5734 return ERR(HB_Err_Invalid_Argument);
5735
5736 s = &sr[script_index].Script;
5737 lsr = s->LangSysRecord;
5738
5739 if ( language_index == 0xFFFF )
5740 ls = &s->DefaultLangSys;
5741 else
5742 {
5743 if ( language_index >= s->LangSysCount )
5744 return ERR(HB_Err_Invalid_Argument);
5745
5746 ls = &lsr[language_index].LangSys;
5747 }
5748
5749 fi = ls->FeatureIndex;
5750
5751 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
5752 return error;
5753
5754 for ( n = 0; n < ls->FeatureCount; n++ )
5755 {
5756 if ( fi[n] >= fl->FeatureCount )
5757 {
5758 FREE( ftl );
5759 return ERR(HB_Err_Invalid_SubTable_Format);
5760 }
5761 ftl[n] = fr[fi[n]].FeatureTag;
5762 }
5763 ftl[n] = 0;
5764
5765 *feature_tag_list = ftl;
5766
5767 return HB_Err_Ok;
5768 }
5769
5770
5771 /* Do an individual subtable lookup. Returns HB_Err_Ok if positioning
5772 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)5773 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
5774 HB_UShort lookup_index,
5775 HB_Buffer buffer,
5776 HB_UShort context_length,
5777 int nesting_level )
5778 {
5779 HB_Error error = HB_Err_Not_Covered;
5780 HB_UShort i, flags, lookup_count;
5781 HB_GPOSHeader* gpos = gpi->gpos;
5782 HB_Lookup* lo;
5783 int lookup_type;
5784
5785
5786 nesting_level++;
5787
5788 if ( nesting_level > HB_MAX_NESTING_LEVEL )
5789 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
5790
5791 lookup_count = gpos->LookupList.LookupCount;
5792 if (lookup_index >= lookup_count)
5793 return error;
5794
5795 lo = &gpos->LookupList.Lookup[lookup_index];
5796 flags = lo->LookupFlag;
5797 lookup_type = lo->LookupType;
5798
5799 for ( i = 0; i < lo->SubTableCount; i++ )
5800 {
5801 HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
5802
5803 switch (lookup_type) {
5804 case HB_GPOS_LOOKUP_SINGLE:
5805 error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5806 case HB_GPOS_LOOKUP_PAIR:
5807 error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5808 case HB_GPOS_LOOKUP_CURSIVE:
5809 error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5810 case HB_GPOS_LOOKUP_MARKBASE:
5811 error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5812 case HB_GPOS_LOOKUP_MARKLIG:
5813 error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5814 case HB_GPOS_LOOKUP_MARKMARK:
5815 error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5816 case HB_GPOS_LOOKUP_CONTEXT:
5817 error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5818 case HB_GPOS_LOOKUP_CHAIN:
5819 error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
5820 /*case HB_GPOS_LOOKUP_EXTENSION:
5821 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
5822 default:
5823 error = HB_Err_Not_Covered;
5824 }
5825
5826 /* Check whether we have a successful positioning or an error other
5827 than HB_Err_Not_Covered */
5828 if ( error != HB_Err_Not_Covered )
5829 return error;
5830 }
5831
5832 return HB_Err_Not_Covered;
5833 }
5834
5835
5836 HB_INTERNAL HB_Error
_HB_GPOS_Load_SubTable(HB_GPOS_SubTable * st,HB_Stream stream,HB_UShort lookup_type)5837 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
5838 HB_Stream stream,
5839 HB_UShort lookup_type )
5840 {
5841 switch ( lookup_type ) {
5842 case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream );
5843 case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream );
5844 case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream );
5845 case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream );
5846 case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream );
5847 case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream );
5848 case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream );
5849 case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream );
5850 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/
5851 default: return ERR(HB_Err_Invalid_SubTable_Format);
5852 }
5853 }
5854
5855
5856 HB_INTERNAL void
_HB_GPOS_Free_SubTable(HB_GPOS_SubTable * st,HB_UShort lookup_type)5857 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
5858 HB_UShort lookup_type )
5859 {
5860 switch ( lookup_type ) {
5861 case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return;
5862 case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return;
5863 case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return;
5864 case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return;
5865 case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return;
5866 case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return;
5867 case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return;
5868 case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return;
5869 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/
5870 default: return;
5871 }
5872 }
5873
5874
5875 /* apply one lookup to the input string object */
5876
GPOS_Do_String_Lookup(GPOS_Instance * gpi,HB_UShort lookup_index,HB_Buffer buffer)5877 static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
5878 HB_UShort lookup_index,
5879 HB_Buffer buffer )
5880 {
5881 HB_Error error, retError = HB_Err_Not_Covered;
5882 HB_GPOSHeader* gpos = gpi->gpos;
5883
5884 HB_UInt* properties = gpos->LookupList.Properties;
5885
5886 const int nesting_level = 0;
5887 /* 0xFFFF indicates that we don't have a context length yet */
5888 const HB_UShort context_length = 0xFFFF;
5889
5890
5891 gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
5892
5893 buffer->in_pos = 0;
5894 while ( buffer->in_pos < buffer->in_length )
5895 {
5896 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
5897 {
5898 /* Note that the connection between mark and base glyphs hold
5899 exactly one (string) lookup. For example, it would be possible
5900 that in the first lookup, mark glyph X is attached to base
5901 glyph A, and in the next lookup it is attached to base glyph B.
5902 It is up to the font designer to provide meaningful lookups and
5903 lookup order. */
5904
5905 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
5906 if ( error && error != HB_Err_Not_Covered )
5907 return error;
5908 }
5909 else
5910 {
5911 /* Contrary to properties defined in GDEF, user-defined properties
5912 will always stop a possible cursive positioning. */
5913 gpi->last = 0xFFFF;
5914
5915 error = HB_Err_Not_Covered;
5916 }
5917
5918 if ( error == HB_Err_Not_Covered )
5919 (buffer->in_pos)++;
5920 else
5921 retError = error;
5922 }
5923
5924 return retError;
5925 }
5926
5927
Position_CursiveChain(HB_Buffer buffer)5928 static HB_Error Position_CursiveChain ( HB_Buffer buffer )
5929 {
5930 HB_UInt i, j;
5931 HB_Position positions = buffer->positions;
5932
5933 /* First handle all left-to-right connections */
5934 for (j = 0; j < buffer->in_length; j++)
5935 {
5936 if (positions[j].cursive_chain > 0)
5937 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5938 }
5939
5940 /* Then handle all right-to-left connections */
5941 for (i = buffer->in_length; i > 0; i--)
5942 {
5943 j = i - 1;
5944
5945 if (positions[j].cursive_chain < 0)
5946 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
5947 }
5948
5949 return HB_Err_Ok;
5950 }
5951
5952
HB_GPOS_Add_Feature(HB_GPOSHeader * gpos,HB_UShort feature_index,HB_UInt property)5953 HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
5954 HB_UShort feature_index,
5955 HB_UInt property )
5956 {
5957 HB_UShort i;
5958
5959 HB_Feature feature;
5960 HB_UInt* properties;
5961 HB_UShort* index;
5962 HB_UShort lookup_count;
5963
5964 /* Each feature can only be added once */
5965
5966 if ( !gpos ||
5967 feature_index >= gpos->FeatureList.FeatureCount ||
5968 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
5969 return ERR(HB_Err_Invalid_Argument);
5970
5971 gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
5972
5973 properties = gpos->LookupList.Properties;
5974
5975 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
5976 index = feature.LookupListIndex;
5977 lookup_count = gpos->LookupList.LookupCount;
5978
5979 for ( i = 0; i < feature.LookupListCount; i++ )
5980 {
5981 HB_UShort lookup_index = index[i];
5982 if (lookup_index < lookup_count)
5983 properties[lookup_index] |= property;
5984 }
5985
5986 return HB_Err_Ok;
5987 }
5988
5989
5990
HB_GPOS_Clear_Features(HB_GPOSHeader * gpos)5991 HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
5992 {
5993 HB_UShort i;
5994
5995 HB_UInt* properties;
5996
5997
5998 if ( !gpos )
5999 return ERR(HB_Err_Invalid_Argument);
6000
6001 gpos->FeatureList.ApplyCount = 0;
6002
6003 properties = gpos->LookupList.Properties;
6004
6005 for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
6006 properties[i] = 0;
6007
6008 return HB_Err_Ok;
6009 }
6010
6011 #ifdef HB_SUPPORT_MULTIPLE_MASTER
HB_GPOS_Register_MM_Function(HB_GPOSHeader * gpos,HB_MMFunction mmfunc,void * data)6012 HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
6013 HB_MMFunction mmfunc,
6014 void* data )
6015 {
6016 if ( !gpos )
6017 return ERR(HB_Err_Invalid_Argument);
6018
6019 gpos->mmfunc = mmfunc;
6020 gpos->data = data;
6021
6022 return HB_Err_Ok;
6023 }
6024 #endif
6025
6026 /* If `dvi' is TRUE, glyph contour points for anchor points and device
6027 tables are ignored -- you will get device independent values. */
6028
6029
HB_GPOS_Apply_String(HB_Font font,HB_GPOSHeader * gpos,HB_UShort load_flags,HB_Buffer buffer,HB_Bool dvi,HB_Bool r2l)6030 HB_Error HB_GPOS_Apply_String( HB_Font font,
6031 HB_GPOSHeader* gpos,
6032 HB_UShort load_flags,
6033 HB_Buffer buffer,
6034 HB_Bool dvi,
6035 HB_Bool r2l )
6036 {
6037 HB_Error error, retError = HB_Err_Not_Covered;
6038 GPOS_Instance gpi;
6039 int i, j, lookup_count, num_features;
6040
6041 if ( !font || !gpos || !buffer )
6042 return ERR(HB_Err_Invalid_Argument);
6043
6044 if ( buffer->in_length == 0 )
6045 return HB_Err_Not_Covered;
6046
6047 gpi.font = font;
6048 gpi.gpos = gpos;
6049 gpi.load_flags = load_flags;
6050 gpi.r2l = r2l;
6051 gpi.dvi = dvi;
6052
6053 lookup_count = gpos->LookupList.LookupCount;
6054 num_features = gpos->FeatureList.ApplyCount;
6055
6056 if ( num_features )
6057 {
6058 error = _hb_buffer_clear_positions( buffer );
6059 if ( error )
6060 return error;
6061 }
6062
6063 for ( i = 0; i < num_features; i++ )
6064 {
6065 HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i];
6066 HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
6067
6068 for ( j = 0; j < feature.LookupListCount; j++ )
6069 {
6070 HB_UShort lookup_index = feature.LookupListIndex[j];
6071
6072 /* Skip nonexistant lookups */
6073 if (lookup_index >= lookup_count)
6074 continue;
6075
6076 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
6077 if ( error )
6078 {
6079 if ( error != HB_Err_Not_Covered )
6080 return error;
6081 }
6082 else
6083 retError = error;
6084 }
6085 }
6086
6087 if ( num_features )
6088 {
6089 error = Position_CursiveChain ( buffer );
6090 if ( error )
6091 return error;
6092 }
6093
6094 return retError;
6095 }
6096
6097 /* END */
6098