2 * Copyright © 2002, 2003 Sun Microsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Sun Microsystems, Inc. nor the names of
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * This software is provided "AS IS," without a warranty of any kind.
22 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
23 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
24 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
25 * SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR
26 * LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE,
27 * MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES.
28 * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE,
29 * PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
30 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE
31 * THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE
32 * SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37 /* @(#)ttcr.c 1.7 03/01/08 SMI */
41 * @brief TrueTypeCreator method implementation
42 * @author Alexander Gelfenbain <adg@sun.com>
47 #include <sys/types.h>
54 #include <strings.h> /* bzero() only in strings.h on Solaris */
65 /* These must be #defined so that they can be used in initializers */
66 #define T_maxp 0x6D617870
67 #define T_glyf 0x676C7966
68 #define T_head 0x68656164
69 #define T_loca 0x6C6F6361
70 #define T_name 0x6E616D65
71 #define T_hhea 0x68686561
72 #define T_hmtx 0x686D7478
73 #define T_cmap 0x636D6170
74 #define T_vhea 0x76686561
75 #define T_vmtx 0x766D7478
76 #define T_OS2 0x4F532F32
77 #define T_post 0x706F7374
78 #define T_kern 0x6B65726E
79 #define T_cvt 0x63767420
88 * this is a duplicate code from sft.c but it is left here for performance reasons
91 #define _inline static __inline__
93 #define _inline static
96 _inline guint32 mkTag(guint8 a, guint8 b, guint8 c, guint8 d) {
97 return (a << 24) | (b << 16) | (c << 8) | d;
100 /*- Data access macros for data stored in big-endian or little-endian format */
101 _inline gint16 GetInt16(const guint8 *ptr, size_t offset, int bigendian)
107 t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
109 t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
115 _inline guint16 GetUInt16(const guint8 *ptr, size_t offset, int bigendian)
121 t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
123 t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
129 _inline gint32 GetInt32(const guint8 *ptr, size_t offset, int bigendian)
135 t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
136 (ptr+offset)[2] << 8 | (ptr+offset)[3];
138 t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
139 (ptr+offset)[1] << 8 | (ptr+offset)[0];
145 _inline guint32 GetUInt32(const guint8 *ptr, size_t offset, int bigendian)
152 t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
153 (ptr+offset)[2] << 8 | (ptr+offset)[3];
155 t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
156 (ptr+offset)[1] << 8 | (ptr+offset)[0];
163 _inline void PutInt16(gint16 val, guint8 *ptr, size_t offset, int bigendian)
168 ptr[offset] = (val >> 8) & 0xFF;
169 ptr[offset+1] = val & 0xFF;
171 ptr[offset+1] = (val >> 8) & 0xFF;
172 ptr[offset] = val & 0xFF;
177 _inline void PutUInt16(guint16 val, guint8 *ptr, size_t offset, int bigendian)
182 ptr[offset] = (val >> 8) & 0xFF;
183 ptr[offset+1] = val & 0xFF;
185 ptr[offset+1] = (val >> 8) & 0xFF;
186 ptr[offset] = val & 0xFF;
192 _inline void PutUInt32(guint32 val, guint8 *ptr, size_t offset, int bigendian)
197 ptr[offset] = (val >> 24) & 0xFF;
198 ptr[offset+1] = (val >> 16) & 0xFF;
199 ptr[offset+2] = (val >> 8) & 0xFF;
200 ptr[offset+3] = val & 0xFF;
202 ptr[offset+3] = (val >> 24) & 0xFF;
203 ptr[offset+2] = (val >> 16) & 0xFF;
204 ptr[offset+1] = (val >> 8) & 0xFF;
205 ptr[offset] = val & 0xFF;
211 _inline void PutInt32(gint32 val, guint8 *ptr, size_t offset, int bigendian)
216 ptr[offset] = (val >> 24) & 0xFF;
217 ptr[offset+1] = (val >> 16) & 0xFF;
218 ptr[offset+2] = (val >> 8) & 0xFF;
219 ptr[offset+3] = val & 0xFF;
221 ptr[offset+3] = (val >> 24) & 0xFF;
222 ptr[offset+2] = (val >> 16) & 0xFF;
223 ptr[offset+1] = (val >> 8) & 0xFF;
224 ptr[offset] = val & 0xFF;
229 static int TableEntryCompareF(const void *l, const void *r)
231 return ((const TableEntry *) l)->tag - ((const TableEntry *) r)->tag;
234 static int NameRecordCompareF(const void *l, const void *r)
236 NameRecord *ll = (NameRecord *) l;
237 NameRecord *rr = (NameRecord *) r;
239 if (ll->platformID != rr->platformID) {
240 return ll->platformID - rr->platformID;
241 } else if (ll->encodingID != rr->encodingID) {
242 return ll->encodingID - rr->encodingID;
243 } else if (ll->languageID != rr->languageID) {
244 return ll->languageID - rr->languageID;
245 } else if (ll->nameID != rr->nameID) {
246 return ll->nameID - rr->nameID;
252 static guint32 CheckSum(guint32 *ptr, guint32 length)
255 guint32 *endptr = ptr + ((length + 3) & (guint32) ~3) / 4;
257 while (ptr < endptr) sum += *ptr++;
262 _inline void *smalloc(size_t size)
264 void *res = malloc(size);
269 _inline void *scalloc(size_t n, size_t size)
271 void *res = calloc(n, size);
280 void TrueTypeCreatorNewEmpty(guint32 tag, TrueTypeCreator **_this)
282 TrueTypeCreator *ptr = smalloc(sizeof(TrueTypeCreator));
284 ptr->tables = listNewEmpty();
285 listSetElementDtor(ptr->tables, (GDestroyNotify)TrueTypeTableDispose);
292 void TrueTypeCreatorDispose(TrueTypeCreator *_this)
294 listDispose(_this->tables);
298 int AddTable(TrueTypeCreator *_this, TrueTypeTable *table)
301 listAppend(_this->tables, table);
306 void RemoveTable(TrueTypeCreator *_this, guint32 tag)
310 if (listCount(_this->tables)) {
311 listToFirst(_this->tables);
313 if (((TrueTypeTable *) listCurrent(_this->tables))->tag == tag) {
314 listRemove(_this->tables);
316 if (listNext(_this->tables)) {
324 static void ProcessTables(TrueTypeCreator *);
326 int StreamToMemory(TrueTypeCreator *_this, guint8 **ptr, guint32 *length)
328 guint16 numTables, searchRange=1, entrySelector=0, rangeShift;
329 guint32 s, offset, checkSumAdjustment = 0;
334 guint8 *head = NULL; /* saved pointer to the head table data for checkSumAdjustment calculation */
336 if ((n = listCount(_this->tables)) == 0) return SF_TTFORMAT;
338 ProcessTables(_this);
340 /* ProcessTables() adds 'loca' and 'hmtx' */
342 n = listCount(_this->tables);
343 numTables = (guint16) n;
346 te = scalloc(n, sizeof(TableEntry));
348 listToFirst(_this->tables);
349 for (i = 0; i < n; i++) {
350 GetRawData((TrueTypeTable *) listCurrent(_this->tables), &te[i].data, &te[i].length, &te[i].tag);
351 listNext(_this->tables);
354 qsort(te, n, sizeof(TableEntry), TableEntryCompareF);
359 } while (searchRange <= numTables);
363 rangeShift = numTables * 16 - searchRange;
365 s = offset = 12 + 16 * n;
367 for (i = 0; i < n; i++) {
368 s += (te[i].length + 3) & (guint32) ~3;
369 /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */
375 PutUInt32(_this->tag, ttf, 0, 1);
376 PutUInt16(numTables, ttf, 4, 1);
377 PutUInt16(searchRange, ttf, 6, 1);
378 PutUInt16(entrySelector, ttf, 8, 1);
379 PutUInt16(rangeShift, ttf, 10, 1);
381 /* Table Directory */
382 for (i = 0; i < n; i++) {
383 PutUInt32(te[i].tag, ttf + 12, 16 * i, 1);
384 PutUInt32(CheckSum((guint32 *) te[i].data, te[i].length), ttf + 12, 16 * i + 4, 1);
385 PutUInt32(offset, ttf + 12, 16 * i + 8, 1);
386 PutUInt32(te[i].length, ttf + 12, 16 * i + 12, 1);
388 if (te[i].tag == T_head) {
392 memcpy(ttf+offset, te[i].data, (te[i].length + 3) & (guint32) ~3 );
393 offset += (te[i].length + 3) & (guint32) ~3;
394 /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */
400 for (i = 0; i < s / 4; i++) checkSumAdjustment += p[i];
401 PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8, 1);
409 int StreamToFile(TrueTypeCreator *_this, const char* fname)
415 if (!fname) return SF_BADFILE;
416 if ((fd = open(fname, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0644)) == -1) return SF_BADFILE;
418 if ((r = StreamToMemory(_this, &ptr, &length)) != SF_OK) return r;
420 if (write(fd, ptr, length) != length) {
434 * TrueTypeTable private methods
437 #define TABLESIZE_head 54
438 #define TABLESIZE_hhea 36
439 #define TABLESIZE_maxp 32
443 /* Table data points to
444 * --------------------------------------------
445 * generic tdata_generic struct
446 * 'head' TABLESIZE_head bytes of memory
447 * 'hhea' TABLESIZE_hhea bytes of memory
448 * 'loca' tdata_loca struct
449 * 'maxp' TABLESIZE_maxp bytes of memory
450 * 'glyf' list of GlyphData structs (defined in sft.h)
451 * 'name' list of NameRecord structs (defined in sft.h)
452 * 'post' tdata_post struct
457 #define CMAP_SUBTABLE_INIT 10
458 #define CMAP_SUBTABLE_INCR 10
459 #define CMAP_PAIR_INIT 500
460 #define CMAP_PAIR_INCR 500
463 guint32 id; /* subtable ID (platform/encoding ID) */
464 guint32 n; /* number of used translation pairs */
465 guint32 m; /* number of allocated translation pairs */
466 guint32 *xc; /* character array */
467 guint32 *xg; /* glyph array */
471 guint32 n; /* number of used CMAP sub-tables */
472 guint32 m; /* number of allocated CMAP sub-tables */
473 CmapSubTable *s; /* sotred array of sub-tables */
483 guint32 nbytes; /* number of bytes in loca table */
484 guint8 *ptr; /* pointer to the data */
490 gint16 underlinePosition;
491 gint16 underlineThickness;
492 guint32 isFixedPitch;
493 void *ptr; /* format-specific pointer */
497 /* allocate memory for a TT table */
498 static guint8 *ttmalloc(guint32 nbytes)
503 n = (nbytes + 3) & (guint32) ~3;
511 static void FreeGlyphData(void *ptr)
513 GlyphData *p = (GlyphData *) ptr;
514 if (p->ptr) free(p->ptr);
518 static void TrueTypeTableDispose_generic(TrueTypeTable *_this)
522 tdata_generic *pdata = (tdata_generic *) _this->data;
523 if (pdata->nbytes) free(pdata->ptr);
530 static void TrueTypeTableDispose_head(TrueTypeTable *_this)
533 if (_this->data) free(_this->data);
538 static void TrueTypeTableDispose_hhea(TrueTypeTable *_this)
541 if (_this->data) free(_this->data);
546 static void TrueTypeTableDispose_loca(TrueTypeTable *_this)
550 tdata_loca *p = (tdata_loca *) _this->data;
551 if (p->ptr) free(p->ptr);
558 static void TrueTypeTableDispose_maxp(TrueTypeTable *_this)
561 if (_this->data) free(_this->data);
566 static void TrueTypeTableDispose_glyf(TrueTypeTable *_this)
569 if (_this->data) listDispose((list) _this->data);
574 static void TrueTypeTableDispose_cmap(TrueTypeTable *_this)
581 t = (table_cmap *) _this->data;
585 for (i = 0; i < t->m; i++) {
586 if (s[i].xc) free(s[i].xc);
587 if (s[i].xg) free(s[i].xg);
597 static void TrueTypeTableDispose_name(TrueTypeTable *_this)
600 if (_this->data) listDispose((list) _this->data);
605 static void TrueTypeTableDispose_post(TrueTypeTable *_this)
608 tdata_post *p = (tdata_post *) _this->data;
610 if (p->format == 0x00030000) {
613 fprintf(stderr, "Unsupported format of a 'post' table: %08X.\n", p->format);
621 /* destructor vtable */
625 void (*f)(TrueTypeTable *);
628 {0, TrueTypeTableDispose_generic},
629 {T_head, TrueTypeTableDispose_head},
630 {T_hhea, TrueTypeTableDispose_hhea},
631 {T_loca, TrueTypeTableDispose_loca},
632 {T_maxp, TrueTypeTableDispose_maxp},
633 {T_glyf, TrueTypeTableDispose_glyf},
634 {T_cmap, TrueTypeTableDispose_cmap},
635 {T_name, TrueTypeTableDispose_name},
636 {T_post, TrueTypeTableDispose_post}
640 static int GetRawData_generic(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
643 assert(_this->data != 0);
645 *ptr = ((tdata_generic *) _this->data)->ptr;
646 *len = ((tdata_generic *) _this->data)->nbytes;
647 *tag = ((tdata_generic *) _this->data)->tag;
653 static int GetRawData_head(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
655 *len = TABLESIZE_head;
656 *ptr = (guint8 *) _this->data;
662 static int GetRawData_hhea(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
664 *len = TABLESIZE_hhea;
665 *ptr = (guint8 *) _this->data;
671 static int GetRawData_loca(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
675 assert(_this->data != 0);
677 p = (tdata_loca *) _this->data;
679 if (p->nbytes == 0) return TTCR_ZEROGLYPHS;
688 static int GetRawData_maxp(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
690 *len = TABLESIZE_maxp;
691 *ptr = (guint8 *) _this->data;
697 static int GetRawData_glyf(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
699 guint32 n, nbytes = 0;
700 list l = (list) _this->data;
701 /* guint16 curID = 0; */ /* to check if glyph IDs are sequential and start from zero */
708 if (listCount(l) == 0) return TTCR_ZEROGLYPHS;
712 /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */
713 nbytes += ((GlyphData *) listCurrent(l))->nbytes;
714 } while (listNext(l));
716 p = _this->rawdata = ttmalloc(nbytes);
720 n = ((GlyphData *) listCurrent(l))->nbytes;
722 memcpy(p, ((GlyphData *) listCurrent(l))->ptr, n);
725 } while (listNext(l));
728 *ptr = _this->rawdata;
735 static guint8 *PackCmapType0(CmapSubTable *s, guint32 *length)
737 guint8 *ptr = smalloc(262);
742 PutUInt16(0, ptr, 0, 1);
743 PutUInt16(262, ptr, 2, 1);
744 PutUInt16(0, ptr, 4, 1);
746 for (i = 0; i < 256; i++) {
748 for (j = 0; j < s->n; j++) {
750 g = (guint16) s->xg[j];
760 /* XXX it only handles Format 0 encoding tables */
761 static guint8 *PackCmap(CmapSubTable *s, guint32 *length)
763 return PackCmapType0(s, length);
766 static int GetRawData_cmap(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
770 guint32 *sizes; /* of subtables */
779 t = (table_cmap *) _this->data;
783 subtables = scalloc(t->n, sizeof(guint8 *));
784 sizes = scalloc(t->n, sizeof(guint32));
786 for (i = 0; i < t->n; i++) {
787 subtables[i] = PackCmap(t->s+i, &l);
792 cmapsize = tlen + 4 + 8 * t->n;
793 _this->rawdata = cmap = ttmalloc(cmapsize);
795 PutUInt16(0, cmap, 0, 1);
796 PutUInt16(t->n, cmap, 2, 1);
797 coffset = 4 + t->n * 8;
799 for (i = 0; i < t->n; i++) {
800 PutUInt16(t->s[i].id >> 16, cmap + 4, i * 8, 1);
801 PutUInt16(t->s[i].id & 0xFF, cmap + 4, 2 + i * 8, 1);
802 PutUInt32(coffset, cmap + 4, 4 + i * 8, 1);
803 memcpy(cmap + coffset, subtables[i], sizes[i]);
819 static int GetRawData_name(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
823 gint16 i=0, n; /* number of Name Records */
834 l = (list) _this->data;
837 if ((n = listCount(l)) == 0) return TTCR_NONAMES;
839 nr = scalloc(n, sizeof(NameRecord));
844 memcpy(nr+i, listCurrent(l), sizeof(NameRecord));
845 stringLen += nr[i].slen;
847 } while (listNext(l));
849 if (stringLen > 65535) {
851 return TTCR_NAMETOOLONG;
854 qsort(nr, n, sizeof(NameRecord), NameRecordCompareF);
856 nameLen = stringLen + 12 * n + 6;
857 name = ttmalloc(nameLen);
859 PutUInt16(0, name, 0, 1);
860 PutUInt16(n, name, 2, 1);
861 PutUInt16(6 + 12 * n, name, 4, 1);
866 for (i = 0; i < n; i++) {
867 PutUInt16(nr[i].platformID, p1, 0, 1);
868 PutUInt16(nr[i].encodingID, p1, 2, 1);
869 PutUInt16(nr[i].languageID, p1, 4, 1);
870 PutUInt16(nr[i].nameID, p1, 6, 1);
871 PutUInt16(nr[i].slen, p1, 8, 1);
872 PutUInt16(p2 - (name + 6 + 12 * n), p1, 10, 1);
873 memcpy(p2, nr[i].sptr, nr[i].slen);
874 /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf("\n"); }; */
880 _this->rawdata = name;
886 /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */
891 static int GetRawData_post(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
893 tdata_post *p = (tdata_post *) _this->data;
898 if (_this->rawdata) free(_this->rawdata);
900 if (p->format == 0x00030000) {
902 post = ttmalloc(postLen);
903 PutUInt32(0x00030000, post, 0, 1);
904 PutUInt32(p->italicAngle, post, 4, 1);
905 PutUInt16(p->underlinePosition, post, 8, 1);
906 PutUInt16(p->underlineThickness, post, 10, 1);
907 PutUInt16(p->isFixedPitch, post, 12, 1);
910 fprintf(stderr, "Unrecognized format of a post table: %08X.\n", p->format);
911 ret = TTCR_POSTFORMAT;
914 *ptr = _this->rawdata = post;
927 int (*f)(TrueTypeTable *, guint8 **, guint32 *, guint32 *);
930 {0, GetRawData_generic},
931 {T_head, GetRawData_head},
932 {T_hhea, GetRawData_hhea},
933 {T_loca, GetRawData_loca},
934 {T_maxp, GetRawData_maxp},
935 {T_glyf, GetRawData_glyf},
936 {T_cmap, GetRawData_cmap},
937 {T_name, GetRawData_name},
938 {T_post, GetRawData_post}
944 * TrueTypeTable public methods
947 /* Note: Type42 fonts only need these tables:
948 * head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
950 * Microsoft required tables
951 * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2
953 * Apple required tables
954 * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post
958 TrueTypeTable *TrueTypeTableNew(guint32 tag,
962 TrueTypeTable *table;
963 tdata_generic *pdata;
965 table = smalloc(sizeof(TrueTypeTable));
966 pdata = (tdata_generic *) smalloc(sizeof(tdata_generic));
967 pdata->nbytes = nbytes;
970 pdata->ptr = ttmalloc(nbytes);
971 memcpy(pdata->ptr, ptr, nbytes);
978 table->rawdata = NULL;
983 TrueTypeTable *TrueTypeTableNew_head(guint32 fontRevision,
988 guint16 lowestRecPPEM,
989 gint16 fontDirectionHint)
991 TrueTypeTable *table;
994 assert(created != 0);
996 table = smalloc(sizeof(TrueTypeTable));
997 ptr = ttmalloc(TABLESIZE_head);
1000 PutUInt32(0x00010000, ptr, 0, 1); /* version */
1001 PutUInt32(fontRevision, ptr, 4, 1);
1002 PutUInt32(0x5F0F3CF5, ptr, 12, 1); /* magic number */
1003 PutUInt16(flags, ptr, 16, 1);
1004 PutUInt16(unitsPerEm, ptr, 18, 1);
1005 memcpy(ptr+20, created, 8); /* Created Long Date */
1006 bzero(ptr+28, 8); /* Modified Long Date */
1007 PutUInt16(macStyle, ptr, 44, 1);
1008 PutUInt16(lowestRecPPEM, ptr, 46, 1);
1009 PutUInt16(fontDirectionHint, ptr, 48, 1);
1010 PutUInt16(0, ptr, 52, 1); /* glyph data format: 0 */
1012 table->data = (void *) ptr;
1013 table->tag = T_head;
1014 table->rawdata = NULL;
1019 TrueTypeTable *TrueTypeTableNew_hhea(gint16 ascender,
1022 gint16 caretSlopeRise,
1023 gint16 caretSlopeRun)
1025 TrueTypeTable *table;
1028 table = smalloc(sizeof(TrueTypeTable));
1029 ptr = ttmalloc(TABLESIZE_hhea);
1031 PutUInt32(0x00010000, ptr, 0, 1); /* version */
1032 PutUInt16(ascender, ptr, 4, 1);
1033 PutUInt16(descender, ptr, 6, 1);
1034 PutUInt16(linegap, ptr, 8, 1);
1035 PutUInt16(caretSlopeRise, ptr, 18, 1);
1036 PutUInt16(caretSlopeRun, ptr, 20, 1);
1037 PutUInt16(0, ptr, 22, 1); /* reserved 1 */
1038 PutUInt16(0, ptr, 24, 1); /* reserved 2 */
1039 PutUInt16(0, ptr, 26, 1); /* reserved 3 */
1040 PutUInt16(0, ptr, 28, 1); /* reserved 4 */
1041 PutUInt16(0, ptr, 30, 1); /* reserved 5 */
1042 PutUInt16(0, ptr, 32, 1); /* metricDataFormat */
1044 table->data = (void *) ptr;
1045 table->tag = T_hhea;
1046 table->rawdata = NULL;
1051 TrueTypeTable *TrueTypeTableNew_loca(void)
1053 TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1054 table->data = smalloc(sizeof(tdata_loca));
1056 ((tdata_loca *)table->data)->nbytes = 0;
1057 ((tdata_loca *)table->data)->ptr = NULL;
1059 table->tag = T_loca;
1060 table->rawdata = NULL;
1065 TrueTypeTable *TrueTypeTableNew_maxp(guint8 *maxp, int size)
1067 TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1068 table->data = ttmalloc(TABLESIZE_maxp);
1070 if (maxp && size == TABLESIZE_maxp) {
1071 memcpy(table->data, maxp, TABLESIZE_maxp);
1074 table->tag = T_maxp;
1075 table->rawdata = NULL;
1080 TrueTypeTable *TrueTypeTableNew_glyf(void)
1082 TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1083 list l = listNewEmpty();
1087 listSetElementDtor(l, FreeGlyphData);
1090 table->rawdata = NULL;
1091 table->tag = T_glyf;
1096 TrueTypeTable *TrueTypeTableNew_cmap(void)
1098 TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1099 table_cmap *cmap = smalloc(sizeof(table_cmap));
1102 cmap->m = CMAP_SUBTABLE_INIT;
1103 cmap->s = (CmapSubTable *) scalloc(CMAP_SUBTABLE_INIT, sizeof(CmapSubTable));
1104 memset(cmap->s, 0, sizeof(CmapSubTable) * CMAP_SUBTABLE_INIT);
1106 table->data = (table_cmap *) cmap;
1108 table->rawdata = NULL;
1109 table->tag = T_cmap;
1114 static void DisposeNameRecord(void *ptr)
1117 NameRecord *nr = (NameRecord *) ptr;
1118 if (nr->sptr) free(nr->sptr);
1123 static NameRecord* NameRecordNewCopy(NameRecord *nr)
1125 NameRecord *p = smalloc(sizeof(NameRecord));
1127 memcpy(p, nr, sizeof(NameRecord));
1130 p->sptr = smalloc(p->slen);
1131 memcpy(p->sptr, nr->sptr, p->slen);
1137 TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr)
1139 TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1140 list l = listNewEmpty();
1144 listSetElementDtor(l, DisposeNameRecord);
1148 for (i = 0; i < n; i++) {
1149 listAppend(l, NameRecordNewCopy(nr+i));
1154 table->rawdata = NULL;
1155 table->tag = T_name;
1160 TrueTypeTable *TrueTypeTableNew_post(guint32 format,
1161 guint32 italicAngle,
1162 gint16 underlinePosition,
1163 gint16 underlineThickness,
1164 guint32 isFixedPitch)
1166 TrueTypeTable *table;
1169 assert(format == 0x00030000); /* Only format 3.0 is supported at this time */
1170 table = smalloc(sizeof(TrueTypeTable));
1171 post = smalloc(sizeof(tdata_post));
1173 post->format = format;
1174 post->italicAngle = italicAngle;
1175 post->underlinePosition = underlinePosition;
1176 post->underlineThickness = underlineThickness;
1177 post->isFixedPitch = isFixedPitch;
1181 table->rawdata = NULL;
1182 table->tag = T_post;
1189 void TrueTypeTableDispose(TrueTypeTable *_this)
1191 /* XXX do a binary search */
1196 if (_this->rawdata) free(_this->rawdata);
1198 for(i=0; i < sizeof(vtable1)/sizeof(*vtable1); i++) {
1199 if (_this->tag == vtable1[i].tag) {
1200 vtable1[i].f(_this);
1204 assert(!"Unknown TrueType table.\n");
1207 int GetRawData(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
1209 /* XXX do a binary search */
1217 *ptr = NULL; *len = 0; *tag = 0;
1219 if (_this->rawdata) {
1220 free(_this->rawdata);
1221 _this->rawdata = NULL;
1224 for(i=0; i < sizeof(vtable2)/sizeof(*vtable2); i++) {
1225 if (_this->tag == vtable2[i].tag) {
1226 return vtable2[i].f(_this, ptr, len, tag);
1230 assert(!"Unknwon TrueType table.\n");
1231 return TTCR_UNKNOWN;
1234 void cmapAdd(TrueTypeTable *table, guint32 id, guint32 c, guint32 g)
1241 assert(table->tag == T_cmap);
1242 t = (table_cmap *) table->data; assert(t != 0);
1243 s = t->s; assert(s != 0);
1247 for (i = 0; i < t->n; i++) {
1248 if (s[i].id == id) {
1257 tmp = scalloc(t->m + CMAP_SUBTABLE_INCR, sizeof(CmapSubTable));
1258 memset(tmp, 0, t->m + CMAP_SUBTABLE_INCR * sizeof(CmapSubTable));
1259 memcpy(tmp, s, sizeof(CmapSubTable) * t->m);
1260 t->m += CMAP_SUBTABLE_INCR;
1266 for (i = 0; i < t->n; i++) {
1267 if (s[i].id > id) break;
1271 memmove(s+i+1, s+i, t->n-i);
1278 s[i].m = CMAP_PAIR_INIT;
1279 s[i].xc = scalloc(CMAP_PAIR_INIT, sizeof(guint32));
1280 s[i].xg = scalloc(CMAP_PAIR_INIT, sizeof(guint32));
1283 if (s[i].n == s[i].m) {
1284 guint32 *tmp1 = scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(guint32));
1285 guint32 *tmp2 = scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(guint32));
1288 memcpy(tmp1, s[i].xc, sizeof(guint32) * s[i].m);
1289 memcpy(tmp2, s[i].xg, sizeof(guint32) * s[i].m);
1290 s[i].m += CMAP_PAIR_INCR;
1297 s[i].xc[s[i].n] = c;
1298 s[i].xg[s[i].n] = g;
1302 guint32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, TrueTypeFont *fnt)
1306 int ret, n, ncomponents;
1311 assert(table->tag == T_glyf);
1313 if (!glyphdata) return -1;
1315 glyphlist = listNewEmpty();
1317 ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist);
1319 l = (list) table->data;
1320 if (listCount(l) > 0) {
1322 ret = n = ((GlyphData *) listCurrent(l))->newID + 1;
1326 glyphdata->newID = n++;
1327 listAppend(l, glyphdata);
1329 if (ncomponents > 1) {
1330 listPositionAt(glyphlist, 1); /* glyphData->glyphID is always the first glyph on the list */
1333 currentID = (guint32) listCurrent(glyphlist);
1334 /* XXX expensive! should be rewritten with sorted arrays! */
1337 if (((GlyphData *) listCurrent(l))->glyphID == currentID) {
1341 } while (listNext(l));
1344 gd = GetTTRawGlyphData(fnt, currentID);
1348 } while (listNext(glyphlist));
1351 listDispose(glyphlist);
1355 guint32 glyfCount(const TrueTypeTable *table)
1358 assert(table->tag == T_glyf);
1359 return listCount((list) table->data);
1363 void nameAdd(TrueTypeTable *table, NameRecord *nr)
1368 assert(table->tag == T_name);
1370 l = (list) table->data;
1372 listAppend(l, NameRecordNewCopy(nr));
1375 static TrueTypeTable *FindTable(TrueTypeCreator *tt, guint32 tag)
1377 if (listIsEmpty(tt->tables)) return NULL;
1379 listToFirst(tt->tables);
1382 if (((TrueTypeTable *) listCurrent(tt->tables))->tag == tag) {
1383 return listCurrent(tt->tables);
1385 } while (listNext(tt->tables));
1390 /* This function processes all the tables and synchronizes them before creating
1391 * the output TrueType stream.
1393 * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' ***
1397 * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables.
1398 * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table.
1399 * - Stores indexToLocFormat in 'head'
1400 * - updates 'maxp' table
1401 * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics
1405 static void ProcessTables(TrueTypeCreator *tt)
1407 TrueTypeTable *glyf, *loca, *head, *maxp, *hhea;
1409 guint32 nGlyphs, locaLen = 0, glyfLen = 0;
1410 gint16 xMin = 0, yMin = 0, xMax = 0, yMax = 0;
1412 gint16 indexToLocFormat;
1413 guint8 *glyfPtr, *locaPtr, *hmtxPtr, *hheaPtr;
1416 guint16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0;
1417 TTSimpleGlyphMetrics *met;
1419 guint32 *gid; /* array of old glyphIDs */
1421 glyf = FindTable(tt, T_glyf);
1422 glyphlist = (list) glyf->data;
1423 nGlyphs = listCount(glyphlist);
1424 assert(nGlyphs != 0);
1425 gid = scalloc(nGlyphs, sizeof(guint32));
1427 RemoveTable(tt, T_loca);
1428 RemoveTable(tt, T_hmtx);
1430 /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */
1432 listToFirst(glyphlist);
1434 GlyphData *gd = (GlyphData *) listCurrent(glyphlist);
1436 glyfLen += gd->nbytes;
1437 /* XXX if (gd->nbytes & 1) glyfLen++; */
1440 assert(gd->newID == i);
1441 gid[i++] = gd->glyphID;
1442 /* gd->glyphID = i++; */
1444 /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */
1446 if (gd->nbytes != 0) {
1447 z = GetInt16(gd->ptr, 2, 1);
1448 if (z < xMin) xMin = z;
1450 z = GetInt16(gd->ptr, 4, 1);
1451 if (z < yMin) yMin = z;
1453 z = GetInt16(gd->ptr, 6, 1);
1454 if (z > xMax) xMax = z;
1456 z = GetInt16(gd->ptr, 8, 1);
1457 if (z > yMax) yMax = z;
1460 if (gd->compflag == 0) { /* non-composite glyph */
1461 if (gd->npoints > maxPoints) maxPoints = gd->npoints;
1462 if (gd->ncontours > maxContours) maxContours = gd->ncontours;
1463 } else { /* composite glyph */
1464 if (gd->npoints > maxCompositePoints) maxCompositePoints = gd->npoints;
1465 if (gd->ncontours > maxCompositeContours) maxCompositeContours = gd->ncontours;
1468 } while (listNext(glyphlist));
1470 indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0;
1471 locaLen = indexToLocFormat ? (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1;
1473 glyfPtr = ttmalloc(glyfLen);
1474 locaPtr = ttmalloc(locaLen);
1475 met = scalloc(nGlyphs, sizeof(TTSimpleGlyphMetrics));
1478 listToFirst(glyphlist);
1482 GlyphData *gd = (GlyphData *) listCurrent(glyphlist);
1484 if (gd->compflag) { /* re-number all components */
1485 guint16 flags, index;
1486 guint8 *ptr = gd->ptr + 10;
1489 flags = GetUInt16(ptr, 0, 1);
1490 index = GetUInt16(ptr, 2, 1);
1491 /* XXX use the sorted array of old to new glyphID mapping and do a binary search */
1492 for (j = 0; j < nGlyphs; j++) {
1493 if (gid[j] == index) {
1497 /* printf("X: %d -> %d.\n", index, j); */
1499 PutUInt16((guint16) j, ptr, 2, 1);
1503 if (flags & ARG_1_AND_2_ARE_WORDS) {
1509 if (flags & WE_HAVE_A_SCALE) {
1511 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
1513 } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
1516 } while (flags & MORE_COMPONENTS);
1519 if (gd->nbytes != 0) {
1520 memcpy(p1, gd->ptr, gd->nbytes);
1522 if (indexToLocFormat == 1) {
1523 PutUInt32(p1 - glyfPtr, p2, 0, 1);
1526 PutUInt16((p1 - glyfPtr) >> 1, p2, 0, 1);
1531 /* fill the array of metrics */
1532 met[i].adv = gd->aw;
1533 met[i].sb = gd->lsb;
1535 } while (listNext(glyphlist));
1539 if (indexToLocFormat == 1) {
1540 PutUInt32(p1 - glyfPtr, p2, 0, 1);
1542 PutUInt16((p1 - glyfPtr) >> 1, p2, 0, 1);
1545 glyf->rawdata = glyfPtr;
1547 loca = TrueTypeTableNew_loca(); assert(loca != 0);
1548 ((tdata_loca *) loca->data)->ptr = locaPtr;
1549 ((tdata_loca *) loca->data)->nbytes = locaLen;
1553 head = FindTable(tt, T_head);
1554 PutInt16(xMin, head->data, 36, 1);
1555 PutInt16(yMin, head->data, 38, 1);
1556 PutInt16(xMax, head->data, 40, 1);
1557 PutInt16(yMax, head->data, 42, 1);
1558 PutInt16(indexToLocFormat, head->data, 50, 1);
1560 maxp = FindTable(tt, T_maxp);
1562 PutUInt16(nGlyphs, maxp->data, 4, 1);
1563 PutUInt16(maxPoints, maxp->data, 6, 1);
1564 PutUInt16(maxContours, maxp->data, 8, 1);
1565 PutUInt16(maxCompositePoints, maxp->data, 10, 1);
1566 PutUInt16(maxCompositeContours, maxp->data, 12, 1);
1569 /* XXX do not overwrite the existing data. Fix: re-calculate these numbers here */
1570 PutUInt16(2, maxp->data, 14, 1); /* maxZones is always 2 */
1571 PutUInt16(0, maxp->data, 16, 1); /* maxTwilightPoints */
1572 PutUInt16(0, maxp->data, 18, 1); /* maxStorage */
1573 PutUInt16(0, maxp->data, 20, 1); /* maxFunctionDefs */
1574 PutUint16(0, maxp->data, 22, 1); /* maxInstructionDefs */
1575 PutUint16(0, maxp->data, 24, 1); /* maxStackElements */
1576 PutUint16(0, maxp->data, 26, 1); /* maxSizeOfInstructions */
1577 PutUint16(0, maxp->data, 28, 1); /* maxComponentElements */
1578 PutUint16(0, maxp->data, 30, 1); /* maxComponentDepth */
1582 * Generate an htmx table and update hhea table
1584 hhea = FindTable(tt, T_hhea); assert(hhea != 0);
1585 hheaPtr = (guint8 *) hhea->data;
1587 for (i = nGlyphs - 1; i > 0; i--) {
1588 if (met[i].adv != met[i-1].adv) break;
1590 nlsb = nGlyphs - 1 - i;
1592 hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2;
1593 hmtxPtr = ttmalloc(hmtxSize);
1596 for (i = 0; i < nGlyphs; i++) {
1597 if (i < nGlyphs - nlsb) {
1598 PutUInt16(met[i].adv, p1, 0, 1);
1599 PutUInt16(met[i].sb, p1, 2, 1);
1602 PutUInt16(met[i].sb, p1, 0, 1);
1607 AddTable(tt, TrueTypeTableNew(T_hmtx, hmtxSize, hmtxPtr));
1608 PutUInt16(nGlyphs - nlsb, hheaPtr, 34, 1);
1616 TrueTypeCreator *ttcr;
1617 guint8 *t1, *t2, *t3, *t4, *t5, *t6, *t7;
1619 TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr);
1621 t1 = malloc(1000); memset(t1, 'a', 1000);
1622 t2 = malloc(2000); memset(t2, 'b', 2000);
1623 t3 = malloc(3000); memset(t3, 'c', 3000);
1624 t4 = malloc(4000); memset(t4, 'd', 4000);
1625 t5 = malloc(5000); memset(t5, 'e', 5000);
1626 t6 = malloc(6000); memset(t6, 'f', 6000);
1627 t7 = malloc(7000); memset(t7, 'g', 7000);
1629 AddTable(ttcr, TrueTypeTableNew(0x6D617870, 1000, t1));
1630 AddTable(ttcr, TrueTypeTableNew(0x4F532F32, 2000, t2));
1631 AddTable(ttcr, TrueTypeTableNew(0x636D6170, 3000, t3));
1632 AddTable(ttcr, TrueTypeTableNew(0x6C6F6361, 4000, t4));
1633 AddTable(ttcr, TrueTypeTableNew(0x68686561, 5000, t5));
1634 AddTable(ttcr, TrueTypeTableNew(0x676C7966, 6000, t6));
1635 AddTable(ttcr, TrueTypeTableNew(0x6B65726E, 7000, t7));
1646 StreamToFile(ttcr, "ttcrout.ttf");
1648 TrueTypeCreatorDispose(ttcr);