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