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