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