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