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