mkfontscale.c revision 245f6787
1/* 2 Copyright (c) 2002-2003 by Juliusz Chroboczek 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21*/ 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26 27#include <sys/types.h> 28#include <dirent.h> 29#include <unistd.h> 30#include <errno.h> 31#include <ctype.h> 32 33#include <X11/Xos.h> 34#include <X11/fonts/fontenc.h> 35#include <ft2build.h> 36#include FT_FREETYPE_H 37#include FT_SFNT_NAMES_H 38#include FT_TRUETYPE_TABLES_H 39#include FT_TRUETYPE_IDS_H 40#include FT_TYPE1_TABLES_H 41#include FT_BDF_H 42#include FT_XFREE86_H 43 44#include "list.h" 45#include "hash.h" 46#include "data.h" 47#include "ident.h" 48 49#define NPREFIX 1024 50 51#ifndef MAXFONTFILENAMELEN 52#define MAXFONTFILENAMELEN 1024 53#endif 54#ifndef MAXFONTNAMELEN 55#define MAXFONTNAMELEN 1024 56#endif 57 58/* Two levels of macro calls are needed so that we stringify the value 59 of MAXFONT... and not the string "MAXFONT..." */ 60#define QUOTE(x) #x 61#define STRINGIFY(x) QUOTE(x) 62 63static char *encodings_array[] = 64 { "ascii-0", 65 "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5", 66 "iso8859-6", "iso8859-6.8", "iso8859-6.8x", "iso8859-6.16", 67 "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10", 68 "iso8859-11", "iso8859-12", "iso8859-13", "iso8859-14", 69 "iso8859-15", "iso8859-16", 70 "ansi-1251", "koi8-r", "koi8-u", "koi8-ru", "koi8-e", "koi8-uni", 71 "tis620-2", 72 "sun.unicode.india-0", "suneu-greek", 73 "adobe-standard", "adobe-symbol", 74 "ibm-cp437", "ibm-cp850", "ibm-cp852", "ibm-cp866", "microsoft-cp1252", 75 /* But not "adobe-dingbats", as it uses generic glyph names. */ 76 "cns11643-1", "cns11643-2", "cns11643-3", 77 "jisx0201.1976-0", "jisx0208.1983-0", "jisx0208.1990-0", 78 "jisx0212.1990-0", "big5-0", "big5.eten-0", "big5hkscs-0", 79 "gb2312.1980-0", "gb18030.2000-0", "gb18030.2000-1", 80 "ksc5601.1987-0", "ksc5601.1992-3"}; 81 82static char *extra_encodings_array[] = 83 { "iso10646-1", "adobe-fontspecific", "microsoft-symbol" }; 84 85static ListPtr encodings, extra_encodings; 86static char *outfilename; 87 88#define countof(_a) (sizeof(_a)/sizeof((_a)[0])) 89 90static int doDirectory(char*, int, ListPtr); 91static int checkEncoding(FT_Face face, char *encoding_name); 92static int checkExtraEncoding(FT_Face face, char *encoding_name, int found); 93static int find_cmap(int type, int pid, int eid, FT_Face face); 94static char* notice_foundry(char *notice); 95static char* vendor_foundry(signed char *vendor); 96static int readFontScale(HashTablePtr entries, char *dirname); 97ListPtr makeXLFD(char *filename, FT_Face face, int); 98static int readEncodings(ListPtr encodings, char *dirname); 99 100static FT_Library ft_library; 101static float bigEncodingFuzz = 0.02; 102 103static int relative; 104static int doScalable; 105static int doBitmaps; 106static int doISO10646_1_encoding; 107static int onlyEncodings; 108static ListPtr encodingsToDo; 109static int reencodeLegacy; 110static char *encodingPrefix; 111static char *exclusionSuffix; 112 113static void 114usage(void) 115{ 116 fprintf(stderr, 117 "mkfontscale [ -b ] [ -s ] [ -o filename ] [-x suffix ]\n" 118 " [ -a encoding ] [ -f fuzz ] [ -l ] " 119 " [ -e directory ] [ -p prefix ] [ -n ] [ -r ] \n" 120 " [-u] [-U] [ directory ]...\n"); 121} 122 123int 124main(int argc, char **argv) 125{ 126 int argn; 127 FT_Error ftrc; 128 int rc, ll = 0; 129 char prefix[NPREFIX]; 130 131 encodingPrefix = NULL; 132 exclusionSuffix = NULL; 133 134 if(getcwd(prefix, NPREFIX - 1) == NULL) { 135 perror("Couldn't get cwd"); 136 exit(1); 137 } 138 if(prefix[strlen(prefix) - 1] != '/') 139 strcat(prefix, "/"); 140 encodingPrefix = dsprintf("%s", prefix); 141 142 outfilename = NULL; 143 144 encodings = makeList(encodings_array, countof(encodings_array), NULL, 0); 145 146 extra_encodings = makeList(extra_encodings_array, 147 countof(extra_encodings_array), 148 NULL, 0); 149 doBitmaps = 0; 150 doISO10646_1_encoding = 1; 151 doScalable = 1; 152 onlyEncodings = 0; 153 relative = 0; 154 reencodeLegacy = 1; 155 encodingsToDo = NULL; 156 157 argn = 1; 158 while(argn < argc) { 159 if(argv[argn][0] == '\0' || argv[argn][0] != '-') 160 break; 161 if(argv[argn][1] == '-') { 162 argn++; 163 break; 164 } else if (strcmp(argv[argn], "-x") == 0) { 165 if(argn >= argc - 1) { 166 usage(); 167 exit(1); 168 } 169 exclusionSuffix = argv[argn + 1]; 170 argn += 2; 171 } else if(strcmp(argv[argn], "-a") == 0) { 172 if(argn >= argc - 1) { 173 usage(); 174 exit(1); 175 } 176 makeList(&argv[argn + 1], 1, encodings, 0); 177 argn += 2; 178 } else if(strcmp(argv[argn], "-p") == 0) { 179 if(argn >= argc - 1) { 180 usage(); 181 exit(1); 182 } 183 if(strlen(argv[argn + 1]) > NPREFIX - 1) { 184 usage(); 185 exit(1); 186 } 187 free(encodingPrefix); 188 encodingPrefix = dsprintf("%s", argv[argn + 1]); 189 argn += 2; 190 } else if(strcmp(argv[argn], "-e") == 0) { 191 if(argn >= argc - 1) { 192 usage(); 193 exit(1); 194 } 195 rc = readEncodings(encodingsToDo, argv[argn + 1]); 196 if(rc < 0) 197 exit(1); 198 argn += 2; 199 } else if(strcmp(argv[argn], "-b") == 0) { 200 doBitmaps = 1; 201 argn++; 202 } else if(strcmp(argv[argn], "-u") == 0) { 203 doISO10646_1_encoding = 0; 204 argn++; 205 } else if(strcmp(argv[argn], "-U") == 0) { 206 doISO10646_1_encoding = 1; 207 argn++; 208 } else if(strcmp(argv[argn], "-s") == 0) { 209 doScalable = 0; 210 argn++; 211 } else if(strcmp(argv[argn], "-n") == 0) { 212 onlyEncodings = 1; 213 argn++; 214 } else if(strcmp(argv[argn], "-r") == 0) { 215 relative = 1; 216 argn++; 217 } else if(strcmp(argv[argn], "-l") == 0) { 218 reencodeLegacy = !reencodeLegacy; 219 argn++; 220 } else if(strcmp(argv[argn], "-o") == 0) { 221 if(argn >= argc - 1) { 222 usage(); 223 exit(1); 224 } 225 outfilename = argv[argn + 1]; 226 argn += 2; 227 } else if(strcmp(argv[argn], "-f") == 0) { 228 if(argn >= argc - 1) { 229 usage(); 230 exit(1); 231 } 232 bigEncodingFuzz = atof(argv[argn + 1]) / 100.0; 233 argn += 2; 234 } else if (strcmp(argv[argn], "-r") == 0) { /* ignore for now */ 235 argn++; 236 } else if (strcmp(argv[argn], "-n") == 0) { 237 argn++; 238 } else { 239 usage(); 240 exit(1); 241 } 242 } 243 244 if(outfilename == NULL) { 245 if(doBitmaps) 246 outfilename = "fonts.dir"; 247 else 248 outfilename = "fonts.scale"; 249 } 250 251 ftrc = FT_Init_FreeType(&ft_library); 252 if(ftrc) { 253 fprintf(stderr, "Could not initialise FreeType library: %d\n", ftrc); 254 exit(1); 255 } 256 257 ll = listLength(encodingsToDo); 258 259 if (argn == argc) 260 doDirectory(".", ll, encodingsToDo); 261 else 262 while(argn < argc) { 263 doDirectory(argv[argn], ll, encodingsToDo); 264 argn++; 265 } 266 return 0; 267} 268 269static int 270getNameHelper(FT_Face face, int nid, int pid, int eid, 271 FT_SfntName *name_return) 272{ 273 FT_SfntName name; 274 int n, i; 275 276 n = FT_Get_Sfnt_Name_Count(face); 277 if(n <= 0) 278 return 0; 279 280 for(i = 0; i < n; i++) { 281 if(FT_Get_Sfnt_Name(face, i, &name)) 282 continue; 283 if(name.name_id == nid && 284 name.platform_id == pid && 285 (eid < 0 || name.encoding_id == eid)) { 286 switch(name.platform_id) { 287 case TT_PLATFORM_APPLE_UNICODE: 288 case TT_PLATFORM_MACINTOSH: 289 if(name.language_id != TT_MAC_LANGID_ENGLISH) 290 continue; 291 break; 292 case TT_PLATFORM_MICROSOFT: 293 if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES && 294 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM) 295 continue; 296 break; 297 default: 298 continue; 299 } 300 if(name.string_len > 0) { 301 *name_return = name; 302 return 1; 303 } 304 } 305 } 306 return 0; 307} 308 309static char * 310getName(FT_Face face, int nid) 311{ 312 FT_SfntName name; 313 char *string; 314 int i; 315 316 if(getNameHelper(face, nid, 317 TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) || 318 getNameHelper(face, nid, 319 TT_PLATFORM_APPLE_UNICODE, -1, &name)) { 320 string = malloc(name.string_len / 2 + 1); 321 if(string == NULL) { 322 fprintf(stderr, "Couldn't allocate name\n"); 323 exit(1); 324 } 325 for(i = 0; i < name.string_len / 2; i++) { 326 if(name.string[2 * i] != 0) 327 string[i] = '?'; 328 else 329 string[i] = name.string[2 * i + 1]; 330 } 331 string[i] = '\0'; 332 return string; 333 } 334 335 /* Pretend that Apple Roman is ISO 8859-1. */ 336 if(getNameHelper(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, 337 &name)) { 338 string = malloc(name.string_len + 1); 339 if(string == NULL) { 340 fprintf(stderr, "Couldn't allocate name\n"); 341 exit(1); 342 } 343 memcpy(string, name.string, name.string_len); 344 string[name.string_len] = '\0'; 345 return string; 346 } 347 348 return NULL; 349} 350 351static char* 352os2Weight(int weight) 353{ 354 if(weight < 150) 355 return "thin"; 356 else if(weight < 250) 357 return "extralight"; 358 else if(weight < 350) 359 return "light"; 360 else if(weight < 450) 361 return "medium"; /* officially "normal" */ 362 else if(weight < 550) 363 return "medium"; 364 else if(weight < 650) 365 return "semibold"; 366 else if(weight < 750) 367 return "bold"; 368 else if(weight < 850) 369 return "extrabold"; 370 else 371 return "black"; 372} 373 374static char* 375os2Width(int width) 376{ 377 if(width <= 1) 378 return "ultracondensed"; 379 else if(width <= 2) 380 return "extracondensed"; 381 else if(width <= 3) 382 return "condensed"; 383 else if(width <= 4) 384 return "semicondensed"; 385 else if(width <= 5) 386 return "normal"; 387 else if(width <= 6) 388 return "semiexpanded"; 389 else if(width <= 7) 390 return "expanded"; 391 else if(width <= 8) 392 return "extraexpanded"; 393 else 394 return "ultraexpanded"; 395} 396 397static char *widths[] = { 398 "ultracondensed", "extracondensed", "condensed", "semicondensed", 399 "normal", "semiexpanded", "expanded", "extraexpanded", "ultraexpanded" 400}; 401 402#define NUMWIDTHS (sizeof(widths) / sizeof(widths[0])) 403 404static char* 405nameWidth(char *name) 406{ 407 char buf[500]; 408 int i; 409 int n = strlen(name); 410 411 if(n >= 499) return NULL; 412 for(i = 0; i < n; i++) 413 buf[i] = tolower(name[i]); 414 buf[i] = '\0'; 415 416 for(i = 0; i < NUMWIDTHS; i++) 417 if(strstr(buf, widths[i])) 418 return widths[i]; 419 return NULL; 420} 421 422static char* 423t1Weight(char *weight) 424{ 425 if(!weight) 426 return NULL; 427 if(strcmp(weight, "Thin") == 0) 428 return "thin"; 429 if(strcmp(weight, "Light") == 0) 430 return "light"; 431 if(strcmp(weight, "Regular") == 0) 432 return "medium"; 433 if(strcmp(weight, "Normal") == 0) 434 return "medium"; 435 if(strcmp(weight, "Medium") == 0) 436 return "medium"; 437 if(strcmp(weight, "Book") == 0) 438 return "medium"; 439 if(strcmp(weight, "Roman") == 0) /* Some URW++ fonts do that! */ 440 return "medium"; 441 if(strcmp(weight, "Demi") == 0) 442 return "semibold"; 443 if(strcmp(weight, "DemiBold") == 0) 444 return "semibold"; 445 if(strcmp(weight, "SemiBold") == 0) /* some TeX fonts apparently do that */ 446 return "semibold"; 447 else if(strcmp(weight, "Bold") == 0) 448 return "bold"; 449 else if(strcmp(weight, "Black") == 0) 450 return "black"; 451 else { 452 fprintf(stderr, "Unknown Type 1 weight \"%s\"\n", weight); 453 return NULL; 454 } 455} 456 457static int 458unsafe(char c) 459{ 460 return 461 c < 0x20 || c > 0x7E || 462 c == '[' || c == ']' || c == '(' || c == ')' || c == '\\' || c == '-'; 463} 464 465static char * 466safe(char* s) 467{ 468 int i, len, safe_flag = 1; 469 char *t; 470 471 i = 0; 472 while(s[i] != '\0') { 473 if(unsafe(s[i])) 474 safe_flag = 0; 475 i++; 476 } 477 478 if(safe_flag) return s; 479 480 len = i; 481 t = malloc(len + 1); 482 if(t == NULL) { 483 perror("Couldn't allocate string"); 484 exit(1); 485 } 486 487 for(i = 0; i < len; i++) { 488 if(unsafe(s[i])) 489 t[i] = ' '; 490 else 491 t[i] = s[i]; 492 } 493 t[i] = '\0'; 494 return t; 495} 496 497ListPtr 498makeXLFD(char *filename, FT_Face face, int isBitmap) 499{ 500 ListPtr xlfd = NULL; 501 char *foundry, *family, *weight, *slant, *sWidth, *adstyle, 502 *spacing, *full_name; 503 TT_Header *head; 504 TT_HoriHeader *hhea; 505 TT_OS2 *os2; 506 TT_Postscript *post; 507 PS_FontInfoRec *t1info, t1info_rec; 508 int rc; 509 510 foundry = NULL; 511 family = NULL; 512 weight = NULL; 513 slant = NULL; 514 sWidth = NULL; 515 adstyle = NULL; 516 spacing = NULL; 517 full_name = NULL; 518 519 head = FT_Get_Sfnt_Table(face, ft_sfnt_head); 520 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); 521 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); 522 post = FT_Get_Sfnt_Table(face, ft_sfnt_post); 523 524 rc = FT_Get_PS_Font_Info(face, &t1info_rec); 525 if(rc == 0) 526 t1info = &t1info_rec; 527 else 528 t1info = NULL; 529 530 if(!family) 531 family = getName(face, TT_NAME_ID_FONT_FAMILY); 532 if(!family) 533 family = getName(face, TT_NAME_ID_FULL_NAME); 534 if(!family) 535 family = getName(face, TT_NAME_ID_PS_NAME); 536 537 if(!full_name) 538 full_name = getName(face, TT_NAME_ID_FULL_NAME); 539 if(!full_name) 540 full_name = getName(face, TT_NAME_ID_PS_NAME); 541 542 if(os2 && os2->version != 0xFFFF) { 543 if(!weight) 544 weight = os2Weight(os2->usWeightClass); 545 if(!sWidth) 546 sWidth = os2Width(os2->usWidthClass); 547 if(!foundry) 548 foundry = vendor_foundry(os2->achVendID); 549 if(!slant) 550 slant = os2->fsSelection & 1 ? "i" : "r"; 551 } 552 553 if(post) { 554 if(!spacing) { 555 if(post->isFixedPitch) { 556 if(hhea->min_Left_Side_Bearing >= 0 && 557 hhea->xMax_Extent <= hhea->advance_Width_Max) { 558 spacing = "c"; 559 } else { 560 spacing = "m"; 561 } 562 } else { 563 spacing = "p"; 564 } 565 } 566 } 567 568 if(t1info) { 569 if(!family) 570 family = t1info->family_name; 571 if(!family) 572 family = t1info->full_name; 573 if(!full_name) 574 full_name = t1info->full_name; 575 if(!foundry) 576 foundry = notice_foundry(t1info->notice); 577 if(!weight) 578 weight = t1Weight(t1info->weight); 579 if(!spacing) 580 spacing = t1info->is_fixed_pitch ? "m" : "p"; 581 if(!slant) { 582 /* Bitstream fonts have positive italic angle. */ 583 slant = 584 t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ? 585 "i" : "r"; 586 } 587 } 588 589 if(!full_name) { 590 fprintf(stderr, "Couldn't determine full name for %s\n", filename); 591 full_name = filename; 592 } 593 594 if(head) { 595 if(!slant) 596 slant = head->Mac_Style & 2 ? "i" : "r"; 597 if(!weight) 598 weight = head->Mac_Style & 1 ? "bold" : "medium"; 599 } 600 601 if(!slant) { 602 fprintf(stderr, "Couldn't determine slant for %s\n", filename); 603 slant = "r"; 604 } 605 606 if(!weight) { 607 fprintf(stderr, "Couldn't determine weight for %s\n", filename); 608 weight = "medium"; 609 } 610 611 if(!foundry) { 612 char *notice; 613 notice = getName(face, TT_NAME_ID_TRADEMARK); 614 if(notice) { 615 foundry = notice_foundry(notice); 616 } 617 if(!foundry) { 618 notice = getName(face, TT_NAME_ID_MANUFACTURER); 619 if(notice) { 620 foundry = notice_foundry(notice); 621 } 622 } 623 } 624 625 if(strcmp(slant, "i") == 0) { 626 if(strstr(full_name, "Oblique")) 627 slant = "o"; 628 if(strstr(full_name, "Slanted")) 629 slant = "o"; 630 } 631 632 if(!sWidth) 633 sWidth = nameWidth(full_name); 634 635 if(!foundry) foundry = "misc"; 636 if(!family) { 637 fprintf(stderr, "Couldn't get family name for %s\n", filename); 638 family = filename; 639 } 640 641 if(!weight) weight = "medium"; 642 if(!slant) slant = "r"; 643 if(!sWidth) sWidth = "normal"; 644 if(!adstyle) adstyle = ""; 645 if(!spacing) spacing = "p"; 646 647 /* Yes, it's a memory leak. */ 648 foundry = safe(foundry); 649 family = safe(family); 650 651 if(!isBitmap) { 652 xlfd = listConsF(xlfd, 653 "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0", 654 foundry, family, 655 weight, slant, sWidth, adstyle, spacing); 656 } else { 657 int i, w, h, xres, yres; 658 for(i = 0; i < face->num_fixed_sizes; i++) { 659 w = face->available_sizes[i].width; 660 h = face->available_sizes[i].height; 661 xres = 75; 662 yres = (double)h / w * xres; 663 xlfd = listConsF(xlfd, 664 "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d", 665 foundry, family, 666 weight, slant, sWidth, adstyle, 667 h, (int)(h / (double)yres * 72.27 * 10 + 0.5), 668 xres, yres, 669 spacing, 60); 670 } 671 } 672 return xlfd; 673} 674 675static int 676readFontScale(HashTablePtr entries, char *dirname) 677{ 678 int n = strlen(dirname); 679 char *filename; 680 FILE *in; 681 int rc, count, i; 682 char file[MAXFONTFILENAMELEN+1], font[MAXFONTNAMELEN+1]; 683 684 if(dirname[n - 1] == '/') 685 filename = dsprintf("%sfonts.scale", dirname); 686 else 687 filename = dsprintf("%s/fonts.scale", dirname); 688 if(filename == NULL) 689 return -1; 690 691 in = fopen(filename, "r"); 692 free(filename); 693 if(in == NULL) { 694 if(errno != ENOENT) 695 perror("open(fonts.scale)"); 696 return -1; 697 } 698 699 rc = fscanf(in, "%d\n", &count); 700 if(rc != 1) { 701 fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname); 702 fclose(in); 703 return -1; 704 } 705 706 for(i = 0; i < count; i++) { 707 rc = fscanf(in, 708 "%" STRINGIFY(MAXFONTFILENAMELEN) "s " 709 "%" STRINGIFY(MAXFONTNAMELEN) "[^\n]\n", 710 file, font); 711 if(rc != 2) 712 break; 713 putHash(entries, font, file, 100); 714 } 715 fclose(in); 716 return 1; 717} 718 719static int 720filePrio(char *filename) 721{ 722 int n = strlen(filename); 723 if(n < 4) 724 return 0; 725 if(strcmp(filename + n - 4, ".otf") == 0) 726 return 6; 727 if(strcmp(filename + n - 4, ".OTF") == 0) 728 return 6; 729 if(strcmp(filename + n - 4, ".ttf") == 0) 730 return 5; 731 if(strcmp(filename + n - 4, ".TTF") == 0) 732 return 5; 733 if(strcmp(filename + n - 4, ".pcf") == 0) 734 return 4; 735 if(strcmp(filename + n - 4, ".PCF") == 0) 736 return 4; 737 if(strcmp(filename + n - 3, ".gz") == 0) 738 return 3; 739#ifdef X_BZIP2_FONT_COMPRESSION 740 if(strcmp(filename + n - 4, ".bz2") == 0) 741 return 2; 742#endif 743 if(strcmp(filename + n - 2, ".Z") == 0) 744 return 2; 745 if(strcmp(filename + n - 4, ".bdf") == 0) 746 return 1; 747 if(strcmp(filename + n - 4, ".BDF") == 0) 748 return 1; 749 return 0; 750} 751 752static int 753doDirectory(char *dirname_given, int numEncodings, ListPtr encodingsToDo) 754{ 755 char *dirname, *fontscale_name, *filename, *encdir; 756 FILE *fontscale, *encfile; 757 DIR *dirp; 758 struct dirent *entry; 759 FT_Error ftrc; 760 FT_Face face; 761 ListPtr encoding, xlfd, lp; 762 HashTablePtr entries; 763 HashBucketPtr *array; 764 int i, n, found, rc; 765 int isBitmap=0,xl=0; 766 767 if (exclusionSuffix) 768 xl = strlen (exclusionSuffix); 769 770 i = strlen(dirname_given); 771 if(i == 0) 772 dirname = dsprintf("./"); 773 else if(dirname_given[i - 1] != '/') 774 dirname = dsprintf("%s/", dirname_given); 775 else 776 dirname = dsprintf("%s", dirname_given); 777 778 if(dirname == NULL) { 779 perror("dirname"); 780 exit(1); 781 } 782 783 if (onlyEncodings) 784 goto encodings; 785 786 entries = makeHashTable(); 787 if(doBitmaps && !doScalable) { 788 readFontScale(entries, dirname); 789 } 790 791 if(strcmp(outfilename, "-") == 0) 792 fontscale_name = NULL; 793 else { 794 if(outfilename[0] == '/') 795 fontscale_name = dsprintf("%s", outfilename); 796 else 797 fontscale_name = dsprintf("%s%s", dirname, outfilename); 798 if(fontscale_name == NULL) { 799 perror("fontscale_name"); 800 exit(1); 801 } 802 } 803 804 dirp = opendir(dirname); 805 if(dirp == NULL) { 806 fprintf(stderr, "%s: ", dirname); 807 perror("opendir"); 808 return 0; 809 } 810 811 if(fontscale_name == NULL) 812 fontscale = stdout; 813 else 814 fontscale = fopen(fontscale_name, "wb"); 815 816 if(fontscale == NULL) { 817 fprintf(stderr, "%s: ", fontscale_name); 818 perror("fopen(w)"); 819 return 0; 820 } 821 822 while((entry = readdir(dirp)) != NULL) { 823 int have_face = 0; 824 char *xlfd_name = NULL; 825 xlfd = NULL; 826 827 if (xl) { 828 int dl = strlen (entry->d_name); 829 if (strcmp (entry->d_name + dl - xl, exclusionSuffix) == 0) 830 continue; 831 } 832 833 filename = dsprintf("%s%s", dirname, entry->d_name); 834 835 if(doBitmaps) 836 rc = bitmapIdentify(filename, &xlfd_name); 837 else 838 rc = 0; 839 840 if(rc < 0) 841 goto done; 842 843 if(rc == 0) { 844 ftrc = FT_New_Face(ft_library, filename, 0, &face); 845 if(ftrc) 846 goto done; 847 have_face = 1; 848 849 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 850 851 if(!isBitmap) { 852 /* Workaround for bitmap-only SFNT fonts */ 853 if(FT_IS_SFNT(face) && face->num_fixed_sizes > 0 && 854 strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) { 855 TT_MaxProfile *maxp; 856 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 857 if(maxp != NULL && maxp->maxContours == 0) 858 isBitmap = 1; 859 } 860 } 861 862 if(isBitmap) { 863 if(!doBitmaps) 864 goto done; 865 } else { 866 if(!doScalable) 867 goto done; 868 } 869 870 if(isBitmap) { 871 BDF_PropertyRec prop; 872 rc = FT_Get_BDF_Property(face, "FONT", &prop); 873 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 874 xlfd_name = malloc(strlen(prop.u.atom) + 1); 875 if(xlfd_name == NULL) 876 goto done; 877 strcpy(xlfd_name, prop.u.atom); 878 } 879 } 880 } 881 882 if(xlfd_name) { 883 /* We know it's a bitmap font, and we know its XLFD */ 884 int n = strlen(xlfd_name); 885 if(reencodeLegacy && 886 n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) { 887 char *s; 888 889 s = malloc(n - 10); 890 memcpy(s, xlfd_name, n - 11); 891 s[n - 11] = '\0'; 892 xlfd = listCons(s, xlfd); 893 } else { 894 /* Not a reencodable font -- skip all the rest of the loop body */ 895 putHash(entries, xlfd_name, entry->d_name, filePrio(entry->d_name)); 896 goto done; 897 } 898 } 899 900 if(!have_face) { 901 ftrc = FT_New_Face(ft_library, filename, 0, &face); 902 if(ftrc) 903 goto done; 904 have_face = 1; 905 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 906 907 if(!isBitmap) { 908 if(face->num_fixed_sizes > 0) { 909 TT_MaxProfile *maxp; 910 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 911 if(maxp != NULL && maxp->maxContours == 0) 912 isBitmap = 1; 913 } 914 } 915 } 916 917 if(xlfd == NULL) 918 xlfd = makeXLFD(entry->d_name, face, isBitmap); 919 920 found = 0; 921 922 for(lp = xlfd; lp; lp = lp->next) { 923 char buf[MAXFONTNAMELEN]; 924 for(encoding = encodings; encoding; encoding = encoding->next) { 925 if(checkEncoding(face, encoding->value)) { 926 found = 1; 927 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 928 lp->value, encoding->value); 929 putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); 930 } 931 } 932 for(encoding = extra_encodings; encoding; 933 encoding = encoding->next) { 934 if(checkExtraEncoding(face, encoding->value, found)) { 935 /* Do not set found! */ 936 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 937 lp->value, encoding->value); 938 putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); 939 } 940 } 941 } 942 done: 943 if(have_face) 944 FT_Done_Face(face); 945 deepDestroyList(xlfd); 946 xlfd = NULL; 947 free(filename); 948 } 949 950 closedir(dirp); 951 n = hashElements(entries); 952 fprintf(fontscale, "%d\n", n); 953 array = hashArray(entries, 1); 954 for(i = 0; i < n; i++) 955 fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key); 956 destroyHashArray(array); 957 entries = NULL; 958 if(fontscale_name) { 959 fclose(fontscale); 960 free(fontscale_name); 961 } 962 963 encodings: 964 encdir = dsprintf("%s%s", dirname, "encodings.dir"); 965 966 if(encdir == NULL) { 967 perror("encodings"); 968 exit(1); 969 } 970 unlink(encdir); 971 972 if (numEncodings) { 973 encfile = fopen(encdir, "w"); 974 if(encfile == NULL) { 975 perror("open(encodings.dir)"); 976 exit(1); 977 } 978 fprintf(encfile, "%d\n", numEncodings); 979 encodingsToDo = sortList(encodingsToDo); 980 for(lp = encodingsToDo; lp; lp = lp->next) { 981 fprintf(encfile, "%s\n", lp->value); 982 } 983 fclose (encfile); 984 } 985 986 free(dirname); 987 return 1; 988} 989 990#define CODE_IGNORED(c) ((c) < 0x20 || \ 991 ((c) >= 0x7F && (c) <= 0xA0) || \ 992 (c) == 0xAD || (c) == 0xF71B) 993 994static int 995checkEncoding(FT_Face face, char *encoding_name) 996{ 997 FontEncPtr encoding; 998 FontMapPtr mapping; 999 int i, j, c, koi8; 1000 char *n; 1001 1002 encoding = FontEncFind(encoding_name, NULL); 1003 if(!encoding) 1004 return 0; 1005 1006 /* An encoding is ``small'' if one of the following is true: 1007 - it is linear and has no more than 256 codepoints; or 1008 - it is a matrix encoding and has no more than one column. 1009 1010 For small encodings using Unicode indices, we require perfect 1011 coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility. 1012 1013 For large encodings, we require coverage up to bigEncodingFuzz. 1014 1015 For encodings using PS names (currently Adobe Standard and 1016 Adobe Symbol only), we require perfect coverage. */ 1017 1018 1019 if(FT_Has_PS_Glyph_Names(face)) { 1020 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1021 if(mapping->type == FONT_ENCODING_POSTSCRIPT) { 1022 if(encoding->row_size > 0) { 1023 for(i = encoding->first; i < encoding->size; i++) { 1024 for(j = encoding->first_col; 1025 j < encoding->row_size; 1026 j++) { 1027 n = FontEncName((i<<8) | j, mapping); 1028 if(n && FT_Get_Name_Index(face, n) == 0) { 1029 return 0; 1030 } 1031 } 1032 } 1033 return 1; 1034 } else { 1035 for(i = encoding->first; i < encoding->size; i++) { 1036 n = FontEncName(i, mapping); 1037 if(n && FT_Get_Name_Index(face, n) == 0) { 1038 return 0; 1039 } 1040 } 1041 return 1; 1042 } 1043 } 1044 } 1045 } 1046 1047 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1048 if(find_cmap(mapping->type, mapping->pid, mapping->eid, face)) { 1049 int total = 0, failed = 0; 1050 if(encoding->row_size > 0) { 1051 int estimate = 1052 (encoding->size - encoding->first) * 1053 (encoding->row_size - encoding->first_col); 1054 for(i = encoding->first; i < encoding->size; i++) { 1055 for(j = encoding->first_col; 1056 j < encoding->row_size; 1057 j++) { 1058 c = FontEncRecode((i<<8) | j, mapping); 1059 if(CODE_IGNORED(c)) { 1060 continue; 1061 } else { 1062 if(FT_Get_Char_Index(face, c) == 0) { 1063 failed++; 1064 } 1065 total++; 1066 if((encoding->size <= 1 && failed > 0) || 1067 ((float)failed >= bigEncodingFuzz * estimate)) { 1068 return 0; 1069 } 1070 } 1071 } 1072 } 1073 if((float)failed >= total * bigEncodingFuzz) 1074 return 0; 1075 else 1076 return 1; 1077 } else { 1078 int estimate = encoding->size - encoding->first; 1079 /* For the KOI8 encodings, we ignore the lack of 1080 linedrawing and pseudo-math characters */ 1081 if(strncmp(encoding->name, "koi8-", 5) == 0) 1082 koi8 = 1; 1083 else 1084 koi8 = 0; 1085 for(i = encoding->first; i < encoding->size; i++) { 1086 c = FontEncRecode(i, mapping); 1087 if(CODE_IGNORED(c) || 1088 (koi8 && ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) { 1089 continue; 1090 } else { 1091 if(FT_Get_Char_Index(face, c) == 0) { 1092 failed++; 1093 } 1094 total++; 1095 if((encoding->size <= 256 && failed > 0) || 1096 ((float)failed >= bigEncodingFuzz * estimate)) { 1097 return 0; 1098 } 1099 } 1100 } 1101 if((float)failed >= total * bigEncodingFuzz) 1102 return 0; 1103 else 1104 return 1; 1105 } 1106 } 1107 } 1108 return 0; 1109} 1110 1111static int 1112find_cmap(int type, int pid, int eid, FT_Face face) 1113{ 1114 int i, n, rc; 1115 FT_CharMap cmap = NULL; 1116 1117 n = face->num_charmaps; 1118 1119 switch(type) { 1120 case FONT_ENCODING_TRUETYPE: /* specific cmap */ 1121 for(i=0; i<n; i++) { 1122 cmap = face->charmaps[i]; 1123 if(cmap->platform_id == pid && cmap->encoding_id == eid) { 1124 rc = FT_Set_Charmap(face, cmap); 1125 if(rc == 0) 1126 return 1; 1127 } 1128 } 1129 break; 1130 case FONT_ENCODING_UNICODE: /* any Unicode cmap */ 1131 /* prefer Microsoft Unicode */ 1132 for(i=0; i<n; i++) { 1133 cmap = face->charmaps[i]; 1134 if(cmap->platform_id == TT_PLATFORM_MICROSOFT && 1135 cmap->encoding_id == TT_MS_ID_UNICODE_CS) { 1136 rc = FT_Set_Charmap(face, cmap); 1137 if(rc == 0) 1138 return 1; 1139 } 1140 } 1141 /* Try Apple Unicode */ 1142 for(i=0; i<n; i++) { 1143 cmap = face->charmaps[i]; 1144 if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) { 1145 rc = FT_Set_Charmap(face, cmap); 1146 if(rc == 0) 1147 return 1; 1148 } 1149 } 1150 /* ISO Unicode? */ 1151 for(i=0; i<n; i++) { 1152 cmap = face->charmaps[i]; 1153 if(cmap->platform_id == TT_PLATFORM_ISO) { 1154 rc = FT_Set_Charmap(face, cmap); 1155 if(rc == 0) 1156 return 1; 1157 } 1158 } 1159 break; 1160 default: 1161 return 0; 1162 } 1163 return 0; 1164} 1165 1166static int 1167checkExtraEncoding(FT_Face face, char *encoding_name, int found) 1168{ 1169 int c; 1170 1171 if(strcasecmp(encoding_name, "iso10646-1") == 0) { 1172 if(doISO10646_1_encoding && find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) { 1173 int found = 0; 1174 /* Export as Unicode if there are at least 15 BMP 1175 characters that are not a space or ignored. */ 1176 for(c = 0x21; c < 0x10000; c++) { 1177 if(CODE_IGNORED(c)) 1178 continue; 1179 if(FT_Get_Char_Index(face, c) > 0) 1180 found++; 1181 if(found >= 15) 1182 return 1; 1183 } 1184 return 0; 1185 } else 1186 return 0; 1187 } else if(strcasecmp(encoding_name, "microsoft-symbol") == 0) { 1188 if(find_cmap(FONT_ENCODING_TRUETYPE, 1189 TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, 1190 face)) 1191 return 1; 1192 else 1193 return 0; 1194 } else if(strcasecmp(encoding_name, "adobe-fontspecific") == 0) { 1195 if(!found) { 1196 if(FT_Has_PS_Glyph_Names(face)) 1197 return 1; 1198 else 1199 return 0; 1200 } else 1201 return 0; 1202 } else { 1203 fprintf(stderr, "Unknown extra encoding %s\n", encoding_name); 1204 return 0; 1205 } 1206} 1207 1208static char* 1209notice_foundry(char *notice) 1210{ 1211 int i; 1212 for(i = 0; i < countof(notice_foundries); i++) 1213 if(notice && strstr(notice, notice_foundries[i][0])) 1214 return notice_foundries[i][1]; 1215 return NULL; 1216} 1217 1218static int 1219vendor_match(signed char *vendor, char *vendor_string) 1220{ 1221 /* vendor is not necessarily NUL-terminated. */ 1222 int i, len; 1223 len = strlen(vendor_string); 1224 if(memcmp(vendor, vendor_string, len) != 0) 1225 return 0; 1226 for(i = len; i < 4; i++) 1227 if(vendor[i] != ' ' && vendor[i] != '\0') 1228 return 0; 1229 return 1; 1230} 1231 1232static char* 1233vendor_foundry(signed char *vendor) 1234{ 1235 int i; 1236 for(i = 0; i < countof(vendor_foundries); i++) 1237 if(vendor_match(vendor, vendor_foundries[i][0])) 1238 return vendor_foundries[i][1]; 1239 return NULL; 1240} 1241 1242static int 1243readEncodings(ListPtr encodings, char *dirname) 1244{ 1245 char *fullname; 1246 DIR *dirp; 1247 struct dirent *file; 1248 char **names, **name; 1249 1250 if(strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/') 1251 dirname[strlen(dirname) - 1] = '\0'; 1252 1253 dirp = opendir(dirname); 1254 if(dirp == NULL) { 1255 perror("opendir"); 1256 return -1; 1257 } 1258 1259 while((file = readdir(dirp)) != NULL) { 1260 fullname = dsprintf("%s/%s", dirname, file->d_name); 1261 if(fullname == NULL) { 1262 fprintf(stderr, "Couldn't allocate fullname\n"); 1263 closedir(dirp); 1264 return -1; 1265 } 1266 1267 names = FontEncIdentify(fullname); 1268 if(!names) 1269 continue; 1270 1271 for(name = names; *name; name++) { 1272 if(fullname[0] != '/' && !relative) { 1273 char *n; 1274 n = dsprintf("%s%s", encodingPrefix, fullname); 1275 if(n == NULL) { 1276 fprintf(stderr, "Couldn't allocate name\n"); 1277 closedir(dirp); 1278 return -1; 1279 } 1280 encodingsToDo = listConsF(encodingsToDo, "%s %s", *name, n); 1281 free(n); 1282 } else { 1283 encodingsToDo = 1284 listConsF(encodingsToDo, "%s %s", *name, fullname); 1285 } 1286 if(encodingsToDo == NULL) { 1287 fprintf(stderr, "Couldn't allocate encodings\n"); 1288 closedir(dirp); 1289 return -1; 1290 } 1291 } 1292 free(names); /* only the spine */ 1293 } 1294 closedir(dirp); 1295 return 0; 1296} 1297