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 cv->cvf.cvf4.IdCaretValue = GET_UShort(); | |
446 | |
447 FORGET_Frame(); | |
448 break; | |
449 | |
450 default: | |
451 return ERR(HB_Err_Invalid_SubTable_Format); | |
452 } | |
453 | |
454 return HB_Err_Ok; | |
455 } | |
456 | |
457 | |
458 static void Free_CaretValue( HB_CaretValue* cv) | |
459 { | |
460 if ( cv->CaretValueFormat == 3 ) | |
461 _HB_OPEN_Free_Device( &cv->cvf.cvf3.Device ); | |
462 } | |
463 | |
464 | |
465 /* LigGlyph */ | |
466 | |
467 static HB_Error Load_LigGlyph( HB_LigGlyph* lg, | |
468 HB_Stream stream ) | |
469 { | |
470 HB_Error error; | |
471 | |
472 HB_UShort n, m, count; | |
473 HB_UInt cur_offset, new_offset, base_offset; | |
474 | |
475 HB_CaretValue* cv; | |
476 | |
477 | |
478 base_offset = FILE_Pos(); | |
479 | |
480 if ( ACCESS_Frame( 2L ) ) | |
481 return error; | |
482 | |
483 count = lg->CaretCount = GET_UShort(); | |
484 | |
485 FORGET_Frame(); | |
486 | |
487 lg->CaretValue = NULL; | |
488 | |
489 if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) ) | |
490 return error; | |
491 | |
492 cv = lg->CaretValue; | |
493 | |
494 for ( n = 0; n < count; n++ ) | |
495 { | |
496 if ( ACCESS_Frame( 2L ) ) | |
497 goto Fail; | |
498 | |
499 new_offset = GET_UShort() + base_offset; | |
500 | |
501 FORGET_Frame(); | |
502 | |
503 cur_offset = FILE_Pos(); | |
504 if ( FILE_Seek( new_offset ) || | |
505 ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok ) | |
506 goto Fail; | |
507 (void)FILE_Seek( cur_offset ); | |
508 } | |
509 | |
510 return HB_Err_Ok; | |
511 | |
512 Fail: | |
513 for ( m = 0; m < n; m++ ) | |
514 Free_CaretValue( &cv[m] ); | |
515 | |
516 FREE( cv ); | |
517 return error; | |
518 } | |
519 | |
520 | |
521 static void Free_LigGlyph( HB_LigGlyph* lg) | |
522 { | |
523 HB_UShort n, count; | |
524 | |
525 HB_CaretValue* cv; | |
526 | |
527 | |
528 if ( lg->CaretValue ) | |
529 { | |
530 count = lg->CaretCount; | |
531 cv = lg->CaretValue; | |
532 | |
533 for ( n = 0; n < count; n++ ) | |
534 Free_CaretValue( &cv[n] ); | |
535 | |
536 FREE( cv ); | |
537 } | |
538 } | |
539 | |
540 | |
541 /* LigCaretList */ | |
542 | |
543 static HB_Error Load_LigCaretList( HB_LigCaretList* lcl, | |
544 HB_Stream stream ) | |
545 { | |
546 HB_Error error; | |
547 | |
548 HB_UShort m, n, count; | |
549 HB_UInt cur_offset, new_offset, base_offset; | |
550 | |
551 HB_LigGlyph* lg; | |
552 | |
553 | |
554 base_offset = FILE_Pos(); | |
555 | |
556 if ( ACCESS_Frame( 2L ) ) | |
557 return error; | |
558 | |
559 new_offset = GET_UShort() + base_offset; | |
560 | |
561 FORGET_Frame(); | |
562 | |
563 cur_offset = FILE_Pos(); | |
564 if ( FILE_Seek( new_offset ) || | |
565 ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok
) | |
566 return error; | |
567 (void)FILE_Seek( cur_offset ); | |
568 | |
569 if ( ACCESS_Frame( 2L ) ) | |
570 goto Fail2; | |
571 | |
572 count = lcl->LigGlyphCount = GET_UShort(); | |
573 | |
574 FORGET_Frame(); | |
575 | |
576 lcl->LigGlyph = NULL; | |
577 | |
578 if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) ) | |
579 goto Fail2; | |
580 | |
581 lg = lcl->LigGlyph; | |
582 | |
583 for ( n = 0; n < count; n++ ) | |
584 { | |
585 if ( ACCESS_Frame( 2L ) ) | |
586 goto Fail1; | |
587 | |
588 new_offset = GET_UShort() + base_offset; | |
589 | |
590 FORGET_Frame(); | |
591 | |
592 cur_offset = FILE_Pos(); | |
593 if ( FILE_Seek( new_offset ) || | |
594 ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok ) | |
595 goto Fail1; | |
596 (void)FILE_Seek( cur_offset ); | |
597 } | |
598 | |
599 lcl->loaded = TRUE; | |
600 | |
601 return HB_Err_Ok; | |
602 | |
603 Fail1: | |
604 for ( m = 0; m < n; m++ ) | |
605 Free_LigGlyph( &lg[m] ); | |
606 | |
607 FREE( lg ); | |
608 | |
609 Fail2: | |
610 _HB_OPEN_Free_Coverage( &lcl->Coverage ); | |
611 return error; | |
612 } | |
613 | |
614 | |
615 static void Free_LigCaretList( HB_LigCaretList* lcl ) | |
616 { | |
617 HB_UShort n, count; | |
618 | |
619 HB_LigGlyph* lg; | |
620 | |
621 | |
622 if ( !lcl->loaded ) | |
623 return; | |
624 | |
625 if ( lcl->LigGlyph ) | |
626 { | |
627 count = lcl->LigGlyphCount; | |
628 lg = lcl->LigGlyph; | |
629 | |
630 for ( n = 0; n < count; n++ ) | |
631 Free_LigGlyph( &lg[n] ); | |
632 | |
633 FREE( lg ); | |
634 } | |
635 | |
636 _HB_OPEN_Free_Coverage( &lcl->Coverage ); | |
637 } | |
638 | |
639 | |
640 | |
641 /*********** | |
642 * GDEF API | |
643 ***********/ | |
644 | |
645 | |
646 static HB_UShort Get_New_Class( HB_GDEFHeader* gdef, | |
647 HB_UShort glyphID, | |
648 HB_UShort index ) | |
649 { | |
650 HB_UShort glyph_index, array_index, count; | |
651 HB_UShort byte, bits; | |
652 | |
653 HB_ClassRangeRecord* gcrr; | |
654 HB_UShort** ngc; | |
655 | |
656 | |
657 if ( glyphID >= gdef->LastGlyph ) | |
658 return 0; | |
659 | |
660 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; | |
661 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; | |
662 ngc = gdef->NewGlyphClasses; | |
663 | |
664 if ( index < count && glyphID < gcrr[index].Start ) | |
665 { | |
666 array_index = index; | |
667 if ( index == 0 ) | |
668 glyph_index = glyphID; | |
669 else | |
670 glyph_index = glyphID - gcrr[index - 1].End - 1; | |
671 } | |
672 else | |
673 { | |
674 array_index = index + 1; | |
675 glyph_index = glyphID - gcrr[index].End - 1; | |
676 } | |
677 | |
678 byte = ngc[array_index][glyph_index / 4]; | |
679 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); | |
680 | |
681 return bits & 0x000F; | |
682 } | |
683 | |
684 | |
685 | |
686 HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef, | |
687 HB_UShort glyphID, | |
688 HB_UShort* property ) | |
689 { | |
690 HB_UShort class = 0, index = 0; /* shut compiler up */ | |
691 | |
692 HB_Error error; | |
693 | |
694 | |
695 if ( !gdef || !property ) | |
696 return ERR(HB_Err_Invalid_Argument); | |
697 | |
698 /* first, we check for mark attach classes */ | |
699 | |
700 if ( gdef->MarkAttachClassDef.loaded ) | |
701 { | |
702 error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &ind
ex ); | |
703 if ( error && error != HB_Err_Not_Covered ) | |
704 return error; | |
705 if ( !error ) | |
706 { | |
707 *property = class << 8; | |
708 return HB_Err_Ok; | |
709 } | |
710 } | |
711 | |
712 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); | |
713 if ( error && error != HB_Err_Not_Covered ) | |
714 return error; | |
715 | |
716 /* if we have a constructed class table, check whether additional | |
717 values have been assigned */ | |
718 | |
719 if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses ) | |
720 class = Get_New_Class( gdef, glyphID, index ); | |
721 | |
722 switch ( class ) | |
723 { | |
724 default: | |
725 case UNCLASSIFIED_GLYPH: | |
726 *property = 0; | |
727 break; | |
728 | |
729 case SIMPLE_GLYPH: | |
730 *property = HB_GDEF_BASE_GLYPH; | |
731 break; | |
732 | |
733 case LIGATURE_GLYPH: | |
734 *property = HB_GDEF_LIGATURE; | |
735 break; | |
736 | |
737 case MARK_GLYPH: | |
738 *property = HB_GDEF_MARK; | |
739 break; | |
740 | |
741 case COMPONENT_GLYPH: | |
742 *property = HB_GDEF_COMPONENT; | |
743 break; | |
744 } | |
745 | |
746 return HB_Err_Ok; | |
747 } | |
748 | |
749 | |
750 static HB_Error Make_ClassRange( HB_ClassDefinition* cd, | |
751 HB_UShort start, | |
752 HB_UShort end, | |
753 HB_UShort class ) | |
754 { | |
755 HB_Error error; | |
756 HB_UShort index; | |
757 | |
758 HB_ClassDefFormat2* cdf2; | |
759 HB_ClassRangeRecord* crr; | |
760 | |
761 | |
762 cdf2 = &cd->cd.cd2; | |
763 | |
764 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, | |
765 cdf2->ClassRangeCount + 1 , | |
766 HB_ClassRangeRecord ) ) | |
767 return error; | |
768 | |
769 cdf2->ClassRangeCount++; | |
770 | |
771 crr = cdf2->ClassRangeRecord; | |
772 index = cdf2->ClassRangeCount - 1; | |
773 | |
774 crr[index].Start = start; | |
775 crr[index].End = end; | |
776 crr[index].Class = class; | |
777 | |
778 return HB_Err_Ok; | |
779 } | |
780 | |
781 | |
782 | |
783 HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef, | |
784 HB_UShort num_glyphs, | |
785 HB_UShort glyph_count, | |
786 HB_UShort* glyph_array, | |
787 HB_UShort* class_array ) | |
788 { | |
789 HB_UShort start, curr_glyph, curr_class; | |
790 HB_UShort n, m, count; | |
791 HB_Error error; | |
792 | |
793 HB_ClassDefinition* gcd; | |
794 HB_ClassRangeRecord* gcrr; | |
795 HB_UShort** ngc; | |
796 | |
797 | |
798 if ( !gdef || !glyph_array || !class_array ) | |
799 return ERR(HB_Err_Invalid_Argument); | |
800 | |
801 gcd = &gdef->GlyphClassDef; | |
802 | |
803 /* We build a format 2 table */ | |
804 | |
805 gcd->ClassFormat = 2; | |
806 | |
807 gcd->cd.cd2.ClassRangeCount = 0; | |
808 gcd->cd.cd2.ClassRangeRecord = NULL; | |
809 | |
810 start = glyph_array[0]; | |
811 curr_class = class_array[0]; | |
812 curr_glyph = start; | |
813 | |
814 if ( curr_class >= 5 ) | |
815 { | |
816 error = ERR(HB_Err_Invalid_Argument); | |
817 goto Fail4; | |
818 } | |
819 | |
820 glyph_count--; | |
821 | |
822 for ( n = 0; n < glyph_count + 1; n++ ) | |
823 { | |
824 if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] ) | |
825 { | |
826 if ( n == glyph_count ) | |
827 { | |
828 if ( ( error = Make_ClassRange( gcd, start, | |
829 curr_glyph, | |
830 curr_class) ) != HB_Err_Ok ) | |
831 goto Fail3; | |
832 } | |
833 else | |
834 { | |
835 if ( curr_glyph == 0xFFFF ) | |
836 { | |
837 error = ERR(HB_Err_Invalid_Argument); | |
838 goto Fail3; | |
839 } | |
840 else | |
841 curr_glyph++; | |
842 } | |
843 } | |
844 else | |
845 { | |
846 if ( ( error = Make_ClassRange( gcd, start, | |
847 curr_glyph - 1, | |
848 curr_class) ) != HB_Err_Ok ) | |
849 goto Fail3; | |
850 | |
851 if ( curr_glyph > glyph_array[n] ) | |
852 { | |
853 error = ERR(HB_Err_Invalid_Argument); | |
854 goto Fail3; | |
855 } | |
856 | |
857 start = glyph_array[n]; | |
858 curr_class = class_array[n]; | |
859 curr_glyph = start; | |
860 | |
861 if ( curr_class >= 5 ) | |
862 { | |
863 error = ERR(HB_Err_Invalid_Argument); | |
864 goto Fail3; | |
865 } | |
866 | |
867 if ( n == glyph_count ) | |
868 { | |
869 if ( ( error = Make_ClassRange( gcd, start, | |
870 curr_glyph, | |
871 curr_class) ) != HB_Err_Ok ) | |
872 goto Fail3; | |
873 } | |
874 else | |
875 { | |
876 if ( curr_glyph == 0xFFFF ) | |
877 { | |
878 error = ERR(HB_Err_Invalid_Argument); | |
879 goto Fail3; | |
880 } | |
881 else | |
882 curr_glyph++; | |
883 } | |
884 } | |
885 } | |
886 | |
887 /* now prepare the arrays for class values assigned during the lookup | |
888 process */ | |
889 | |
890 if ( ALLOC_ARRAY( gdef->NewGlyphClasses, | |
891 gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) ) | |
892 goto Fail3; | |
893 | |
894 count = gcd->cd.cd2.ClassRangeCount; | |
895 gcrr = gcd->cd.cd2.ClassRangeRecord; | |
896 ngc = gdef->NewGlyphClasses; | |
897 | |
898 /* We allocate arrays for all glyphs not covered by the class range | |
899 records. Each element holds four class values. */ | |
900 | |
901 if ( count > 0 ) | |
902 { | |
903 if ( gcrr[0].Start ) | |
904 { | |
905 if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) ) | |
906 goto Fail2; | |
907 } | |
908 | |
909 for ( n = 1; n < count; n++ ) | |
910 { | |
911 if ( gcrr[n].Start - gcrr[n - 1].End > 1 ) | |
912 if ( ALLOC_ARRAY( ngc[n], | |
913 ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4, | |
914 HB_UShort ) ) | |
915 goto Fail1; | |
916 } | |
917 | |
918 if ( gcrr[count - 1].End != num_glyphs - 1 ) | |
919 { | |
920 if ( ALLOC_ARRAY( ngc[count], | |
921 ( num_glyphs - gcrr[count - 1].End + 2 ) / 4, | |
922 HB_UShort ) ) | |
923 goto Fail1; | |
924 } | |
925 } | |
926 else if ( num_glyphs > 0 ) | |
927 { | |
928 if ( ALLOC_ARRAY( ngc[count], | |
929 ( num_glyphs + 3 ) / 4, | |
930 HB_UShort ) ) | |
931 goto Fail2; | |
932 } | |
933 | |
934 gdef->LastGlyph = num_glyphs - 1; | |
935 | |
936 gdef->MarkAttachClassDef_offset = 0L; | |
937 gdef->MarkAttachClassDef.loaded = FALSE; | |
938 | |
939 gcd->loaded = TRUE; | |
940 | |
941 return HB_Err_Ok; | |
942 | |
943 Fail1: | |
944 for ( m = 0; m < n; m++ ) | |
945 FREE( ngc[m] ); | |
946 | |
947 Fail2: | |
948 FREE( gdef->NewGlyphClasses ); | |
949 | |
950 Fail3: | |
951 FREE( gcd->cd.cd2.ClassRangeRecord ); | |
952 | |
953 Fail4: | |
954 return error; | |
955 } | |
956 | |
957 | |
958 static void Free_NewGlyphClasses( HB_GDEFHeader* gdef ) | |
959 { | |
960 HB_UShort** ngc; | |
961 HB_UShort n, count; | |
962 | |
963 | |
964 if ( gdef->NewGlyphClasses ) | |
965 { | |
966 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1; | |
967 ngc = gdef->NewGlyphClasses; | |
968 | |
969 for ( n = 0; n < count; n++ ) | |
970 FREE( ngc[n] ); | |
971 | |
972 FREE( ngc ); | |
973 } | |
974 } | |
975 | |
976 | |
977 HB_INTERNAL HB_Error | |
978 _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef, | |
979 HB_UShort glyphID, | |
980 HB_UShort property ) | |
981 { | |
982 HB_Error error; | |
983 HB_UShort class, new_class, index = 0; /* shut compiler up */ | |
984 HB_UShort byte, bits, mask; | |
985 HB_UShort array_index, glyph_index, count; | |
986 | |
987 HB_ClassRangeRecord* gcrr; | |
988 HB_UShort** ngc; | |
989 | |
990 | |
991 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); | |
992 if ( error && error != HB_Err_Not_Covered ) | |
993 return error; | |
994 | |
995 /* we don't accept glyphs covered in `GlyphClassDef' */ | |
996 | |
997 if ( !error ) | |
998 return HB_Err_Not_Covered; | |
999 | |
1000 switch ( property ) | |
1001 { | |
1002 case 0: | |
1003 new_class = UNCLASSIFIED_GLYPH; | |
1004 break; | |
1005 | |
1006 case HB_GDEF_BASE_GLYPH: | |
1007 new_class = SIMPLE_GLYPH; | |
1008 break; | |
1009 | |
1010 case HB_GDEF_LIGATURE: | |
1011 new_class = LIGATURE_GLYPH; | |
1012 break; | |
1013 | |
1014 case HB_GDEF_MARK: | |
1015 new_class = MARK_GLYPH; | |
1016 break; | |
1017 | |
1018 case HB_GDEF_COMPONENT: | |
1019 new_class = COMPONENT_GLYPH; | |
1020 break; | |
1021 | |
1022 default: | |
1023 return ERR(HB_Err_Invalid_Argument); | |
1024 } | |
1025 | |
1026 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; | |
1027 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; | |
1028 ngc = gdef->NewGlyphClasses; | |
1029 | |
1030 if ( index < count && glyphID < gcrr[index].Start ) | |
1031 { | |
1032 array_index = index; | |
1033 if ( index == 0 ) | |
1034 glyph_index = glyphID; | |
1035 else | |
1036 glyph_index = glyphID - gcrr[index - 1].End - 1; | |
1037 } | |
1038 else | |
1039 { | |
1040 array_index = index + 1; | |
1041 glyph_index = glyphID - gcrr[index].End - 1; | |
1042 } | |
1043 | |
1044 byte = ngc[array_index][glyph_index / 4]; | |
1045 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); | |
1046 class = bits & 0x000F; | |
1047 | |
1048 /* we don't overwrite existing entries */ | |
1049 | |
1050 if ( !class ) | |
1051 { | |
1052 bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 ); | |
1053 mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) ); | |
1054 | |
1055 ngc[array_index][glyph_index / 4] &= mask; | |
1056 ngc[array_index][glyph_index / 4] |= bits; | |
1057 } | |
1058 | |
1059 return HB_Err_Ok; | |
1060 } | |
1061 | |
1062 | |
1063 HB_INTERNAL HB_Error | |
1064 _HB_GDEF_Check_Property( HB_GDEFHeader* gdef, | |
1065 HB_GlyphItem gitem, | |
1066 HB_UShort flags, | |
1067 HB_UShort* property ) | |
1068 { | |
1069 HB_Error error; | |
1070 | |
1071 if ( gdef ) | |
1072 { | |
1073 HB_UShort basic_glyph_class; | |
1074 HB_UShort desired_attachment_class; | |
1075 | |
1076 if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN ) | |
1077 { | |
1078 error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperti
es ); | |
1079 if ( error ) | |
1080 return error; | |
1081 } | |
1082 | |
1083 *property = gitem->gproperties; | |
1084 | |
1085 /* If the glyph was found in the MarkAttachmentClass table, | |
1086 * then that class value is the high byte of the result, | |
1087 * otherwise the low byte contains the basic type of the glyph | |
1088 * as defined by the GlyphClassDef table. | |
1089 */ | |
1090 if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) | |
1091 basic_glyph_class = HB_GDEF_MARK; | |
1092 else | |
1093 basic_glyph_class = *property; | |
1094 | |
1095 /* Return Not_Covered, if, for example, basic_glyph_class | |
1096 * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURE
S | |
1097 */ | |
1098 if ( flags & basic_glyph_class ) | |
1099 return HB_Err_Not_Covered; | |
1100 | |
1101 /* The high byte of LookupFlags has the meaning | |
1102 * "ignore marks of attachment type different than | |
1103 * the attachment type specified." | |
1104 */ | |
1105 desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS; | |
1106 if ( desired_attachment_class ) | |
1107 { | |
1108 if ( basic_glyph_class == HB_GDEF_MARK && | |
1109 *property != desired_attachment_class ) | |
1110 return HB_Err_Not_Covered; | |
1111 } | |
1112 } else { | |
1113 *property = 0; | |
1114 } | |
1115 | |
1116 return HB_Err_Ok; | |
1117 } | |
1118 | |
1119 HB_INTERNAL HB_Error | |
1120 _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef, | |
1121 HB_Stream stream, | |
1122 HB_Lookup* lo, | |
1123 HB_UShort num_lookups) | |
1124 { | |
1125 HB_Error error = HB_Err_Ok; | |
1126 HB_UShort i; | |
1127 | |
1128 /* We now check the LookupFlags for values larger than 0xFF to find | |
1129 out whether we need to load the `MarkAttachClassDef' field of the | |
1130 GDEF table -- this hack is necessary for OpenType 1.2 tables since | |
1131 the version field of the GDEF table hasn't been incremented. | |
1132 | |
1133 For constructed GDEF tables, we only load it if | |
1134 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of | |
1135 a constructed mark attach table is not supported currently). */ | |
1136 | |
1137 if ( gdef && | |
1138 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) | |
1139 { | |
1140 for ( i = 0; i < num_lookups; i++ ) | |
1141 { | |
1142 | |
1143 if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) | |
1144 { | |
1145 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || | |
1146 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef, | |
1147 256, stream ) ) != HB_Err_Ok ) | |
1148 goto Done; | |
1149 | |
1150 break; | |
1151 } | |
1152 } | |
1153 } | |
1154 | |
1155 Done: | |
1156 return error; | |
1157 } | |
1158 | |
1159 /* END */ | |
OLD | NEW |