]> git.donarmstrong.com Git - xournal.git/blob - src/ttsubset/ttcr.c
Print via gtk-print instead of libgnomeprint
[xournal.git] / src / ttsubset / ttcr.c
1 /*
2  * Copyright © 2002, 2003 Sun Microsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
20  * This software is provided "AS IS," without a warranty of any kind.
21  *
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.
33  *
34  */
35
36 /* $Id$ */
37 /* @(#)ttcr.c 1.7 03/01/08 SMI */
38
39 /*
40  * @file ttcr.c
41  * @brief TrueTypeCreator method implementation
42  * @author Alexander Gelfenbain <adg@sun.com>
43  * @version 1.3
44  *
45  */
46
47 #include <sys/types.h>
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #include <fcntl.h>
52 #include <stdlib.h>
53 #ifdef sun
54 #include <strings.h> /* bzero() only in strings.h on Solaris */
55 #else
56 #include <string.h>
57 #endif
58 #include <assert.h>
59 #include "ttcr.h"
60
61 #ifndef O_BINARY
62 #define O_BINARY 0
63 #endif
64
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
80
81 typedef struct {
82     guint32 tag;
83     guint32 length;
84     guint8  *data;
85 } TableEntry;
86
87 /*
88  * this is a duplicate code from sft.c but it is left here for performance reasons
89  */
90 #ifdef __GNUC__
91 #define _inline static __inline__
92 #else
93 #define _inline static
94 #endif
95
96 _inline guint32 mkTag(guint8 a, guint8 b, guint8 c, guint8 d) {
97     return (a << 24) | (b << 16) | (c << 8) | d;
98 }
99
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)
102 {
103     gint16 t;
104     assert(ptr != 0);
105     
106     if (bigendian) {
107         t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
108     } else {
109         t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
110     }
111         
112     return t;
113 }
114
115 _inline guint16 GetUInt16(const guint8 *ptr, size_t offset, int bigendian)
116 {
117     guint16 t;
118     assert(ptr != 0);
119
120     if (bigendian) {
121         t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
122     } else {
123         t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
124     }
125
126     return t;
127 }
128
129 _inline gint32  GetInt32(const guint8 *ptr, size_t offset, int bigendian)
130 {
131     gint32 t;
132     assert(ptr != 0);
133     
134     if (bigendian) {
135         t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
136             (ptr+offset)[2] << 8  | (ptr+offset)[3];
137     } else {
138         t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
139             (ptr+offset)[1] << 8  | (ptr+offset)[0];
140     }
141         
142     return t;
143 }
144
145 _inline guint32 GetUInt32(const guint8 *ptr, size_t offset, int bigendian)
146 {
147     guint32 t;
148     assert(ptr != 0);
149     
150
151     if (bigendian) {
152         t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
153             (ptr+offset)[2] << 8  | (ptr+offset)[3];
154     } else {
155         t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
156             (ptr+offset)[1] << 8  | (ptr+offset)[0];
157     }
158         
159     return t;
160 }
161
162
163 _inline void PutInt16(gint16 val, guint8 *ptr, size_t offset, int bigendian)
164 {
165     assert(ptr != 0);
166
167     if (bigendian) {
168         ptr[offset] = (val >> 8) & 0xFF;
169         ptr[offset+1] = val & 0xFF;
170     } else {
171         ptr[offset+1] = (val >> 8) & 0xFF;
172         ptr[offset] = val & 0xFF;
173     }
174
175 }
176
177 _inline void PutUInt16(guint16 val, guint8 *ptr, size_t offset, int bigendian)
178 {
179     assert(ptr != 0);
180
181     if (bigendian) {
182         ptr[offset] = (val >> 8) & 0xFF;
183         ptr[offset+1] = val & 0xFF;
184     } else {
185         ptr[offset+1] = (val >> 8) & 0xFF;
186         ptr[offset] = val & 0xFF;
187     }
188
189 }
190
191
192 _inline void PutUInt32(guint32 val, guint8 *ptr, size_t offset, int bigendian)
193 {
194     assert(ptr != 0);
195
196     if (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;
201     } else {
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;
206     }
207
208 }
209
210
211 _inline void PutInt32(gint32 val, guint8 *ptr, size_t offset, int bigendian)
212 {
213     assert(ptr != 0);
214
215     if (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;
220     } else {
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;
225     }
226
227 }
228
229 static int TableEntryCompareF(const void *l, const void *r)
230 {
231     return ((const TableEntry *) l)->tag - ((const TableEntry *) r)->tag;
232 }
233
234 static int NameRecordCompareF(const void *l, const void *r)
235 {
236     NameRecord *ll = (NameRecord *) l;
237     NameRecord *rr = (NameRecord *) r;
238
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;
247     }
248     return 0;
249 }
250     
251
252 static guint32 CheckSum(guint32 *ptr, guint32 length)
253 {
254     guint32 sum = 0;
255     guint32 *endptr = ptr + ((length + 3) & (guint32) ~3) / 4;
256
257     while (ptr < endptr) sum += *ptr++;
258
259     return sum;
260 }
261
262 _inline void *smalloc(size_t size)
263 {
264     void *res = malloc(size);
265     assert(res != 0);
266     return res;
267 }
268
269 _inline void *scalloc(size_t n, size_t size)
270 {
271     void *res = calloc(n, size);
272     assert(res != 0);
273     return res;
274 }
275
276 /*
277  * Public functions
278  */
279
280 void TrueTypeCreatorNewEmpty(guint32 tag, TrueTypeCreator **_this)
281 {
282     TrueTypeCreator *ptr = smalloc(sizeof(TrueTypeCreator));
283
284     ptr->tables = listNewEmpty();
285     listSetElementDtor(ptr->tables, (GDestroyNotify)TrueTypeTableDispose);
286
287     ptr->tag = tag;
288
289     *_this = ptr;
290 }
291
292 void TrueTypeCreatorDispose(TrueTypeCreator *_this)
293 {
294     listDispose(_this->tables);
295     free(_this);
296 }
297
298 int AddTable(TrueTypeCreator *_this, TrueTypeTable *table)
299 {
300     if (table != 0) {
301         listAppend(_this->tables, table);
302     }
303     return SF_OK;
304 }
305
306 void RemoveTable(TrueTypeCreator *_this, guint32 tag)
307 {
308     int done = 0;
309     
310     if (listCount(_this->tables)) {
311         listToFirst(_this->tables);
312         do {
313             if (((TrueTypeTable *) listCurrent(_this->tables))->tag == tag) {
314                 listRemove(_this->tables);
315             } else {
316                 if (listNext(_this->tables)) {
317                     done = 1;
318                 }
319             }
320         } while (!done);
321     }
322 }
323
324 static void ProcessTables(TrueTypeCreator *);
325
326 int StreamToMemory(TrueTypeCreator *_this, guint8 **ptr, guint32 *length)
327 {
328     guint16 numTables, searchRange=1, entrySelector=0, rangeShift;
329     guint32 s, offset, checkSumAdjustment = 0;
330     guint32 *p;
331     guint8 *ttf;
332     int i=0, n;
333     TableEntry *te;
334     guint8 *head = NULL;     /* saved pointer to the head table data for checkSumAdjustment calculation */
335     
336     if ((n = listCount(_this->tables)) == 0) return SF_TTFORMAT;
337
338     ProcessTables(_this);
339
340     /* ProcessTables() adds 'loca' and 'hmtx' */
341     
342     n = listCount(_this->tables);
343     numTables = (guint16) n;
344     
345
346     te = scalloc(n, sizeof(TableEntry));
347
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);
352     }
353
354     qsort(te, n, sizeof(TableEntry), TableEntryCompareF);
355     
356     do {
357         searchRange *= 2;
358         entrySelector++;
359     } while (searchRange <= numTables);
360
361     searchRange *= 8;
362     entrySelector--;
363     rangeShift = numTables * 16 - searchRange;
364
365     s = offset = 12 + 16 * n;
366
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; */
370     }
371
372     ttf = smalloc(s);
373
374     /* Offset Table */
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);
380
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);
387
388         if (te[i].tag == T_head) {
389             head = ttf + offset;
390         }
391
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; */
395     }
396
397     free(te);
398
399     p = (guint32 *) ttf;
400     for (i = 0; i < s / 4; i++) checkSumAdjustment += p[i];
401     PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8, 1);
402
403     *ptr = ttf;
404     *length = s;
405     
406     return SF_OK;
407 }
408
409 int StreamToFile(TrueTypeCreator *_this, const char* fname)
410 {
411     guint8 *ptr;
412     guint32 length;
413     int fd, r;
414
415     if (!fname) return SF_BADFILE;
416     if ((fd = open(fname, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0644)) == -1) return SF_BADFILE;
417
418     if ((r = StreamToMemory(_this, &ptr, &length)) != SF_OK) return r;
419
420     if (write(fd, ptr, length) != length) {
421         r = SF_FILEIO;
422     } else {
423         r = SF_OK;
424     }
425
426     close(fd);
427     free(ptr);
428     return r;
429 }
430
431
432
433 /*
434  * TrueTypeTable private methods
435  */
436
437 #define TABLESIZE_head 54
438 #define TABLESIZE_hhea 36
439 #define TABLESIZE_maxp 32
440
441
442
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
453  *
454  */
455
456
457 #define CMAP_SUBTABLE_INIT 10
458 #define CMAP_SUBTABLE_INCR 10
459 #define CMAP_PAIR_INIT 500
460 #define CMAP_PAIR_INCR 500
461
462 typedef struct {
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                           */
468 } CmapSubTable;
469
470 typedef struct {
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           */
474 } table_cmap;
475
476 typedef struct {
477     guint32 tag;
478     guint32 nbytes;
479     guint8 *ptr;
480 } tdata_generic;
481
482 typedef struct {
483     guint32 nbytes;                      /* number of bytes in loca table */
484     guint8 *ptr;                          /* pointer to the data */
485 } tdata_loca;
486
487 typedef struct {
488     guint32 format;
489     guint32 italicAngle;
490     gint16  underlinePosition;
491     gint16  underlineThickness;
492     guint32 isFixedPitch;
493     void   *ptr;                        /* format-specific pointer */
494 } tdata_post;
495     
496
497 /* allocate memory for a TT table */
498 static guint8 *ttmalloc(guint32 nbytes)
499 {
500     guint32 n; 
501     guint8 *res;
502
503     n = (nbytes + 3) & (guint32) ~3;
504     res = malloc(n);
505     assert(res != 0);
506     bzero(res, n);
507
508     return res;
509 }
510     
511 static void FreeGlyphData(void *ptr)
512 {
513     GlyphData *p = (GlyphData *) ptr;
514     if (p->ptr) free(p->ptr);
515     free(p);
516 }
517
518 static void TrueTypeTableDispose_generic(TrueTypeTable *_this)
519 {
520     if (_this) {
521         if (_this->data) {
522             tdata_generic *pdata = (tdata_generic *) _this->data;
523             if (pdata->nbytes) free(pdata->ptr);
524             free(_this->data);
525         }
526         free(_this);
527     }
528 }
529
530 static void TrueTypeTableDispose_head(TrueTypeTable *_this)
531 {
532     if (_this) {
533         if (_this->data) free(_this->data);
534         free(_this);
535     }
536 }
537
538 static void TrueTypeTableDispose_hhea(TrueTypeTable *_this)
539 {
540     if (_this) {
541         if (_this->data) free(_this->data);
542         free(_this);
543     }
544 }
545
546 static void TrueTypeTableDispose_loca(TrueTypeTable *_this)
547 {
548     if (_this) {
549         if (_this->data) {
550             tdata_loca *p = (tdata_loca *) _this->data;
551             if (p->ptr) free(p->ptr);
552             free(_this->data);
553         }
554         free(_this);
555     }
556 }
557
558 static void TrueTypeTableDispose_maxp(TrueTypeTable *_this)
559 {
560     if (_this) {
561         if (_this->data) free(_this->data);
562         free(_this);
563     }
564 }
565
566 static void TrueTypeTableDispose_glyf(TrueTypeTable *_this)
567 {
568     if (_this) {
569         if (_this->data) listDispose((list) _this->data);
570         free(_this);
571     }
572 }
573
574 static void TrueTypeTableDispose_cmap(TrueTypeTable *_this)
575 {
576     table_cmap *t;
577     CmapSubTable *s;
578     int i;
579     
580     if (_this) {
581         t = (table_cmap *) _this->data;
582         if (t) {
583             s = t->s;
584             if (s) {
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);
588                 }
589                 free(s);
590             }
591             free(t);
592         }
593         free(_this);
594     }
595 }
596
597 static void TrueTypeTableDispose_name(TrueTypeTable *_this)
598 {
599     if (_this) {
600         if (_this->data) listDispose((list) _this->data);
601         free(_this);
602     }
603 }
604
605 static void TrueTypeTableDispose_post(TrueTypeTable *_this)
606 {
607     if (_this) {
608         tdata_post *p = (tdata_post *) _this->data;
609         if (p) {
610             if (p->format == 0x00030000) {
611                 /* do nothing */
612             } else {
613                 fprintf(stderr, "Unsupported format of a 'post' table: %08X.\n", p->format);
614             }
615             free(p);
616         }
617         free(_this);
618     }
619 }
620
621 /* destructor vtable */
622
623 static struct {
624     guint32 tag;
625     void (*f)(TrueTypeTable *);
626 } vtable1[] =
627 {
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}
637     
638 };
639
640 static int GetRawData_generic(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
641 {
642     assert(_this != 0);
643     assert(_this->data != 0);
644
645     *ptr = ((tdata_generic *) _this->data)->ptr;
646     *len = ((tdata_generic *) _this->data)->nbytes;
647     *tag = ((tdata_generic *) _this->data)->tag;
648
649     return TTCR_OK;
650 }
651
652
653 static int GetRawData_head(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
654 {
655     *len = TABLESIZE_head;
656     *ptr = (guint8 *) _this->data;
657     *tag = T_head;
658     
659     return TTCR_OK;
660 }
661
662 static int GetRawData_hhea(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
663 {
664     *len = TABLESIZE_hhea;
665     *ptr = (guint8 *) _this->data;
666     *tag = T_hhea;
667     
668     return TTCR_OK;
669 }
670
671 static int GetRawData_loca(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
672 {
673     tdata_loca *p;
674
675     assert(_this->data != 0);
676
677     p = (tdata_loca *) _this->data;
678
679     if (p->nbytes == 0) return TTCR_ZEROGLYPHS;
680
681     *ptr = p->ptr;
682     *len = p->nbytes;
683     *tag = T_loca;
684
685     return TTCR_OK;
686 }
687
688 static int GetRawData_maxp(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
689 {
690     *len = TABLESIZE_maxp;
691     *ptr = (guint8 *) _this->data;
692     *tag = T_maxp;
693     
694     return TTCR_OK;
695 }
696
697 static int GetRawData_glyf(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
698 {
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 */
702     guint8 *p;
703
704     *ptr = NULL;
705     *len = 0;
706     *tag = 0;
707
708     if (listCount(l) == 0) return TTCR_ZEROGLYPHS;
709
710     listToFirst(l);
711     do {
712         /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */
713         nbytes += ((GlyphData *) listCurrent(l))->nbytes;
714     } while (listNext(l));
715
716     p = _this->rawdata = ttmalloc(nbytes);
717
718     listToFirst(l);
719     do {
720         n = ((GlyphData *) listCurrent(l))->nbytes;
721         if (n != 0) {
722             memcpy(p, ((GlyphData *) listCurrent(l))->ptr, n);
723             p += n;
724         }
725     } while (listNext(l));
726
727     *len = nbytes;
728     *ptr = _this->rawdata;
729     *tag = T_glyf;
730
731     return TTCR_OK;
732 }
733
734 /* cmap packers */
735 static guint8 *PackCmapType0(CmapSubTable *s, guint32 *length)
736 {
737     guint8 *ptr = smalloc(262);
738     guint8 *p = ptr + 6;
739     int i, j;
740     guint16 g;
741
742     PutUInt16(0, ptr, 0, 1);
743     PutUInt16(262, ptr, 2, 1);
744     PutUInt16(0, ptr, 4, 1);
745
746     for (i = 0; i < 256; i++) {
747         g = 0;
748         for (j = 0; j < s->n; j++) {
749             if (s->xc[j] == i) {
750                 g = (guint16) s->xg[j];
751             }
752         }
753         p[i] = (guint8) g;
754     }
755     *length = 262;
756     return ptr;
757 }
758             
759
760 /* XXX it only handles Format 0 encoding tables */
761 static guint8 *PackCmap(CmapSubTable *s, guint32 *length)
762 {
763     return PackCmapType0(s, length);
764 }
765
766 static int GetRawData_cmap(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
767 {
768     table_cmap *t;
769     guint8 **subtables;
770     guint32 *sizes;            /* of subtables */
771     int i;
772     guint32 tlen = 0;
773     guint32 l;
774     guint32 cmapsize;
775     guint8 *cmap;
776     guint32 coffset;
777
778     assert(_this != 0);
779     t = (table_cmap *) _this->data;
780     assert(t != 0);
781     assert(t->n != 0);
782
783     subtables = scalloc(t->n, sizeof(guint8 *));
784     sizes = scalloc(t->n, sizeof(guint32));
785
786     for (i = 0; i < t->n; i++) {
787         subtables[i] = PackCmap(t->s+i, &l);
788         sizes[i] = l;
789         tlen += l;
790     }
791
792     cmapsize = tlen + 4 + 8 * t->n;
793     _this->rawdata = cmap = ttmalloc(cmapsize);
794
795     PutUInt16(0, cmap, 0, 1);
796     PutUInt16(t->n, cmap, 2, 1);
797     coffset = 4 + t->n * 8;
798
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]);
804         free(subtables[i]);
805         coffset += sizes[i];
806     }
807
808     free(subtables);
809     free(sizes);
810
811     *ptr = cmap;
812     *len = cmapsize;
813     *tag = T_cmap;
814
815     return TTCR_OK;
816 }
817
818
819 static int GetRawData_name(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
820 {
821     list l;
822     NameRecord *nr;
823     gint16 i=0, n;                          /* number of Name Records */
824     guint8 *name;
825     guint16 nameLen;
826     int stringLen = 0;
827     guint8 *p1, *p2;
828
829     *ptr = NULL;
830     *len = 0;
831     *tag = 0;
832
833     assert(_this != 0);
834     l = (list) _this->data;
835     assert(l != 0);
836
837     if ((n = listCount(l)) == 0) return TTCR_NONAMES;
838
839     nr = scalloc(n, sizeof(NameRecord));
840
841     listToFirst(l);
842
843     do {
844         memcpy(nr+i, listCurrent(l), sizeof(NameRecord));
845         stringLen += nr[i].slen;
846         i++;
847     } while (listNext(l));
848
849     if (stringLen > 65535) {
850         free(nr);
851         return TTCR_NAMETOOLONG;
852     }
853
854     qsort(nr, n, sizeof(NameRecord), NameRecordCompareF);
855
856     nameLen = stringLen + 12 * n + 6;
857     name = ttmalloc(nameLen); 
858
859     PutUInt16(0, name, 0, 1);
860     PutUInt16(n, name, 2, 1);
861     PutUInt16(6 + 12 * n, name, 4, 1);
862
863     p1 = name + 6;
864     p2 = p1 + 12 * n;
865
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"); }; */
875         p2 += nr[i].slen;
876         p1 += 12;
877     }
878
879     free(nr);
880     _this->rawdata = name;
881
882     *ptr = name;
883     *len = nameLen;
884     *tag = T_name;
885
886      /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */
887
888     return TTCR_OK;
889 }
890
891 static int GetRawData_post(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
892 {
893     tdata_post *p = (tdata_post *) _this->data;
894     guint8 *post = NULL;
895     guint32 postLen = 0;
896     int ret;
897
898     if (_this->rawdata) free(_this->rawdata);
899
900     if (p->format == 0x00030000) {
901         postLen = 32;
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);
908         ret = TTCR_OK;
909     } else {
910         fprintf(stderr, "Unrecognized format of a post table: %08X.\n", p->format);
911         ret = TTCR_POSTFORMAT;
912     }
913
914     *ptr = _this->rawdata = post;
915     *len = postLen;
916     *tag = T_post;
917
918     return ret;
919 }
920
921     
922
923     
924
925 static struct {
926     guint32 tag;
927     int (*f)(TrueTypeTable *, guint8 **, guint32 *, guint32 *);
928 } vtable2[] =
929 {
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}
939     
940     
941 };
942  
943 /*
944  * TrueTypeTable public methods
945  */
946
947 /* Note: Type42 fonts only need these tables:
948  *        head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
949  *
950  * Microsoft required tables
951  *        cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2
952  *
953  * Apple required tables
954  *        cmap, glyf, head, hhea, hmtx, loca, maxp, name, post
955  *
956  */
957
958 TrueTypeTable *TrueTypeTableNew(guint32 tag,
959                                 guint32 nbytes,
960                                 guint8 *ptr)
961 {
962     TrueTypeTable *table;
963     tdata_generic *pdata;
964
965     table = smalloc(sizeof(TrueTypeTable));
966     pdata = (tdata_generic *) smalloc(sizeof(tdata_generic)); 
967     pdata->nbytes = nbytes;
968     pdata->tag = tag;
969     if (nbytes) {
970         pdata->ptr = ttmalloc(nbytes); 
971         memcpy(pdata->ptr, ptr, nbytes);
972     } else {
973         pdata->ptr = NULL;
974     }
975
976     table->tag = 0;
977     table->data = pdata;
978     table->rawdata = NULL;
979
980     return table;
981 }
982     
983 TrueTypeTable *TrueTypeTableNew_head(guint32 fontRevision,
984                                      guint16 flags,
985                                      guint16 unitsPerEm,
986                                      guint8  *created,
987                                      guint16 macStyle,
988                                      guint16 lowestRecPPEM,
989                                      gint16  fontDirectionHint)
990 {
991     TrueTypeTable *table;
992     guint8 *ptr;
993
994     assert(created != 0);
995
996     table  = smalloc(sizeof(TrueTypeTable));  
997     ptr  = ttmalloc(TABLESIZE_head);
998
999
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 */
1011
1012     table->data = (void *) ptr;
1013     table->tag = T_head;
1014     table->rawdata = NULL;
1015
1016     return table;
1017 }
1018
1019 TrueTypeTable *TrueTypeTableNew_hhea(gint16  ascender,
1020                                      gint16  descender,
1021                                      gint16  linegap,
1022                                      gint16  caretSlopeRise,
1023                                      gint16  caretSlopeRun)
1024 {
1025     TrueTypeTable *table;
1026     guint8 *ptr;
1027
1028     table  = smalloc(sizeof(TrueTypeTable));
1029     ptr  = ttmalloc(TABLESIZE_hhea);
1030
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 */
1043     
1044     table->data = (void *) ptr;
1045     table->tag = T_hhea;
1046     table->rawdata = NULL;
1047
1048     return table;
1049 }
1050
1051 TrueTypeTable *TrueTypeTableNew_loca(void)
1052 {
1053     TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1054     table->data = smalloc(sizeof(tdata_loca));
1055
1056     ((tdata_loca *)table->data)->nbytes = 0;
1057     ((tdata_loca *)table->data)->ptr = NULL;
1058
1059     table->tag = T_loca;
1060     table->rawdata = NULL;
1061
1062     return table;
1063 }
1064
1065 TrueTypeTable *TrueTypeTableNew_maxp(guint8 *maxp, int size)
1066 {
1067     TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1068     table->data = ttmalloc(TABLESIZE_maxp);
1069
1070     if (maxp && size == TABLESIZE_maxp) {
1071         memcpy(table->data, maxp, TABLESIZE_maxp);
1072     }
1073     
1074     table->tag = T_maxp;
1075     table->rawdata = NULL;
1076
1077     return table;
1078 }
1079
1080 TrueTypeTable *TrueTypeTableNew_glyf(void)
1081 {
1082     TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1083     list l = listNewEmpty();
1084     
1085     assert(l != 0);
1086
1087     listSetElementDtor(l, FreeGlyphData);
1088
1089     table->data = l;
1090     table->rawdata = NULL;
1091     table->tag = T_glyf;
1092
1093     return table;
1094 }
1095
1096 TrueTypeTable *TrueTypeTableNew_cmap(void)
1097 {
1098     TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1099     table_cmap *cmap = smalloc(sizeof(table_cmap));
1100     
1101     cmap->n = 0;
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);
1105     
1106     table->data = (table_cmap *) cmap;
1107
1108     table->rawdata = NULL;
1109     table->tag = T_cmap;
1110
1111     return table;
1112 }
1113
1114 static void DisposeNameRecord(void *ptr)
1115 {
1116     if (ptr != 0) {
1117         NameRecord *nr = (NameRecord *) ptr;
1118         if (nr->sptr) free(nr->sptr);
1119         free(ptr);
1120     }
1121 }
1122
1123 static NameRecord* NameRecordNewCopy(NameRecord *nr)
1124 {
1125     NameRecord *p = smalloc(sizeof(NameRecord));
1126
1127     memcpy(p, nr, sizeof(NameRecord));
1128
1129     if (p->slen) {
1130         p->sptr = smalloc(p->slen);
1131         memcpy(p->sptr, nr->sptr, p->slen);
1132     }
1133
1134     return p;
1135 }
1136
1137 TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr)
1138 {
1139     TrueTypeTable *table = smalloc(sizeof(TrueTypeTable));
1140     list l = listNewEmpty();
1141     
1142     assert(l != 0);
1143
1144     listSetElementDtor(l, DisposeNameRecord);
1145
1146     if (n != 0) {
1147         int i;
1148         for (i = 0; i < n; i++) {
1149             listAppend(l, NameRecordNewCopy(nr+i));
1150         }
1151     }
1152
1153     table->data = l;
1154     table->rawdata = NULL;
1155     table->tag = T_name;
1156
1157     return table;
1158 }
1159
1160 TrueTypeTable *TrueTypeTableNew_post(guint32 format,
1161                                      guint32 italicAngle,
1162                                      gint16 underlinePosition,
1163                                      gint16 underlineThickness,
1164                                      guint32 isFixedPitch)
1165 {
1166     TrueTypeTable *table;
1167     tdata_post *post;
1168
1169     assert(format == 0x00030000);                 /* Only format 3.0 is supported at this time */
1170     table = smalloc(sizeof(TrueTypeTable));
1171     post = smalloc(sizeof(tdata_post));
1172
1173     post->format = format;
1174     post->italicAngle = italicAngle;
1175     post->underlinePosition = underlinePosition;
1176     post->underlineThickness = underlineThickness;
1177     post->isFixedPitch = isFixedPitch;
1178     post->ptr = NULL;
1179
1180     table->data = post;
1181     table->rawdata = NULL;
1182     table->tag = T_post;
1183
1184     return table;
1185 }
1186
1187
1188
1189 void TrueTypeTableDispose(TrueTypeTable *_this)
1190 {
1191     /* XXX do a binary search */
1192     int i;
1193
1194     assert(_this != 0);
1195
1196     if (_this->rawdata) free(_this->rawdata);
1197
1198     for(i=0; i < sizeof(vtable1)/sizeof(*vtable1); i++) {
1199         if (_this->tag == vtable1[i].tag) {
1200             vtable1[i].f(_this);
1201             return;
1202         }
1203     }
1204     assert(!"Unknown TrueType table.\n");
1205 }
1206
1207 int GetRawData(TrueTypeTable *_this, guint8 **ptr, guint32 *len, guint32 *tag)
1208 {
1209     /* XXX do a binary search */
1210     int i;
1211
1212     assert(_this != 0);
1213     assert(ptr != 0);
1214     assert(len != 0);
1215     assert(tag != 0);
1216
1217     *ptr = NULL; *len = 0; *tag = 0;
1218
1219     if (_this->rawdata) {
1220         free(_this->rawdata);
1221         _this->rawdata = NULL;
1222     }
1223
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);
1227         }
1228     }
1229
1230     assert(!"Unknwon TrueType table.\n");
1231     return TTCR_UNKNOWN;
1232 }
1233     
1234 void cmapAdd(TrueTypeTable *table, guint32 id, guint32 c, guint32 g)
1235 {
1236     int i, found;
1237     table_cmap *t;
1238     CmapSubTable *s;
1239
1240     assert(table != 0);
1241     assert(table->tag == T_cmap);
1242     t = (table_cmap *) table->data; assert(t != 0);
1243     s = t->s; assert(s != 0);
1244
1245     found = 0;
1246
1247     for (i = 0; i < t->n; i++) {
1248         if (s[i].id == id) {
1249             found = 1;
1250             break;
1251         }
1252     }
1253
1254     if (!found) {
1255         if (t->n == t->m) {
1256             CmapSubTable *tmp;
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;
1261             free(s);
1262             s = tmp;
1263             t->s = s;
1264         }
1265
1266         for (i = 0; i < t->n; i++) {
1267             if (s[i].id > id) break;
1268         }
1269
1270         if (i < t->n) {
1271             memmove(s+i+1, s+i, t->n-i);
1272         }
1273
1274         t->n++;
1275
1276         s[i].id = id;
1277         s[i].n = 0;
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));
1281     }
1282
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));
1286         assert(tmp1 != 0);
1287         assert(tmp2 != 0);
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;
1291         free(s[i].xc);
1292         free(s[i].xg);
1293         s[i].xc = tmp1;
1294         s[i].xg = tmp2;
1295     }
1296
1297     s[i].xc[s[i].n] = c;
1298     s[i].xg[s[i].n] = g;
1299     s[i].n++;
1300 }
1301
1302 guint32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, TrueTypeFont *fnt)
1303 {
1304     list l;
1305     guint32 currentID;
1306     int ret, n, ncomponents;
1307     list glyphlist;
1308     GlyphData *gd;
1309
1310     assert(table != 0);
1311     assert(table->tag == T_glyf);
1312
1313     if (!glyphdata) return -1;
1314
1315     glyphlist = listNewEmpty();
1316
1317     ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist);
1318
1319     l = (list) table->data;
1320     if (listCount(l) > 0) {
1321         listToLast(l);
1322         ret = n = ((GlyphData *) listCurrent(l))->newID + 1;
1323     } else {
1324         ret = n = 0;
1325     }
1326     glyphdata->newID = n++;
1327     listAppend(l, glyphdata);
1328
1329     if (ncomponents > 1) {
1330         listPositionAt(glyphlist, 1);       /* glyphData->glyphID is always the first glyph on the list */
1331         do {
1332             int found = 0;
1333             currentID = (guint32) listCurrent(glyphlist);
1334             /* XXX expensive! should be rewritten with sorted arrays! */
1335             listToFirst(l);
1336             do {
1337                 if (((GlyphData *) listCurrent(l))->glyphID == currentID) {
1338                     found = 1;
1339                     break;
1340                 }
1341             } while (listNext(l));
1342
1343             if (!found) {
1344                 gd = GetTTRawGlyphData(fnt, currentID);
1345                 gd->newID = n++;
1346                 listAppend(l, gd);
1347             }
1348         } while (listNext(glyphlist));
1349     }
1350
1351     listDispose(glyphlist);
1352     return ret;
1353 }
1354
1355 guint32 glyfCount(const TrueTypeTable *table)
1356 {
1357     assert(table != 0);
1358     assert(table->tag == T_glyf);
1359     return listCount((list) table->data);
1360 }
1361     
1362
1363 void nameAdd(TrueTypeTable *table, NameRecord *nr)
1364 {
1365     list l;
1366
1367     assert(table != 0);
1368     assert(table->tag == T_name);
1369
1370     l = (list) table->data;
1371
1372     listAppend(l, NameRecordNewCopy(nr));
1373 }
1374                
1375 static TrueTypeTable *FindTable(TrueTypeCreator *tt, guint32 tag)
1376 {
1377     if (listIsEmpty(tt->tables)) return NULL;
1378
1379     listToFirst(tt->tables);
1380
1381     do {
1382         if (((TrueTypeTable *) listCurrent(tt->tables))->tag == tag) {
1383             return listCurrent(tt->tables);
1384         }
1385     } while (listNext(tt->tables));
1386
1387     return NULL;
1388 }
1389
1390 /* This function processes all the tables and synchronizes them before creating
1391  * the output TrueType stream.
1392  *
1393  * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' ***
1394  *
1395  * It does:
1396  *
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
1402  *   in 'hhea' table
1403  *
1404  */
1405 static void ProcessTables(TrueTypeCreator *tt)
1406 {
1407     TrueTypeTable *glyf, *loca, *head, *maxp, *hhea;
1408     list glyphlist;
1409     guint32 nGlyphs, locaLen = 0, glyfLen = 0;
1410     gint16 xMin = 0, yMin = 0, xMax = 0, yMax = 0;
1411     int i = 0;
1412     gint16 indexToLocFormat;
1413     guint8 *glyfPtr, *locaPtr, *hmtxPtr, *hheaPtr;
1414     guint32 hmtxSize;
1415     guint8 *p1, *p2;
1416     guint16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0;
1417     TTSimpleGlyphMetrics *met;
1418     int nlsb = 0;
1419     guint32 *gid;                        /* array of old glyphIDs */
1420
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));
1426
1427     RemoveTable(tt, T_loca);
1428     RemoveTable(tt, T_hmtx);
1429
1430     /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */
1431
1432     listToFirst(glyphlist);
1433     do {
1434         GlyphData *gd = (GlyphData *) listCurrent(glyphlist);
1435         gint16 z;
1436         glyfLen += gd->nbytes;
1437         /* XXX if (gd->nbytes & 1) glyfLen++; */
1438
1439
1440         assert(gd->newID == i);
1441         gid[i++] = gd->glyphID;
1442         /* gd->glyphID = i++; */
1443
1444         /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */
1445
1446         if (gd->nbytes != 0) {
1447             z = GetInt16(gd->ptr, 2, 1);
1448             if (z < xMin) xMin = z;
1449
1450             z = GetInt16(gd->ptr, 4, 1);
1451             if (z < yMin) yMin = z;
1452         
1453             z = GetInt16(gd->ptr, 6, 1);
1454             if (z > xMax) xMax = z;
1455         
1456             z = GetInt16(gd->ptr, 8, 1);
1457             if (z > yMax) yMax = z;
1458         }
1459
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;
1466         }
1467         
1468     } while (listNext(glyphlist));
1469
1470     indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0;
1471     locaLen = indexToLocFormat ?  (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1;
1472
1473     glyfPtr = ttmalloc(glyfLen);
1474     locaPtr = ttmalloc(locaLen); 
1475     met = scalloc(nGlyphs, sizeof(TTSimpleGlyphMetrics));
1476     i = 0;
1477
1478     listToFirst(glyphlist);
1479     p1 = glyfPtr;
1480     p2 = locaPtr;
1481     do {
1482         GlyphData *gd = (GlyphData *) listCurrent(glyphlist);
1483         
1484         if (gd->compflag) {                       /* re-number all components */
1485             guint16 flags, index;
1486             guint8 *ptr = gd->ptr + 10;
1487             do {
1488                 int j;
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) {
1494                         break;
1495                     }
1496                 }
1497                 /* printf("X: %d -> %d.\n", index, j); */
1498
1499                 PutUInt16((guint16) j, ptr, 2, 1);
1500
1501                 ptr += 4;
1502
1503                 if (flags & ARG_1_AND_2_ARE_WORDS) {
1504                     ptr += 4;
1505                 } else {
1506                     ptr += 2;
1507                 }
1508
1509                 if (flags & WE_HAVE_A_SCALE) {
1510                     ptr += 2;
1511                 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
1512                     ptr += 4;
1513                 } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
1514                     ptr += 8;
1515                 }
1516             } while (flags & MORE_COMPONENTS);
1517         }
1518
1519         if (gd->nbytes != 0) {
1520             memcpy(p1, gd->ptr, gd->nbytes);
1521         }
1522         if (indexToLocFormat == 1) {
1523             PutUInt32(p1 - glyfPtr, p2, 0, 1);
1524             p2 += 4;
1525         } else {
1526             PutUInt16((p1 - glyfPtr) >> 1, p2, 0, 1);
1527             p2 += 2;
1528         }
1529         p1 += gd->nbytes;
1530
1531         /* fill the array of metrics */
1532         met[i].adv = gd->aw;
1533         met[i].sb  = gd->lsb;
1534         i++;
1535     } while (listNext(glyphlist));
1536
1537     free(gid);
1538
1539     if (indexToLocFormat == 1) {
1540         PutUInt32(p1 - glyfPtr, p2, 0, 1);
1541     } else {
1542         PutUInt16((p1 - glyfPtr) >> 1, p2, 0, 1);
1543     }
1544
1545     glyf->rawdata = glyfPtr;
1546
1547     loca = TrueTypeTableNew_loca(); assert(loca != 0);
1548     ((tdata_loca *) loca->data)->ptr = locaPtr;
1549     ((tdata_loca *) loca->data)->nbytes = locaLen;
1550
1551     AddTable(tt, loca);
1552     
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);
1559
1560     maxp = FindTable(tt, T_maxp);
1561
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);
1567
1568 #if 0
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          */
1579 #endif
1580
1581     /*
1582      * Generate an htmx table and update hhea table
1583      */
1584     hhea = FindTable(tt, T_hhea); assert(hhea != 0);
1585     hheaPtr = (guint8 *) hhea->data;
1586     if (nGlyphs > 2) {
1587         for (i = nGlyphs - 1; i > 0; i--) {
1588             if (met[i].adv != met[i-1].adv) break;
1589         }
1590         nlsb = nGlyphs - 1 - i;
1591     }
1592     hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2;
1593     hmtxPtr = ttmalloc(hmtxSize);
1594     p1 = hmtxPtr;
1595
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);
1600             p1 += 4;
1601         } else {
1602             PutUInt16(met[i].sb, p1, 0, 1);
1603             p1 += 2;
1604         }
1605     }
1606
1607     AddTable(tt, TrueTypeTableNew(T_hmtx, hmtxSize, hmtxPtr));
1608     PutUInt16(nGlyphs - nlsb, hheaPtr, 34, 1);
1609     free(hmtxPtr);
1610     free(met);
1611 }
1612
1613 #ifdef TEST_TTCR
1614 int main(void)
1615 {
1616     TrueTypeCreator *ttcr;
1617     guint8 *t1, *t2, *t3, *t4, *t5, *t6, *t7;
1618
1619     TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr);
1620
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);
1628
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));
1636
1637     free(t1);
1638     free(t2);
1639     free(t3);
1640     free(t4);
1641     free(t5);
1642     free(t6);
1643     free(t7);
1644
1645
1646     StreamToFile(ttcr, "ttcrout.ttf");
1647
1648     TrueTypeCreatorDispose(ttcr);
1649     return 0;
1650 }
1651 #endif