OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg | |
3 * Copyright (C) 2006 Behdad Esfahbod | |
4 * | |
5 * This is part of HarfBuzz, an OpenType Layout engine library. | |
6 * | |
7 * Permission is hereby granted, without written agreement and without | |
8 * license or royalty fees, to use, copy, modify, and distribute this | |
9 * software and its documentation for any purpose, provided that the | |
10 * above copyright notice and the following two paragraphs appear in | |
11 * all copies of this software. | |
12 * | |
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
17 * DAMAGE. | |
18 * | |
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
24 */ | |
25 | |
26 #include "harfbuzz-impl.h" | |
27 #include "harfbuzz-gdef-private.h" | |
28 #include "harfbuzz-open-private.h" | |
29 | |
30 static HB_Error Load_AttachList( HB_AttachList* al, | |
31 HB_Stream stream ); | |
32 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl, | |
33 HB_Stream stream ); | |
34 | |
35 static void Free_AttachList( HB_AttachList* al); | |
36 static void Free_LigCaretList( HB_LigCaretList* lcl); | |
37 | |
38 static void Free_NewGlyphClasses( HB_GDEFHeader* gdef); | |
39 | |
40 | |
41 | |
42 /* GDEF glyph classes */ | |
43 | |
44 #define UNCLASSIFIED_GLYPH 0 | |
45 #define SIMPLE_GLYPH 1 | |
46 #define LIGATURE_GLYPH 2 | |
47 #define MARK_GLYPH 3 | |
48 #define COMPONENT_GLYPH 4 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 HB_Error HB_New_GDEF_Table( HB_GDEFHeader** retptr ) | |
56 { | |
57 HB_Error error; | |
58 | |
59 HB_GDEFHeader* gdef; | |
60 | |
61 if ( !retptr ) | |
62 return ERR(HB_Err_Invalid_Argument); | |
63 | |
64 if ( ALLOC( gdef, sizeof( *gdef ) ) ) | |
65 return error; | |
66 | |
67 gdef->GlyphClassDef.loaded = FALSE; | |
68 gdef->AttachList.loaded = FALSE; | |
69 gdef->LigCaretList.loaded = FALSE; | |
70 gdef->MarkAttachClassDef_offset = 0; | |
71 gdef->MarkAttachClassDef.loaded = FALSE; | |
72 | |
73 gdef->LastGlyph = 0; | |
74 gdef->NewGlyphClasses = NULL; | |
75 | |
76 *retptr = gdef; | |
77 | |
78 return HB_Err_Ok; | |
79 } | |
80 | |
81 | |
82 HB_Error HB_Load_GDEF_Table( HB_Stream stream, | |
83 HB_GDEFHeader** retptr ) | |
84 { | |
85 HB_Error error; | |
86 HB_UInt cur_offset, new_offset, base_offset; | |
87 | |
88 HB_GDEFHeader* gdef; | |
89 | |
90 | |
91 if ( !retptr ) | |
92 return ERR(HB_Err_Invalid_Argument); | |
93 | |
94 if ( GOTO_Table( TTAG_GDEF ) ) | |
95 return error; | |
96 | |
97 if (( error = HB_New_GDEF_Table ( &gdef ) )) | |
98 return error; | |
99 | |
100 base_offset = FILE_Pos(); | |
101 | |
102 /* skip version */ | |
103 | |
104 if ( FILE_Seek( base_offset + 4L ) || | |
105 ACCESS_Frame( 2L ) ) | |
106 goto Fail0; | |
107 | |
108 new_offset = GET_UShort(); | |
109 | |
110 FORGET_Frame(); | |
111 | |
112 /* all GDEF subtables are optional */ | |
113 | |
114 if ( new_offset ) | |
115 { | |
116 new_offset += base_offset; | |
117 | |
118 /* only classes 1-4 are allowed here */ | |
119 | |
120 cur_offset = FILE_Pos(); | |
121 if ( FILE_Seek( new_offset ) || | |
122 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->GlyphClassDef, 5, | |
123 stream ) ) != HB_Err_Ok ) | |
124 goto Fail0; | |
125 (void)FILE_Seek( cur_offset ); | |
126 } | |
127 | |
128 if ( ACCESS_Frame( 2L ) ) | |
129 goto Fail1; | |
130 | |
131 new_offset = GET_UShort(); | |
132 | |
133 FORGET_Frame(); | |
134 | |
135 if ( new_offset ) | |
136 { | |
137 new_offset += base_offset; | |
138 | |
139 cur_offset = FILE_Pos(); | |
140 if ( FILE_Seek( new_offset ) || | |
141 ( error = Load_AttachList( &gdef->AttachList, | |
142 stream ) ) != HB_Err_Ok ) | |
143 goto Fail1; | |
144 (void)FILE_Seek( cur_offset ); | |
145 } | |
146 | |
147 if ( ACCESS_Frame( 2L ) ) | |
148 goto Fail2; | |
149 | |
150 new_offset = GET_UShort(); | |
151 | |
152 FORGET_Frame(); | |
153 | |
154 if ( new_offset ) | |
155 { | |
156 new_offset += base_offset; | |
157 | |
158 cur_offset = FILE_Pos(); | |
159 if ( FILE_Seek( new_offset ) || | |
160 ( error = Load_LigCaretList( &gdef->LigCaretList, | |
161 stream ) ) != HB_Err_Ok ) | |
162 goto Fail2; | |
163 (void)FILE_Seek( cur_offset ); | |
164 } | |
165 | |
166 /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We | |
167 first have to scan the LookupFlag values to find out whether we | |
168 must load it or not. Here we only store the offset of the table. */ | |
169 | |
170 if ( ACCESS_Frame( 2L ) ) | |
171 goto Fail3; | |
172 | |
173 new_offset = GET_UShort(); | |
174 | |
175 FORGET_Frame(); | |
176 | |
177 if ( new_offset ) | |
178 gdef->MarkAttachClassDef_offset = new_offset + base_offset; | |
179 else | |
180 gdef->MarkAttachClassDef_offset = 0; | |
181 | |
182 *retptr = gdef; | |
183 | |
184 return HB_Err_Ok; | |
185 | |
186 Fail3: | |
187 Free_LigCaretList( &gdef->LigCaretList ); | |
188 | |
189 Fail2: | |
190 Free_AttachList( &gdef->AttachList ); | |
191 | |
192 Fail1: | |
193 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef ); | |
194 | |
195 Fail0: | |
196 FREE( gdef ); | |
197 | |
198 return error; | |
199 } | |
200 | |
201 | |
202 HB_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef ) | |
203 { | |
204 Free_LigCaretList( &gdef->LigCaretList ); | |
205 Free_AttachList( &gdef->AttachList ); | |
206 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef ); | |
207 _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef ); | |
208 | |
209 Free_NewGlyphClasses( gdef ); | |
210 | |
211 FREE( gdef ); | |
212 | |
213 return HB_Err_Ok; | |
214 } | |
215 | |
216 | |
217 | |
218 | |
219 /******************************* | |
220 * AttachList related functions | |
221 *******************************/ | |
222 | |
223 | |
224 /* AttachPoint */ | |
225 | |
226 static HB_Error Load_AttachPoint( HB_AttachPoint* ap, | |
227 HB_Stream stream ) | |
228 { | |
229 HB_Error error; | |
230 | |
231 HB_UShort n, count; | |
232 HB_UShort* pi; | |
233 | |
234 | |
235 if ( ACCESS_Frame( 2L ) ) | |
236 return error; | |
237 | |
238 count = ap->PointCount = GET_UShort(); | |
239 | |
240 FORGET_Frame(); | |
241 | |
242 ap->PointIndex = NULL; | |
243 | |
244 if ( count ) | |
245 { | |
246 if ( ALLOC_ARRAY( ap->PointIndex, count, HB_UShort ) ) | |
247 return error; | |
248 | |
249 pi = ap->PointIndex; | |
250 | |
251 if ( ACCESS_Frame( count * 2L ) ) | |
252 { | |
253 FREE( pi ); | |
254 return error; | |
255 } | |
256 | |
257 for ( n = 0; n < count; n++ ) | |
258 pi[n] = GET_UShort(); | |
259 | |
260 FORGET_Frame(); | |
261 } | |
262 | |
263 return HB_Err_Ok; | |
264 } | |
265 | |
266 | |
267 static void Free_AttachPoint( HB_AttachPoint* ap ) | |
268 { | |
269 FREE( ap->PointIndex ); | |
270 } | |
271 | |
272 | |
273 /* AttachList */ | |
274 | |
275 static HB_Error Load_AttachList( HB_AttachList* al, | |
276 HB_Stream stream ) | |
277 { | |
278 HB_Error error; | |
279 | |
280 HB_UShort n, m, count; | |
281 HB_UInt cur_offset, new_offset, base_offset; | |
282 | |
283 HB_AttachPoint* ap; | |
284 | |
285 | |
286 base_offset = FILE_Pos(); | |
287 | |
288 if ( ACCESS_Frame( 2L ) ) | |
289 return error; | |
290 | |
291 new_offset = GET_UShort() + base_offset; | |
292 | |
293 FORGET_Frame(); | |
294 | |
295 cur_offset = FILE_Pos(); | |
296 if ( FILE_Seek( new_offset ) || | |
297 ( error = _HB_OPEN_Load_Coverage( &al->Coverage, stream ) ) != HB_Err_Ok
) | |
298 return error; | |
299 (void)FILE_Seek( cur_offset ); | |
300 | |
301 if ( ACCESS_Frame( 2L ) ) | |
302 goto Fail2; | |
303 | |
304 count = al->GlyphCount = GET_UShort(); | |
305 | |
306 FORGET_Frame(); | |
307 | |
308 al->AttachPoint = NULL; | |
309 | |
310 if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) ) | |
311 goto Fail2; | |
312 | |
313 ap = al->AttachPoint; | |
314 | |
315 for ( n = 0; n < count; n++ ) | |
316 { | |
317 if ( ACCESS_Frame( 2L ) ) | |
318 goto Fail1; | |
319 | |
320 new_offset = GET_UShort() + base_offset; | |
321 | |
322 FORGET_Frame(); | |
323 | |
324 cur_offset = FILE_Pos(); | |
325 if ( FILE_Seek( new_offset ) || | |
326 ( error = Load_AttachPoint( &ap[n], stream ) ) != HB_Err_Ok ) | |
327 goto Fail1; | |
328 (void)FILE_Seek( cur_offset ); | |
329 } | |
330 | |
331 al->loaded = TRUE; | |
332 | |
333 return HB_Err_Ok; | |
334 | |
335 Fail1: | |
336 for ( m = 0; m < n; m++ ) | |
337 Free_AttachPoint( &ap[m] ); | |
338 | |
339 FREE( ap ); | |
340 | |
341 Fail2: | |
342 _HB_OPEN_Free_Coverage( &al->Coverage ); | |
343 return error; | |
344 } | |
345 | |
346 | |
347 static void Free_AttachList( HB_AttachList* al) | |
348 { | |
349 HB_UShort n, count; | |
350 | |
351 HB_AttachPoint* ap; | |
352 | |
353 | |
354 if ( !al->loaded ) | |
355 return; | |
356 | |
357 if ( al->AttachPoint ) | |
358 { | |
359 count = al->GlyphCount; | |
360 ap = al->AttachPoint; | |
361 | |
362 for ( n = 0; n < count; n++ ) | |
363 Free_AttachPoint( &ap[n] ); | |
364 | |
365 FREE( ap ); | |
366 } | |
367 | |
368 _HB_OPEN_Free_Coverage( &al->Coverage ); | |
369 } | |
370 | |
371 | |
372 | |
373 /********************************* | |
374 * LigCaretList related functions | |
375 *********************************/ | |
376 | |
377 | |
378 /* CaretValueFormat1 */ | |
379 /* CaretValueFormat2 */ | |
380 /* CaretValueFormat3 */ | |
381 /* CaretValueFormat4 */ | |
382 | |
383 static HB_Error Load_CaretValue( HB_CaretValue* cv, | |
384 HB_Stream stream ) | |
385 { | |
386 HB_Error error; | |
387 | |
388 HB_UInt cur_offset, new_offset, base_offset; | |
389 | |
390 | |
391 base_offset = FILE_Pos(); | |
392 | |
393 if ( ACCESS_Frame( 2L ) ) | |
394 return error; | |
395 | |
396 cv->CaretValueFormat = GET_UShort(); | |
397 | |
398 FORGET_Frame(); | |
399 | |
400 switch ( cv->CaretValueFormat ) | |
401 { | |
402 case 1: | |
403 if ( ACCESS_Frame( 2L ) ) | |
404 return error; | |
405 | |
406 cv->cvf.cvf1.Coordinate = GET_Short(); | |
407 | |
408 FORGET_Frame(); | |
409 | |
410 break; | |
411 | |
412 case 2: | |
413 if ( ACCESS_Frame( 2L ) ) | |
414 return error; | |
415 | |
416 cv->cvf.cvf2.CaretValuePoint = GET_UShort(); | |
417 | |
418 FORGET_Frame(); | |
419 | |
420 break; | |
421 | |
422 case 3: | |
423 if ( ACCESS_Frame( 4L ) ) | |
424 return error; | |
425 | |
426 cv->cvf.cvf3.Coordinate = GET_Short(); | |
427 | |
428 new_offset = GET_UShort() + base_offset; | |
429 | |
430 FORGET_Frame(); | |
431 | |
432 cur_offset = FILE_Pos(); | |
433 if ( FILE_Seek( new_offset ) || | |
434 ( error = _HB_OPEN_Load_Device( &cv->cvf.cvf3.Device, | |
435 stream ) ) != HB_Err_Ok ) | |
436 return error; | |
437 (void)FILE_Seek( cur_offset ); | |
438 | |
439 break; | |
440 | |
441 case 4: | |
442 if ( ACCESS_Frame( 2L ) ) | |
443 return error; | |
444 | |
445 #ifdef HB_SUPPORT_MULTIPLE_MASTER | |
446 cv->cvf.cvf4.IdCaretValue = GET_UShort(); | |
447 #else | |
448 (void) GET_UShort(); | |
449 #endif | |
450 | |
451 FORGET_Frame(); | |
452 break; | |
453 | |
454 default: | |
455 return ERR(HB_Err_Invalid_SubTable_Format); | |
456 } | |
457 | |
458 return HB_Err_Ok; | |
459 } | |
460 | |
461 | |
462 static void Free_CaretValue( HB_CaretValue* cv) | |
463 { | |
464 if ( cv->CaretValueFormat == 3 ) | |
465 _HB_OPEN_Free_Device( cv->cvf.cvf3.Device ); | |
466 } | |
467 | |
468 | |
469 /* LigGlyph */ | |
470 | |
471 static HB_Error Load_LigGlyph( HB_LigGlyph* lg, | |
472 HB_Stream stream ) | |
473 { | |
474 HB_Error error; | |
475 | |
476 HB_UShort n, m, count; | |
477 HB_UInt cur_offset, new_offset, base_offset; | |
478 | |
479 HB_CaretValue* cv; | |
480 | |
481 | |
482 base_offset = FILE_Pos(); | |
483 | |
484 if ( ACCESS_Frame( 2L ) ) | |
485 return error; | |
486 | |
487 count = lg->CaretCount = GET_UShort(); | |
488 | |
489 FORGET_Frame(); | |
490 | |
491 lg->CaretValue = NULL; | |
492 | |
493 if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) ) | |
494 return error; | |
495 | |
496 cv = lg->CaretValue; | |
497 | |
498 for ( n = 0; n < count; n++ ) | |
499 { | |
500 if ( ACCESS_Frame( 2L ) ) | |
501 goto Fail; | |
502 | |
503 new_offset = GET_UShort() + base_offset; | |
504 | |
505 FORGET_Frame(); | |
506 | |
507 cur_offset = FILE_Pos(); | |
508 if ( FILE_Seek( new_offset ) || | |
509 ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok ) | |
510 goto Fail; | |
511 (void)FILE_Seek( cur_offset ); | |
512 } | |
513 | |
514 return HB_Err_Ok; | |
515 | |
516 Fail: | |
517 for ( m = 0; m < n; m++ ) | |
518 Free_CaretValue( &cv[m] ); | |
519 | |
520 FREE( cv ); | |
521 return error; | |
522 } | |
523 | |
524 | |
525 static void Free_LigGlyph( HB_LigGlyph* lg) | |
526 { | |
527 HB_UShort n, count; | |
528 | |
529 HB_CaretValue* cv; | |
530 | |
531 | |
532 if ( lg->CaretValue ) | |
533 { | |
534 count = lg->CaretCount; | |
535 cv = lg->CaretValue; | |
536 | |
537 for ( n = 0; n < count; n++ ) | |
538 Free_CaretValue( &cv[n] ); | |
539 | |
540 FREE( cv ); | |
541 } | |
542 } | |
543 | |
544 | |
545 /* LigCaretList */ | |
546 | |
547 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl, | |
548 HB_Stream stream ) | |
549 { | |
550 HB_Error error; | |
551 | |
552 HB_UShort m, n, count; | |
553 HB_UInt cur_offset, new_offset, base_offset; | |
554 | |
555 HB_LigGlyph* lg; | |
556 | |
557 | |
558 base_offset = FILE_Pos(); | |
559 | |
560 if ( ACCESS_Frame( 2L ) ) | |
561 return error; | |
562 | |
563 new_offset = GET_UShort() + base_offset; | |
564 | |
565 FORGET_Frame(); | |
566 | |
567 cur_offset = FILE_Pos(); | |
568 if ( FILE_Seek( new_offset ) || | |
569 ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok
) | |
570 return error; | |
571 (void)FILE_Seek( cur_offset ); | |
572 | |
573 if ( ACCESS_Frame( 2L ) ) | |
574 goto Fail2; | |
575 | |
576 count = lcl->LigGlyphCount = GET_UShort(); | |
577 | |
578 FORGET_Frame(); | |
579 | |
580 lcl->LigGlyph = NULL; | |
581 | |
582 if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) ) | |
583 goto Fail2; | |
584 | |
585 lg = lcl->LigGlyph; | |
586 | |
587 for ( n = 0; n < count; n++ ) | |
588 { | |
589 if ( ACCESS_Frame( 2L ) ) | |
590 goto Fail1; | |
591 | |
592 new_offset = GET_UShort() + base_offset; | |
593 | |
594 FORGET_Frame(); | |
595 | |
596 cur_offset = FILE_Pos(); | |
597 if ( FILE_Seek( new_offset ) || | |
598 ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok ) | |
599 goto Fail1; | |
600 (void)FILE_Seek( cur_offset ); | |
601 } | |
602 | |
603 lcl->loaded = TRUE; | |
604 | |
605 return HB_Err_Ok; | |
606 | |
607 Fail1: | |
608 for ( m = 0; m < n; m++ ) | |
609 Free_LigGlyph( &lg[m] ); | |
610 | |
611 FREE( lg ); | |
612 | |
613 Fail2: | |
614 _HB_OPEN_Free_Coverage( &lcl->Coverage ); | |
615 return error; | |
616 } | |
617 | |
618 | |
619 static void Free_LigCaretList( HB_LigCaretList* lcl ) | |
620 { | |
621 HB_UShort n, count; | |
622 | |
623 HB_LigGlyph* lg; | |
624 | |
625 | |
626 if ( !lcl->loaded ) | |
627 return; | |
628 | |
629 if ( lcl->LigGlyph ) | |
630 { | |
631 count = lcl->LigGlyphCount; | |
632 lg = lcl->LigGlyph; | |
633 | |
634 for ( n = 0; n < count; n++ ) | |
635 Free_LigGlyph( &lg[n] ); | |
636 | |
637 FREE( lg ); | |
638 } | |
639 | |
640 _HB_OPEN_Free_Coverage( &lcl->Coverage ); | |
641 } | |
642 | |
643 | |
644 | |
645 /*********** | |
646 * GDEF API | |
647 ***********/ | |
648 | |
649 | |
650 static HB_UShort Get_New_Class( HB_GDEFHeader* gdef, | |
651 HB_UShort glyphID, | |
652 HB_UShort index ) | |
653 { | |
654 HB_UShort glyph_index, array_index, count; | |
655 HB_UShort byte, bits; | |
656 | |
657 HB_ClassRangeRecord* gcrr; | |
658 HB_UShort** ngc; | |
659 | |
660 | |
661 if ( glyphID >= gdef->LastGlyph ) | |
662 return 0; | |
663 | |
664 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; | |
665 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; | |
666 ngc = gdef->NewGlyphClasses; | |
667 | |
668 if ( index < count && glyphID < gcrr[index].Start ) | |
669 { | |
670 array_index = index; | |
671 if ( index == 0 ) | |
672 glyph_index = glyphID; | |
673 else | |
674 glyph_index = glyphID - gcrr[index - 1].End - 1; | |
675 } | |
676 else | |
677 { | |
678 array_index = index + 1; | |
679 glyph_index = glyphID - gcrr[index].End - 1; | |
680 } | |
681 | |
682 byte = ngc[array_index][glyph_index / 4]; | |
683 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); | |
684 | |
685 return bits & 0x000F; | |
686 } | |
687 | |
688 | |
689 | |
690 HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef, | |
691 HB_UShort glyphID, | |
692 HB_UShort* property ) | |
693 { | |
694 HB_UShort class = 0, index = 0; /* shut compiler up */ | |
695 | |
696 HB_Error error; | |
697 | |
698 | |
699 if ( !gdef || !property ) | |
700 return ERR(HB_Err_Invalid_Argument); | |
701 | |
702 /* first, we check for mark attach classes */ | |
703 | |
704 if ( gdef->MarkAttachClassDef.loaded ) | |
705 { | |
706 error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &ind
ex ); | |
707 if ( error && error != HB_Err_Not_Covered ) | |
708 return error; | |
709 if ( !error ) | |
710 { | |
711 *property = class << 8; | |
712 return HB_Err_Ok; | |
713 } | |
714 } | |
715 | |
716 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); | |
717 if ( error && error != HB_Err_Not_Covered ) | |
718 return error; | |
719 | |
720 /* if we have a constructed class table, check whether additional | |
721 values have been assigned */ | |
722 | |
723 if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses ) | |
724 class = Get_New_Class( gdef, glyphID, index ); | |
725 | |
726 switch ( class ) | |
727 { | |
728 default: | |
729 case UNCLASSIFIED_GLYPH: | |
730 *property = 0; | |
731 break; | |
732 | |
733 case SIMPLE_GLYPH: | |
734 *property = HB_GDEF_BASE_GLYPH; | |
735 break; | |
736 | |
737 case LIGATURE_GLYPH: | |
738 *property = HB_GDEF_LIGATURE; | |
739 break; | |
740 | |
741 case MARK_GLYPH: | |
742 *property = HB_GDEF_MARK; | |
743 break; | |
744 | |
745 case COMPONENT_GLYPH: | |
746 *property = HB_GDEF_COMPONENT; | |
747 break; | |
748 } | |
749 | |
750 return HB_Err_Ok; | |
751 } | |
752 | |
753 | |
754 static HB_Error Make_ClassRange( HB_ClassDefinition* cd, | |
755 HB_UShort start, | |
756 HB_UShort end, | |
757 HB_UShort class ) | |
758 { | |
759 HB_Error error; | |
760 HB_UShort index; | |
761 | |
762 HB_ClassDefFormat2* cdf2; | |
763 HB_ClassRangeRecord* crr; | |
764 | |
765 | |
766 cdf2 = &cd->cd.cd2; | |
767 | |
768 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, | |
769 cdf2->ClassRangeCount + 1 , | |
770 HB_ClassRangeRecord ) ) | |
771 return error; | |
772 | |
773 cdf2->ClassRangeCount++; | |
774 | |
775 crr = cdf2->ClassRangeRecord; | |
776 index = cdf2->ClassRangeCount - 1; | |
777 | |
778 crr[index].Start = start; | |
779 crr[index].End = end; | |
780 crr[index].Class = class; | |
781 | |
782 return HB_Err_Ok; | |
783 } | |
784 | |
785 | |
786 | |
787 HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef, | |
788 HB_UShort num_glyphs, | |
789 HB_UShort glyph_count, | |
790 HB_UShort* glyph_array, | |
791 HB_UShort* class_array ) | |
792 { | |
793 HB_UShort start, curr_glyph, curr_class; | |
794 HB_UShort n, m, count; | |
795 HB_Error error; | |
796 | |
797 HB_ClassDefinition* gcd; | |
798 HB_ClassRangeRecord* gcrr; | |
799 HB_UShort** ngc; | |
800 | |
801 | |
802 if ( !gdef || !glyph_array || !class_array ) | |
803 return ERR(HB_Err_Invalid_Argument); | |
804 | |
805 gcd = &gdef->GlyphClassDef; | |
806 | |
807 /* We build a format 2 table */ | |
808 | |
809 gcd->ClassFormat = 2; | |
810 | |
811 gcd->cd.cd2.ClassRangeCount = 0; | |
812 gcd->cd.cd2.ClassRangeRecord = NULL; | |
813 | |
814 start = glyph_array[0]; | |
815 curr_class = class_array[0]; | |
816 curr_glyph = start; | |
817 | |
818 if ( curr_class >= 5 ) | |
819 { | |
820 error = ERR(HB_Err_Invalid_Argument); | |
821 goto Fail4; | |
822 } | |
823 | |
824 glyph_count--; | |
825 | |
826 for ( n = 0; n < glyph_count + 1; n++ ) | |
827 { | |
828 if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] ) | |
829 { | |
830 if ( n == glyph_count ) | |
831 { | |
832 if ( ( error = Make_ClassRange( gcd, start, | |
833 curr_glyph, | |
834 curr_class) ) != HB_Err_Ok ) | |
835 goto Fail3; | |
836 } | |
837 else | |
838 { | |
839 if ( curr_glyph == 0xFFFF ) | |
840 { | |
841 error = ERR(HB_Err_Invalid_Argument); | |
842 goto Fail3; | |
843 } | |
844 else | |
845 curr_glyph++; | |
846 } | |
847 } | |
848 else | |
849 { | |
850 if ( ( error = Make_ClassRange( gcd, start, | |
851 curr_glyph - 1, | |
852 curr_class) ) != HB_Err_Ok ) | |
853 goto Fail3; | |
854 | |
855 if ( curr_glyph > glyph_array[n] ) | |
856 { | |
857 error = ERR(HB_Err_Invalid_Argument); | |
858 goto Fail3; | |
859 } | |
860 | |
861 start = glyph_array[n]; | |
862 curr_class = class_array[n]; | |
863 curr_glyph = start; | |
864 | |
865 if ( curr_class >= 5 ) | |
866 { | |
867 error = ERR(HB_Err_Invalid_Argument); | |
868 goto Fail3; | |
869 } | |
870 | |
871 if ( n == glyph_count ) | |
872 { | |
873 if ( ( error = Make_ClassRange( gcd, start, | |
874 curr_glyph, | |
875 curr_class) ) != HB_Err_Ok ) | |
876 goto Fail3; | |
877 } | |
878 else | |
879 { | |
880 if ( curr_glyph == 0xFFFF ) | |
881 { | |
882 error = ERR(HB_Err_Invalid_Argument); | |
883 goto Fail3; | |
884 } | |
885 else | |
886 curr_glyph++; | |
887 } | |
888 } | |
889 } | |
890 | |
891 /* now prepare the arrays for class values assigned during the lookup | |
892 process */ | |
893 | |
894 if ( ALLOC_ARRAY( gdef->NewGlyphClasses, | |
895 gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) ) | |
896 goto Fail3; | |
897 | |
898 count = gcd->cd.cd2.ClassRangeCount; | |
899 gcrr = gcd->cd.cd2.ClassRangeRecord; | |
900 ngc = gdef->NewGlyphClasses; | |
901 | |
902 /* We allocate arrays for all glyphs not covered by the class range | |
903 records. Each element holds four class values. */ | |
904 | |
905 if ( count > 0 ) | |
906 { | |
907 if ( gcrr[0].Start ) | |
908 { | |
909 if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) ) | |
910 goto Fail2; | |
911 } | |
912 | |
913 for ( n = 1; n < count; n++ ) | |
914 { | |
915 if ( gcrr[n].Start - gcrr[n - 1].End > 1 ) | |
916 if ( ALLOC_ARRAY( ngc[n], | |
917 ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4, | |
918 HB_UShort ) ) | |
919 goto Fail1; | |
920 } | |
921 | |
922 if ( gcrr[count - 1].End != num_glyphs - 1 ) | |
923 { | |
924 if ( ALLOC_ARRAY( ngc[count], | |
925 ( num_glyphs - gcrr[count - 1].End + 2 ) / 4, | |
926 HB_UShort ) ) | |
927 goto Fail1; | |
928 } | |
929 } | |
930 else if ( num_glyphs > 0 ) | |
931 { | |
932 if ( ALLOC_ARRAY( ngc[count], | |
933 ( num_glyphs + 3 ) / 4, | |
934 HB_UShort ) ) | |
935 goto Fail2; | |
936 } | |
937 | |
938 gdef->LastGlyph = num_glyphs - 1; | |
939 | |
940 gdef->MarkAttachClassDef_offset = 0L; | |
941 gdef->MarkAttachClassDef.loaded = FALSE; | |
942 | |
943 gcd->loaded = TRUE; | |
944 | |
945 return HB_Err_Ok; | |
946 | |
947 Fail1: | |
948 for ( m = 0; m < n; m++ ) | |
949 FREE( ngc[m] ); | |
950 | |
951 Fail2: | |
952 FREE( gdef->NewGlyphClasses ); | |
953 | |
954 Fail3: | |
955 FREE( gcd->cd.cd2.ClassRangeRecord ); | |
956 | |
957 Fail4: | |
958 return error; | |
959 } | |
960 | |
961 | |
962 static void Free_NewGlyphClasses( HB_GDEFHeader* gdef ) | |
963 { | |
964 HB_UShort** ngc; | |
965 HB_UShort n, count; | |
966 | |
967 | |
968 if ( gdef->NewGlyphClasses ) | |
969 { | |
970 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1; | |
971 ngc = gdef->NewGlyphClasses; | |
972 | |
973 for ( n = 0; n < count; n++ ) | |
974 FREE( ngc[n] ); | |
975 | |
976 FREE( ngc ); | |
977 } | |
978 } | |
979 | |
980 | |
981 HB_INTERNAL HB_Error | |
982 _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef, | |
983 HB_UShort glyphID, | |
984 HB_UShort property ) | |
985 { | |
986 HB_Error error; | |
987 HB_UShort class, new_class, index = 0; /* shut compiler up */ | |
988 HB_UShort byte, bits, mask; | |
989 HB_UShort array_index, glyph_index, count; | |
990 | |
991 HB_ClassRangeRecord* gcrr; | |
992 HB_UShort** ngc; | |
993 | |
994 | |
995 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); | |
996 if ( error && error != HB_Err_Not_Covered ) | |
997 return error; | |
998 | |
999 /* we don't accept glyphs covered in `GlyphClassDef' */ | |
1000 | |
1001 if ( !error ) | |
1002 return HB_Err_Not_Covered; | |
1003 | |
1004 switch ( property ) | |
1005 { | |
1006 case 0: | |
1007 new_class = UNCLASSIFIED_GLYPH; | |
1008 break; | |
1009 | |
1010 case HB_GDEF_BASE_GLYPH: | |
1011 new_class = SIMPLE_GLYPH; | |
1012 break; | |
1013 | |
1014 case HB_GDEF_LIGATURE: | |
1015 new_class = LIGATURE_GLYPH; | |
1016 break; | |
1017 | |
1018 case HB_GDEF_MARK: | |
1019 new_class = MARK_GLYPH; | |
1020 break; | |
1021 | |
1022 case HB_GDEF_COMPONENT: | |
1023 new_class = COMPONENT_GLYPH; | |
1024 break; | |
1025 | |
1026 default: | |
1027 return ERR(HB_Err_Invalid_Argument); | |
1028 } | |
1029 | |
1030 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; | |
1031 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; | |
1032 ngc = gdef->NewGlyphClasses; | |
1033 | |
1034 if ( index < count && glyphID < gcrr[index].Start ) | |
1035 { | |
1036 array_index = index; | |
1037 if ( index == 0 ) | |
1038 glyph_index = glyphID; | |
1039 else | |
1040 glyph_index = glyphID - gcrr[index - 1].End - 1; | |
1041 } | |
1042 else | |
1043 { | |
1044 array_index = index + 1; | |
1045 glyph_index = glyphID - gcrr[index].End - 1; | |
1046 } | |
1047 | |
1048 byte = ngc[array_index][glyph_index / 4]; | |
1049 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); | |
1050 class = bits & 0x000F; | |
1051 | |
1052 /* we don't overwrite existing entries */ | |
1053 | |
1054 if ( !class ) | |
1055 { | |
1056 bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 ); | |
1057 mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) ); | |
1058 | |
1059 ngc[array_index][glyph_index / 4] &= mask; | |
1060 ngc[array_index][glyph_index / 4] |= bits; | |
1061 } | |
1062 | |
1063 return HB_Err_Ok; | |
1064 } | |
1065 | |
1066 | |
1067 HB_INTERNAL HB_Error | |
1068 _HB_GDEF_Check_Property( HB_GDEFHeader* gdef, | |
1069 HB_GlyphItem gitem, | |
1070 HB_UShort flags, | |
1071 HB_UShort* property ) | |
1072 { | |
1073 HB_Error error; | |
1074 | |
1075 if ( gdef ) | |
1076 { | |
1077 HB_UShort basic_glyph_class; | |
1078 HB_UShort desired_attachment_class; | |
1079 | |
1080 if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN ) | |
1081 { | |
1082 error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperti
es ); | |
1083 if ( error ) | |
1084 return error; | |
1085 } | |
1086 | |
1087 *property = gitem->gproperties; | |
1088 | |
1089 /* If the glyph was found in the MarkAttachmentClass table, | |
1090 * then that class value is the high byte of the result, | |
1091 * otherwise the low byte contains the basic type of the glyph | |
1092 * as defined by the GlyphClassDef table. | |
1093 */ | |
1094 if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) | |
1095 basic_glyph_class = HB_GDEF_MARK; | |
1096 else | |
1097 basic_glyph_class = *property; | |
1098 | |
1099 /* Return Not_Covered, if, for example, basic_glyph_class | |
1100 * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURE
S | |
1101 */ | |
1102 if ( flags & basic_glyph_class ) | |
1103 return HB_Err_Not_Covered; | |
1104 | |
1105 /* The high byte of LookupFlags has the meaning | |
1106 * "ignore marks of attachment type different than | |
1107 * the attachment type specified." | |
1108 */ | |
1109 desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS; | |
1110 if ( desired_attachment_class ) | |
1111 { | |
1112 if ( basic_glyph_class == HB_GDEF_MARK && | |
1113 *property != desired_attachment_class ) | |
1114 return HB_Err_Not_Covered; | |
1115 } | |
1116 } else { | |
1117 *property = 0; | |
1118 } | |
1119 | |
1120 return HB_Err_Ok; | |
1121 } | |
1122 | |
1123 HB_INTERNAL HB_Error | |
1124 _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef, | |
1125 HB_Stream stream, | |
1126 HB_Lookup* lo, | |
1127 HB_UShort num_lookups) | |
1128 { | |
1129 HB_Error error = HB_Err_Ok; | |
1130 HB_UShort i; | |
1131 | |
1132 /* We now check the LookupFlags for values larger than 0xFF to find | |
1133 out whether we need to load the `MarkAttachClassDef' field of the | |
1134 GDEF table -- this hack is necessary for OpenType 1.2 tables since | |
1135 the version field of the GDEF table hasn't been incremented. | |
1136 | |
1137 For constructed GDEF tables, we only load it if | |
1138 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of | |
1139 a constructed mark attach table is not supported currently). */ | |
1140 | |
1141 if ( gdef && | |
1142 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) | |
1143 { | |
1144 for ( i = 0; i < num_lookups; i++ ) | |
1145 { | |
1146 | |
1147 if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) | |
1148 { | |
1149 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || | |
1150 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef, | |
1151 256, stream ) ) != HB_Err_Ok ) | |
1152 goto Done; | |
1153 | |
1154 break; | |
1155 } | |
1156 } | |
1157 } | |
1158 | |
1159 Done: | |
1160 return error; | |
1161 } | |
1162 | |
1163 /* END */ | |
OLD | NEW |