1/***********************************************************************
2 *                                                                     *
3 * $Id: hpgsfont.c 385 2007-03-18 18:32:07Z softadm $
4 *                                                                     *
5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript   *
6 *        API for rendering a scene and thus renders to a variety of   *
7 *        devices and fileformats.                                     *
8 *                                                                     *
9 * (C) 2004-2006 ev-i Informationstechnologie GmbH  http://www.ev-i.at *
10 *                                                                     *
11 * Author: Wolfgang Glas                                               *
12 *                                                                     *
13 *  hpgs is free software; you can redistribute it and/or              *
14 * modify it under the terms of the GNU Lesser General Public          *
15 * License as published by the Free Software Foundation; either        *
16 * version 2.1 of the License, or (at your option) any later version.  *
17 *                                                                     *
18 * hpgs is distributed in the hope that it will be useful,             *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of      *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   *
21 * Lesser General Public License for more details.                     *
22 *                                                                     *
23 * You should have received a copy of the GNU Lesser General Public    *
24 * License along with this library; if not, write to the               *
25 * Free Software  Foundation, Inc., 59 Temple Place, Suite 330,        *
26 * Boston, MA  02111-1307  USA                                         *
27 *                                                                     *
28 ***********************************************************************
29 *                                                                     *
30 * The implementation of the public API for ttf font handling.         *
31 *                                                                     *
32 ***********************************************************************/
33
34#include<hpgsfont.h>
35#include<string.h>
36
37#ifdef WIN32
38#include <windows.h>
39#else
40#include<dirent.h>
41#endif
42
43#if defined ( __MINGW32__ ) || defined ( _MSC_VER )
44#include<malloc.h>
45#else
46#include<alloca.h>
47#endif
48
49static hpgs_mutex_t font_dir_mutex;
50static hpgs_font_dentry *font_directory = 0;
51static size_t font_directory_sz = 0;
52static size_t font_directory_alloc_sz = 0;
53
54// Standard glyph names in mac encoding cf.
55// to the OpenType spec.
56static char *std_glyph_names[] = {
57  // 0 - 9
58  ".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign","dollar","percent","ampersand",
59  // 10 - 19
60  "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero",
61  // 20 - 29
62  "one","two","three","four","five","six","seven","eight","nine","colon",
63  // 30 - 39
64  "semicolon","less","equal","greater","question","at","A","B","C","D",
65  // 40 - 49
66  "E","F","G","H","I","J","K","L","M","N",
67  // 50 - 59
68  "O","P","Q","R","S","T","U","V","W","X",
69  // 60 - 69
70  "Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","grave","a","b",
71  // 70 - 79
72  "c","d","e","f","g","h","i","j","k","l",
73  // 80 - 89
74  "m","n","o","p","q","r","s","t","u","v",
75  // 90 - 99
76  "w","x","y","z","braceleft","bar","braceright","asciitilde","Adieresis","Aring",
77  // 100 - 109
78  "Ccedilla","Eacute","Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex","adieresis","atilde",
79  // 110 - 119
80  "aring","ccedilla","eacute","egrave","ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis",
81  // 120 - 129
82  "ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute","ugrave","ucircumflex","udieresis",
83  // 130 - 139
84  "dagger","degree","cent","sterling","section","bullet","paragraph","germandbls","registered","copyright",
85  // 140 - 149
86  "trademark","acute","dieresis","notequal","AE","Oslash","infinity","plusminus","lessequal","greaterequal",
87  // 150 - 159
88  "yen","mu","partialdiff","summation","product","pi","integral","ordfeminine","ordmasculine","Omega",
89  // 160 - 169
90  "ae","oslash","questiondown","exclamdown","logicalnot","radical","florin","approxequal","Delta","guillemotleft",
91  // 170 - 179
92  "guillemotright","ellipsis","space","Agrave","Atilde","Otilde","OE","oe","endash","emdash",
93  // 180 - 189
94  "quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis","fraction","currency",
95  // 190 - 199
96  "guilsinglleft","guilsinglright","fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase","perthousand","Acircumflex",
97  // 200 - 209
98  "Ecircumflex","Aacute","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex",
99  // 210 - 219
100  0,"Ograve","Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde","macron","breve",
101  // 220 - 229
102  "dotaccent","ring","cedilla","hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron",
103  // 230 - 239
104  "Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn","thorn","minus",
105  // 240 - 249
106  "multiply","onesuperior","twosuperior","threesuperior","onehalf","onequarter","threequarters","franc","Gbreve","gbreve",
107  // 250 - 257
108  "Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron","dcroat"
109};
110
111void hpgs_font_init()
112{
113  hpgs_mutex_init(&font_dir_mutex);
114}
115
116void hpgs_font_cleanup()
117{
118  hpgs_mutex_lock(&font_dir_mutex);
119
120  size_t i;
121
122  for (i=0;i<font_directory_sz;++i)
123    {
124      if (font_directory[i].font_name) free (font_directory[i].font_name);
125      if (font_directory[i].filename) free (font_directory[i].filename);
126
127      if (font_directory[i].font)
128        hpgs_destroy_font(font_directory[i].font);
129    }
130
131  if (font_directory) free(font_directory);
132
133  font_directory = 0;
134  font_directory_sz = 0;
135  font_directory_alloc_sz = 0;
136
137  hpgs_mutex_unlock(&font_dir_mutex);
138
139  hpgs_mutex_destroy(&font_dir_mutex);
140}
141
142static void push_font_to_directory(char *name, char *fn)
143{
144  if (font_directory_sz>=font_directory_alloc_sz)
145    {
146      hpgs_font_dentry *d = realloc(font_directory,sizeof(hpgs_font_dentry)*2*font_directory_alloc_sz);
147
148      if (!d) { free(name); free(fn); return; }
149
150      font_directory = d;
151      font_directory_alloc_sz *= 2;
152    }
153
154  font_directory[font_directory_sz].font_name = name;
155  font_directory[font_directory_sz].filename = fn;
156  font_directory[font_directory_sz].font = 0;
157
158  // hpgs_log("name,fn=%s,%s.\n",name,fn);
159
160  ++font_directory_sz;
161}
162
163// helpers for big-endian binary file treatment.
164static int read_uint32(hpgs_istream *is, uint32_t *x)
165{
166  int c1,c2,c3,c4;
167
168  c1=hpgs_getc(is);
169  if (c1<0) return -1;
170  c2=hpgs_getc(is);
171  if (c2<0) return -1;
172  c3=hpgs_getc(is);
173  if (c3<0) return -1;
174  c4=hpgs_getc(is);
175  if (c4<0) return -1;
176
177  *x =
178    (((uint32_t)(c1))<<24)|
179    (((uint32_t)(c2))<<16)|
180    (((uint32_t)(c3))<<8)|
181    ((uint32_t)(c4));
182
183  return 0;
184}
185
186static int read_int32(hpgs_istream *is, int32_t *x) { return read_uint32(is,(uint32_t *)x); }
187
188static int read_uint16(hpgs_istream *is, uint16_t *x)
189{
190  int c1,c2;
191
192  c1=hpgs_getc(is);
193  if (c1<0) return -1;
194  c2=hpgs_getc(is);
195  if (c2<0) return -1;
196
197  *x =
198    (((uint16_t)(c1))<<8)|
199    ((uint16_t)(c2));
200
201  return 0;
202}
203
204static int read_int16(hpgs_istream *is, int16_t *x) { return read_uint16(is,(uint16_t *)x); }
205
206static int read_uint8(hpgs_istream *is, uint8_t *x)
207{
208  int c;
209
210  c=hpgs_getc(is);
211  if (c<0) return -1;
212
213  *x = (uint8_t)(c);
214  return 0;
215}
216
217static int read_int8(hpgs_istream *is, int8_t *x) { return read_uint8(is,(uint8_t *)x); }
218
219// convert the next n bytes from the stream as ucs2 string
220// to a utf-8 string.
221//
222static int ucs2_stream_string_to_utf8(hpgs_istream *is, size_t n, char *str)
223{
224  size_t i;
225
226  for (i=0;i<n;i+=2)
227    {
228      uint16_t file_code;
229
230      if (read_uint16(is,&file_code)) return -1;
231
232      if (file_code < 0x80)
233        *str++ = file_code;
234      else if (file_code < 0x800)
235        {
236          *str++ = (file_code >> 6) | 0xC0;
237          *str++ = (file_code & 0x3f) | 0x80;
238        }
239      else
240        {
241          *str++ = (file_code >> 12) | 0xE0;
242          *str++ = ((file_code >> 6) & 0x3f) | 0x80;
243          *str++ = (file_code & 0x3f) | 0x80;
244        }
245    }
246
247  *str++ = 0;
248  return 0;
249}
250
251static int ascii_stream_string_to_utf8(hpgs_istream *is, size_t n, char *str)
252{
253  size_t i;
254
255  for (i=0;i<n;++i)
256    {
257      int c = hpgs_getc(is);
258
259      if (c < 0) return -1;
260
261      *str++ = c;
262    }
263
264  *str++ = 0;
265
266  return 0;
267}
268
269static int read_table_entry(hpgs_istream *is, hpgs_font_table_entry *e)
270{
271  if (read_uint32(is,&e->tag)) return -1;
272  if (read_uint32(is,&e->checksum)) return -1;
273  if (read_uint32(is,&e->offset)) return -1;
274  if (read_uint32(is,&e->length)) return -1;
275  return 0;
276}
277
278static void init_font_cmap_data(hpgs_font_cmap_data *cmap_data)
279{
280  cmap_data->ranges_sz = 0;
281  cmap_data->ranges = 0;
282  cmap_data->glyphIndexArray_sz = 0;
283  cmap_data->glyphIndexArray = 0;
284}
285
286static void cleanup_font_cmap_data(hpgs_font_cmap_data *cmap_data)
287{
288  if (cmap_data->ranges) free(cmap_data->ranges);
289  if (cmap_data->glyphIndexArray) free(cmap_data->glyphIndexArray);
290}
291
292static void init_font_post_data(hpgs_font_post_data *post_data)
293{
294  memset(post_data,0,sizeof(hpgs_font_post_data));
295}
296
297static void cleanup_font_post_data(hpgs_font_post_data *post_data)
298{
299  if (post_data->names) free((void*)post_data->names);
300  if (post_data->name_data) free((void*)post_data->name_data);
301}
302
303static void init_font_glyph_data(hpgs_font_glyph_data *glyph_data)
304{
305  hpgs_bbox_null(&glyph_data->bbox);
306
307  glyph_data->points_sz = 0;
308  glyph_data->points = 0;
309
310  glyph_data->refs_sz = 0;
311  glyph_data->refs_alloc_sz = 0;
312  glyph_data->refs = 0;
313}
314
315static void cleanup_font_glyph_data(hpgs_font_glyph_data *glyph_data)
316{
317  if (glyph_data->points) free(glyph_data->points);
318  if (glyph_data->refs) free(glyph_data->refs);
319}
320
321static int font_glyph_data_push_ref(hpgs_font_glyph_data *glyph_data,const hpgs_matrix *m, uint16_t gid)
322{
323  if (HPGS_GROW_ARRAY_MIN_SIZE(glyph_data,hpgs_font_glyph_ref,refs,refs_sz,refs_alloc_sz,8)) return -1;
324
325  glyph_data->refs[glyph_data->refs_sz].matrix = *m;
326  glyph_data->refs[glyph_data->refs_sz].gid = gid;
327  ++glyph_data->refs_sz;
328  return 0;
329}
330
331static unsigned cmap_find_unicode(const hpgs_font *font, int unicode)
332{
333  size_t i0 = 0;
334  size_t i1 = font->cmap_data.ranges_sz;
335
336  if (unicode <= 0 || unicode > 65535) return 0;
337
338  // binary search for the endCode.
339  while (i0 < i1)
340    {
341      size_t i = i0+(i1-i0)/2;
342
343      if (font->cmap_data.ranges[i].endCode < unicode)
344        i0 = i+1;
345      else
346        i1 = i;
347    }
348
349  // undefined glyph.
350  if (i0 >= font->cmap_data.ranges_sz || unicode < font->cmap_data.ranges[i0].startCode)
351    return 0;
352
353  const hpgs_font_cmap_code_range *range = &font->cmap_data.ranges[i0];
354
355  uint16_t gid;
356
357  if (range->idRangeOffset)
358      {
359        size_t idx =
360          (range->idRangeOffset/2 - (font->cmap_data.ranges_sz - i0)) +
361          unicode - range->startCode;
362
363        if (idx < 0 || idx >= font->cmap_data.glyphIndexArray_sz)
364          return 0;
365
366        gid = font->cmap_data.glyphIndexArray[idx];
367      }
368    else
369      gid = unicode + range->idDelta;
370
371  if (gid >= font->maxp_data.numGlyphs) gid = 0;
372  return gid;
373}
374
375
376static uint32_t make_ttf_tag(const char *c)
377{
378  return
379    (((uint32_t)(unsigned char)(c[0]))<<24)|
380    (((uint32_t)(unsigned char)(c[1]))<<16)|
381    (((uint32_t)(unsigned char)(c[2]))<<8)|
382    ((uint32_t)(unsigned char)(c[3]));
383}
384
385static int read_header(hpgs_font_header *header, hpgs_istream *is)
386{
387  int i;
388
389  header->name_table = -1;
390  header->head_table = -1;
391  header->hhea_table = -1;
392  header->maxp_table = -1;
393  header->hmtx_table = -1;
394  header->loca_table = -1;
395  header->cmap_table = -1;
396  header->post_table = -1;
397  header->glyf_table = -1;
398  header->kern_table = -1;
399
400  if (read_int32(is,&header->version)) return -1;
401
402
403  // Chaeck the version tag.
404  if (header->version != 0x00010000 /* TrueType */) return -1;
405
406  /* OpenType uses a header->version == 0x4f54544f,
407     but OpenType support is out of sight now, since this
408     involves interpretation of CFF compact PostScript font
409     programs. */
410
411  if (read_uint16(is,&header->numtab)) return -1;
412  if (read_uint16(is,&header->searchRange)) return -1;
413  if (read_uint16(is,&header->entrySel)) return -1;
414  if (read_uint16(is,&header->rangeShift)) return -1;
415
416  if (header->numtab > HPGS_FONT_MAX_TTF_TABLES) return -1;
417
418  for (i=0;i<header->numtab;++i)
419    {
420      if (read_table_entry(is,&header->tables[i])) return -1;
421
422      if (header->tables[i].tag == make_ttf_tag("name"))
423        header->name_table = i;
424      else if (header->tables[i].tag == make_ttf_tag("head"))
425        header->head_table = i;
426      else if (header->tables[i].tag == make_ttf_tag("hhea"))
427        header->hhea_table = i;
428      else if (header->tables[i].tag == make_ttf_tag("maxp"))
429        header->maxp_table = i;
430      else if (header->tables[i].tag == make_ttf_tag("hmtx"))
431        header->hmtx_table = i;
432      else if (header->tables[i].tag == make_ttf_tag("loca"))
433        header->loca_table = i;
434      else if (header->tables[i].tag == make_ttf_tag("cmap"))
435        header->cmap_table = i;
436      else if (header->tables[i].tag == make_ttf_tag("post"))
437        header->post_table = i;
438      else if (header->tables[i].tag == make_ttf_tag("glyf"))
439        header->glyf_table = i;
440      else if (header->tables[i].tag == make_ttf_tag("kern"))
441        header->kern_table = i;
442    }
443
444  return 0;
445}
446
447static int seek_table(hpgs_istream *is,
448                      hpgs_font_header *header, int table)
449{
450  if (table < 0) return -1;
451
452  return hpgs_istream_seek(is,header->tables[table].offset);
453}
454
455static int seek_font_table(hpgs_font *font, int table)
456{
457  if (table < 0) return -1;
458
459  return hpgs_istream_seek(font->is,font->header.tables[table].offset);
460}
461
462static int  seek_font_table_off(hpgs_font *font, int table, size_t off)
463{
464  if (table < 0) return -1;
465
466  return hpgs_istream_seek(font->is,font->header.tables[table].offset+off);
467}
468
469static char *scan_name_table(hpgs_font_header *header,
470                             hpgs_istream *is)
471{
472  if (seek_table(is,header,header->name_table) < 0) return 0;
473
474  uint16_t  format;  // Format selector (=0).
475  uint16_t  count;   // Number of name records.
476  uint16_t  stringOffset; //  Offset to start of string storage (from start of table).
477
478  if (read_uint16(is,&format)) return 0;
479  if (read_uint16(is,&count)) return 0;
480  if (read_uint16(is,&stringOffset)) return 0;
481
482  int i;
483
484  for (i=0;i<(int)count;++i)
485    {
486      uint16_t  platformID; // Platform ID.
487      uint16_t  encodingID; // Platform-specific encoding ID.
488      uint16_t  languageID; // Language ID.
489      uint16_t  nameID;     // Name ID.
490      uint16_t  length;     // String length (in bytes).
491      uint16_t  offset;     // String offset from start of storage area (in bytes).
492
493      if (read_uint16(is,&platformID)) return 0;
494      if (read_uint16(is,&encodingID)) return 0;
495      if (read_uint16(is,&languageID)) return 0;
496      if (read_uint16(is,&nameID)) return 0;
497      if (read_uint16(is,&length)) return 0;
498      if (read_uint16(is,&offset)) return 0;
499
500      // if (nameID     == 4)
501      //   hpgs_log("platformID,encodingID,languageID = %d,%d,%d.\n",
502      //            (int)platformID,(int)encodingID,(int)languageID);
503
504      // check for
505      // platformID 1 (Apple)
506      // encodingID 0 (Roman)
507      // languageID 0 (English)
508      // nameID     4 (full font name)
509      //
510      if (platformID == 1 &&
511          encodingID == 0 &&
512          languageID == 0 &&
513          nameID     == 4   )
514        {
515          if (hpgs_istream_seek(is,
516                                header->tables[header->name_table].offset+
517                                (size_t)stringOffset+
518                                (size_t)offset ) < 0)
519            return 0;
520
521          char *name = alloca((size_t)length * 3 + 1);
522
523          if (ascii_stream_string_to_utf8(is,(size_t)length,name))
524            return 0;
525
526          return strdup(name);
527        }
528
529      // check for
530      // platformID 0 (Unicode)
531      // encodingID 3 (Unicode 2.0 BMP)
532      // languageID 0 (not used for platform ID 0)
533      // nameID     4 (full font name)
534      //
535      if (platformID == 0 &&
536          encodingID == 3 &&
537          languageID == 0 &&
538          nameID     == 4   )
539        {
540          if (hpgs_istream_seek(is,
541                                header->tables[header->name_table].offset+
542                                (size_t)stringOffset+
543                                (size_t)offset ) < 0)
544            return 0;
545
546
547          char *name = alloca((size_t)length * 3 + 1);
548
549          if (ucs2_stream_string_to_utf8(is,(size_t)length,name))
550            return 0;
551
552          return strdup(name);
553        }
554    }
555
556  return 0;
557}
558
559static int hpgs_scan_font_dir(const char *path)
560{
561  hpgs_istream *is=0;
562  hpgs_font_header header;
563
564#ifdef WIN32
565  // go through font directory.
566  char *pat =  hpgs_sprintf_malloc("%s\\*.ttf",path);
567
568  if (!pat)
569    return hpgs_set_error(hpgs_i18n("Out of memory reading font directory %s."),path);
570
571  HANDLE d;
572  WIN32_FIND_DATAA data;
573
574  if ((d=FindFirstFileA(pat,&data)) == INVALID_HANDLE_VALUE)
575    {
576      free(pat);
577      return hpgs_set_error(hpgs_i18n("Cannot open font directory %s."),path);
578    }
579
580  free(pat);
581
582  do
583    {
584     char * fn = hpgs_sprintf_malloc("%s\\%s",path,data.cFileName);
585
586      if (!fn)
587        {
588          FindClose(d);
589          return hpgs_set_error(hpgs_i18n("Out of memory reading font directory %s."),path);
590        }
591
592      is = hpgs_new_file_istream(fn);
593      if (!is) { free(fn); continue; }
594
595      if (read_header(&header,is) == 0)
596        {
597          char *name = scan_name_table(&header,is);
598
599          if (name)
600            push_font_to_directory(name,fn);
601          else
602            free(fn);
603        }
604      else
605        free(fn);
606
607      hpgs_istream_close(is);
608      is = 0;
609    }
610  while (FindNextFileA(d,&data));
611
612  FindClose(d);
613
614#else
615  // go through font directory.
616  DIR *d;
617  struct dirent *data;
618
619  if ((d=opendir(path))==0)
620    return hpgs_set_error(hpgs_i18n("Cannot open font directory %s."),path);
621
622  while ((data=readdir(d)) != 0)
623    {
624      int l = strlen(data->d_name);
625
626      if (strcmp(data->d_name+l-4,".ttf") &&
627          strcmp(data->d_name+l-4,".TTF")   ) continue;
628
629      char * fn = hpgs_sprintf_malloc("%s/%s",path,data->d_name);
630
631      if (!fn)
632        {
633          closedir (d);
634          return hpgs_set_error(hpgs_i18n("Out of memory reading font directory %s."),path);
635        }
636
637      is = hpgs_new_file_istream(fn);
638      if (!is) { free(fn); continue; }
639
640      if (read_header(&header,is) == 0)
641        {
642          char *name = scan_name_table(&header,is);
643
644          if (name)
645            push_font_to_directory(name,fn);
646          else
647            free(fn);
648        }
649      else
650        free(fn);
651
652      hpgs_istream_close(is);
653      is = 0;
654    }
655
656  closedir (d);
657#endif
658  return 0;
659}
660
661static int font_dentry_compare(const void *a, const void *b)
662{
663  hpgs_font_dentry *fa = (hpgs_font_dentry *)a;
664  hpgs_font_dentry *fb = (hpgs_font_dentry *)b;
665
666  return strcmp(fa->font_name,fb->font_name);
667}
668
669static int hpgs_scan_font_dirs()
670{
671  // already scanned ?
672  hpgs_mutex_lock(&font_dir_mutex);
673
674  if (font_directory) { hpgs_mutex_unlock(&font_dir_mutex); return 0; }
675
676  font_directory = (hpgs_font_dentry *)malloc(sizeof(hpgs_font_dentry)*256);
677  if (!font_directory)
678    {
679      hpgs_mutex_unlock(&font_dir_mutex);
680      return hpgs_set_error(hpgs_i18n("Out of memory scanning font directories."));
681    }
682  font_directory_alloc_sz = 256;
683  font_directory_sz = 0;
684
685#ifdef WIN32
686  const char *root = getenv("SYSTEMROOT");
687  char *path =  hpgs_sprintf_malloc("%s\\fonts",root);
688  int ret = hpgs_scan_font_dir(path);
689  free(path);
690#else
691
692  const char *font_path = getenv("HPGS_FONT_PATH");
693
694  if (!font_path || strlen(font_path) <= 0)
695    font_path = "/usr/X11R6/lib/X11/fonts/truetype:/usr/X11R6/lib/X11/fonts/TTF:/usr/local/share/fonts:/usr/local/share/fonts/truetype:/usr/local/share/fonts/TTF";
696
697  char *font_path_dup = hpgs_alloca(strlen(font_path));
698
699  strcpy (font_path_dup,font_path);
700
701  int npaths=0,ret=0;
702  int nerrors = 0;
703
704  char *fp;
705  char *last_font = font_path_dup;
706
707  for (fp = font_path_dup;;++fp)
708    {
709      if (*fp == ':' || *fp == 0)
710        {
711          hpgs_bool eos = (*fp == 0);
712          if (!eos) *fp = 0;
713
714          if (fp - last_font > 0)
715            {
716              if (hpgs_scan_font_dir(last_font))
717                {
718                  ++nerrors;
719                  hpgs_log("hpgs_scan_font_dirs: %s\n",hpgs_get_error());
720                }
721              ++npaths;
722            }
723
724          if (eos) break;
725          last_font = fp + 1;
726        }
727    }
728
729  if (nerrors == npaths)
730    ret = -1;
731
732#endif
733  qsort(font_directory,font_directory_sz,sizeof(hpgs_font_dentry),font_dentry_compare);
734
735  hpgs_mutex_unlock(&font_dir_mutex);
736  return ret;
737}
738
739static int read_head_table(hpgs_font *font)
740{
741  if (seek_font_table(font,font->header.head_table) < 0) return -1;
742
743  if (read_uint32(font->is,&font->head_data.version)) return -1;
744  if (read_uint32(font->is,&font->head_data.fontRevision)) return -1;
745  if (read_uint32(font->is,&font->head_data.checkSumAdjustment)) return -1;
746  if (read_uint32(font->is,&font->head_data.magicNumber)) return -1;
747  if (read_uint16(font->is,&font->head_data.flags)) return -1;
748  if (read_uint16(font->is,&font->head_data.unitsPerEm)) return -1;
749  if (read_int32(font->is,&font->head_data.created_low)) return -1;
750  if (read_int32(font->is,&font->head_data.created_high)) return -1;
751  if (read_int32(font->is,&font->head_data.modified_low)) return -1;
752  if (read_int32(font->is,&font->head_data.modified_high)) return -1;
753  if (read_int16(font->is,&font->head_data.xMin)) return -1;
754  if (read_int16(font->is,&font->head_data.yMin)) return -1;
755  if (read_int16(font->is,&font->head_data.xMax)) return -1;
756  if (read_int16(font->is,&font->head_data.yMax)) return -1;
757  if (read_uint16(font->is,&font->head_data.macStyle)) return -1;
758  if (read_int16(font->is,&font->head_data.lowestRecPPEM)) return -1;
759  if (read_int16(font->is,&font->head_data.fontDirectionHint)) return -1;
760  if (read_int16(font->is,&font->head_data.indexToLocFormat)) return -1;
761  if (read_int16(font->is,&font->head_data.glyphDataFormat)) return -1;
762
763  return 0;
764}
765
766static int read_hhea_table(hpgs_font *font)
767{
768  if (seek_font_table(font,font->header.hhea_table) < 0) return -1;
769
770  if (read_uint32(font->is,&font->hhea_data.version)) return -1;
771  if (read_int16(font->is,&font->hhea_data.ascent)) return -1;
772  if (read_int16(font->is,&font->hhea_data.descent)) return -1;
773  if (read_int16(font->is,&font->hhea_data.lineGap)) return -1;
774  if (read_uint16(font->is,&font->hhea_data.advanceWidthMax)) return -1;
775  if (read_int16(font->is,&font->hhea_data.minLeftSideBearing)) return -1;
776  if (read_int16(font->is,&font->hhea_data.minRightSideBearing)) return -1;
777  if (read_int16(font->is,&font->hhea_data.xMaxExtent)) return -1;
778  if (read_int16(font->is,&font->hhea_data.caretSlopeRise)) return -1;
779  if (read_int16(font->is,&font->hhea_data.caretSlopeRun)) return -1;
780  if (read_int16(font->is,&font->hhea_data.caretOffset)) return -1;
781  if (read_int16(font->is,&font->hhea_data.reserved1)) return -1;
782  if (read_int16(font->is,&font->hhea_data.reserved2)) return -1;
783  if (read_int16(font->is,&font->hhea_data.reserved3)) return -1;
784  if (read_int16(font->is,&font->hhea_data.reserved4)) return -1;
785  if (read_int16(font->is,&font->hhea_data.metricDataFormat)) return -1;
786  if (read_uint16(font->is,&font->hhea_data.numOfLongHorMetrics)) return -1;
787
788  return 0;
789}
790
791static int read_maxp_table(hpgs_font *font)
792{
793  if (seek_font_table(font,font->header.maxp_table) < 0) return -1;
794
795  if (read_uint32(font->is,&font->maxp_data.version)) return -1;
796  if (read_uint16(font->is,&font->maxp_data.numGlyphs)) return -1;
797  if (read_uint16(font->is,&font->maxp_data.maxPoints)) return -1;
798  if (read_uint16(font->is,&font->maxp_data.maxContours)) return -1;
799  if (read_uint16(font->is,&font->maxp_data.maxComponentPoints)) return -1;
800  if (read_uint16(font->is,&font->maxp_data.maxComponentContours)) return -1;
801  if (read_uint16(font->is,&font->maxp_data.maxZones)) return -1;
802  if (read_uint16(font->is,&font->maxp_data.maxTwilightPoints)) return -1;
803  if (read_uint16(font->is,&font->maxp_data.maxStorage)) return -1;
804  if (read_uint16(font->is,&font->maxp_data.maxFunctionDefs)) return -1;
805  if (read_uint16(font->is,&font->maxp_data.maxInstructionDefs)) return -1;
806  if (read_uint16(font->is,&font->maxp_data.maxStackElements)) return -1;
807  if (read_uint16(font->is,&font->maxp_data.maxSizeOfInstructions)) return -1;
808  if (read_uint16(font->is,&font->maxp_data.maxComponentElements)) return -1;
809  if (read_uint16(font->is,&font->maxp_data.maxComponentDepth)) return -1;
810
811  return 0;
812}
813
814static int read_hmtx_table(hpgs_font *font)
815{
816  if (font->hhea_data.numOfLongHorMetrics < 1) return -1;
817
818  if (seek_font_table(font,font->header.hmtx_table) < 0) return -1;
819
820  font->hmtx_data = (hpgs_font_longHorMetrics *)
821    malloc(sizeof(hpgs_font_longHorMetrics)*font->maxp_data.numGlyphs);
822
823  if (!font->hmtx_data) return -1;
824
825  int i = 0;
826
827  while (i<font->hhea_data.numOfLongHorMetrics)
828    {
829      if (read_uint16(font->is,&font->hmtx_data[i].advanceWidth)) return -1;
830      if (read_int16(font->is,&font->hmtx_data[i].leftSideBearing)) return -1;
831      ++i;
832    }
833
834  while (i<font->maxp_data.numGlyphs)
835    {
836      font->hmtx_data[i].advanceWidth =
837        font->hmtx_data[font->hhea_data.numOfLongHorMetrics-1].advanceWidth;
838
839      if (read_int16(font->is,&font->hmtx_data[i].leftSideBearing)) return -1;
840      ++i;
841    }
842
843  return 0;
844}
845
846static int read_loca_table(hpgs_font *font)
847{
848  if (seek_font_table(font,font->header.loca_table) < 0) return -1;
849
850  if (font->head_data.indexToLocFormat)
851    font->loca_data_sz = font->header.tables[font->header.loca_table].length/4;
852  else
853    font->loca_data_sz = font->header.tables[font->header.loca_table].length/2;
854
855  font->loca_data = (uint32_t*)malloc(sizeof(uint32_t)*font->loca_data_sz);
856
857  if (!font->loca_data) return -1;
858
859  size_t i;
860
861  if (font->head_data.indexToLocFormat)
862    {
863      for (i=0;i<font->loca_data_sz;++i)
864        if (read_uint32(font->is,&font->loca_data[i])) return -1;
865    }
866  else
867    {
868      for (i=0;i<font->loca_data_sz;++i)
869        {
870          uint16_t x;
871
872          if (read_uint16(font->is,&x)) return -1;
873
874          font->loca_data[i] = ((uint32_t)x) << 1;
875        }
876    }
877
878  return 0;
879}
880
881static int kern_pair_compare(const void *a, const void *b)
882{
883  hpgs_font_kern_pair *ka = (hpgs_font_kern_pair *)a;
884  hpgs_font_kern_pair *kb = (hpgs_font_kern_pair *)b;
885
886  if (ka->left_gid < kb->left_gid) return -1;
887  if (ka->left_gid > kb->left_gid) return 1;
888
889  if (ka->right_gid < kb->right_gid) return -1;
890  if (ka->right_gid > kb->right_gid) return 1;
891
892  return 0;
893}
894
895static int read_kern_table(hpgs_font *font)
896{
897  // kerning must not be available, so this is not an error.
898  if (font->header.kern_table < 0) return 0;
899
900  if (seek_font_table(font,font->header.kern_table) < 0) return -1;
901
902  uint16_t version; // Table version number (starts at 0)
903  uint16_t nTables; // Number of subtables in the kerning table.
904
905  if (read_uint16(font->is,&version)) return -1;
906  if (read_uint16(font->is,&nTables)) return -1;
907
908  // extra offset for seeking next subtable.
909  size_t extra_off = 4;
910
911  uint16_t iTable;
912
913  for (iTable = 0; iTable < nTables; ++iTable)
914    {
915      if (iTable &&
916          seek_font_table_off(font,font->header.kern_table,extra_off) < 0)
917        return -1;
918
919      uint16_t length; // Length of the subtable, in bytes (including this header).
920      uint16_t coverage; // What type of information is contained in this table.
921
922      if (read_uint16(font->is,&version))  return -1;
923      if (read_uint16(font->is,&length))   return -1;
924      if (read_uint16(font->is,&coverage)) return -1;
925
926      extra_off += length;
927
928      // we seek a table with horzonal kern data in format 0.
929      if ((coverage & 0xfff3) == 0x0001)
930        {
931          uint16_t  nPairs; // This gives the number of kerning pairs in the table.
932          uint16_t  searchRange; // The largest power of two less than or equal to the value of nPairs, multiplied by the size in bytes of an entry in the table.
933          uint16_t  entrySelector; // This is calculated as log2 of the largest power of two less than or equal to the value of nPairs. This value indicates how many iterations of the search loop will have to be made. (For example, in a list of eight items, there would have to be three iterations of the loop).
934          uint16_t  rangeShift; // The value of nPairs minus the largest power of two less than or equal to nPairs, and then multiplied by the size in bytes of an entry in the table.
935
936          if (read_uint16(font->is,&nPairs))  return -1;
937          if (read_uint16(font->is,&searchRange))  return -1;
938          if (read_uint16(font->is,&entrySelector))  return -1;
939          if (read_uint16(font->is,&rangeShift))  return -1;
940
941          font->kern_data_sz = nPairs;
942
943          font->kern_data =
944            (hpgs_font_kern_pair*)malloc(sizeof(hpgs_font_kern_pair)*font->kern_data_sz);
945
946          if (!font->kern_data) return -1;
947
948          size_t i;
949
950          for (i=0;i<font->kern_data_sz;++i)
951            {
952              int16_t value;
953
954              if (read_uint16(font->is,&font->kern_data[i].left_gid)) return -1;
955              if (read_uint16(font->is,&font->kern_data[i].right_gid)) return -1;
956              if (read_int16(font->is,&value)) return -1;
957
958              font->kern_data[i].value = (double)value/(double)font->head_data.unitsPerEm;
959            }
960
961          // That's all we can interpret.
962          break;
963        }
964    }
965
966  if (font->kern_data)
967    qsort(font->kern_data,font->kern_data_sz,sizeof(hpgs_font_kern_pair),kern_pair_compare);
968
969  return 0;
970}
971
972static int read_cmap_table(hpgs_font *font)
973{
974  if (seek_font_table(font,font->header.cmap_table) < 0) return -1;
975
976  uint16_t dummy;
977  uint16_t numberSubtables;
978
979  if (read_uint16(font->is,&dummy)) return -1;
980  if (read_uint16(font->is,&numberSubtables)) return -1;
981
982  uint32_t offset = 0;
983
984  // search type 4 subtable.
985  while (numberSubtables)
986    {
987      uint16_t platformID;
988      uint16_t platformSpecificID;
989
990     if (read_uint16(font->is,&platformID)) return -1;
991     if (read_uint16(font->is,&platformSpecificID)) return -1;
992     if (read_uint32(font->is,&offset)) return -1;
993
994     if (platformID == 3 && platformSpecificID == 1)
995       break;
996
997     --numberSubtables;
998    }
999
1000  // no suitable subtable found.
1001  if (!numberSubtables) return -1;
1002
1003  if (seek_font_table_off(font,font->header.cmap_table,offset) < 0)
1004    return -1;
1005
1006  if (read_uint16(font->is,&dummy)) return -1; // version
1007
1008  // character map is not of type 4.
1009  if (dummy != 4) return -1;
1010
1011  uint16_t length;
1012  if (read_uint16(font->is,&length)) return -1;
1013
1014  if (read_uint16(font->is,&dummy)) return -1; // language
1015  if (read_uint16(font->is,&dummy)) return -1; // segCountX2
1016
1017  font->cmap_data.ranges_sz = dummy/2;
1018
1019  font->cmap_data.ranges = (hpgs_font_cmap_code_range*)
1020    malloc(sizeof(hpgs_font_cmap_code_range) * font->cmap_data.ranges_sz);
1021
1022  font->cmap_data.glyphIndexArray_sz =
1023    length - 8*2 - 4*2 * font->cmap_data.ranges_sz;
1024
1025  font->cmap_data.glyphIndexArray = (uint16_t*)
1026    malloc(sizeof(uint16_t)*font->cmap_data.glyphIndexArray_sz);
1027
1028  if (read_uint16(font->is,&dummy)) return -1; // searchRange
1029  if (read_uint16(font->is,&dummy)) return -1; // entrySelector
1030  if (read_uint16(font->is,&dummy)) return -1; // rangeShift
1031
1032  size_t i;
1033
1034  for (i=0; i<font->cmap_data.ranges_sz; ++i)
1035    if (read_uint16(font->is,&font->cmap_data.ranges[i].endCode)) return -1;
1036
1037  if (read_uint16(font->is,&dummy)) return -1; // reservedPad
1038
1039  for (i=0; i<font->cmap_data.ranges_sz; ++i)
1040    if (read_uint16(font->is,&font->cmap_data.ranges[i].startCode)) return -1;
1041
1042  for (i=0; i<font->cmap_data.ranges_sz; ++i)
1043    if (read_uint16(font->is,&font->cmap_data.ranges[i].idDelta)) return -1;
1044
1045  for (i=0; i<font->cmap_data.ranges_sz; ++i)
1046    if (read_uint16(font->is,&font->cmap_data.ranges[i].idRangeOffset)) return -1;
1047
1048  for (i=0; i<font->cmap_data.glyphIndexArray_sz; ++i)
1049    if (read_uint16(font->is,&font->cmap_data.glyphIndexArray[i])) return -1;
1050
1051  return 0;
1052}
1053
1054static int read_post_table(hpgs_font *font)
1055{
1056  if (seek_font_table(font,font->header.post_table) < 0) return -1;
1057
1058  if (read_int32(font->is,&font->post_data.version)) return -1;
1059
1060  if (font->post_data.version != 0x00020000) return -1;
1061
1062  if (read_int32(font->is,&font->post_data.italicAngle)) return -1;
1063  if (read_int16(font->is,&font->post_data.underlinePosition)) return -1;
1064  if (read_int16(font->is,&font->post_data.underlineThickness)) return -1;
1065  if (read_uint32(font->is,&font->post_data.isFixedPitch)) return -1;
1066  if (read_uint32(font->is,&font->post_data.minMemType42)) return -1;
1067  if (read_uint32(font->is,&font->post_data.maxMemType42)) return -1;
1068  if (read_uint32(font->is,&font->post_data.minMemType1)) return -1;
1069  if (read_uint32(font->is,&font->post_data.maxMemType1)) return -1;
1070  if (read_uint16(font->is,&font->post_data.numberOfGlyphs)) return -1;
1071
1072  font->post_data.names = (const char**)malloc((size_t)font->post_data.numberOfGlyphs*sizeof(const char**));
1073
1074  if (!font->post_data.names) return -1;
1075
1076  size_t name_data_sz =
1077    font->header.tables[font->header.post_table].length - 34 - 2*(size_t)font->post_data.numberOfGlyphs;
1078  char *name_data = malloc(name_data_sz);
1079
1080  size_t ig;
1081
1082  uint16_t *glyphNameIndex = hpgs_alloca((size_t)font->post_data.numberOfGlyphs*sizeof(uint16_t));
1083
1084  size_t numberNewGlyphs = 0;
1085
1086  for (ig=0; ig<font->post_data.numberOfGlyphs; ++ig)
1087    {
1088      if (read_uint16(font->is,&glyphNameIndex[ig])) return -1;
1089
1090      if (glyphNameIndex[ig] >= numberNewGlyphs)
1091        numberNewGlyphs = (size_t)glyphNameIndex[ig] + 1;
1092    }
1093
1094  uint32_t *name_offsets = 0;
1095
1096  if (numberNewGlyphs > 258)
1097    {
1098      numberNewGlyphs -= 258;
1099
1100      name_offsets = hpgs_alloca(numberNewGlyphs*sizeof(uint32_t));
1101
1102      size_t id = 0;
1103
1104      for (ig=0; ig<numberNewGlyphs; ++ig)
1105        {
1106          uint8_t name_l;
1107
1108          if (read_uint8(font->is,&name_l)) return -1;
1109
1110          name_offsets[ig] = id;
1111
1112          while (name_l)
1113            {
1114              if (id >= name_data_sz) return -1;
1115              int c;
1116              if ((c=hpgs_getc(font->is)) < 0)
1117                return -1;
1118
1119              name_data[id] = c;
1120              ++id;
1121              --name_l;
1122            }
1123
1124          if (id >= name_data_sz) return -1;
1125          name_data[id] = '\0';
1126          ++id;
1127        }
1128    }
1129  else
1130    numberNewGlyphs = 0;
1131
1132  for (ig=0; ig<font->post_data.numberOfGlyphs; ++ig)
1133    {
1134      if (glyphNameIndex[ig] < 258)
1135        font->post_data.names[ig] = std_glyph_names[glyphNameIndex[ig]];
1136      else if  ((size_t)glyphNameIndex[ig] - 258 < numberNewGlyphs)
1137        font->post_data.names[ig] = name_data + name_offsets[(size_t)glyphNameIndex[ig] - 258];
1138      else
1139        font->post_data.names[ig] = 0;
1140    }
1141
1142  font->post_data.name_data = name_data;
1143
1144  return 0;
1145}
1146
1147static int load_glyph_gid(hpgs_font *font,
1148                          hpgs_font_glyph_data *glyph_data,
1149                          uint16_t gid)
1150{
1151  // character out of range for loca data ?
1152  if (gid+1 >= font->loca_data_sz) return -1;
1153
1154  init_font_glyph_data(glyph_data);
1155
1156  // check for an empty glyph description.
1157  if (font->loca_data[gid+1] <= font->loca_data[gid])
1158    return 0;
1159
1160  // seek character data in file.
1161  if (seek_font_table_off(font,font->header.glyf_table,
1162                          (size_t)font->loca_data[gid]) < 0)
1163    return -1;
1164
1165  int16_t numberOfContours;
1166  int16_t xMin,yMin,xMax,yMax;
1167
1168  if (read_int16(font->is,&numberOfContours)) return -1;
1169  if (read_int16(font->is,&xMin)) return -1;
1170  if (read_int16(font->is,&yMin)) return -1;
1171  if (read_int16(font->is,&xMax)) return -1;
1172  if (read_int16(font->is,&yMax)) return -1;
1173
1174  glyph_data->bbox.llx = (double)xMin/(double)font->head_data.unitsPerEm;
1175  glyph_data->bbox.lly = (double)yMin/(double)font->head_data.unitsPerEm;
1176  glyph_data->bbox.urx = (double)xMax/(double)font->head_data.unitsPerEm;
1177  glyph_data->bbox.ury = (double)yMax/(double)font->head_data.unitsPerEm;
1178
1179  // hpgs_log("bbox: %lg,%lg,%lg,%lg.\n",
1180  //          glyph_data->bbox.llx,glyph_data->bbox.lly,glyph_data->bbox.urx,glyph_data->bbox.ury);
1181
1182   if (numberOfContours > 0)
1183     {
1184       // simple glyph description.
1185       uint16_t *endPtsOfContours = (uint16_t *)hpgs_alloca(numberOfContours*sizeof(uint16_t));
1186
1187       unsigned ic;
1188       for (ic = 0; ic<numberOfContours; ++ic)
1189         {
1190           if (read_uint16(font->is,&endPtsOfContours[ic])) goto error;
1191           // hpgs_log("endPtsOfContours[%u]: %d.\n",
1192           //          ic,(int)endPtsOfContours[ic]);
1193         }
1194
1195       glyph_data->points_sz = endPtsOfContours[numberOfContours-1]+1;
1196       glyph_data->points = (hpgs_font_glyph_point*)malloc(sizeof(hpgs_font_glyph_point)*glyph_data->points_sz);
1197
1198       if (!glyph_data->points) goto error;
1199
1200       // read instructions.
1201       uint16_t instructionLength;
1202
1203       if (read_uint16(font->is,&instructionLength))goto error;
1204
1205       uint8_t *instructions = (uint8_t *)hpgs_alloca(instructionLength);
1206
1207       if (hpgs_istream_read(instructions,1,instructionLength,font->is) != instructionLength)
1208         goto error;
1209
1210       // read and unfold flags.
1211       uint8_t *flags = (uint8_t *)hpgs_alloca(glyph_data->points_sz);
1212
1213       size_t i = 0;
1214
1215       while (i<glyph_data->points_sz)
1216         {
1217           if (read_uint8(font->is,&flags[i])) goto error;
1218
1219           // check for repat flag
1220           if (flags[i] & (1<<3))
1221             {
1222               uint8_t f = flags[i];
1223               uint8_t repeat;
1224               if (read_uint8(font->is,&repeat)) goto error;
1225
1226               while (repeat && i<glyph_data->points_sz)
1227                 {
1228                   --repeat;
1229                   ++i;
1230                   flags[i] = f;
1231                 }
1232             }
1233
1234           ++i;
1235         }
1236
1237       // read the x coordinates.
1238       int16_t *xCoordinates = (int16_t *)hpgs_alloca(glyph_data->points_sz*sizeof(int16_t));
1239
1240       for (i=0;i<glyph_data->points_sz;++i)
1241         {
1242           if (flags[i] & (1<<1)) // x-Short vector
1243             {
1244               uint8_t x;
1245
1246               if (read_uint8(font->is,&x)) goto error;
1247
1248               if (flags[i] & (1<<4)) // sign of x
1249                 xCoordinates[i] = (int16_t)x;
1250               else
1251                 xCoordinates[i] = -(int16_t)x;
1252             }
1253           else
1254             {
1255               if (flags[i] & (1<<4)) // This x is same
1256                 {
1257                   xCoordinates[i] = 0;
1258                 }
1259               else
1260                 {
1261                   if (read_int16(font->is,&xCoordinates[i])) goto error;
1262                 }
1263             }
1264
1265           // hpgs_log("flags,x[%u]: %2.2x,%d.\n",
1266           //          (unsigned)i,(unsigned)flags[i],(int)xCoordinates[i]);
1267          }
1268
1269       // read the y coordinates.
1270       int16_t *yCoordinates = (int16_t *)hpgs_alloca(glyph_data->points_sz*sizeof(int16_t));
1271
1272       for (i=0;i<glyph_data->points_sz;++i)
1273         {
1274           if (flags[i] & (1<<2)) // y-Short vector
1275             {
1276               uint8_t y;
1277
1278               if (read_uint8(font->is,&y)) goto error;
1279
1280               if (flags[i] & (1<<5)) // sign of y
1281                 yCoordinates[i] = (int16_t)y;
1282               else
1283                 yCoordinates[i] = -(int16_t)y;
1284             }
1285           else
1286             {
1287               if (flags[i] & (1<<5)) // This y is same
1288                 {
1289                   yCoordinates[i] = 0;
1290                 }
1291               else
1292                 {
1293                   if (read_int16(font->is,&yCoordinates[i])) goto error;
1294                 }
1295             }
1296           // hpgs_log("flags,y[%u]: %2.2x,%d.\n",
1297           //          (unsigned)i,(unsigned)flags[i],(int)yCoordinates[i]);
1298         }
1299
1300       // now unfold the contour data.
1301       i = 0;
1302
1303       hpgs_point p = { 0.0, 0.0 };
1304
1305       for (ic = 0; ic<numberOfContours; ++ic)
1306         {
1307           int ii = 0;
1308
1309           while (i <= endPtsOfContours[ic])
1310             {
1311               p.x += (double)xCoordinates[i]/(double)font->head_data.unitsPerEm;
1312               p.y += (double)yCoordinates[i]/(double)font->head_data.unitsPerEm;
1313
1314               glyph_data->points[i].p = p;
1315
1316               if (ii == 0)
1317                 glyph_data->points[i].flags = HPGS_FONT_GLYPH_POINT_START;
1318               else if (flags[i] & (1<<0)) // on curve flags
1319                 glyph_data->points[i].flags = HPGS_FONT_GLYPH_POINT_ONCURVE;
1320               else
1321                 glyph_data->points[i].flags = HPGS_FONT_GLYPH_POINT_CONTROL;
1322
1323               // hpgs_log("p: %d,%lg,%lg.\n",
1324               //          glyph_data->points[i].flags,
1325               //          p.x*(double)font->head_data.unitsPerEm,p.y*(double)font->head_data.unitsPerEm);
1326
1327               ++i;
1328               ++ii;
1329             }
1330         }
1331
1332     }
1333   else if (numberOfContours < 0)
1334     {
1335       // composite glyph.
1336       uint16_t flags;
1337       uint16_t glyphIndex;
1338
1339       hpgs_matrix m;
1340
1341       do
1342         {
1343           if (read_uint16(font->is,&flags)) goto error;
1344           if (read_uint16(font->is,&glyphIndex)) goto error;
1345
1346           // read offsets.
1347           if (flags & 1) // ARG_1_AND_2_ARE_WORDS
1348             {
1349               // offsets are 2 byte values
1350               int16_t dx;
1351               int16_t dy;
1352
1353               if (read_int16(font->is,&dx)) goto error;
1354               if (read_int16(font->is,&dy)) goto error;
1355
1356               // if (flags & (1 << 1)) FIXME ARGS_ARE_XY_VALUES
1357               m.dx = (double)dx/(double)font->head_data.unitsPerEm;
1358               m.dy = (double)dy/(double)font->head_data.unitsPerEm;
1359             }
1360           else
1361             {
1362               // offsets are byte values
1363               int8_t dx;
1364               int8_t dy;
1365
1366               if (read_int8(font->is,&dx)) goto error;
1367               if (read_int8(font->is,&dy)) goto error;
1368
1369               m.dx = (double)dx/(double)font->head_data.unitsPerEm;
1370               m.dy = (double)dy/(double)font->head_data.unitsPerEm;
1371             }
1372
1373           // read transformation matrix.
1374           if (flags & (1 << 3)) // WE_HAVE_A_SCALE
1375             {
1376               int16_t scale;
1377               if (read_int16(font->is,&scale)) goto error;
1378
1379               m.mxx = m.myy = (double)scale/16384.0;
1380               m.mxy = m.myx = 0.0;
1381             }
1382           else if (flags & (1 << 6)) // WE_HAVE_AN_X_AND_Y_SCALE
1383             {
1384               int16_t xscale;
1385               int16_t yscale;
1386               if (read_int16(font->is,&xscale)) goto error;
1387               if (read_int16(font->is,&yscale)) goto error;
1388
1389               m.mxx = (double)xscale/16384.0;
1390               m.myy = (double)yscale/16384.0;
1391               m.mxy = m.myx = 0.0;
1392             }
1393           else if (flags & (1 << 7)) // WE_HAVE_A_TWO_BY_TWO
1394             {
1395               int16_t mxx;
1396               int16_t mxy;
1397               int16_t myx;
1398               int16_t myy;
1399
1400               if (read_int16(font->is,&mxx)) goto error;
1401               if (read_int16(font->is,&mxy)) goto error;
1402               if (read_int16(font->is,&myx)) goto error;
1403               if (read_int16(font->is,&myy)) goto error;
1404
1405               m.mxx = (double)mxx/16384.0;
1406               m.mxy = (double)mxy/16384.0;
1407               m.myx = (double)myx/16384.0;
1408               m.myy = (double)myy/16384.0;
1409             }
1410           else
1411             {
1412               m.mxx = m.myy = 1.0;
1413               m.mxy = m.myx = 0.0;
1414             }
1415
1416           if (font_glyph_data_push_ref(glyph_data,&m,glyphIndex))
1417             goto error;
1418
1419           // hpgs_log("ref: %d,(%lg,%lg,%lg,%lg,%lg,%lg).\n",
1420           //          (int)glyphIndex,
1421           //          m.dx,m.dy,m.mxx,m.mxy,m.myx,m.myy);
1422         }
1423       while (flags & (1 << 5)); // MORE_COMPONENTS
1424     }
1425
1426   return 0;
1427
1428 error:
1429  cleanup_font_glyph_data(glyph_data);
1430  return -1;
1431}
1432
1433static hpgs_font_glyph_data *find_glyph_gid(hpgs_font *font,
1434                                            unsigned gid)
1435{
1436  if (gid > font->maxp_data.numGlyphs) gid = 0;
1437
1438  // cache hit ?
1439  if (font->glyph_cache_positions[gid] >= 0)
1440    return &font->glyph_cache[font->glyph_cache_positions[gid]];
1441
1442  hpgs_mutex_lock(&font->mutex);
1443
1444  if (font->glyph_cache_positions[gid] >= 0)
1445    {
1446      hpgs_mutex_unlock(&font->mutex);
1447      return &font->glyph_cache[font->glyph_cache_positions[gid]];
1448    }
1449
1450  // try to load new glyph.
1451  hpgs_font_glyph_data *glyph_data =
1452    &font->glyph_cache[font->n_cached_glyphs];
1453
1454  if (load_glyph_gid(font,glyph_data,gid) == 0)
1455    {
1456      // seek glyph in kern table.
1457      size_t i0 = 0;
1458      size_t i1 = font->kern_data_sz;
1459
1460      while (i0<i1)
1461        {
1462          size_t i = i0+(i1-i0)/2;
1463
1464          if (font->kern_data[i].left_gid < gid)
1465            i0 = i+1;
1466          else
1467            i1 = i;
1468        }
1469
1470      if (i0 < font->kern_data_sz && font->kern_data[i0].left_gid == gid)
1471        {
1472          glyph_data->begin_kern_pair = i0;
1473
1474          // find end of equal range.
1475          i1 = font->kern_data_sz;
1476
1477          while (i0<i1)
1478            {
1479              size_t i = i0+(i1-i0)/2;
1480
1481              if (font->kern_data[i].left_gid <= gid)
1482                i0 = i+1;
1483              else
1484                i1 = i;
1485            }
1486
1487          glyph_data->end_kern_pair = i0;
1488        }
1489      else
1490        {
1491          glyph_data->begin_kern_pair = 0;
1492          glyph_data->end_kern_pair = 0;
1493        }
1494
1495      // enter successfully read glyph into cache.
1496      font->glyph_cache_positions[gid] = font->n_cached_glyphs;
1497      ++font->n_cached_glyphs;
1498    }
1499  else
1500    glyph_data = 0;
1501
1502  hpgs_mutex_unlock(&font->mutex);
1503
1504  return glyph_data;
1505}
1506
1507static double find_kern_value(hpgs_font *font,
1508                              uint16_t gid,
1509                              uint16_t gid_n)
1510{
1511  if (!font->kern_data) return 0.0;
1512
1513  hpgs_font_glyph_data *glyph_data = find_glyph_gid(font,gid);
1514
1515  if (gid_n > font->maxp_data.numGlyphs) gid_n = 0;
1516
1517  size_t i0 = glyph_data->begin_kern_pair;
1518  size_t i1 = glyph_data->end_kern_pair;
1519
1520  while (i0<i1)
1521    {
1522      size_t i = i0+(i1-i0)/2;
1523
1524      if (font->kern_data[i].right_gid < gid_n)
1525        i0 = i+1;
1526      else
1527        i1 = i;
1528    }
1529
1530  if (i0 < glyph_data->end_kern_pair &&
1531      font->kern_data[i0].right_gid == gid_n)
1532    return font->kern_data[i0].value;
1533
1534  return 0.0;
1535}
1536
1537static hpgs_font *hpgs_open_font(const char *fn, const char *name)
1538{
1539  hpgs_font *ret = (hpgs_font *)malloc(sizeof(hpgs_font));
1540
1541  if (!ret)
1542    {
1543      hpgs_set_error(hpgs_i18n("Out of memory allocating font structure for font %s."),name);
1544      return 0;
1545    }
1546
1547  ret->is = 0;
1548  ret->hmtx_data = 0;
1549  ret->loca_data = 0;
1550  ret->loca_data_sz = 0;
1551
1552  ret->kern_data = 0;
1553  ret->kern_data_sz = 0;
1554
1555  ret->glyph_cache_positions = 0;
1556  ret->n_cached_glyphs = 0;
1557  ret->glyph_cache = 0;
1558
1559  init_font_cmap_data(&ret->cmap_data);
1560
1561  init_font_post_data(&ret->post_data);
1562
1563  ret->is = hpgs_new_file_istream(fn);
1564
1565  if (!ret->is)
1566    {
1567      hpgs_set_error(hpgs_i18n("Cannot open font %s in file %s."),name,fn);
1568      goto error;
1569    }
1570
1571  if (read_header(&ret->header,ret->is))
1572    {
1573      hpgs_set_error(hpgs_i18n("Error reading header of font %s."),name);
1574      goto error;
1575    }
1576
1577  if (read_head_table(ret))
1578    {
1579      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"head",name);
1580      goto error;
1581    }
1582
1583  if (read_hhea_table(ret))
1584    {
1585      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"hhea",name);
1586      goto error;
1587    }
1588
1589  if (read_maxp_table(ret))
1590    {
1591      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"maxp",name);
1592      goto error;
1593    }
1594
1595  if (read_hmtx_table(ret))
1596    {
1597      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"hmtx",name);
1598      goto error;
1599    }
1600
1601  if (read_loca_table(ret))
1602    {
1603      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"loca",name);
1604      goto error;
1605    }
1606
1607  if (read_cmap_table(ret))
1608    {
1609      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"cmap",name);
1610      goto error;
1611    }
1612
1613  if (read_post_table(ret))
1614    {
1615      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"post",name);
1616      goto error;
1617    }
1618
1619  if (read_kern_table(ret))
1620    {
1621      hpgs_set_error(hpgs_i18n("Error reading table %s of font %s."),"kern",name);
1622      goto error;
1623    }
1624
1625  ret->glyph_cache =
1626    (hpgs_font_glyph_data *)malloc(sizeof(hpgs_font_glyph_data)*ret->maxp_data.numGlyphs);
1627
1628  if (!ret->glyph_cache) goto error;
1629
1630  ret->glyph_cache_positions =
1631    (int *)malloc(sizeof(int)*ret->maxp_data.numGlyphs);
1632
1633  if (!ret->glyph_cache_positions) goto error;
1634
1635  int i;
1636
1637  for (i=0;i<ret->maxp_data.numGlyphs;++i)
1638    ret->glyph_cache_positions[i] = -1;
1639
1640  hpgs_mutex_init(&ret->mutex);
1641  ret->nref = 1;
1642  return ret;
1643
1644 error:
1645  if (ret->glyph_cache_positions) free(ret->glyph_cache_positions);
1646  if (ret->glyph_cache) free(ret->glyph_cache);
1647
1648  if (ret->kern_data) free(ret->kern_data);
1649  cleanup_font_cmap_data(&ret->cmap_data);
1650  cleanup_font_post_data(&ret->post_data);
1651  if (ret->loca_data) free(ret->loca_data);
1652  if (ret->hmtx_data) free(ret->hmtx_data);
1653  if (ret->is) hpgs_istream_close(ret->is);
1654  free(ret);
1655  return 0;
1656}
1657
1658
1659/*!
1660   Loads the given font from disk. Depending on your operating system,
1661   the appropriate font directories are scanned for a truetype file which
1662   contains the font of the given name.
1663   \c name is expected to be utf-8 encoded, which is almost no problem,
1664   since all known font names are ASCII-encoded.
1665 */
1666hpgs_font *hpgs_find_font(const char *name)
1667{
1668  // read font directory if not done yet
1669  if (hpgs_scan_font_dirs()) return 0;
1670
1671  // binary search in font directory.
1672  size_t i0 = 0;
1673  size_t i1 = font_directory_sz;
1674
1675  // binary search for the endCode.
1676  while (i0 < i1)
1677    {
1678      size_t i = i0+(i1-i0)/2;
1679
1680      if (strcmp(font_directory[i].font_name,name) < 0)
1681        i0 = i+1;
1682      else
1683        i1 = i;
1684    }
1685
1686  if (i0 >= font_directory_sz || strcmp(font_directory[i0].font_name,name))
1687    {
1688      hpgs_set_error(hpgs_i18n("Cannot find font %s."),name);
1689      return 0;
1690    }
1691
1692  if (font_directory[i0].font == 0)
1693    {
1694      hpgs_mutex_lock(&font_dir_mutex);
1695      if (font_directory[i0].font == 0)
1696        font_directory[i0].font = hpgs_open_font(font_directory[i0].filename,
1697                                                 font_directory[i0].font_name);
1698      hpgs_mutex_unlock(&font_dir_mutex);
1699    }
1700
1701  if (font_directory[i0].font == 0) return 0;
1702
1703  hpgs_mutex_lock(&font_directory[i0].font->mutex);
1704  ++font_directory[i0].font->nref;
1705  hpgs_mutex_unlock(&font_directory[i0].font->mutex);
1706  return font_directory[i0].font;
1707}
1708
1709
1710/*!
1711   Frees all resources associated with this font object.
1712 */
1713void hpgs_destroy_font(hpgs_font *font)
1714{
1715  hpgs_mutex_lock(&font->mutex);
1716  --font->nref;
1717  hpgs_bool have_refs = (font->nref>0);
1718  hpgs_mutex_unlock(&font->mutex);
1719
1720  if (have_refs) return;
1721
1722  if (font->glyph_cache_positions) free(font->glyph_cache_positions);
1723
1724  unsigned gid;
1725
1726  for (gid=0;gid<font->n_cached_glyphs;++gid)
1727    cleanup_font_glyph_data(&font->glyph_cache[gid]);
1728
1729  if (font->glyph_cache) free(font->glyph_cache);
1730
1731  if (font->kern_data) free(font->kern_data);
1732
1733  cleanup_font_cmap_data(&font->cmap_data);
1734  cleanup_font_post_data(&font->post_data);
1735  if (font->loca_data) free(font->loca_data);
1736  if (font->hmtx_data) free(font->hmtx_data);
1737  if (font->is) hpgs_istream_close(font->is);
1738  hpgs_mutex_destroy(&font->mutex);
1739  free(font);
1740}
1741
1742/*!
1743   Gets the maximal ascent of the font.
1744 */
1745double hpgs_font_get_ascent(hpgs_font *font)
1746{
1747  return (double)font->hhea_data.ascent / (double)font->head_data.unitsPerEm;
1748}
1749
1750/*!
1751   Gets the maximal descent of the font.
1752 */
1753double hpgs_font_get_descent(hpgs_font *font)
1754{
1755  return (double)font->hhea_data.descent / (double)font->head_data.unitsPerEm;
1756}
1757
1758/*!
1759   Gets the typographical line gap of the font.
1760 */
1761double hpgs_font_get_line_gap(hpgs_font *font)
1762{
1763  return (double)font->hhea_data.lineGap / (double)font->head_data.unitsPerEm;
1764}
1765
1766/*!
1767   Gets the height of capital letters above the baseline,
1768   computed from the size of the capital letter M.
1769 */
1770double hpgs_font_get_cap_height(hpgs_font *font)
1771{
1772  unsigned gid = cmap_find_unicode(font,'M');
1773
1774  hpgs_font_glyph_data *glyph_data = find_glyph_gid(font,gid);
1775
1776  if (!glyph_data)
1777    return hpgs_set_error(hpgs_i18n("Error reading glyph number %d from file."),(int)gid);
1778
1779  return glyph_data->bbox.ury;
1780}
1781
1782/*!
1783   Gets the number of glyphs in this font. This information might
1784   be useful, if you keep a hash map with additional information for
1785   the glyphs.
1786 */
1787unsigned hpgs_font_get_glyph_count(hpgs_font *font)
1788{
1789  return font->maxp_data.numGlyphs;
1790}
1791
1792/*!
1793   Gets the glyph ID of the given unicode character. The
1794   returned glpyh id is used by several other font functions.
1795 */
1796unsigned hpgs_font_get_glyph_id(hpgs_font *font, int uc)
1797{
1798  return cmap_find_unicode(font,uc);
1799}
1800
1801/*!
1802   Gets the PostScript glyph name of the specified glpyh id.
1803   This function retunrs a null pointer, if the glyph does not have
1804   a PostScript name. In this situation you can use a glyph name
1805   of the form \c uniXXXX, where XXXX is the upppercase 4-digit
1806   hexadecimal unicode of the glpyh.
1807
1808   You can get a glyph id for a given unicode character
1809   using \c hpgs_font_get_glyph_id.
1810
1811   Return -1, if an error occurrs.
1812 */
1813const char *hpgs_font_get_glyph_name(hpgs_font *font, unsigned gid)
1814{
1815  if (gid > font->post_data.numberOfGlyphs) return 0;
1816
1817  return font->post_data.names[gid];
1818}
1819
1820/*!
1821   Gets the bounding box of the specified glpyh id.
1822
1823   You can get a glyph id for a given unicode character
1824   using \c hpgs_font_get_glyph_id.
1825
1826   Return -1, if an error occurrs.
1827 */
1828int hpgs_font_get_glyph_bbox(hpgs_font *font, hpgs_bbox *bb, unsigned gid)
1829{
1830  hpgs_font_glyph_data *glyph_data = find_glyph_gid(font,gid);
1831
1832  if (!glyph_data)
1833    return hpgs_set_error(hpgs_i18n("Error reading glyph number %d from file."),(int)gid);
1834
1835  *bb = glyph_data->bbox;
1836
1837  return 0;
1838}
1839
1840/*!
1841   Gets the horizontal and vertical advance of the given glyph
1842   id. The unit of the returned vector is em, the nominal size
1843   of the letter M of the font. For almost any font one em is actually
1844   larger than the size of the capital letter M.
1845
1846   You can get a glyph id for a given unicode character
1847   using \c hpgs_font_get_glyph_id.
1848
1849   Return -1, if an error occurrs.
1850 */
1851int hpgs_font_get_glyph_metrics(hpgs_font *font, hpgs_point *m, unsigned gid)
1852{
1853  if (gid > font->maxp_data.numGlyphs) gid = 0;
1854
1855  m->x = (double)font->hmtx_data[gid].advanceWidth/(double)font->head_data.unitsPerEm;
1856  m->y = 0.0;
1857
1858  return 0;
1859}
1860
1861/*!
1862   Gets the horizontal and vertical kerning correction for the given glyph
1863   ids. The unit of the returned vector is em, the nominal size
1864   of the letter M of the font. For almost any font one em is actually
1865   larger than the size of the capital letter M.
1866
1867   You can get a glyph id for a given unicode character
1868   using \c hpgs_font_get_glyph_id.
1869
1870   Return -1, if an error occurrs.
1871 */
1872int hpgs_font_get_kern_metrics(hpgs_font *font, hpgs_point *m, unsigned gid_l, unsigned gid_r)
1873{
1874  if (!font->kern_data) { m->y = m->x = 0.0; return 0; }
1875
1876  m->x = find_kern_value(font,gid_l,gid_r);
1877  m->y = 0.0;
1878
1879  return 0;
1880}
1881
1882/*!
1883   Gets the horizontal and vertical advance of the given unicode
1884   string given in utf8 encoding. The unit of the returned vector is em,
1885   the nominal size of the letter M of the font. For almost any font
1886   one em is actually larger than the size of the capital letter M.
1887
1888   Return -1, if an error occurrs.
1889 */
1890int hpgs_font_get_utf8_metrics(hpgs_font *font, hpgs_point *m, const char *str, int strlen)
1891{
1892  m->x = 0.0;
1893  m->y = 0.0;
1894
1895  if (strlen == 0) return 0;
1896
1897  const char *s = str;
1898
1899  int uc = hpgs_next_utf8(&s);
1900  unsigned gid = cmap_find_unicode(font,uc);
1901
1902  while (uc != 0)
1903    {
1904      m->x += (double)font->hmtx_data[gid].advanceWidth/(double)font->head_data.unitsPerEm;
1905
1906      if (strlen >= 0 && (s - str) >= strlen) return 0;
1907
1908      // next glyph
1909      uc = hpgs_next_utf8(&s);
1910
1911      // end of string.
1912      if (uc == 0) return 0;
1913
1914      unsigned gid_n = cmap_find_unicode(font,uc);
1915
1916      m->x += find_kern_value(font,gid,gid_n);
1917
1918      gid = gid_n;
1919    }
1920
1921  return 0;
1922}
1923
1924// dispatch a 2nd order spline
1925static int quad_to(void *ctxt,
1926                   hpgs_curveto_func_t curveto_func,
1927                   const hpgs_point *p0,
1928                   const hpgs_point *p1,
1929                   const hpgs_point *p2 )
1930{
1931  hpgs_point pm0,pm1;
1932
1933  pm0.x = (1.0/3.0) * p0->x  + (2.0/3.0) * p1->x;
1934  pm0.y = (1.0/3.0) * p0->y  + (2.0/3.0) * p1->y;
1935
1936  pm1.x = (1.0/3.0) * p2->x  + (2.0/3.0) * p1->x;
1937  pm1.y = (1.0/3.0) * p2->y  + (2.0/3.0) * p1->y;
1938
1939  return curveto_func(ctxt,&pm0,&pm1,p2);
1940}
1941
1942static int decompose_glyph_internal(hpgs_font *font,
1943                                    void *ctxt,
1944                                    hpgs_moveto_func_t moveto_func,
1945                                    hpgs_lineto_func_t lineto_func,
1946                                    hpgs_curveto_func_t curveto_func,
1947                                    const hpgs_matrix *m,
1948                                    unsigned gid)
1949{
1950  hpgs_font_glyph_data *glyph_data = find_glyph_gid(font,gid);
1951
1952  if (!glyph_data)
1953    return hpgs_set_error(hpgs_i18n("Error reading glyph number %d from file."),(int)gid);
1954
1955  int ret = 0;
1956
1957  // Output the glpyh outline.
1958  if (glyph_data->points_sz)
1959    {
1960      size_t i;
1961      hpgs_point last_out = {0.0,0.0};
1962      hpgs_point start_out = {0.0,0.0};
1963      hpgs_point ctrl_out = {0.0,0.0};
1964      hpgs_font_glyph_point *start_p = 0;
1965      hpgs_font_glyph_point *last_p = 0;
1966
1967      for (i=0;i<glyph_data->points_sz;++i)
1968        {
1969          hpgs_font_glyph_point *point = &glyph_data->points[i];
1970
1971          switch(point->flags)
1972            {
1973            case HPGS_FONT_GLYPH_POINT_START:
1974              // close subpath.
1975              if (i>0 && start_p && last_p)
1976                {
1977                  switch (last_p->flags)
1978                    {
1979                    case HPGS_FONT_GLYPH_POINT_ONCURVE:
1980                      if (lineto_func(ctxt,&start_out) < 0)
1981                        return -1;
1982                      ++ret;
1983                      break;
1984                    case HPGS_FONT_GLYPH_POINT_CONTROL:
1985                      if (quad_to(ctxt,curveto_func,&last_out,&ctrl_out,&start_out) < 0)
1986                        return -1;
1987                      ++ret;
1988                     }
1989                }
1990
1991              hpgs_matrix_xform(&start_out,m,&point->p);
1992              if (moveto_func(ctxt,&start_out) < 0)
1993                return -1;
1994              start_p = point;
1995              last_out = start_out;
1996              break;
1997
1998            case HPGS_FONT_GLYPH_POINT_CONTROL:
1999              {
2000                hpgs_point c_out;
2001                hpgs_matrix_xform(&c_out,m,&point->p);
2002                // generate intermediate on curve point from
2003                // consecutive control points.
2004
2005                if (start_p && last_p && last_p->flags == HPGS_FONT_GLYPH_POINT_CONTROL)
2006                  {
2007                    hpgs_point out;
2008                    out.x = (ctrl_out.x + c_out.x) * 0.5;
2009                    out.y = (ctrl_out.y + c_out.y) * 0.5;
2010
2011                    if (quad_to(ctxt,curveto_func,&last_out,&ctrl_out,&out) < 0)
2012                      return -1;
2013
2014                    last_out = out;
2015                  }
2016                ctrl_out = c_out;
2017              }
2018              break;
2019
2020            case HPGS_FONT_GLYPH_POINT_ONCURVE:
2021              if (start_p && last_p)
2022                {
2023                  hpgs_point out;
2024                  hpgs_matrix_xform(&out,m,&point->p);
2025
2026                  switch (last_p->flags)
2027                    {
2028                    default:
2029                      // HPGS_FONT_GLYPH_POINT_ONCURVE, HPGS_FONT_GLYPH_POINT_START
2030                      if (lineto_func(ctxt,&out) < 0)
2031                        return -1;
2032                      break;
2033                    case HPGS_FONT_GLYPH_POINT_CONTROL:
2034                      if (quad_to(ctxt,curveto_func,&last_out,&ctrl_out,&out) < 0)
2035                        return -1;
2036                    }
2037
2038                  last_out = out;
2039                }
2040            }
2041
2042          last_p = point;
2043        }
2044      // close last subpath.
2045      if (i>0 && start_p && last_p)
2046        {
2047          switch (last_p->flags)
2048            {
2049            case HPGS_FONT_GLYPH_POINT_ONCURVE:
2050              if (lineto_func(ctxt,&start_out) < 0)
2051                return -1;
2052              ++ret;
2053              break;
2054            case HPGS_FONT_GLYPH_POINT_CONTROL:
2055              if (quad_to(ctxt,curveto_func,&last_out,&ctrl_out,&start_out) < 0)
2056                return -1;
2057              ++ret;
2058            }
2059        }
2060    }
2061
2062  // output referenced glyphs.
2063  if (glyph_data->refs_sz)
2064    {
2065      size_t i;
2066
2067      for (i=0;i<glyph_data->refs_sz;++i)
2068        {
2069          hpgs_matrix mm;
2070
2071          hpgs_matrix_concat(&mm,m,&glyph_data->refs[i].matrix);
2072
2073          int r = decompose_glyph_internal(font,ctxt,
2074                                           moveto_func,lineto_func,curveto_func,
2075                                           &mm,glyph_data->refs[i].gid);
2076
2077          if (r < 0) return -1;
2078          ret += r;
2079        }
2080    }
2081
2082  return ret;
2083}
2084
2085/*!
2086   Decomposes the outline of the given glyph id
2087   using the given moveto/linto/curveto functions and
2088   the specified transformation matrix.
2089
2090   You can get a glyph id for a given unicode character
2091   using \c hpgs_font_get_glyph_id.
2092
2093   Returns the number of outlines drawn or -1, if an error occurrs.
2094 */
2095int hpgs_font_decompose_glyph(hpgs_font *font,
2096                              void *ctxt,
2097                              hpgs_moveto_func_t moveto_func,
2098                              hpgs_lineto_func_t lineto_func,
2099                              hpgs_curveto_func_t curveto_func,
2100                              const hpgs_matrix *m,
2101                              unsigned gid)
2102{
2103  return decompose_glyph_internal(font,ctxt,
2104                                  moveto_func,lineto_func,curveto_func,m,gid);
2105}
2106
2107/*!
2108   Draws the outline of the given glyph id
2109   to the given device by issuing moveto/linto/curveto/fill  operations.
2110
2111   You can get a glyph id for a given unicode character
2112   using \c hpgs_font_get_glyph_id.
2113
2114   Returns -1, if an error occurrs.
2115 */
2116int hpgs_font_draw_glyph(hpgs_font *font,
2117                         hpgs_device *device,
2118                         const hpgs_matrix *m,
2119                         unsigned gid)
2120{
2121  int r=hpgs_font_decompose_glyph(font,device,
2122                                  (hpgs_moveto_func_t)device->vtable->moveto,
2123                                  (hpgs_lineto_func_t)device->vtable->lineto,
2124                                  (hpgs_curveto_func_t)device->vtable->curveto,
2125                                  m,gid);
2126  if (r<0)  return -1;
2127  if (r==0) return 0;
2128
2129  return hpgs_fill(device,HPGS_FALSE);
2130}
2131
2132/*!
2133   Decomposes the outline of the given utf8-encoded unicode string
2134   using the given moveto/linto/curveto/fill functions and
2135   the specified transformation matrix.
2136
2137   Returns -1, if an error occurrs.
2138 */
2139int hpgs_font_decompose_utf8(hpgs_font *font,
2140                             void *ctxt,
2141                             hpgs_moveto_func_t moveto_func,
2142                             hpgs_lineto_func_t lineto_func,
2143                             hpgs_curveto_func_t curveto_func,
2144                             hpgs_fill_func_t fill_func,
2145                             const hpgs_matrix *m,
2146                             const char *str, int strlen)
2147{
2148  if (strlen == 0) return 0;
2149
2150  const char *s = str;
2151
2152  int uc = hpgs_next_utf8(&s);
2153  uint16_t gid = cmap_find_unicode(font,uc);
2154
2155  hpgs_matrix mm = *m;
2156
2157  while (uc != 0)
2158    {
2159      int r=decompose_glyph_internal(font,ctxt,
2160                                     moveto_func,lineto_func,curveto_func,&mm,gid);
2161
2162      if (r<0) return -1;
2163
2164      if (r>0 && fill_func(ctxt,HPGS_FALSE))
2165        return -1;
2166
2167      if (strlen >= 0 && (s - str) >= strlen) return 0;
2168
2169      double d = (double)font->hmtx_data[gid].advanceWidth/(double)font->head_data.unitsPerEm;
2170
2171      // next glyph
2172      uc = hpgs_next_utf8(&s);
2173
2174      // end of string.
2175      if (uc == 0) return 0;
2176
2177      uint16_t gid_n = cmap_find_unicode(font,uc);
2178
2179      d += find_kern_value(font,gid,gid_n);
2180
2181      mm.dx += d * mm.mxx;
2182      mm.dy += d * mm.myx;
2183      gid = gid_n;
2184    }
2185
2186  return 0;
2187}
2188
2189/*!
2190   Draws the outline of the given utf8-encoded unicode string
2191   to the given device by issuing moveto/linto/curveto/fill  operations.
2192
2193   Returns -1, if an error occurrs.
2194 */
2195int hpgs_font_draw_utf8(hpgs_font *font,
2196                        hpgs_device *device,
2197                        const hpgs_matrix *m, const char *str, int strlen)
2198{
2199  return hpgs_font_decompose_utf8(font,device,
2200                                  (hpgs_moveto_func_t)device->vtable->moveto,
2201                                  (hpgs_lineto_func_t)device->vtable->lineto,
2202                                  (hpgs_curveto_func_t)device->vtable->curveto,
2203                                  (hpgs_fill_func_t)device->vtable->fill,
2204                                  m,str,strlen);
2205}
2206