-
Notifications
You must be signed in to change notification settings - Fork 42
/
ttf2mesh.c
4594 lines (4143 loc) · 155 KB
/
ttf2mesh.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 by Sergey Fetisov <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/*********************************** MODULE ***********************************/
/********************************* DEFINITIONS ********************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/* --------------- System dependent definitions and includes ---------------- */
/* General OS selection definition */
#if defined(ANDROID)
# define TTF_ANDROID
# define _DEFAULT_SOURCE 1
# define PATH_SEP '/'
# include <dirent.h>
#elif defined(__linux) || defined(__linux__)
# define TTF_LINUX
# define _DEFAULT_SOURCE 1
# define PATH_SEP '/'
# include <dirent.h>
#elif defined(__WINNT__) || defined(_WIN32) || defined(_WIN64)
# define TTF_WINDOWS
# define _CRT_SECURE_NO_WARNINGS
# define PATH_SEP '\\'
# define PATH_MAX MAX_PATH
# include <windows.h>
#endif
#include "ttf2mesh.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#if defined(TTF_NO_SIGNAL_H)
# define TTF_BREAKPOINT
#else
# include <signal.h>
# define TTF_BREAKPOINT raise(SIGINT)
#endif
/* Big/little endian definitions */
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
# if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
# define HOST_IS_LITTLE_ENDIAN
# endif
#elif defined(REG_DWORD)
# if (REG_DWORD == REG_DWORD_LITTLE_ENDIAN)
# define HOST_IS_LITTLE_ENDIAN
# endif
#else
# error NO __BYTE_ORDER__ DEFINITION
#endif
#define ANDROID_FONTS_PATH \
"/system/fonts"
#define LINUX_FONTS_PATH \
"/usr/share/fonts", \
"/usr/local/share/fonts", \
"~/.fonts"
#define WINDOWS_FONTS_PATH \
"C:\\Windows\\Fonts"
/* ---------------------- Different common definitions ---------------------- */
/* Minimal single precision value */
#define EPSILON 1e-7f
/* Pi. It specified more decimal places than it necessary for */
/* single precision floating numbers. Let the preprocessor do */
/* the optimization accurately. */
#ifdef M_PI
# define pi M_PI
#else
# define pi 3.14159265358979323846
#endif
/* Swapping of two values */
#define SWAP(type, A, B) { type tmp = A; A = B; B = tmp; }
/* -------------------- Working with vectors on xy-plane -------------------- */
#define VECLEN2(a) ((a)[0] * (a)[0] + (a)[1] * (a)[1]) /* Squared length vector */
#define VECLEN(a) (sqrtf(VECLEN2(a))) /* Vector length */
#define VECDOT(a, b) (a[0] * b[0] + a[1] * b[1]) /* Dot product of two vectors */
#define VECCROSS(a, b) (a[0] * b[1] - a[1] * b[0]) /* Third component of cross product of two vectors on xy-plane */
/* Subtraction of vectors */
#define VECSUB(res, a, b) { \
(res)[0] = (a)[0] - (b)[0]; \
(res)[1] = (a)[1] - (b)[1]; \
}
/* Sum of vectors */
#define VECADD(res, a, b) { \
(res)[0] = (a)[0] + (b)[0]; \
(res)[1] = (a)[1] + (b)[1]; \
}
/* Vector scaling */
#define VECSCALE(res, v, scale) { \
float S = (scale); \
(res)[0] = (v)[0] * S; \
(res)[1] = (v)[1] * S; \
}
/* Projecting a vector onto the basis vectors e1 and e2 */
#define VECPROJ(res, vec, e1, e2) { \
float t; \
t = VECDOT(vec, e1); \
res[1] = VECDOT(vec, e2); \
res[0] = t; \
}
/* Cramer's rule for 2x2 system */
#define CRAMER2x2(x, y, a11, a12, c1, a21, a22, c2) { \
float det = (a11) * (a22) - (a12) * (a21); \
x = ((c1) * (a22) - (c2) * (a12)) / det; \
y = ((c2) * (a11) - (c1) * (a21)) / det; \
}
/* --------------------- Working with doubly linked list --------------------- */
#define LIST_DETACH(element) { \
(element)->prev->next = (element)->next; \
(element)->next->prev = (element)->prev; }
#define LIST_INS_AFTER(what, where) { \
(what)->prev = (where); \
(what)->next = (where)->next; \
(what)->prev->next = (what); \
(what)->next->prev = (what); } \
#define LIST_ATTACH(root, element) { \
(element)->prev = (root); \
(element)->next = (root)->next; \
(root)->next->prev = (element); \
(root)->next = (element); }
#define LIST_REATTACH(new_root, element) { LIST_DETACH(element); LIST_ATTACH(new_root, element); }
#define LIST_INS_LAST(root, element) LIST_INS_AFTER(element, (root)->prev)
#define LIST_EMPTY(root) ((root)->next == (root))
#define LIST_FIRST(root) ((root)->next)
#define LIST_INIT(root) { (root)->next = (root); (root)->prev = (root); }
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************* TRUETYPE FORMAT ******************************/
/******************************** SPECIFICATION *******************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
#pragma pack(push, 1)
typedef struct ttf_header
{
uint32_t sfntVersion; /* 0x00010000 or 0x4F54544F ('OTTO') */
uint16_t numTables; /* Number of tables */
uint16_t searchRange; /* (Maximum power of 2 <= numTables) x 16 */
uint16_t entrySelector; /* Log2(maximum power of 2 <= numTables) */
uint16_t rangeShift; /* NumTables x 16-searchRange */
} ttf_file_hdr_t;
/* https://docs.microsoft.com/typography/opentype/spec/cmap */
typedef struct ttf_cmap_table
{
uint16_t version; /* Table version number (0) */
uint16_t numTables; /* Number of encoding tables that follow */
struct
{
uint16_t platformID; /* Platform ID */
uint16_t encodingID; /* Platform-specific encoding ID */
uint32_t offset; /* Byte offset from beginning of table to the subtable for this encoding */
} encRecs[1];
} ttf_cmap_t;
typedef struct ttf_cmap_format4_table
{
uint16_t format; /* Format number is set to 4 */
uint16_t length; /* This is the length in bytes of the subtable */
uint16_t language; /* see https://docs.microsoft.com/typography/opentype/spec/cmap#language */
uint16_t segCountX2; /* 2 × segCount */
uint16_t searchRange; /* 2 × (2**floor(log2(segCount))) */
uint16_t entrySelector; /* log2(searchRange/2) */
uint16_t rangeShift; /* 2 × segCount - searchRange */
} ttf_fmt4_t;
typedef struct ttf_cmap_format12_table
{
uint16_t format; /* Format number is set to 12 */
uint16_t reserved;
uint32_t length; /* This is the length in bytes of the subtable */
uint32_t language; /* see https://docs.microsoft.com/typography/opentype/spec/cmap#language */
uint32_t numGroups;
} ttf_fmt12_t;
typedef struct ttf_cmap_format12_sequential_map_group {
uint32_t startCharCode;
uint32_t endCharCode;
uint32_t startGlyphID;
} ttf_fmt12_smg_t;
typedef struct ttf_glyf_table_header
{
int16_t numberOfContours; /* simple glyph if >= 0. composite glyph if < 0 */
int16_t xMin; /* Minimum x for coordinate data */
int16_t yMin; /* Minimum y for coordinate data */
int16_t xMax; /* Maximum x for coordinate data */
int16_t yMax; /* Maximum y for coordinate data */
} ttf_glyfh_t;
typedef struct ttf_table_record
{
char tableTag[4]; /* Table identifier */
uint32_t checkSum; /* CheckSum for this table */
uint32_t offset; /* Offset from beginning of TrueType font file */
uint32_t length; /* Length of this table */
} ttf_tab_rec_t;
/* https://docs.microsoft.com/typography/opentype/spec/head */
typedef struct ttf_head_table
{
uint16_t majorVersion; /* Major version number of the font header table — set to 1 */
uint16_t minorVersion; /* Minor version number of the font header table — set to 0 */
int16_t fontRevisionI; /* Set by font manufacturer. Integer part of revision value */
uint16_t fontRevisionF; /* Set by font manufacturer. Fractional part of revision value */
uint32_t checkSumAdjustment; /* see https://docs.microsoft.com/typography/opentype/spec/head */
uint32_t magicNumber; /* Set to 0x5F0F3CF5 */
uint16_t flags; /* see https://docs.microsoft.com/typography/opentype/spec/head */
uint16_t unitsPerEm; /* see https://docs.microsoft.com/typography/opentype/spec/head */
uint64_t created; /* Number of seconds since 24:00 that started 01.06.1904 in GMT/UTC time zone */
uint64_t modified; /* Number of seconds since 24:00 that started 01.06.1904 in GMT/UTC time zone */
int16_t xMin; /* For all glyph bounding boxes */
int16_t yMin; /* For all glyph bounding boxes */
int16_t xMax; /* For all glyph bounding boxes */
int16_t yMax; /* For all glyph bounding boxes */
uint16_t macStyle;
uint16_t lowestRecPPEM; /* Smallest readable size in pixels */
int16_t fontDirectionHint; /* Deprecated (Set to 2) */
int16_t indexToLocFormat; /* 0 for short offsets (Offset16), 1 for long (Offset32) */
int16_t glyphDataFormat; /* 0 for current format */
} ttf_head_t;
/* https://docs.microsoft.com/ru-ru/typography/opentype/spec/maxp */
typedef struct ttf_maxp_table
{
uint16_t verMaj; /* 0x0001 for version 1.0 */
uint16_t verMin;
uint16_t numGlyphs; /* The number of glyphs in the font */
/* fields below are actual for version 1.0 or greater */
uint16_t maxPoints; /* Maximum points in a non-composite glyph */
uint16_t maxContours; /* Maximum contours in a non-composite glyph */
uint16_t maxCompositePoints; /* Maximum points in a composite glyph */
uint16_t maxCompositeContours; /* Maximum contours in a composite glyph */
uint16_t maxZones; /* 1 if instructions do not use the twilight zone (Z0), or 2 if instructions do use Z0; should be set to 2 in most cases */
uint16_t maxTwilightPoints; /* Maximum points used in Z0 */
uint16_t maxStorage; /* Number of Storage Area locations */
uint16_t maxFunctionDefs; /* Number of FDEFs, equal to the highest function number + 1 */
uint16_t maxInstructionDefs; /* Number of IDEFs */
uint16_t maxStackElements; /* Maximum stack depth across Font Program ('fpgm' table), CVT Program ('prep' table) and all glyph instructions (in the 'glyf' table) */
uint16_t maxSizeOfInstructions; /* Maximum byte count for glyph instructions */
uint16_t maxComponentElements; /* Maximum number of components referenced at “top level” for any composite glyph */
uint16_t maxComponentDepth; /* Maximum levels of recursion; 1 for simple components */
} ttf_maxp_t;
/* https://docs.microsoft.com/ru-ru/typography/opentype/spec/name */
typedef struct ttf_namerecord
{
uint16_t platformID; /* Platform ID */
uint16_t encodingID; /* Platform-specific encoding ID */
uint16_t languageID; /* Language ID */
uint16_t nameID; /* Name ID */
uint16_t length; /* String length (in bytes) */
uint16_t offset; /* String offset from start of storage area (in bytes) */
} ttf_namerec_t;
/* https://docs.microsoft.com/ru-ru/typography/opentype/spec/name */
typedef struct ttf_name_table
{
uint16_t format; /* Format selector (=0/1) */
uint16_t count; /* Number of name records */
uint16_t stringOffset; /* Offset to start of string storage (from start of table) */
ttf_namerec_t nameRecord[1]; /* nameRecord[count] The name records where count is the number of records */
/*
extension for format 1:
uint16 langTagCount Number of language-tag records.
LangTagRecord langTagRecord[langTagCount] The language-tag records where langTagCount is the number of records.
*/
} ttf_name_t;
/* https://docs.microsoft.com/ru-ru/typography/opentype/spec/hhea */
typedef struct ttf_hhea_table
{
uint16_t majorVersion; /* Major version number of the horizontal header table — set to 1 */
uint16_t minorVersion; /* Minor version number of the horizontal header table — set to 0 */
int16_t ascender; /* Typographic ascent (Distance from baseline of highest ascender) */
int16_t descender; /* Typographic descent (Distance from baseline of lowest descender) */
int16_t lineGap; /* Typographic line gap. Negative LineGap values are treated as zero in some legacy platform implementations */
uint16_t advanceWidthMax; /* Maximum advance width value in 'hmtx' table */
int16_t minLeftSideBearing; /* Minimum left sidebearing value in 'hmtx' table */
int16_t minRightSideBearing; /* Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)) */
int16_t xMaxExtent; /* Max(lsb + (xMax - xMin)) */
int16_t caretSlopeRise; /* Used to calculate the slope of the cursor (rise/run); 1 for vertical */
int16_t caretSlopeRun; /* 0 for vertical */
int16_t caretOffset; /* The amount by which a slanted highlight on a glyph needs to be shifted to produce the best appearance. Set to 0 for non-slanted fonts */
int16_t reserved1; /* set to 0 */
int16_t reserved2; /* set to 0 */
int16_t reserved3; /* set to 0 */
int16_t reserved4; /* set to 0 */
int16_t metricDataFormat; /* 0 for current format */
uint16_t numberOfHMetrics; /* Number of hMetric entries in 'hmtx' table */
} ttf_hhea_t;
/* https://docs.microsoft.com/en-us/typography/opentype/spec/os2 */
/* see description in ttf_t definition */
typedef struct ttf_os2_table
{
uint16_t version;
int16_t xAvgCharWidth;
uint16_t usWeightClass;
uint16_t usWidthClass;
uint16_t fsType;
int16_t ySubscriptXSize;
int16_t ySubscriptYSize;
int16_t ySubscriptXOffset;
int16_t ySubscriptYOffset;
int16_t ySuperscriptXSize;
int16_t ySuperscriptYSize;
int16_t ySuperscriptXOffset;
int16_t ySuperscriptYOffset;
int16_t yStrikeoutSize;
int16_t yStrikeoutPosition;
int16_t sFamilyClass;
uint8_t panose[10];
uint8_t ulUnicodeRange[16];
char achVendID[4];
uint16_t fsSelection;
uint16_t usFirstCharIndex;
uint16_t usLastCharIndex;
int16_t sTypoAscender;
int16_t sTypoDescender;
int16_t sTypoLineGap;
uint16_t usWinAscent;
uint16_t usWinDescent;
} ttf_os2_t;
#pragma pack(pop)
/* ------------------- Parser private structure ------------------ */
typedef struct ttf_parser_private_struct
{
ttf_file_hdr_t *hdr;
ttf_head_t *phead;
ttf_os2_t *pos2;
ttf_maxp_t *pmaxp;
ttf_cmap_t *pcmap;
ttf_fmt4_t *pfmt4;
ttf_fmt12_t *pfmt12;
ttf_name_t *pname;
ttf_hhea_t *phhea;
uint16_t *phmtx;
uint8_t *pglyf;
uint8_t *ploca;
uint16_t *ploca16;
uint32_t *ploca32;
int shead;
int sos2;
int smaxp;
int sloca;
int scmap;
int sfmt4;
int sfmt12;
int sname;
int shhea;
int shmtx;
int sglyf;
uint32_t glyf_csum;
} pps_t;
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/*************************** TRUETYPE FORMAT PARSER ***************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
const ubrange_t ubranges[163] =
{
{0x0000, 0x007F, "Basic Latin"},
{0x0080, 0x00FF, "Latin-1 Supplement"},
{0x0100, 0x017F, "Latin Extended-A"},
{0x0180, 0x024F, "Latin Extended-B"},
{0x0250, 0x02AF, "IPA Extensions"},
{0x02B0, 0x02FF, "Spacing Modifier Letters"},
{0x0300, 0x036F, "Combining Diacritical Marks"},
{0x0370, 0x03FF, "Greek and Coptic"},
{0x0400, 0x04FF, "Cyrillic"},
{0x0500, 0x052F, "Cyrillic Supplement"},
{0x0530, 0x058F, "Armenian"},
{0x0590, 0x05FF, "Hebrew"},
{0x0600, 0x06FF, "Arabic"},
{0x0700, 0x074F, "Syriac"},
{0x0750, 0x077F, "Arabic Supplement"},
{0x0780, 0x07BF, "Thaana"},
{0x07C0, 0x07FF, "NKo"},
{0x0800, 0x083F, "Samaritan"},
{0x0840, 0x085F, "Mandaic"},
{0x0860, 0x086F, "Syriac Supplement"},
{0x08A0, 0x08FF, "Arabic Extended-A"},
{0x0900, 0x097F, "Devanagari"},
{0x0980, 0x09FF, "Bengali"},
{0x0A00, 0x0A7F, "Gurmukhi"},
{0x0A80, 0x0AFF, "Gujarati"},
{0x0B00, 0x0B7F, "Oriya"},
{0x0B80, 0x0BFF, "Tamil"},
{0x0C00, 0x0C7F, "Telugu"},
{0x0C80, 0x0CFF, "Kannada"},
{0x0D00, 0x0D7F, "Malayalam"},
{0x0D80, 0x0DFF, "Sinhala"},
{0x0E00, 0x0E7F, "Thai"},
{0x0E80, 0x0EFF, "Lao"},
{0x0F00, 0x0FFF, "Tibetan"},
{0x1000, 0x109F, "Myanmar"},
{0x10A0, 0x10FF, "Georgian"},
{0x1100, 0x11FF, "Hangul Jamo"},
{0x1200, 0x137F, "Ethiopic"},
{0x1380, 0x139F, "Ethiopic Supplement"},
{0x13A0, 0x13FF, "Cherokee"},
{0x1400, 0x167F, "Unified Canadian Aboriginal Syllabics"},
{0x1680, 0x169F, "Ogham"},
{0x16A0, 0x16FF, "Runic"},
{0x1700, 0x171F, "Tagalog"},
{0x1720, 0x173F, "Hanunoo"},
{0x1740, 0x175F, "Buhid"},
{0x1760, 0x177F, "Tagbanwa"},
{0x1780, 0x17FF, "Khmer"},
{0x1800, 0x18AF, "Mongolian"},
{0x18B0, 0x18FF, "Unified Canadian Aboriginal Syllabics Extended"},
{0x1900, 0x194F, "Limbu"},
{0x1950, 0x197F, "Tai Le"},
{0x1980, 0x19DF, "New Tai Lue"},
{0x19E0, 0x19FF, "Khmer Symbols"},
{0x1A00, 0x1A1F, "Buginese"},
{0x1A20, 0x1AAF, "Tai Tham"},
{0x1AB0, 0x1AFF, "Combining Diacritical Marks Extended"},
{0x1B00, 0x1B7F, "Balinese"},
{0x1B80, 0x1BBF, "Sundanese"},
{0x1BC0, 0x1BFF, "Batak"},
{0x1C00, 0x1C4F, "Lepcha"},
{0x1C50, 0x1C7F, "Ol Chiki"},
{0x1C80, 0x1C8F, "Cyrillic Extended-C"},
{0x1C90, 0x1CBF, "Georgian Extended"},
{0x1CC0, 0x1CCF, "Sundanese Supplement"},
{0x1CD0, 0x1CFF, "Vedic Extensions"},
{0x1D00, 0x1D7F, "Phonetic Extensions"},
{0x1D80, 0x1DBF, "Phonetic Extensions Supplement"},
{0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement"},
{0x1E00, 0x1EFF, "Latin Extended Additional"},
{0x1F00, 0x1FFF, "Greek Extended"},
{0x2000, 0x206F, "General Punctuation"},
{0x2070, 0x209F, "Superscripts and Subscripts"},
{0x20A0, 0x20CF, "Currency Symbols"},
{0x20D0, 0x20FF, "Combining Diacritical Marks for Symbols"},
{0x2100, 0x214F, "Letterlike Symbols"},
{0x2150, 0x218F, "Number Forms"},
{0x2190, 0x21FF, "Arrows"},
{0x2200, 0x22FF, "Mathematical Operators"},
{0x2300, 0x23FF, "Miscellaneous Technical"},
{0x2400, 0x243F, "Control Pictures"},
{0x2440, 0x245F, "Optical Character Recognition"},
{0x2460, 0x24FF, "Enclosed Alphanumerics"},
{0x2500, 0x257F, "Box Drawing"},
{0x2580, 0x259F, "Block Elements"},
{0x25A0, 0x25FF, "Geometric Shapes"},
{0x2600, 0x26FF, "Miscellaneous Symbols"},
{0x2700, 0x27BF, "Dingbats"},
{0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A"},
{0x27F0, 0x27FF, "Supplemental Arrows-A"},
{0x2800, 0x28FF, "Braille Patterns"},
{0x2900, 0x297F, "Supplemental Arrows-B"},
{0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B"},
{0x2A00, 0x2AFF, "Supplemental Mathematical Operators"},
{0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows"},
{0x2C00, 0x2C5F, "Glagolitic"},
{0x2C60, 0x2C7F, "Latin Extended-C"},
{0x2C80, 0x2CFF, "Coptic"},
{0x2D00, 0x2D2F, "Georgian Supplement"},
{0x2D30, 0x2D7F, "Tifinagh"},
{0x2D80, 0x2DDF, "Ethiopic Extended"},
{0x2DE0, 0x2DFF, "Cyrillic Extended-A"},
{0x2E00, 0x2E7F, "Supplemental Punctuation"},
{0x2E80, 0x2EFF, "CJK Radicals Supplement"},
{0x2F00, 0x2FDF, "Kangxi Radicals"},
{0x2FF0, 0x2FFF, "Ideographic Description Characters"},
{0x3000, 0x303F, "CJK Symbols and Punctuation"},
{0x3040, 0x309F, "Hiragana"},
{0x30A0, 0x30FF, "Katakana"},
{0x3100, 0x312F, "Bopomofo"},
{0x3130, 0x318F, "Hangul Compatibility Jamo"},
{0x3190, 0x319F, "Kanbun"},
{0x31A0, 0x31BF, "Bopomofo Extended"},
{0x31C0, 0x31EF, "CJK Strokes"},
{0x31F0, 0x31FF, "Katakana Phonetic Extensions"},
{0x3200, 0x32FF, "Enclosed CJK Letters and Months"},
{0x3300, 0x33FF, "CJK Compatibility"},
{0x3400, 0x4DBF, "CJK Unified Ideographs Extension A"},
{0x4DC0, 0x4DFF, "Yijing Hexagram Symbols"},
{0x4E00, 0x9FFF, "CJK Unified Ideographs"},
{0xA000, 0xA48F, "Yi Syllables"},
{0xA490, 0xA4CF, "Yi Radicals"},
{0xA4D0, 0xA4FF, "Lisu"},
{0xA500, 0xA63F, "Vai"},
{0xA640, 0xA69F, "Cyrillic Extended-B"},
{0xA6A0, 0xA6FF, "Bamum"},
{0xA700, 0xA71F, "Modifier Tone Letters"},
{0xA720, 0xA7FF, "Latin Extended-D"},
{0xA800, 0xA82F, "Syloti Nagri"},
{0xA830, 0xA83F, "Common Indic Number Forms"},
{0xA840, 0xA87F, "Phags-pa"},
{0xA880, 0xA8DF, "Saurashtra"},
{0xA8E0, 0xA8FF, "Devanagari Extended"},
{0xA900, 0xA92F, "Kayah Li"},
{0xA930, 0xA95F, "Rejang"},
{0xA960, 0xA97F, "Hangul Jamo Extended-A"},
{0xA980, 0xA9DF, "Javanese"},
{0xA9E0, 0xA9FF, "Myanmar Extended-B"},
{0xAA00, 0xAA5F, "Cham"},
{0xAA60, 0xAA7F, "Myanmar Extended-A"},
{0xAA80, 0xAADF, "Tai Viet"},
{0xAAE0, 0xAAFF, "Meetei Mayek Extensions"},
{0xAB00, 0xAB2F, "Ethiopic Extended-A"},
{0xAB30, 0xAB6F, "Latin Extended-E"},
{0xAB70, 0xABBF, "Cherokee Supplement"},
{0xABC0, 0xABFF, "Meetei Mayek"},
{0xAC00, 0xD7AF, "Hangul Syllables"},
{0xD7B0, 0xD7FF, "Hangul Jamo Extended-B"},
{0xD800, 0xDB7F, "High Surrogates"},
{0xDB80, 0xDBFF, "High Private Use Surrogates"},
{0xDC00, 0xDFFF, "Low Surrogates"},
{0xE000, 0xF8FF, "Private Use Area"},
{0xF900, 0xFAFF, "CJK Compatibility Ideographs"},
{0xFB00, 0xFB4F, "Alphabetic Presentation Forms"},
{0xFB50, 0xFDFF, "Arabic Presentation Forms-A"},
{0xFE00, 0xFE0F, "Variation Selectors"},
{0xFE10, 0xFE1F, "Vertical Forms"},
{0xFE20, 0xFE2F, "Combining Half Marks"},
{0xFE30, 0xFE4F, "CJK Compatibility Forms"},
{0xFE50, 0xFE6F, "Small Form Variants"},
{0xFE70, 0xFEFF, "Arabic Presentation Forms-B"},
{0xFF00, 0xFFEF, "Halfwidth and Fullwidth Forms"},
{0xFFF0, 0xFFFF, "Specials"}
};
#ifdef __cplusplus
extern "C" {
#endif
/* Big/little endian conversion helpers */
#if defined(HOST_IS_LITTLE_ENDIAN)
static __inline uint16_t big16toh(uint16_t x)
{
return ((unsigned short int) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)));
}
static __inline uint32_t big32toh(uint32_t x)
{
return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) |
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
}
static __inline uint64_t big64toh(uint64_t x)
{
return ((uint64_t)big32toh((uint32_t)x) << 32) | big32toh(x >> 32);
}
# define conv16(v) v = big16toh(v)
# define conv32(v) v = big32toh(v)
# define conv64(v) v = big64toh(v)
#else
static __inline uint16_t big16toh(uint16_t x)
{
return x;
}
static __inline uint32_t big32toh(uint32_t x)
{
return x;
}
static __inline uint64_t big64toh(uint64_t x)
{
return x;
}
# define conv16(v)
# define conv32(v)
# define conv64(v)
#endif
static uint32_t ttf_checksum(const void *data, int size)
{
uint32_t *ptr;
uint32_t sum;
sum = 0;
ptr = (uint32_t *)data;
while (size > 0)
{
sum += big32toh(*ptr++);
size -= 4;
}
return sum;
}
#define check(cond, code) \
if (!(cond)) { result = code; goto error; }
ttf_outline_t *allocate_ttf_outline(int ncontours, int npoints)
{
ttf_outline_t *res;
int n = sizeof(ttf_outline_t);
n += npoints * sizeof(ttf_point_t); /* points buffer size */
n += (ncontours - 1) * sizeof(res->cont); /* contours buffer size */
res = (ttf_outline_t *)calloc(n, 1);
if (res == NULL) return NULL;
res->ncontours = ncontours;
res->total_points = npoints;
res->cont[0].pt = (ttf_point_t *)&res->cont[ncontours];
return res;
}
int parse_simple_glyph(ttf_glyph_t *glyph, int glyph_index, uint8_t *p, int avail)
{
uint16_t *endPtsOfContours;
uint8_t flag;
uint8_t rep;
ttf_glyfh_t hdr;
int32_t x, y;
int i, j, n;
/* read and store glyph header */
if (avail < (int)sizeof(ttf_glyfh_t)) return TTF_ERR_FMT;
hdr = *(ttf_glyfh_t *)p;
conv16(hdr.numberOfContours);
conv16(hdr.xMin);
conv16(hdr.yMin);
conv16(hdr.xMax);
conv16(hdr.yMax);
p += sizeof(ttf_glyfh_t);
avail -= sizeof(ttf_glyfh_t);
/* read endPtsOfContours */
if (hdr.numberOfContours == 0) return TTF_ERR_FMT;
if (avail < hdr.numberOfContours * 2) return TTF_ERR_FMT;
endPtsOfContours = (uint16_t *)p;
p += hdr.numberOfContours * 2;
avail -= hdr.numberOfContours * 2;
/* fill glyph structure and allocate points */
glyph->ncontours = hdr.numberOfContours;
glyph->npoints = big16toh(endPtsOfContours[glyph->ncontours - 1]) + 1;
glyph->xbounds[0] = hdr.xMin;
glyph->xbounds[1] = hdr.xMax;
glyph->ybounds[0] = hdr.yMin;
glyph->ybounds[1] = hdr.yMax;
/* initialize outline */
glyph->outline = allocate_ttf_outline(glyph->ncontours, glyph->npoints);
if (glyph->outline == NULL) return TTF_ERR_NOMEM;
j = 0;
n = -1;
for (i = 0; i < glyph->ncontours; i++)
{
j = (int)big16toh(endPtsOfContours[i]);
glyph->outline->cont[i].length = j - n;
glyph->outline->cont[i].subglyph_id = glyph_index;
glyph->outline->cont[i].subglyph_order = 0;
if (i != glyph->ncontours - 1)
glyph->outline->cont[i + 1].pt = glyph->outline->cont[i].pt + j - n;
n = j;
}
/* check initialized outlines */
n = 0;
for (i = 0; i < glyph->outline->ncontours; i++)
{
if (glyph->outline->cont[i].length < 0)
return TTF_ERR_FMT;
n += glyph->outline->cont[i].length;
}
if (n != glyph->npoints)
return TTF_ERR_FMT;
/* read instructionLength */
if (avail < 2) return TTF_ERR_FMT;
n = big16toh(*(uint16_t *)p);
p += 2;
avail -= 2;
/* skip instructions */
if (avail < n) return TTF_ERR_FMT;
p += n;
avail -= n;
/* read flags */
#define ON_CURVE_POINT 0x01
#define X_SHORT_VECTOR 0x02
#define Y_SHORT_VECTOR 0x04
#define REPEAT_FLAG 0x08
#define X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR 0x10
#define Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR 0x20
#define OVERLAP_SIMPLE 0x40
flag = 0;
rep = 0;
for (i = 0; i < glyph->ncontours; i++)
for (j = 0; j < glyph->outline->cont[i].length; j++)
{
if (rep == 0)
{
if (avail < 1) return TTF_ERR_FMT;
flag = *p;
p++;
avail--;
if (flag & REPEAT_FLAG)
{
if (avail < 1) return TTF_ERR_FMT;
rep = *p;
p++;
avail--;
}
}
else
{
rep--;
}
glyph->outline->cont[i].pt[j].onc = (flag & ON_CURVE_POINT) != 0;
glyph->outline->cont[i].pt[j].res = flag;
}
/* read x coordinate */
x = 0;
for (i = 0; i < glyph->ncontours; i++)
for (j = 0; j < glyph->outline->cont[i].length; j++)
{
/*
* X_SHORT X_IS_SAME description
* 0 0 int16 value
* 0 1 apply previous value
* 1 0 uint8, sign -
* 1 1 uint8, sign +
*/
flag = glyph->outline->cont[i].pt[j].res;
switch (flag & (X_SHORT_VECTOR | X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR))
{
case 0:
if (avail < 2) return TTF_ERR_FMT;
x += (int16_t)big16toh(*(int16_t *)p);
avail -= 2;
p += 2;
break;
case X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR:
break;
case X_SHORT_VECTOR:
if (avail < 1) return TTF_ERR_FMT;
x -= *(uint8_t *)p++;
avail--;
break;
case X_SHORT_VECTOR | X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR:
if (avail < 1) return TTF_ERR_FMT;
x += *(uint8_t *)p++;
avail--;
break;
}
glyph->outline->cont[i].pt[j].x = (float)x;
}
/* read y coordinate */
y = 0;
for (i = 0; i < glyph->ncontours; i++)
for (j = 0; j < glyph->outline->cont[i].length; j++)
{
flag = glyph->outline->cont[i].pt[j].res;
switch (flag & (Y_SHORT_VECTOR | Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR))
{
case 0:
if (avail < 2) return TTF_ERR_FMT;
y += (int16_t)big16toh(*(int16_t *)p);
avail -= 2;
p += 2;
break;
case Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR:
break;
case Y_SHORT_VECTOR:
if (avail < 1) return TTF_ERR_FMT;
y -= *(uint8_t *)p++;
avail--;
break;
case Y_SHORT_VECTOR | Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR:
if (avail < 1) return TTF_ERR_FMT;
y += *(uint8_t *)p++;
avail--;
break;
}
glyph->outline->cont[i].pt[j].y = (float)y;
}
/* shift contours */
for (i = 0; i < glyph->outline->ncontours; i++)
{
ttf_point_t *p;
ttf_point_t first;
int offset;
n = glyph->outline->cont[i].length;
p = glyph->outline->cont[i].pt;
if (n < 2) continue;
for (offset = 0; offset < n && !p->onc; offset++)
{
first = p[0];
for (j = 0; j < n - 1; j++)
p[j] = p[j + 1];
p[n - 1] = first;
}
}
return 0;
}
static __inline float f2dot14_to_float(int16_t f2dot14)
{
return (float)f2dot14 / 16384;
}
int parse_composite_glyph(ttf_t *ttf, ttf_glyph_t *glyph, uint8_t *p, int avail)
{
#define ARG_1_AND_2_ARE_WORDS 0x0001
#define ARGS_ARE_XY_VALUES 0x0002
#define ROUND_XY_TO_GRID 0x0004
#define WE_HAVE_A_SCALE 0x0008
#define MORE_COMPONENTS 0x0020
#define WE_HAVE_AN_X_AND_Y_SCALE 0x0040
#define WE_HAVE_A_TWO_BY_TWO 0x0080
#define WE_HAVE_INSTRUCTIONS 0x0100
#define USE_MY_METRICS 0x0200
#define OVERLAP_COMPOUND 0x0400
#define SCALED_COMPONENT_OFFSET 0x0800
#define UNSCALED_COMPONENT_OFFSET 0x1000
uint8_t *stored_p;
int stored_avail;
int nglyphs;
ttf_glyfh_t hdr;
ttf_point_t *curr;
unsigned flags; /* component flag */
unsigned glyphIndex; /* glyph index of component */
int16_t arg1, arg2; /* arguments */
float scale[2][2];
int i, j, n;
/* read and store glyph header */
if (avail < (int)sizeof(ttf_glyfh_t)) return TTF_ERR_FMT;
hdr = *(ttf_glyfh_t *)p;
conv16(hdr.numberOfContours);
conv16(hdr.xMin);
conv16(hdr.yMin);
conv16(hdr.xMax);
conv16(hdr.yMax);
p += sizeof(ttf_glyfh_t);
avail -= sizeof(ttf_glyfh_t);
/* first count the number of glyphs and contours */
flags = MORE_COMPONENTS;
stored_p = p;
stored_avail = avail;
nglyphs = 0;
while (flags & MORE_COMPONENTS)
{
if (avail < 4) return TTF_ERR_FMT;
flags = big16toh(*(uint16_t *)(p + 0));
glyphIndex = big16toh(*(uint16_t *)(p + 2));
avail -= 4;
p += 4;
if (flags & ARGS_ARE_XY_VALUES)
{
/* Argument1 and argument2 are x and y offsets to be added to the glyph */
}
else
{
/* Argument1 and argument2 are two point numbers. */
/* The first point number indicates the point that is to be matched to the new glyph. */
/* The second number indicates the new glyph’s “matched” point */
return TTF_ERR_FMT; /* TODO: support this feature */
}
n = flags & ARG_1_AND_2_ARE_WORDS ? 4 : 2;
if (flags & WE_HAVE_A_SCALE)
n += 2; else
if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
n += 4; else
if (flags & WE_HAVE_A_TWO_BY_TWO)
n += 8;
avail -= n;
p += n;
if (avail < 0) return TTF_ERR_FMT;
if (glyphIndex >= (unsigned)ttf->nglyphs) return TTF_ERR_FMT;
glyph->ncontours += ttf->glyphs[glyphIndex].ncontours;
glyph->npoints += ttf->glyphs[glyphIndex].npoints;
nglyphs++;
}
if (glyph->ncontours == 0 || glyph->npoints == 0)
{
/* FIXME: support composite glyph recursion! */
glyph->ncontours = 0;
glyph->npoints = 0;
return 0;
}
p = stored_p;
avail = stored_avail;
/* initialize outline */
glyph->outline = allocate_ttf_outline(glyph->ncontours, glyph->npoints);
if (glyph->outline == NULL) return TTF_ERR_NOMEM;
/* initialize other glyph fields */
glyph->composite = 1;
glyph->xbounds[0] = hdr.xMin;
glyph->xbounds[1] = hdr.xMax;
glyph->ybounds[0] = hdr.yMin;
glyph->ybounds[1] = hdr.yMax;
n = 0;
nglyphs = 0;
curr = glyph->outline->cont[0].pt;
flags = MORE_COMPONENTS;
while (flags & MORE_COMPONENTS)
{
/* reading flags, glyph index and transformation matrix */
flags = big16toh(*(uint16_t *)(p + 0));
glyphIndex = big16toh(*(uint16_t *)(p + 2));
avail -= 4;
p += 4;
if (flags & ARG_1_AND_2_ARE_WORDS)
{
arg1 = big16toh(*(uint16_t *)(p + 0));
arg2 = big16toh(*(uint16_t *)(p + 2));
avail -= 4;
p += 4;
}
else
{
arg1 = (int8_t)*p++;
arg2 = (int8_t)*p++;
avail -= 2;
}
scale[0][0] = 1.0f;
scale[0][1] = 0.0f;
scale[1][0] = 0.0f;
scale[1][1] = 1.0f;
if (flags & WE_HAVE_A_SCALE)
{
scale[0][0] = f2dot14_to_float(big16toh(*(int16_t *)p));
scale[1][1] = scale[0][0];