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