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
HB_New_GDEF_Table(HB_GDEFHeader ** retptr)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
HB_Load_GDEF_Table(HB_Stream stream,HB_GDEFHeader ** retptr)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
HB_Done_GDEF_Table(HB_GDEFHeader * gdef)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
Load_AttachPoint(HB_AttachPoint * ap,HB_Stream stream)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
Free_AttachPoint(HB_AttachPoint * ap)267 static void Free_AttachPoint( HB_AttachPoint* ap )
268 {
269 FREE( ap->PointIndex );
270 }
271
272
273 /* AttachList */
274
Load_AttachList(HB_AttachList * al,HB_Stream stream)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
Free_AttachList(HB_AttachList * al)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
Load_CaretValue(HB_CaretValue * cv,HB_Stream stream)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
Free_CaretValue(HB_CaretValue * cv)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
Load_LigGlyph(HB_LigGlyph * lg,HB_Stream stream)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
Free_LigGlyph(HB_LigGlyph * lg)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
Load_LigCaretList(HB_LigCaretList * lcl,HB_Stream stream)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
Free_LigCaretList(HB_LigCaretList * lcl)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
Get_New_Class(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort index)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
HB_GDEF_Get_Glyph_Property(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort * property)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, &index );
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
Make_ClassRange(HB_ClassDefinition * cd,HB_UShort start,HB_UShort end,HB_UShort class)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
HB_GDEF_Build_ClassDefinition(HB_GDEFHeader * gdef,HB_UShort num_glyphs,HB_UShort glyph_count,HB_UShort * glyph_array,HB_UShort * class_array)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
Free_NewGlyphClasses(HB_GDEFHeader * gdef)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
_HB_GDEF_Add_Glyph_Property(HB_GDEFHeader * gdef,HB_UShort glyphID,HB_UShort property)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
_HB_GDEF_Check_Property(HB_GDEFHeader * gdef,HB_GlyphItem gitem,HB_UShort flags,HB_UShort * property)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->gproperties );
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_LIGATURES
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
_HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags(HB_GDEFHeader * gdef,HB_Stream stream,HB_Lookup * lo,HB_UShort num_lookups)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 */
1164