LCOV - code coverage report
Current view: top level - vcl/source/fontsubset - ttcr.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 730 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 58 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : /*
      21             :  * TrueTypeCreator method implementation
      22             :  *
      23             :  * @author: Alexander Gelfenbain
      24             :  *
      25             :  */
      26             : 
      27             : #if OSL_DEBUG_LEVEL == 0
      28             : #  ifndef NDEBUG
      29             : #    define NDEBUG
      30             : #  endif
      31             : #endif
      32             : #include <assert.h>
      33             : 
      34             : #include "ttcr.hxx"
      35             : #include "list.h"
      36             : #include "string.h"
      37             : 
      38             : namespace vcl
      39             : {
      40             : 
      41             : /*
      42             :  * Private Data Types
      43             :  */
      44             : 
      45             :     struct _TrueTypeCreator {
      46             :         sal_uInt32 tag;                         /**< TrueType file tag */
      47             :         list   tables;                      /**< List of table tags and pointers */
      48             :     };
      49             : 
      50             : /* These must be #defined so that they can be used in initializers */
      51             : #define T_maxp  0x6D617870
      52             : #define T_glyf  0x676C7966
      53             : #define T_head  0x68656164
      54             : #define T_loca  0x6C6F6361
      55             : #define T_name  0x6E616D65
      56             : #define T_hhea  0x68686561
      57             : #define T_hmtx  0x686D7478
      58             : #define T_cmap  0x636D6170
      59             : #define T_post  0x706F7374
      60             : 
      61             : typedef struct {
      62             :     sal_uInt32 tag;
      63             :     sal_uInt32 length;
      64             :     sal_uInt8  *data;
      65             : } TableEntry;
      66             : 
      67             : /*
      68             :  * this is a duplicate code from sft.c but it is left here for performance reasons
      69             :  */
      70             : #ifdef __GNUC__
      71             : #define _inline static __inline__
      72             : #else
      73             : #define _inline static
      74             : #endif
      75             : 
      76             : /*- Data access macros for data stored in big-endian or little-endian format */
      77           0 : _inline sal_Int16 GetInt16( const sal_uInt8* ptr, sal_uInt32 offset, int bigendian)
      78             : {
      79             :     sal_Int16 t;
      80             :     assert(ptr != 0);
      81             : 
      82           0 :     if (bigendian) {
      83           0 :         t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
      84             :     } else {
      85           0 :         t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
      86             :     }
      87             : 
      88           0 :     return t;
      89             : }
      90             : 
      91           0 : _inline sal_uInt16 GetUInt16( const sal_uInt8* ptr, sal_uInt32 offset, int bigendian)
      92             : {
      93             :     sal_uInt16 t;
      94             :     assert(ptr != 0);
      95             : 
      96           0 :     if (bigendian) {
      97           0 :         t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
      98             :     } else {
      99           0 :         t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
     100             :     }
     101             : 
     102           0 :     return t;
     103             : }
     104             : 
     105           0 : _inline void PutInt16(sal_Int16 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
     106             : {
     107             :     assert(ptr != 0);
     108             : 
     109           0 :     if (bigendian) {
     110           0 :         ptr[offset] = (sal_uInt8)((val >> 8) & 0xFF);
     111           0 :         ptr[offset+1] = (sal_uInt8)(val & 0xFF);
     112             :     } else {
     113           0 :         ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
     114           0 :         ptr[offset] = (sal_uInt8)(val & 0xFF);
     115             :     }
     116           0 : }
     117             : 
     118           0 : _inline void PutUInt16(sal_uInt16 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
     119             : {
     120             :     assert(ptr != 0);
     121             : 
     122           0 :     if (bigendian) {
     123           0 :         ptr[offset] = (sal_uInt8)((val >> 8) & 0xFF);
     124           0 :         ptr[offset+1] = (sal_uInt8)(val & 0xFF);
     125             :     } else {
     126           0 :         ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
     127           0 :         ptr[offset] = (sal_uInt8)(val & 0xFF);
     128             :     }
     129           0 : }
     130             : 
     131           0 : _inline void PutUInt32(sal_uInt32 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
     132             : {
     133             :     assert(ptr != 0);
     134             : 
     135           0 :     if (bigendian) {
     136           0 :         ptr[offset]   = (sal_uInt8)((val >> 24) & 0xFF);
     137           0 :         ptr[offset+1] = (sal_uInt8)((val >> 16) & 0xFF);
     138           0 :         ptr[offset+2] = (sal_uInt8)((val >> 8) & 0xFF);
     139           0 :         ptr[offset+3] = (sal_uInt8)(val & 0xFF);
     140             :     } else {
     141           0 :         ptr[offset+3] = (sal_uInt8)((val >> 24) & 0xFF);
     142           0 :         ptr[offset+2] = (sal_uInt8)((val >> 16) & 0xFF);
     143           0 :         ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
     144           0 :         ptr[offset]   = (sal_uInt8)(val & 0xFF);
     145             :     }
     146             : 
     147           0 : }
     148             : 
     149           0 : static int TableEntryCompareF(const void *l, const void *r)
     150             : {
     151           0 :     sal_uInt32 const ltag(static_cast<TableEntry const*>(l)->tag);
     152           0 :     sal_uInt32 const rtag(static_cast<TableEntry const*>(r)->tag);
     153           0 :     return (ltag == rtag) ? 0 : (ltag < rtag) ? -1 : 1;
     154             : }
     155             : 
     156           0 : static int NameRecordCompareF(const void *l, const void *r)
     157             : {
     158           0 :     NameRecord const *ll = static_cast<NameRecord const *>(l);
     159           0 :     NameRecord const *rr = static_cast<NameRecord const *>(r);
     160             : 
     161           0 :     if (ll->platformID != rr->platformID) {
     162           0 :         return (ll->platformID < rr->platformID) ? -1 : 1;
     163           0 :     } else if (ll->encodingID != rr->encodingID) {
     164           0 :         return (ll->encodingID < rr->encodingID) ? -1 : 1;
     165           0 :     } else if (ll->languageID != rr->languageID) {
     166           0 :         return (ll->languageID < rr->languageID) ? -1 : 1;
     167           0 :     } else if (ll->nameID != rr->nameID) {
     168           0 :         return (ll->nameID < rr->nameID) ? -1 : 1;
     169             :     }
     170           0 :     return 0;
     171             : }
     172             : 
     173           0 : static sal_uInt32 CheckSum(sal_uInt32 *ptr, sal_uInt32 length)
     174             : {
     175           0 :     sal_uInt32 sum = 0;
     176           0 :     sal_uInt32 *endptr = ptr + ((length + 3) & (sal_uInt32) ~3) / 4;
     177             : 
     178           0 :     while (ptr < endptr) sum += *ptr++;
     179             : 
     180           0 :     return sum;
     181             : }
     182             : 
     183           0 : _inline void *smalloc(sal_uInt32 size)
     184             : {
     185           0 :     void *res = malloc(size);
     186             :     assert(res != 0);
     187           0 :     return res;
     188             : }
     189             : 
     190           0 : _inline void *scalloc(sal_uInt32 n, sal_uInt32 size)
     191             : {
     192           0 :     void *res = calloc(n, size);
     193             :     assert(res != 0);
     194           0 :     return res;
     195             : }
     196             : 
     197             : /*
     198             :  * Public functions
     199             :  */
     200             : 
     201           0 : void TrueTypeCreatorNewEmpty(sal_uInt32 tag, TrueTypeCreator **_this)
     202             : {
     203           0 :     TrueTypeCreator* ptr = static_cast<TrueTypeCreator*>(smalloc(sizeof(TrueTypeCreator)));
     204             : 
     205           0 :     ptr->tables = listNewEmpty();
     206           0 :     listSetElementDtor(ptr->tables, TrueTypeTableDispose);
     207             : 
     208           0 :     ptr->tag = tag;
     209             : 
     210           0 :     *_this = ptr;
     211           0 : }
     212             : 
     213           0 : int AddTable(TrueTypeCreator *_this, TrueTypeTable *table)
     214             : {
     215           0 :     if (table != 0) {
     216           0 :         listAppend(_this->tables, table);
     217             :     }
     218           0 :     return SF_OK;
     219             : }
     220             : 
     221           0 : void RemoveTable(TrueTypeCreator *_this, sal_uInt32 tag)
     222             : {
     223           0 :     if (listCount(_this->tables))
     224             :     {
     225           0 :         listToFirst(_this->tables);
     226           0 :         int done = 0;
     227           0 :         do {
     228           0 :             if (static_cast<TrueTypeTable *>(listCurrent(_this->tables))->tag == tag)
     229             :             {
     230           0 :                 listRemove(_this->tables);
     231             :             }
     232             :             else
     233             :             {
     234           0 :                 if (listNext(_this->tables))
     235             :                 {
     236           0 :                     done = 1;
     237             :                 }
     238             :             }
     239             :         } while (!done);
     240             :     }
     241           0 : }
     242             : 
     243             : static void ProcessTables(TrueTypeCreator *);
     244             : 
     245           0 : int StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *length)
     246             : {
     247           0 :     sal_uInt16 searchRange=1, entrySelector=0, rangeShift;
     248           0 :     sal_uInt32 s, offset, checkSumAdjustment = 0;
     249             :     sal_uInt32 *p;
     250           0 :     sal_uInt8 *head = NULL;     /* saved pointer to the head table data for checkSumAdjustment calculation */
     251             : 
     252           0 :     if (listIsEmpty(_this->tables)) return SF_TTFORMAT;
     253             : 
     254           0 :     ProcessTables(_this);
     255             : 
     256             :     /* ProcessTables() adds 'loca' and 'hmtx' */
     257             : 
     258           0 :     sal_uInt16 numTables = listCount(_this->tables);
     259             : 
     260           0 :     TableEntry* te = static_cast<TableEntry*>(scalloc(numTables, sizeof(TableEntry)));
     261           0 :     TableEntry* e = te;
     262             : 
     263           0 :     listToFirst(_this->tables);
     264           0 :     do {
     265           0 :         GetRawData(static_cast<TrueTypeTable *>(listCurrent(_this->tables)), &e->data, &e->length, &e->tag);
     266           0 :         ++e;
     267           0 :     } while (listNext(_this->tables));
     268             : 
     269           0 :     qsort(te, numTables, sizeof(TableEntry), TableEntryCompareF);
     270             : 
     271           0 :     do {
     272           0 :         searchRange *= 2;
     273           0 :         entrySelector++;
     274             :     } while (searchRange <= numTables);
     275             : 
     276           0 :     searchRange *= 8;
     277           0 :     entrySelector--;
     278           0 :     rangeShift = numTables * 16 - searchRange;
     279             : 
     280           0 :     s = offset = 12 + 16 * numTables;
     281             : 
     282           0 :     for (int i = 0; i < numTables; ++i) {
     283           0 :         s += (te[i].length + 3) & (sal_uInt32) ~3;
     284             :         /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */
     285             :     }
     286             : 
     287           0 :     sal_uInt8* ttf = static_cast<sal_uInt8*>(smalloc(s));
     288             : 
     289             :     /* Offset Table */
     290           0 :     PutUInt32(_this->tag, ttf, 0, 1);
     291           0 :     PutUInt16(numTables, ttf, 4, 1);
     292           0 :     PutUInt16(searchRange, ttf, 6, 1);
     293           0 :     PutUInt16(entrySelector, ttf, 8, 1);
     294           0 :     PutUInt16(rangeShift, ttf, 10, 1);
     295             : 
     296             :     /* Table Directory */
     297           0 :     for (int i = 0; i < numTables; ++i) {
     298           0 :         PutUInt32(te[i].tag, ttf + 12, 16 * i, 1);
     299           0 :         PutUInt32(CheckSum(reinterpret_cast<sal_uInt32 *>(te[i].data), te[i].length), ttf + 12, 16 * i + 4, 1);
     300           0 :         PutUInt32(offset, ttf + 12, 16 * i + 8, 1);
     301           0 :         PutUInt32(te[i].length, ttf + 12, 16 * i + 12, 1);
     302             : 
     303           0 :         if (te[i].tag == T_head) {
     304           0 :             head = ttf + offset;
     305             :         }
     306             : 
     307           0 :         memcpy(ttf+offset, te[i].data, (te[i].length + 3) & (sal_uInt32) ~3 );
     308           0 :         offset += (te[i].length + 3) & (sal_uInt32) ~3;
     309             :         /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */
     310             :     }
     311             : 
     312           0 :     free(te);
     313             : 
     314           0 :     p = reinterpret_cast<sal_uInt32 *>(ttf);
     315           0 :     for (int i = 0; i < (int)s / 4; ++i) checkSumAdjustment += p[i];
     316           0 :     PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8, 1);
     317             : 
     318           0 :     *ptr = ttf;
     319           0 :     *length = s;
     320             : 
     321           0 :     return SF_OK;
     322             : }
     323             : 
     324           0 : int StreamToFile(TrueTypeCreator *_this, const char* fname)
     325             : {
     326             :     sal_uInt8 *ptr;
     327             :     sal_uInt32 length;
     328             :     int r;
     329             :     FILE* fd;
     330             : 
     331           0 :     if ((r = StreamToMemory(_this, &ptr, &length)) != SF_OK) return r;
     332           0 :     if (fname && (fd = fopen(fname, "wb")) != NULL)
     333             :     {
     334           0 :         if (fwrite(ptr, 1, length, fd) != length) {
     335           0 :             r = SF_FILEIO;
     336             :         } else {
     337           0 :             r = SF_OK;
     338             :         }
     339           0 :         fclose(fd);
     340             :     }
     341             :     else
     342             :     {
     343           0 :         r = SF_BADFILE;
     344             :     }
     345           0 :     free(ptr);
     346           0 :     return r;
     347             : }
     348             : 
     349             : /*
     350             :  * TrueTypeTable private methods
     351             :  */
     352             : 
     353             : #define TABLESIZE_head 54
     354             : #define TABLESIZE_hhea 36
     355             : #define TABLESIZE_maxp 32
     356             : 
     357             : /*    Table         data points to
     358             :  * --------------------------------------------
     359             :  *    generic       tdata_generic struct
     360             :  *    'head'        TABLESIZE_head bytes of memory
     361             :  *    'hhea'        TABLESIZE_hhea bytes of memory
     362             :  *    'loca'        tdata_loca struct
     363             :  *    'maxp'        TABLESIZE_maxp bytes of memory
     364             :  *    'glyf'        list of GlyphData structs (defined in sft.h)
     365             :  *    'name'        list of NameRecord structs (defined in sft.h)
     366             :  *    'post'        tdata_post struct
     367             :  *
     368             :  */
     369             : 
     370             : #define CMAP_SUBTABLE_INIT 10
     371             : #define CMAP_SUBTABLE_INCR 10
     372             : #define CMAP_PAIR_INIT 500
     373             : #define CMAP_PAIR_INCR 500
     374             : 
     375             : typedef struct {
     376             :     sal_uInt32  id;                         /* subtable ID (platform/encoding ID)    */
     377             :     sal_uInt32  n;                          /* number of used translation pairs      */
     378             :     sal_uInt32  m;                          /* number of allocated translation pairs */
     379             :     sal_uInt32 *xc;                         /* character array                       */
     380             :     sal_uInt32 *xg;                         /* glyph array                           */
     381             : } CmapSubTable;
     382             : 
     383             : typedef struct {
     384             :     sal_uInt32 n;                           /* number of used CMAP sub-tables       */
     385             :     sal_uInt32 m;                           /* number of allocated CMAP sub-tables  */
     386             :     CmapSubTable *s;                    /* sotred array of sub-tables           */
     387             : } table_cmap;
     388             : 
     389             : typedef struct {
     390             :     sal_uInt32 tag;
     391             :     sal_uInt32 nbytes;
     392             :     sal_uInt8 *ptr;
     393             : } tdata_generic;
     394             : 
     395             : typedef struct {
     396             :     sal_uInt32 nbytes;                      /* number of bytes in loca table */
     397             :     sal_uInt8 *ptr;                          /* pointer to the data */
     398             : } tdata_loca;
     399             : 
     400             : typedef struct {
     401             :     sal_uInt32 format;
     402             :     sal_uInt32 italicAngle;
     403             :     sal_Int16  underlinePosition;
     404             :     sal_Int16  underlineThickness;
     405             :     sal_uInt32 isFixedPitch;
     406             :     void   *ptr;                        /* format-specific pointer */
     407             : } tdata_post;
     408             : 
     409             : /* allocate memory for a TT table */
     410           0 : static sal_uInt8 *ttmalloc(sal_uInt32 nbytes)
     411             : {
     412             :     sal_uInt32 n;
     413             : 
     414           0 :     n = (nbytes + 3) & (sal_uInt32) ~3;
     415           0 :     sal_uInt8* res = static_cast<sal_uInt8*>(malloc(n));
     416             :     assert(res != 0);
     417           0 :     memset(res, 0, n);
     418             : 
     419           0 :     return res;
     420             : }
     421             : 
     422           0 : static void FreeGlyphData(void *ptr)
     423             : {
     424           0 :     GlyphData *p = static_cast<GlyphData *>(ptr);
     425           0 :     if (p->ptr) free(p->ptr);
     426           0 :     free(p);
     427           0 : }
     428             : 
     429           0 : static void TrueTypeTableDispose_generic(TrueTypeTable *_this)
     430             : {
     431           0 :     if (_this) {
     432           0 :         if (_this->data) {
     433           0 :             tdata_generic *pdata = static_cast<tdata_generic *>(_this->data);
     434           0 :             if (pdata->nbytes) free(pdata->ptr);
     435           0 :             free(_this->data);
     436             :         }
     437           0 :         free(_this);
     438             :     }
     439           0 : }
     440             : 
     441           0 : static void TrueTypeTableDispose_head(TrueTypeTable *_this)
     442             : {
     443           0 :     if (_this) {
     444           0 :         if (_this->data) free(_this->data);
     445           0 :         free(_this);
     446             :     }
     447           0 : }
     448             : 
     449           0 : static void TrueTypeTableDispose_hhea(TrueTypeTable *_this)
     450             : {
     451           0 :     if (_this) {
     452           0 :         if (_this->data) free(_this->data);
     453           0 :         free(_this);
     454             :     }
     455           0 : }
     456             : 
     457           0 : static void TrueTypeTableDispose_loca(TrueTypeTable *_this)
     458             : {
     459           0 :     if (_this) {
     460           0 :         if (_this->data) {
     461           0 :             tdata_loca *p = static_cast<tdata_loca *>(_this->data);
     462           0 :             if (p->ptr) free(p->ptr);
     463           0 :             free(_this->data);
     464             :         }
     465           0 :         free(_this);
     466             :     }
     467           0 : }
     468             : 
     469           0 : static void TrueTypeTableDispose_maxp(TrueTypeTable *_this)
     470             : {
     471           0 :     if (_this) {
     472           0 :         if (_this->data) free(_this->data);
     473           0 :         free(_this);
     474             :     }
     475           0 : }
     476             : 
     477           0 : static void TrueTypeTableDispose_glyf(TrueTypeTable *_this)
     478             : {
     479           0 :     if (_this) {
     480           0 :         if (_this->data) listDispose(static_cast<list>(_this->data));
     481           0 :         free(_this);
     482             :     }
     483           0 : }
     484             : 
     485           0 : static void TrueTypeTableDispose_cmap(TrueTypeTable *_this)
     486             : {
     487           0 :     if (_this) {
     488           0 :         table_cmap *t = static_cast<table_cmap *>(_this->data);
     489           0 :         if (t) {
     490           0 :             CmapSubTable *s = t->s;
     491           0 :             if (s) {
     492           0 :                 for (sal_uInt32 i = 0; i < t->m; i++) {
     493           0 :                     if (s[i].xc) free(s[i].xc);
     494           0 :                     if (s[i].xg) free(s[i].xg);
     495             :                 }
     496           0 :                 free(s);
     497             :             }
     498           0 :             free(t);
     499             :         }
     500           0 :         free(_this);
     501             :     }
     502           0 : }
     503             : 
     504           0 : static void TrueTypeTableDispose_name(TrueTypeTable *_this)
     505             : {
     506           0 :     if (_this) {
     507           0 :         if (_this->data) listDispose(static_cast<list>(_this->data));
     508           0 :         free(_this);
     509             :     }
     510           0 : }
     511             : 
     512           0 : static void TrueTypeTableDispose_post(TrueTypeTable *_this)
     513             : {
     514           0 :     if (_this) {
     515           0 :         tdata_post *p = static_cast<tdata_post *>(_this->data);
     516           0 :         if (p) {
     517           0 :             if (p->format == 0x00030000) {
     518             :                 /* do nothing */
     519             :             } else {
     520           0 :                 fprintf(stderr, "Unsupported format of a 'post' table: %08X.\n", (int)p->format);
     521             :             }
     522           0 :             free(p);
     523             :         }
     524           0 :         free(_this);
     525             :     }
     526           0 : }
     527             : 
     528             : /* destructor vtable */
     529             : 
     530             : static struct {
     531             :     sal_uInt32 tag;
     532             :     void (*f)(TrueTypeTable *);
     533             : } vtable1[] =
     534             : {
     535             :     {0,      TrueTypeTableDispose_generic},
     536             :     {T_head, TrueTypeTableDispose_head},
     537             :     {T_hhea, TrueTypeTableDispose_hhea},
     538             :     {T_loca, TrueTypeTableDispose_loca},
     539             :     {T_maxp, TrueTypeTableDispose_maxp},
     540             :     {T_glyf, TrueTypeTableDispose_glyf},
     541             :     {T_cmap, TrueTypeTableDispose_cmap},
     542             :     {T_name, TrueTypeTableDispose_name},
     543             :     {T_post, TrueTypeTableDispose_post}
     544             : 
     545             : };
     546             : 
     547           0 : static int GetRawData_generic(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     548             : {
     549             :     assert(_this != 0);
     550             :     assert(_this->data != 0);
     551             : 
     552           0 :     *ptr = static_cast<tdata_generic *>(_this->data)->ptr;
     553           0 :     *len = static_cast<tdata_generic *>(_this->data)->nbytes;
     554           0 :     *tag = static_cast<tdata_generic *>(_this->data)->tag;
     555             : 
     556           0 :     return TTCR_OK;
     557             : }
     558             : 
     559           0 : static int GetRawData_head(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     560             : {
     561           0 :     *len = TABLESIZE_head;
     562           0 :     *ptr = static_cast<sal_uInt8 *>(_this->data);
     563           0 :     *tag = T_head;
     564             : 
     565           0 :     return TTCR_OK;
     566             : }
     567             : 
     568           0 : static int GetRawData_hhea(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     569             : {
     570           0 :     *len = TABLESIZE_hhea;
     571           0 :     *ptr = static_cast<sal_uInt8 *>(_this->data);
     572           0 :     *tag = T_hhea;
     573             : 
     574           0 :     return TTCR_OK;
     575             : }
     576             : 
     577           0 : static int GetRawData_loca(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     578             : {
     579             :     tdata_loca *p;
     580             : 
     581             :     assert(_this->data != 0);
     582             : 
     583           0 :     p = static_cast<tdata_loca *>(_this->data);
     584             : 
     585           0 :     if (p->nbytes == 0) return TTCR_ZEROGLYPHS;
     586             : 
     587           0 :     *ptr = p->ptr;
     588           0 :     *len = p->nbytes;
     589           0 :     *tag = T_loca;
     590             : 
     591           0 :     return TTCR_OK;
     592             : }
     593             : 
     594           0 : static int GetRawData_maxp(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     595             : {
     596           0 :     *len = TABLESIZE_maxp;
     597           0 :     *ptr = static_cast<sal_uInt8 *>(_this->data);
     598           0 :     *tag = T_maxp;
     599             : 
     600           0 :     return TTCR_OK;
     601             : }
     602             : 
     603           0 : static int GetRawData_glyf(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     604             : {
     605           0 :     sal_uInt32 n, nbytes = 0;
     606           0 :     list l = static_cast<list>(_this->data);
     607             :     /* sal_uInt16 curID = 0;    */               /* to check if glyph IDs are sequential and start from zero */
     608             :     sal_uInt8 *p;
     609             : 
     610           0 :     *ptr = 0;
     611           0 :     *len = 0;
     612           0 :     *tag = 0;
     613             : 
     614           0 :     if (listCount(l) == 0) return TTCR_ZEROGLYPHS;
     615             : 
     616           0 :     listToFirst(l);
     617           0 :     do {
     618             :         /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */
     619           0 :         nbytes += static_cast<GlyphData *>(listCurrent(l))->nbytes;
     620           0 :     } while (listNext(l));
     621             : 
     622           0 :     p = _this->rawdata = ttmalloc(nbytes);
     623             : 
     624           0 :     listToFirst(l);
     625           0 :     do {
     626           0 :         n = static_cast<GlyphData *>(listCurrent(l))->nbytes;
     627           0 :         if (n != 0) {
     628           0 :             memcpy(p, static_cast<GlyphData *>(listCurrent(l))->ptr, n);
     629           0 :             p += n;
     630             :         }
     631           0 :     } while (listNext(l));
     632             : 
     633           0 :     *len = nbytes;
     634           0 :     *ptr = _this->rawdata;
     635           0 :     *tag = T_glyf;
     636             : 
     637           0 :     return TTCR_OK;
     638             : }
     639             : 
     640             : /* cmap packers */
     641           0 : static sal_uInt8 *PackCmapType0(CmapSubTable *s, sal_uInt32 *length)
     642             : {
     643           0 :     sal_uInt8* ptr = static_cast<sal_uInt8*>(smalloc(262));
     644           0 :     sal_uInt8 *p = ptr + 6;
     645             :     sal_uInt32 i, j;
     646             :     sal_uInt16 g;
     647             : 
     648           0 :     PutUInt16(0, ptr, 0, 1);
     649           0 :     PutUInt16(262, ptr, 2, 1);
     650           0 :     PutUInt16(0, ptr, 4, 1);
     651             : 
     652           0 :     for (i = 0; i < 256; i++) {
     653           0 :         g = 0;
     654           0 :         for (j = 0; j < s->n; j++) {
     655           0 :             if (s->xc[j] == i) {
     656           0 :                 g = (sal_uInt16) s->xg[j];
     657             :             }
     658             :         }
     659           0 :         p[i] = (sal_uInt8) g;
     660             :     }
     661           0 :     *length = 262;
     662           0 :     return ptr;
     663             : }
     664             : 
     665           0 : static sal_uInt8 *PackCmapType6(CmapSubTable *s, sal_uInt32 *length)
     666             : {
     667           0 :     sal_uInt8* ptr = static_cast<sal_uInt8*>(smalloc(s->n*2 + 10));
     668           0 :     sal_uInt8 *p = ptr + 10;
     669             :     sal_uInt32 i, j;
     670             :     sal_uInt16 g;
     671             : 
     672           0 :     PutUInt16(6, ptr, 0, 1);
     673           0 :     PutUInt16((sal_uInt16)(s->n*2+10), ptr, 2, 1);
     674           0 :     PutUInt16(0, ptr, 4, 1);
     675           0 :     PutUInt16(0, ptr, 6, 1);
     676           0 :     PutUInt16((sal_uInt16)(s->n), ptr, 8, 1 );
     677             : 
     678           0 :     for (i = 0; i < s->n; i++) {
     679           0 :         g = 0;
     680           0 :         for (j = 0; j < s->n; j++) {
     681           0 :             if (s->xc[j] == i) {
     682           0 :                 g = (sal_uInt16) s->xg[j];
     683             :             }
     684             :         }
     685           0 :         PutUInt16( g, p, 2*i, 1 );
     686             :     }
     687           0 :     *length = s->n*2+10;
     688           0 :     return ptr;
     689             : }
     690             : 
     691             : /* XXX it only handles Format 0 encoding tables */
     692           0 : static sal_uInt8 *PackCmap(CmapSubTable *s, sal_uInt32 *length)
     693             : {
     694           0 :     if( s->xg[s->n-1] > 0xff )
     695           0 :         return PackCmapType6(s, length);
     696             :     else
     697           0 :         return PackCmapType0(s, length);
     698             : }
     699             : 
     700           0 : static int GetRawData_cmap(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     701             : {
     702             :     table_cmap *t;
     703             :     sal_uInt32 i;
     704           0 :     sal_uInt32 tlen = 0;
     705             :     sal_uInt32 l;
     706             :     sal_uInt32 cmapsize;
     707             :     sal_uInt8 *cmap;
     708             :     sal_uInt32 coffset;
     709             : 
     710             :     assert(_this != 0);
     711           0 :     t = static_cast<table_cmap *>(_this->data);
     712             :     assert(t != 0);
     713             :     assert(t->n != 0);
     714             : 
     715           0 :     sal_uInt8** subtables = static_cast<sal_uInt8**>(scalloc(t->n, sizeof(sal_uInt8 *)));
     716           0 :     sal_uInt32* sizes = static_cast<sal_uInt32*>(scalloc(t->n, sizeof(sal_uInt32)));
     717             : 
     718           0 :     for (i = 0; i < t->n; i++) {
     719           0 :         subtables[i] = PackCmap(t->s+i, &l);
     720           0 :         sizes[i] = l;
     721           0 :         tlen += l;
     722             :     }
     723             : 
     724           0 :     cmapsize = tlen + 4 + 8 * t->n;
     725           0 :     _this->rawdata = cmap = ttmalloc(cmapsize);
     726             : 
     727           0 :     PutUInt16(0, cmap, 0, 1);
     728           0 :     PutUInt16((sal_uInt16)t->n, cmap, 2, 1);
     729           0 :     coffset = 4 + t->n * 8;
     730             : 
     731           0 :     for (i = 0; i < t->n; i++) {
     732           0 :         PutUInt16((sal_uInt16)(t->s[i].id >> 16), cmap + 4, i * 8, 1);
     733           0 :         PutUInt16((sal_uInt16)(t->s[i].id & 0xFF), cmap + 4, 2 + i * 8, 1);
     734           0 :         PutUInt32(coffset, cmap + 4, 4 + i * 8, 1);
     735           0 :         memcpy(cmap + coffset, subtables[i], sizes[i]);
     736           0 :         free(subtables[i]);
     737           0 :         coffset += sizes[i];
     738             :     }
     739             : 
     740           0 :     free(subtables);
     741           0 :     free(sizes);
     742             : 
     743           0 :     *ptr = cmap;
     744           0 :     *len = cmapsize;
     745           0 :     *tag = T_cmap;
     746             : 
     747           0 :     return TTCR_OK;
     748             : }
     749             : 
     750           0 : static int GetRawData_name(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     751             : {
     752             :     list l;
     753           0 :     sal_Int16 i=0, n;                          /* number of Name Records */
     754           0 :     int stringLen = 0;
     755             :     sal_uInt8 *p1, *p2;
     756             : 
     757           0 :     *ptr = 0;
     758           0 :     *len = 0;
     759           0 :     *tag = 0;
     760             : 
     761             :     assert(_this != 0);
     762           0 :     l = static_cast<list>(_this->data);
     763             :     assert(l != 0);
     764             : 
     765           0 :     if ((n = (sal_Int16)listCount(l)) == 0) return TTCR_NONAMES;
     766             : 
     767           0 :     NameRecord* nr = static_cast<NameRecord*>(scalloc(n, sizeof(NameRecord)));
     768             : 
     769           0 :     listToFirst(l);
     770             : 
     771           0 :     do {
     772           0 :         memcpy(nr+i, listCurrent(l), sizeof(NameRecord));
     773           0 :         stringLen += nr[i].slen;
     774           0 :         i++;
     775           0 :     } while (listNext(l));
     776             : 
     777           0 :     if (stringLen > 65535) {
     778           0 :         free(nr);
     779           0 :         return TTCR_NAMETOOLONG;
     780             :     }
     781             : 
     782           0 :     qsort(nr, n, sizeof(NameRecord), NameRecordCompareF);
     783             : 
     784           0 :     int nameLen = stringLen + 12 * n + 6;
     785           0 :     sal_uInt8* name = ttmalloc(nameLen);
     786             : 
     787           0 :     PutUInt16(0, name, 0, 1);
     788           0 :     PutUInt16(n, name, 2, 1);
     789           0 :     PutUInt16((sal_uInt16)(6 + 12 * n), name, 4, 1);
     790             : 
     791           0 :     p1 = name + 6;
     792           0 :     p2 = p1 + 12 * n;
     793             : 
     794           0 :     for (i = 0; i < n; i++) {
     795           0 :         PutUInt16(nr[i].platformID, p1, 0, 1);
     796           0 :         PutUInt16(nr[i].encodingID, p1, 2, 1);
     797           0 :         PutUInt16(nr[i].languageID, p1, 4, 1);
     798           0 :         PutUInt16(nr[i].nameID, p1, 6, 1);
     799           0 :         PutUInt16(nr[i].slen, p1, 8, 1);
     800           0 :         PutUInt16((sal_uInt16)(p2 - (name + 6 + 12 * n)), p1, 10, 1);
     801           0 :         memcpy(p2, nr[i].sptr, nr[i].slen);
     802             :         /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf("\n"); }; */
     803           0 :         p2 += nr[i].slen;
     804           0 :         p1 += 12;
     805             :     }
     806             : 
     807           0 :     free(nr);
     808           0 :     _this->rawdata = name;
     809             : 
     810           0 :     *ptr = name;
     811           0 :     *len = (sal_uInt16)nameLen;
     812           0 :     *tag = T_name;
     813             : 
     814             :     /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */
     815             : 
     816           0 :     return TTCR_OK;
     817             : }
     818             : 
     819           0 : static int GetRawData_post(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
     820             : {
     821           0 :     tdata_post *p = static_cast<tdata_post *>(_this->data);
     822           0 :     sal_uInt8 *post = 0;
     823           0 :     sal_uInt32 postLen = 0;
     824             :     int ret;
     825             : 
     826           0 :     if (_this->rawdata) free(_this->rawdata);
     827             : 
     828           0 :     if (p->format == 0x00030000) {
     829           0 :         postLen = 32;
     830           0 :         post = ttmalloc(postLen);
     831           0 :         PutUInt32(0x00030000, post, 0, 1);
     832           0 :         PutUInt32(p->italicAngle, post, 4, 1);
     833           0 :         PutUInt16(p->underlinePosition, post, 8, 1);
     834           0 :         PutUInt16(p->underlineThickness, post, 10, 1);
     835           0 :         PutUInt16((sal_uInt16)p->isFixedPitch, post, 12, 1);
     836           0 :         ret = TTCR_OK;
     837             :     } else {
     838           0 :         fprintf(stderr, "Unrecognized format of a post table: %08X.\n", (int)p->format);
     839           0 :         ret = TTCR_POSTFORMAT;
     840             :     }
     841             : 
     842           0 :     *ptr = _this->rawdata = post;
     843           0 :     *len = postLen;
     844           0 :     *tag = T_post;
     845             : 
     846           0 :     return ret;
     847             : }
     848             : 
     849             : static struct {
     850             :     sal_uInt32 tag;
     851             :     int (*f)(TrueTypeTable *, sal_uInt8 **, sal_uInt32 *, sal_uInt32 *);
     852             : } vtable2[] =
     853             : {
     854             :     {0,      GetRawData_generic},
     855             :     {T_head, GetRawData_head},
     856             :     {T_hhea, GetRawData_hhea},
     857             :     {T_loca, GetRawData_loca},
     858             :     {T_maxp, GetRawData_maxp},
     859             :     {T_glyf, GetRawData_glyf},
     860             :     {T_cmap, GetRawData_cmap},
     861             :     {T_name, GetRawData_name},
     862             :     {T_post, GetRawData_post}
     863             : 
     864             : };
     865             : 
     866             : /*
     867             :  * TrueTypeTable public methods
     868             :  */
     869             : 
     870             : /* Note: Type42 fonts only need these tables:
     871             :  *        head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
     872             :  *
     873             :  * Microsoft required tables
     874             :  *        cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2
     875             :  *
     876             :  * Apple required tables
     877             :  *        cmap, glyf, head, hhea, hmtx, loca, maxp, name, post
     878             :  *
     879             :  */
     880             : 
     881           0 : TrueTypeTable *TrueTypeTableNew(sal_uInt32 tag,
     882             :                                 sal_uInt32 nbytes,
     883             :                                 const sal_uInt8* ptr)
     884             : {
     885           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
     886           0 :     tdata_generic* pdata = static_cast<tdata_generic*>(smalloc(sizeof(tdata_generic)));
     887           0 :     pdata->nbytes = nbytes;
     888           0 :     pdata->tag = tag;
     889           0 :     if (nbytes) {
     890           0 :         pdata->ptr = ttmalloc(nbytes);
     891           0 :         memcpy(pdata->ptr, ptr, nbytes);
     892             :     } else {
     893           0 :         pdata->ptr = 0;
     894             :     }
     895             : 
     896           0 :     table->tag = 0;
     897           0 :     table->data = pdata;
     898           0 :     table->rawdata = 0;
     899             : 
     900           0 :     return table;
     901             : }
     902             : 
     903           0 : TrueTypeTable *TrueTypeTableNew_head(sal_uInt32 fontRevision,
     904             :                                      sal_uInt16 flags,
     905             :                                      sal_uInt16 unitsPerEm,
     906             :                                      const sal_uInt8* created,
     907             :                                      sal_uInt16 macStyle,
     908             :                                      sal_uInt16 lowestRecPPEM,
     909             :                                      sal_Int16  fontDirectionHint)
     910             : {
     911             :     assert(created != 0);
     912             : 
     913           0 :     TrueTypeTable* table  = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
     914           0 :     sal_uInt8* ptr = ttmalloc(TABLESIZE_head);
     915             : 
     916           0 :     PutUInt32(0x00010000, ptr, 0, 1);             /* version */
     917           0 :     PutUInt32(fontRevision, ptr, 4, 1);
     918           0 :     PutUInt32(0x5F0F3CF5, ptr, 12, 1);            /* magic number */
     919           0 :     PutUInt16(flags, ptr, 16, 1);
     920           0 :     PutUInt16(unitsPerEm, ptr, 18, 1);
     921           0 :     memcpy(ptr+20, created, 8);                   /* Created Long Date */
     922           0 :     memset(ptr+28, 0, 8);                         /* Modified Long Date */
     923           0 :     PutUInt16(macStyle, ptr, 44, 1);
     924           0 :     PutUInt16(lowestRecPPEM, ptr, 46, 1);
     925           0 :     PutUInt16(fontDirectionHint, ptr, 48, 1);
     926           0 :     PutUInt16(0, ptr, 52, 1);                     /* glyph data format: 0 */
     927             : 
     928           0 :     table->data = static_cast<void *>(ptr);
     929           0 :     table->tag = T_head;
     930           0 :     table->rawdata = 0;
     931             : 
     932           0 :     return table;
     933             : }
     934             : 
     935           0 : TrueTypeTable *TrueTypeTableNew_hhea(sal_Int16  ascender,
     936             :                                      sal_Int16  descender,
     937             :                                      sal_Int16  linegap,
     938             :                                      sal_Int16  caretSlopeRise,
     939             :                                      sal_Int16  caretSlopeRun)
     940             : {
     941           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
     942           0 :     sal_uInt8* ptr = ttmalloc(TABLESIZE_hhea);
     943             : 
     944           0 :     PutUInt32(0x00010000, ptr, 0, 1);             /* version */
     945           0 :     PutUInt16(ascender, ptr, 4, 1);
     946           0 :     PutUInt16(descender, ptr, 6, 1);
     947           0 :     PutUInt16(linegap, ptr, 8, 1);
     948           0 :     PutUInt16(caretSlopeRise, ptr, 18, 1);
     949           0 :     PutUInt16(caretSlopeRun, ptr, 20, 1);
     950           0 :     PutUInt16(0, ptr, 22, 1);                     /* reserved 1 */
     951           0 :     PutUInt16(0, ptr, 24, 1);                     /* reserved 2 */
     952           0 :     PutUInt16(0, ptr, 26, 1);                     /* reserved 3 */
     953           0 :     PutUInt16(0, ptr, 28, 1);                     /* reserved 4 */
     954           0 :     PutUInt16(0, ptr, 30, 1);                     /* reserved 5 */
     955           0 :     PutUInt16(0, ptr, 32, 1);                     /* metricDataFormat */
     956             : 
     957           0 :     table->data = static_cast<void *>(ptr);
     958           0 :     table->tag = T_hhea;
     959           0 :     table->rawdata = 0;
     960             : 
     961           0 :     return table;
     962             : }
     963             : 
     964           0 : TrueTypeTable *TrueTypeTableNew_loca()
     965             : {
     966           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
     967           0 :     table->data = smalloc(sizeof(tdata_loca));
     968             : 
     969           0 :     static_cast<tdata_loca *>(table->data)->nbytes = 0;
     970           0 :     static_cast<tdata_loca *>(table->data)->ptr = 0;
     971             : 
     972           0 :     table->tag = T_loca;
     973           0 :     table->rawdata = 0;
     974             : 
     975           0 :     return table;
     976             : }
     977             : 
     978           0 : TrueTypeTable *TrueTypeTableNew_maxp( const sal_uInt8* maxp, int size)
     979             : {
     980           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
     981           0 :     table->data = ttmalloc(TABLESIZE_maxp);
     982             : 
     983           0 :     if (maxp && size == TABLESIZE_maxp) {
     984           0 :         memcpy(table->data, maxp, TABLESIZE_maxp);
     985             :     }
     986             : 
     987           0 :     table->tag = T_maxp;
     988           0 :     table->rawdata = 0;
     989             : 
     990           0 :     return table;
     991             : }
     992             : 
     993           0 : TrueTypeTable *TrueTypeTableNew_glyf()
     994             : {
     995           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
     996           0 :     list l = listNewEmpty();
     997             : 
     998             :     assert(l != 0);
     999             : 
    1000           0 :     listSetElementDtor(l, FreeGlyphData);
    1001             : 
    1002           0 :     table->data = l;
    1003           0 :     table->rawdata = 0;
    1004           0 :     table->tag = T_glyf;
    1005             : 
    1006           0 :     return table;
    1007             : }
    1008             : 
    1009           0 : TrueTypeTable *TrueTypeTableNew_cmap()
    1010             : {
    1011           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
    1012           0 :     table_cmap* cmap = static_cast<table_cmap*>(smalloc(sizeof(table_cmap)));
    1013             : 
    1014           0 :     cmap->n = 0;
    1015           0 :     cmap->m = CMAP_SUBTABLE_INIT;
    1016           0 :     cmap->s = static_cast<CmapSubTable *>(scalloc(CMAP_SUBTABLE_INIT, sizeof(CmapSubTable)));
    1017           0 :     memset(cmap->s, 0, sizeof(CmapSubTable) * CMAP_SUBTABLE_INIT);
    1018             : 
    1019           0 :     table->data = cmap;
    1020             : 
    1021           0 :     table->rawdata = 0;
    1022           0 :     table->tag = T_cmap;
    1023             : 
    1024           0 :     return table;
    1025             : }
    1026             : 
    1027           0 : static void DisposeNameRecord(void *ptr)
    1028             : {
    1029           0 :     if (ptr != 0) {
    1030           0 :         NameRecord *nr = static_cast<NameRecord *>(ptr);
    1031           0 :         if (nr->sptr) free(nr->sptr);
    1032           0 :         free(ptr);
    1033             :     }
    1034           0 : }
    1035             : 
    1036           0 : static NameRecord* NameRecordNewCopy(NameRecord *nr)
    1037             : {
    1038           0 :     NameRecord* p = static_cast<NameRecord*>(smalloc(sizeof(NameRecord)));
    1039             : 
    1040           0 :     memcpy(p, nr, sizeof(NameRecord));
    1041             : 
    1042           0 :     if (p->slen) {
    1043           0 :         p->sptr = static_cast<sal_uInt8*>(smalloc(p->slen));
    1044           0 :         memcpy(p->sptr, nr->sptr, p->slen);
    1045             :     }
    1046             : 
    1047           0 :     return p;
    1048             : }
    1049             : 
    1050           0 : TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr)
    1051             : {
    1052           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
    1053           0 :     list l = listNewEmpty();
    1054             : 
    1055             :     assert(l != 0);
    1056             : 
    1057           0 :     listSetElementDtor(l, DisposeNameRecord);
    1058             : 
    1059           0 :     if (n != 0) {
    1060             :         int i;
    1061           0 :         for (i = 0; i < n; i++) {
    1062           0 :             listAppend(l, NameRecordNewCopy(nr+i));
    1063             :         }
    1064             :     }
    1065             : 
    1066           0 :     table->data = l;
    1067           0 :     table->rawdata = 0;
    1068           0 :     table->tag = T_name;
    1069             : 
    1070           0 :     return table;
    1071             : }
    1072             : 
    1073           0 : TrueTypeTable *TrueTypeTableNew_post(sal_uInt32 format,
    1074             :                                      sal_uInt32 italicAngle,
    1075             :                                      sal_Int16 underlinePosition,
    1076             :                                      sal_Int16 underlineThickness,
    1077             :                                      sal_uInt32 isFixedPitch)
    1078             : {
    1079             :     assert(format == 0x00030000);                 /* Only format 3.0 is supported at this time */
    1080           0 :     TrueTypeTable* table = static_cast<TrueTypeTable*>(smalloc(sizeof(TrueTypeTable)));
    1081           0 :     tdata_post* post = static_cast<tdata_post*>(smalloc(sizeof(tdata_post)));
    1082             : 
    1083           0 :     post->format = format;
    1084           0 :     post->italicAngle = italicAngle;
    1085           0 :     post->underlinePosition = underlinePosition;
    1086           0 :     post->underlineThickness = underlineThickness;
    1087           0 :     post->isFixedPitch = isFixedPitch;
    1088           0 :     post->ptr = 0;
    1089             : 
    1090           0 :     table->data = post;
    1091           0 :     table->rawdata = 0;
    1092           0 :     table->tag = T_post;
    1093             : 
    1094           0 :     return table;
    1095             : }
    1096             : 
    1097           0 : int GetRawData(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
    1098             : {
    1099             :     /* XXX do a binary search */
    1100             :     unsigned int i;
    1101             : 
    1102             :     assert(_this != 0);
    1103             :     assert(ptr != 0);
    1104             :     assert(len != 0);
    1105             :     assert(tag != 0);
    1106             : 
    1107           0 :     *ptr = 0; *len = 0; *tag = 0;
    1108             : 
    1109           0 :     if (_this->rawdata) {
    1110           0 :         free(_this->rawdata);
    1111           0 :         _this->rawdata = 0;
    1112             :     }
    1113             : 
    1114           0 :     for(i=0; i < sizeof(vtable2)/sizeof(*vtable2); i++) {
    1115           0 :         if (_this->tag == vtable2[i].tag) {
    1116           0 :             return vtable2[i].f(_this, ptr, len, tag);
    1117             :         }
    1118             :     }
    1119             : 
    1120             :     assert(!"Unknown TrueType table.\n");
    1121           0 :     return TTCR_UNKNOWN;
    1122             : }
    1123             : 
    1124           0 : void cmapAdd(TrueTypeTable *table, sal_uInt32 id, sal_uInt32 c, sal_uInt32 g)
    1125             : {
    1126             :     sal_uInt32 i, found;
    1127             :     table_cmap *t;
    1128             :     CmapSubTable *s;
    1129             : 
    1130             :     assert(table != 0);
    1131             :     assert(table->tag == T_cmap);
    1132           0 :     t = static_cast<table_cmap *>(table->data); assert(t != 0);
    1133           0 :     s = t->s; assert(s != 0);
    1134             : 
    1135           0 :     found = 0;
    1136             : 
    1137           0 :     for (i = 0; i < t->n; i++) {
    1138           0 :         if (s[i].id == id) {
    1139           0 :             found = 1;
    1140           0 :             break;
    1141             :         }
    1142             :     }
    1143             : 
    1144           0 :     if (!found) {
    1145           0 :         if (t->n == t->m) {
    1146           0 :             CmapSubTable* tmp = static_cast<CmapSubTable*>(scalloc(t->m + CMAP_SUBTABLE_INCR, sizeof(CmapSubTable)));
    1147           0 :             memset(tmp, 0, t->m + CMAP_SUBTABLE_INCR * sizeof(CmapSubTable));
    1148           0 :             memcpy(tmp, s, sizeof(CmapSubTable) * t->m);
    1149           0 :             t->m += CMAP_SUBTABLE_INCR;
    1150           0 :             free(s);
    1151           0 :             s = tmp;
    1152           0 :             t->s = s;
    1153             :         }
    1154             : 
    1155           0 :         for (i = 0; i < t->n; i++) {
    1156           0 :             if (s[i].id > id) break;
    1157             :         }
    1158             : 
    1159           0 :         if (i < t->n) {
    1160           0 :             memmove(s+i+1, s+i, t->n-i);
    1161             :         }
    1162             : 
    1163           0 :         t->n++;
    1164             : 
    1165           0 :         s[i].id = id;
    1166           0 :         s[i].n = 0;
    1167           0 :         s[i].m = CMAP_PAIR_INIT;
    1168           0 :         s[i].xc = static_cast<sal_uInt32*>(scalloc(CMAP_PAIR_INIT, sizeof(sal_uInt32)));
    1169           0 :         s[i].xg = static_cast<sal_uInt32*>(scalloc(CMAP_PAIR_INIT, sizeof(sal_uInt32)));
    1170             :     }
    1171             : 
    1172           0 :     if (s[i].n == s[i].m) {
    1173           0 :         sal_uInt32* tmp1 = static_cast<sal_uInt32*>(scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(sal_uInt32)));
    1174           0 :         sal_uInt32* tmp2 = static_cast<sal_uInt32*>(scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(sal_uInt32)));
    1175             :         assert(tmp1 != 0);
    1176             :         assert(tmp2 != 0);
    1177           0 :         memcpy(tmp1, s[i].xc, sizeof(sal_uInt32) * s[i].m);
    1178           0 :         memcpy(tmp2, s[i].xg, sizeof(sal_uInt32) * s[i].m);
    1179           0 :         s[i].m += CMAP_PAIR_INCR;
    1180           0 :         free(s[i].xc);
    1181           0 :         free(s[i].xg);
    1182           0 :         s[i].xc = tmp1;
    1183           0 :         s[i].xg = tmp2;
    1184             :     }
    1185             : 
    1186           0 :     s[i].xc[s[i].n] = c;
    1187           0 :     s[i].xg[s[i].n] = g;
    1188           0 :     s[i].n++;
    1189           0 : }
    1190             : 
    1191           0 : sal_uInt32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, TrueTypeFont *fnt)
    1192             : {
    1193             :     list l;
    1194             :     sal_uInt32 currentID;
    1195             :     int ret, n, ncomponents;
    1196             : 
    1197             :     assert(table != 0);
    1198             :     assert(table->tag == T_glyf);
    1199             : 
    1200           0 :     if (!glyphdata) return (sal_uInt32)~0;
    1201             : 
    1202           0 :     std::vector< sal_uInt32 > glyphlist;
    1203             : 
    1204           0 :     ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist);
    1205             : 
    1206           0 :     l = static_cast<list>(table->data);
    1207           0 :     if (listCount(l) > 0) {
    1208           0 :         listToLast(l);
    1209           0 :         ret = n = static_cast<GlyphData *>(listCurrent(l))->newID + 1;
    1210             :     } else {
    1211           0 :         ret = n = 0;
    1212             :     }
    1213           0 :     glyphdata->newID = n++;
    1214           0 :     listAppend(l, glyphdata);
    1215             : 
    1216           0 :     if (ncomponents > 1 && glyphlist.size() > 1 )
    1217             :     {
    1218           0 :         std::vector< sal_uInt32 >::const_iterator it = glyphlist.begin();
    1219           0 :         ++it;
    1220             :         /* glyphData->glyphID is always the first glyph on the list */
    1221           0 :         do
    1222             :         {
    1223           0 :             int found = 0;
    1224           0 :             currentID = *it;
    1225             :             /* XXX expensive! should be rewritten with sorted arrays! */
    1226           0 :             listToFirst(l);
    1227           0 :             do {
    1228           0 :                 if (static_cast<GlyphData *>(listCurrent(l))->glyphID == currentID) {
    1229           0 :                     found = 1;
    1230           0 :                     break;
    1231             :                 }
    1232           0 :             } while (listNext(l));
    1233             : 
    1234           0 :             if (!found) {
    1235           0 :                 GlyphData *gd = GetTTRawGlyphData(fnt, currentID);
    1236           0 :                 gd->newID = n++;
    1237           0 :                 listAppend(l, gd);
    1238             :             }
    1239           0 :         } while( ++it !=  glyphlist.end() );
    1240             :     }
    1241             : 
    1242           0 :     return ret;
    1243             : }
    1244             : 
    1245           0 : sal_uInt32 glyfCount(const TrueTypeTable *table)
    1246             : {
    1247             :     assert(table != 0);
    1248             :     assert(table->tag == T_glyf);
    1249           0 :     return listCount(static_cast<list>(table->data));
    1250             : }
    1251             : 
    1252           0 : void nameAdd(TrueTypeTable *table, NameRecord *nr)
    1253             : {
    1254             :     list l;
    1255             : 
    1256             :     assert(table != 0);
    1257             :     assert(table->tag == T_name);
    1258             : 
    1259           0 :     l = static_cast<list>(table->data);
    1260             : 
    1261           0 :     listAppend(l, NameRecordNewCopy(nr));
    1262           0 : }
    1263             : 
    1264           0 : static TrueTypeTable *FindTable(TrueTypeCreator *tt, sal_uInt32 tag)
    1265             : {
    1266           0 :     if (listIsEmpty(tt->tables)) return 0;
    1267             : 
    1268           0 :     listToFirst(tt->tables);
    1269             : 
    1270           0 :     do {
    1271           0 :         if (static_cast<TrueTypeTable *>(listCurrent(tt->tables))->tag == tag) {
    1272           0 :             return static_cast<TrueTypeTable*>(listCurrent(tt->tables));
    1273             :         }
    1274           0 :     } while (listNext(tt->tables));
    1275             : 
    1276           0 :     return 0;
    1277             : }
    1278             : 
    1279             : /* This function processes all the tables and synchronizes them before creating
    1280             :  * the output TrueType stream.
    1281             :  *
    1282             :  * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' ***
    1283             :  *
    1284             :  * It does:
    1285             :  *
    1286             :  * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables.
    1287             :  * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table.
    1288             :  * - Stores indexToLocFormat in 'head'
    1289             :  * - updates 'maxp' table
    1290             :  * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics
    1291             :  *   in 'hhea' table
    1292             :  *
    1293             :  */
    1294           0 : static void ProcessTables(TrueTypeCreator *tt)
    1295             : {
    1296             :     TrueTypeTable *glyf, *loca, *head, *maxp, *hhea;
    1297             :     list glyphlist;
    1298           0 :     sal_uInt32 nGlyphs, locaLen = 0, glyfLen = 0;
    1299           0 :     sal_Int16 xMin = 0, yMin = 0, xMax = 0, yMax = 0;
    1300           0 :     sal_uInt32 i = 0;
    1301             :     sal_Int16 indexToLocFormat;
    1302             :     sal_uInt8 *hmtxPtr, *hheaPtr;
    1303             :     sal_uInt32 hmtxSize;
    1304             :     sal_uInt8 *p1, *p2;
    1305           0 :     sal_uInt16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0;
    1306           0 :     int nlsb = 0;
    1307             :     sal_uInt32 *gid;                        /* array of old glyphIDs */
    1308             : 
    1309           0 :     glyf = FindTable(tt, T_glyf);
    1310           0 :     glyphlist = static_cast<list>(glyf->data);
    1311           0 :     nGlyphs = listCount(glyphlist);
    1312             :     assert(nGlyphs != 0);
    1313           0 :     gid = static_cast<sal_uInt32*>(scalloc(nGlyphs, sizeof(sal_uInt32)));
    1314             : 
    1315           0 :     RemoveTable(tt, T_loca);
    1316           0 :     RemoveTable(tt, T_hmtx);
    1317             : 
    1318             :     /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */
    1319             : 
    1320           0 :     listToFirst(glyphlist);
    1321           0 :     do {
    1322           0 :         GlyphData *gd = static_cast<GlyphData *>(listCurrent(glyphlist));
    1323             :         sal_Int16 z;
    1324           0 :         glyfLen += gd->nbytes;
    1325             :         /* XXX if (gd->nbytes & 1) glyfLen++; */
    1326             : 
    1327             :         assert(gd->newID == i);
    1328           0 :         gid[i++] = gd->glyphID;
    1329             :         /* gd->glyphID = i++; */
    1330             : 
    1331             :         /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */
    1332             : 
    1333           0 :         if (gd->nbytes != 0) {
    1334           0 :             z = GetInt16(gd->ptr, 2, 1);
    1335           0 :             if (z < xMin) xMin = z;
    1336             : 
    1337           0 :             z = GetInt16(gd->ptr, 4, 1);
    1338           0 :             if (z < yMin) yMin = z;
    1339             : 
    1340           0 :             z = GetInt16(gd->ptr, 6, 1);
    1341           0 :             if (z > xMax) xMax = z;
    1342             : 
    1343           0 :             z = GetInt16(gd->ptr, 8, 1);
    1344           0 :             if (z > yMax) yMax = z;
    1345             :         }
    1346             : 
    1347           0 :         if (!gd->compflag) {                                /* non-composite glyph */
    1348           0 :             if (gd->npoints > maxPoints) maxPoints = gd->npoints;
    1349           0 :             if (gd->ncontours > maxContours) maxContours = gd->ncontours;
    1350             :         } else {                                            /* composite glyph */
    1351           0 :             if (gd->npoints > maxCompositePoints) maxCompositePoints = gd->npoints;
    1352           0 :             if (gd->ncontours > maxCompositeContours) maxCompositeContours = gd->ncontours;
    1353             :         }
    1354             : 
    1355           0 :     } while (listNext(glyphlist));
    1356             : 
    1357           0 :     indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0;
    1358           0 :     locaLen = indexToLocFormat ?  (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1;
    1359             : 
    1360           0 :     sal_uInt8* glyfPtr = ttmalloc(glyfLen);
    1361           0 :     sal_uInt8* locaPtr = ttmalloc(locaLen);
    1362           0 :     TTSimpleGlyphMetrics* met = static_cast<TTSimpleGlyphMetrics*>(scalloc(nGlyphs, sizeof(TTSimpleGlyphMetrics)));
    1363           0 :     i = 0;
    1364             : 
    1365           0 :     listToFirst(glyphlist);
    1366           0 :     p1 = glyfPtr;
    1367           0 :     p2 = locaPtr;
    1368           0 :     do {
    1369           0 :         GlyphData *gd = static_cast<GlyphData *>(listCurrent(glyphlist));
    1370             : 
    1371           0 :         if (gd->compflag) {                       /* re-number all components */
    1372             :             sal_uInt16 flags, index;
    1373           0 :             sal_uInt8 *ptr = gd->ptr + 10;
    1374           0 :             do {
    1375             :                 sal_uInt32 j;
    1376           0 :                 flags = GetUInt16(ptr, 0, 1);
    1377           0 :                 index = GetUInt16(ptr, 2, 1);
    1378             :                 /* XXX use the sorted array of old to new glyphID mapping and do a binary search */
    1379           0 :                 for (j = 0; j < nGlyphs; j++) {
    1380           0 :                     if (gid[j] == index) {
    1381           0 :                         break;
    1382             :                     }
    1383             :                 }
    1384             :                 /* printf("X: %d -> %d.\n", index, j); */
    1385             : 
    1386           0 :                 PutUInt16((sal_uInt16) j, ptr, 2, 1);
    1387             : 
    1388           0 :                 ptr += 4;
    1389             : 
    1390           0 :                 if (flags & ARG_1_AND_2_ARE_WORDS) {
    1391           0 :                     ptr += 4;
    1392             :                 } else {
    1393           0 :                     ptr += 2;
    1394             :                 }
    1395             : 
    1396           0 :                 if (flags & WE_HAVE_A_SCALE) {
    1397           0 :                     ptr += 2;
    1398           0 :                 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
    1399           0 :                     ptr += 4;
    1400           0 :                 } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
    1401           0 :                     ptr += 8;
    1402             :                 }
    1403           0 :             } while (flags & MORE_COMPONENTS);
    1404             :         }
    1405             : 
    1406           0 :         if (gd->nbytes != 0) {
    1407           0 :             memcpy(p1, gd->ptr, gd->nbytes);
    1408             :         }
    1409           0 :         if (indexToLocFormat == 1) {
    1410           0 :             PutUInt32(p1 - glyfPtr, p2, 0, 1);
    1411           0 :             p2 += 4;
    1412             :         } else {
    1413           0 :             PutUInt16((sal_uInt16)((p1 - glyfPtr) >> 1), p2, 0, 1);
    1414           0 :             p2 += 2;
    1415             :         }
    1416           0 :         p1 += gd->nbytes;
    1417             : 
    1418             :         /* fill the array of metrics */
    1419           0 :         met[i].adv = gd->aw;
    1420           0 :         met[i].sb  = gd->lsb;
    1421           0 :         i++;
    1422           0 :     } while (listNext(glyphlist));
    1423             : 
    1424           0 :     free(gid);
    1425             : 
    1426           0 :     if (indexToLocFormat == 1) {
    1427           0 :         PutUInt32(p1 - glyfPtr, p2, 0, 1);
    1428             :     } else {
    1429           0 :         PutUInt16((sal_uInt16)((p1 - glyfPtr) >> 1), p2, 0, 1);
    1430             :     }
    1431             : 
    1432           0 :     glyf->rawdata = glyfPtr;
    1433             : 
    1434           0 :     loca = TrueTypeTableNew_loca(); assert(loca != 0);
    1435           0 :     static_cast<tdata_loca *>(loca->data)->ptr = locaPtr;
    1436           0 :     static_cast<tdata_loca *>(loca->data)->nbytes = locaLen;
    1437             : 
    1438           0 :     AddTable(tt, loca);
    1439             : 
    1440           0 :     head = FindTable(tt, T_head);
    1441           0 :     sal_uInt8* const pHeadData = static_cast<sal_uInt8*>(head->data);
    1442           0 :     PutInt16(xMin, pHeadData, 36, 1);
    1443           0 :     PutInt16(yMin, pHeadData, 38, 1);
    1444           0 :     PutInt16(xMax, pHeadData, 40, 1);
    1445           0 :     PutInt16(yMax, pHeadData, 42, 1);
    1446           0 :     PutInt16(indexToLocFormat, pHeadData,  50, 1);
    1447             : 
    1448           0 :     maxp = FindTable(tt, T_maxp);
    1449             : 
    1450           0 :     sal_uInt8* const pMaxpData = static_cast<sal_uInt8*>(maxp->data);
    1451           0 :     PutUInt16((sal_uInt16)nGlyphs, pMaxpData, 4, 1);
    1452           0 :     PutUInt16(maxPoints, pMaxpData, 6, 1);
    1453           0 :     PutUInt16(maxContours, pMaxpData, 8, 1);
    1454           0 :     PutUInt16(maxCompositePoints, pMaxpData, 10, 1);
    1455           0 :     PutUInt16(maxCompositeContours, pMaxpData, 12, 1);
    1456             : 
    1457             :     /*
    1458             :      * Generate an htmx table and update hhea table
    1459             :      */
    1460           0 :     hhea = FindTable(tt, T_hhea); assert(hhea != 0);
    1461           0 :     hheaPtr = static_cast<sal_uInt8 *>(hhea->data);
    1462           0 :     if (nGlyphs > 2) {
    1463           0 :         for (i = nGlyphs - 1; i > 0; i--) {
    1464           0 :             if (met[i].adv != met[i-1].adv) break;
    1465             :         }
    1466           0 :         nlsb = nGlyphs - 1 - i;
    1467             :     }
    1468           0 :     hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2;
    1469           0 :     hmtxPtr = ttmalloc(hmtxSize);
    1470           0 :     p1 = hmtxPtr;
    1471             : 
    1472           0 :     for (i = 0; i < nGlyphs; i++) {
    1473           0 :         if (i < nGlyphs - nlsb) {
    1474           0 :             PutUInt16(met[i].adv, p1, 0, 1);
    1475           0 :             PutUInt16(met[i].sb, p1, 2, 1);
    1476           0 :             p1 += 4;
    1477             :         } else {
    1478           0 :             PutUInt16(met[i].sb, p1, 0, 1);
    1479           0 :             p1 += 2;
    1480             :         }
    1481             :     }
    1482             : 
    1483           0 :     AddTable(tt, TrueTypeTableNew(T_hmtx, hmtxSize, hmtxPtr));
    1484           0 :     PutUInt16((sal_uInt16)(nGlyphs - nlsb), hheaPtr, 34, 1);
    1485           0 :     free(hmtxPtr);
    1486           0 :     free(met);
    1487           0 : }
    1488             : 
    1489             : } // namespace vcl
    1490             : 
    1491             : extern "C"
    1492             : {
    1493             :     /**
    1494             :      * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it.
    1495             :      */
    1496           0 :      void TrueTypeCreatorDispose(vcl::TrueTypeCreator *_this)
    1497             :     {
    1498           0 :         listDispose(_this->tables);
    1499           0 :         free(_this);
    1500           0 :     }
    1501             : 
    1502             :     /**
    1503             :      * Destructor for the TrueTypeTable object.
    1504             :      */
    1505           0 :      void TrueTypeTableDispose(void * arg)
    1506             :     {
    1507           0 :         vcl::TrueTypeTable *_this = static_cast<vcl::TrueTypeTable *>(arg);
    1508             :         /* XXX do a binary search */
    1509             :         unsigned int i;
    1510             : 
    1511             :         assert(_this != 0);
    1512             : 
    1513           0 :         if (_this->rawdata) free(_this->rawdata);
    1514             : 
    1515           0 :         for(i=0; i < sizeof(vcl::vtable1)/sizeof(*vcl::vtable1); i++) {
    1516           0 :             if (_this->tag == vcl::vtable1[i].tag) {
    1517           0 :                 vcl::vtable1[i].f(_this);
    1518           0 :                 return;
    1519             :             }
    1520             :         }
    1521             :         assert(!"Unknown TrueType table.\n");
    1522             :     }
    1523             : }
    1524             : 
    1525             : #ifdef TEST_TTCR
    1526             : _inline sal_uInt32 mkTag(sal_uInt8 a, sal_uInt8 b, sal_uInt8 c, sal_uInt8 d) {
    1527             :     return (a << 24) | (b << 16) | (c << 8) | d;
    1528             : }
    1529             : 
    1530             : int main()
    1531             : {
    1532             :     TrueTypeCreator *ttcr;
    1533             :     sal_uInt8 *t1, *t2, *t3, *t4, *t5, *t6, *t7;
    1534             : 
    1535             :     TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr);
    1536             : 
    1537             :     t1 = malloc(1000); memset(t1, 'a', 1000);
    1538             :     t2 = malloc(2000); memset(t2, 'b', 2000);
    1539             :     t3 = malloc(3000); memset(t3, 'c', 3000);
    1540             :     t4 = malloc(4000); memset(t4, 'd', 4000);
    1541             :     t5 = malloc(5000); memset(t5, 'e', 5000);
    1542             :     t6 = malloc(6000); memset(t6, 'f', 6000);
    1543             :     t7 = malloc(7000); memset(t7, 'g', 7000);
    1544             : 
    1545             :     AddTable(ttcr, TrueTypeTableNew(0x6D617870, 1000, t1));
    1546             :     AddTable(ttcr, TrueTypeTableNew(0x4F532F32, 2000, t2));
    1547             :     AddTable(ttcr, TrueTypeTableNew(0x636D6170, 3000, t3));
    1548             :     AddTable(ttcr, TrueTypeTableNew(0x6C6F6361, 4000, t4));
    1549             :     AddTable(ttcr, TrueTypeTableNew(0x68686561, 5000, t5));
    1550             :     AddTable(ttcr, TrueTypeTableNew(0x676C7966, 6000, t6));
    1551             :     AddTable(ttcr, TrueTypeTableNew(0x6B65726E, 7000, t7));
    1552             : 
    1553             :     free(t1);
    1554             :     free(t2);
    1555             :     free(t3);
    1556             :     free(t4);
    1557             :     free(t5);
    1558             :     free(t6);
    1559             :     free(t7);
    1560             : 
    1561             :     StreamToFile(ttcr, "ttcrout.ttf");
    1562             : 
    1563             :     TrueTypeCreatorDispose(ttcr);
    1564             :     return 0;
    1565             : }
    1566             : #endif
    1567             : 
    1568             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11