mkfontscale.c revision 14734546
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 const char *outfilename; 87 88#define countof(_a) (sizeof(_a)/sizeof((_a)[0])) 89 90static int doDirectory(const 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 const char* notice_foundry(const char *notice); 95static const char* vendor_foundry(const 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 const 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 const 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 const 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 const char* 405nameWidth(const 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 const char* 423t1Weight(const char *weight) 424{ 425 if(!weight) 426 return NULL; 427 if(strcmp(weight, "Thin") == 0) 428 return "thin"; 429 if(strcmp(weight, "ExtraLight") == 0) /* FontForge uses this for 200*/ 430 return "extralight"; 431 if(strcmp(weight, "Light") == 0) 432 return "light"; 433 if(strcmp(weight, "Regular") == 0) 434 return "medium"; 435 if(strcmp(weight, "Normal") == 0) 436 return "medium"; 437 if(strcmp(weight, "Medium") == 0) 438 return "medium"; 439 if(strcmp(weight, "Book") == 0) 440 return "medium"; 441 if(strcmp(weight, "Roman") == 0) /* Some URW++ fonts do that! */ 442 return "medium"; 443 if(strcmp(weight, "Demi") == 0) 444 return "semibold"; 445 if(strcmp(weight, "DemiBold") == 0) 446 return "semibold"; 447 if(strcmp(weight, "SemiBold") == 0) /* some TeX fonts apparently do that */ 448 return "semibold"; 449 else if(strcmp(weight, "Bold") == 0) 450 return "bold"; 451 else if(strcmp(weight, "Heavy") == 0) /* FontForge uses this for 800*/ 452 return "extrabold"; 453 else if(strcmp(weight, "Black") == 0) 454 return "black"; 455 else { 456 fprintf(stderr, "Unknown Type 1 weight \"%s\"\n", weight); 457 return NULL; 458 } 459} 460 461static int 462unsafe(char c) 463{ 464 return 465 c < 0x20 || c > 0x7E || 466 c == '[' || c == ']' || c == '(' || c == ')' || c == '\\' || c == '-'; 467} 468 469static const char * 470safe(const char* s) 471{ 472 int i, len, safe_flag = 1; 473 char *t; 474 475 i = 0; 476 while(s[i] != '\0') { 477 if(unsafe(s[i])) 478 safe_flag = 0; 479 i++; 480 } 481 482 if(safe_flag) return s; 483 484 len = i; 485 t = malloc(len + 1); 486 if(t == NULL) { 487 perror("Couldn't allocate string"); 488 exit(1); 489 } 490 491 for(i = 0; i < len; i++) { 492 if(unsafe(s[i])) 493 t[i] = ' '; 494 else 495 t[i] = s[i]; 496 } 497 t[i] = '\0'; 498 return t; 499} 500 501ListPtr 502makeXLFD(char *filename, FT_Face face, int isBitmap) 503{ 504 ListPtr xlfd = NULL; 505 const char *foundry, *family, *weight, *slant, *sWidth, *adstyle, 506 *spacing, *full_name; 507 TT_Header *head; 508 TT_HoriHeader *hhea; 509 TT_OS2 *os2; 510 TT_Postscript *post; 511 PS_FontInfoRec *t1info, t1info_rec; 512 int rc; 513 514 foundry = NULL; 515 family = NULL; 516 weight = NULL; 517 slant = NULL; 518 sWidth = NULL; 519 adstyle = NULL; 520 spacing = NULL; 521 full_name = NULL; 522 523 head = FT_Get_Sfnt_Table(face, ft_sfnt_head); 524 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); 525 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); 526 post = FT_Get_Sfnt_Table(face, ft_sfnt_post); 527 528 rc = FT_Get_PS_Font_Info(face, &t1info_rec); 529 if(rc == 0) 530 t1info = &t1info_rec; 531 else 532 t1info = NULL; 533 534 if(!family) 535 family = getName(face, TT_NAME_ID_FONT_FAMILY); 536 if(!family) 537 family = getName(face, TT_NAME_ID_FULL_NAME); 538 if(!family) 539 family = getName(face, TT_NAME_ID_PS_NAME); 540 541 if(!full_name) 542 full_name = getName(face, TT_NAME_ID_FULL_NAME); 543 if(!full_name) 544 full_name = getName(face, TT_NAME_ID_PS_NAME); 545 546 if(os2 && os2->version != 0xFFFF) { 547 if(!weight) 548 weight = os2Weight(os2->usWeightClass); 549 if(!sWidth) 550 sWidth = os2Width(os2->usWidthClass); 551 if(!foundry) 552 foundry = vendor_foundry(os2->achVendID); 553 if(!slant) 554 slant = os2->fsSelection & 1 ? "i" : "r"; 555 } 556 557 if(post) { 558 if(!spacing) { 559 if(post->isFixedPitch) { 560 if(hhea->min_Left_Side_Bearing >= 0 && 561 hhea->xMax_Extent <= hhea->advance_Width_Max) { 562 spacing = "c"; 563 } else { 564 spacing = "m"; 565 } 566 } else { 567 spacing = "p"; 568 } 569 } 570 } 571 572 if(t1info) { 573 if(!family) 574 family = t1info->family_name; 575 if(!family) 576 family = t1info->full_name; 577 if(!full_name) 578 full_name = t1info->full_name; 579 if(!foundry) 580 foundry = notice_foundry(t1info->notice); 581 if(!weight) 582 weight = t1Weight(t1info->weight); 583 if(!spacing) 584 spacing = t1info->is_fixed_pitch ? "m" : "p"; 585 if(!slant) { 586 /* Bitstream fonts have positive italic angle. */ 587 slant = 588 t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ? 589 "i" : "r"; 590 } 591 } 592 593 if(!full_name) { 594 fprintf(stderr, "Couldn't determine full name for %s\n", filename); 595 full_name = filename; 596 } 597 598 if(head) { 599 if(!slant) 600 slant = head->Mac_Style & 2 ? "i" : "r"; 601 if(!weight) 602 weight = head->Mac_Style & 1 ? "bold" : "medium"; 603 } 604 605 if(!slant) { 606 fprintf(stderr, "Couldn't determine slant for %s\n", filename); 607 slant = "r"; 608 } 609 610 if(!weight) { 611 fprintf(stderr, "Couldn't determine weight for %s\n", filename); 612 weight = "medium"; 613 } 614 615 if(!foundry) { 616 char *notice; 617 notice = getName(face, TT_NAME_ID_TRADEMARK); 618 if(notice) { 619 foundry = notice_foundry(notice); 620 } 621 if(!foundry) { 622 notice = getName(face, TT_NAME_ID_MANUFACTURER); 623 if(notice) { 624 foundry = notice_foundry(notice); 625 } 626 } 627 } 628 629 if(strcmp(slant, "i") == 0) { 630 if(strstr(full_name, "Oblique")) 631 slant = "o"; 632 if(strstr(full_name, "Slanted")) 633 slant = "o"; 634 } 635 636 if(!sWidth) 637 sWidth = nameWidth(full_name); 638 639 if(!foundry) foundry = "misc"; 640 if(!family) { 641 fprintf(stderr, "Couldn't get family name for %s\n", filename); 642 family = filename; 643 } 644 645 if(!weight) weight = "medium"; 646 if(!slant) slant = "r"; 647 if(!sWidth) sWidth = "normal"; 648 if(!adstyle) adstyle = ""; 649 if(!spacing) spacing = "p"; 650 651 /* Yes, it's a memory leak. */ 652 foundry = safe(foundry); 653 family = safe(family); 654 655 if(!isBitmap) { 656 xlfd = listConsF(xlfd, 657 "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0", 658 foundry, family, 659 weight, slant, sWidth, adstyle, spacing); 660 } else { 661 int i, w, h, xres, yres; 662 for(i = 0; i < face->num_fixed_sizes; i++) { 663 w = face->available_sizes[i].width; 664 h = face->available_sizes[i].height; 665 xres = 75; 666 yres = (double)h / w * xres; 667 xlfd = listConsF(xlfd, 668 "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d", 669 foundry, family, 670 weight, slant, sWidth, adstyle, 671 h, (int)(h / (double)yres * 72.27 * 10 + 0.5), 672 xres, yres, 673 spacing, 60); 674 } 675 } 676 return xlfd; 677} 678 679static int 680readFontScale(HashTablePtr entries, char *dirname) 681{ 682 int n = strlen(dirname); 683 char *filename; 684 FILE *in; 685 int rc, count, i; 686 char file[MAXFONTFILENAMELEN+1], font[MAXFONTNAMELEN+1]; 687 688 if(dirname[n - 1] == '/') 689 filename = dsprintf("%sfonts.scale", dirname); 690 else 691 filename = dsprintf("%s/fonts.scale", dirname); 692 if(filename == NULL) 693 return -1; 694 695 in = fopen(filename, "r"); 696 free(filename); 697 if(in == NULL) { 698 if(errno != ENOENT) 699 perror("open(fonts.scale)"); 700 return -1; 701 } 702 703 rc = fscanf(in, "%d\n", &count); 704 if(rc != 1) { 705 fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname); 706 fclose(in); 707 return -1; 708 } 709 710 for(i = 0; i < count; i++) { 711 rc = fscanf(in, 712 "%" STRINGIFY(MAXFONTFILENAMELEN) "s " 713 "%" STRINGIFY(MAXFONTNAMELEN) "[^\n]\n", 714 file, font); 715 if(rc != 2) 716 break; 717 putHash(entries, font, file, 100); 718 } 719 fclose(in); 720 return 1; 721} 722 723static int 724filePrio(char *filename) 725{ 726 int n = strlen(filename); 727 if(n < 4) 728 return 0; 729 if(strcmp(filename + n - 4, ".otf") == 0) 730 return 6; 731 if(strcmp(filename + n - 4, ".OTF") == 0) 732 return 6; 733 if(strcmp(filename + n - 4, ".ttf") == 0) 734 return 5; 735 if(strcmp(filename + n - 4, ".TTF") == 0) 736 return 5; 737 if(strcmp(filename + n - 4, ".pcf") == 0) 738 return 4; 739 if(strcmp(filename + n - 4, ".PCF") == 0) 740 return 4; 741 if(strcmp(filename + n - 3, ".gz") == 0) 742 return 3; 743#ifdef X_BZIP2_FONT_COMPRESSION 744 if(strcmp(filename + n - 4, ".bz2") == 0) 745 return 2; 746#endif 747 if(strcmp(filename + n - 2, ".Z") == 0) 748 return 2; 749 if(strcmp(filename + n - 4, ".bdf") == 0) 750 return 1; 751 if(strcmp(filename + n - 4, ".BDF") == 0) 752 return 1; 753 return 0; 754} 755 756static int 757doDirectory(const char *dirname_given, int numEncodings, ListPtr encodingsToDo) 758{ 759 char *dirname, *fontscale_name, *filename, *encdir; 760 FILE *fontscale, *encfile; 761 DIR *dirp; 762 struct dirent *entry; 763 FT_Error ftrc; 764 FT_Face face; 765 ListPtr encoding, xlfd, lp; 766 HashTablePtr entries; 767 HashBucketPtr *array; 768 int i, n, found, rc; 769 int isBitmap=0,xl=0; 770 771 if (exclusionSuffix) 772 xl = strlen (exclusionSuffix); 773 774 i = strlen(dirname_given); 775 if(i == 0) 776 dirname = dsprintf("./"); 777 else if(dirname_given[i - 1] != '/') 778 dirname = dsprintf("%s/", dirname_given); 779 else 780 dirname = dsprintf("%s", dirname_given); 781 782 if(dirname == NULL) { 783 perror("dirname"); 784 exit(1); 785 } 786 787 if (onlyEncodings) 788 goto encodings; 789 790 entries = makeHashTable(); 791 if(doBitmaps && !doScalable) { 792 readFontScale(entries, dirname); 793 } 794 795 if(strcmp(outfilename, "-") == 0) 796 fontscale_name = NULL; 797 else { 798 if(outfilename[0] == '/') 799 fontscale_name = dsprintf("%s", outfilename); 800 else 801 fontscale_name = dsprintf("%s%s", dirname, outfilename); 802 if(fontscale_name == NULL) { 803 perror("fontscale_name"); 804 exit(1); 805 } 806 } 807 808 dirp = opendir(dirname); 809 if(dirp == NULL) { 810 fprintf(stderr, "%s: ", dirname); 811 perror("opendir"); 812 return 0; 813 } 814 815 if(fontscale_name == NULL) 816 fontscale = stdout; 817 else 818 fontscale = fopen(fontscale_name, "wb"); 819 820 if(fontscale == NULL) { 821 fprintf(stderr, "%s: ", fontscale_name); 822 perror("fopen(w)"); 823 return 0; 824 } 825 826 while((entry = readdir(dirp)) != NULL) { 827 int have_face = 0; 828 char *xlfd_name = NULL; 829 xlfd = NULL; 830 831 if (xl) { 832 int dl = strlen (entry->d_name); 833 if (strcmp (entry->d_name + dl - xl, exclusionSuffix) == 0) 834 continue; 835 } 836 837 filename = dsprintf("%s%s", dirname, entry->d_name); 838 839 if(doBitmaps) 840 rc = bitmapIdentify(filename, &xlfd_name); 841 else 842 rc = 0; 843 844 if(rc < 0) 845 goto done; 846 847 if(rc == 0) { 848 ftrc = FT_New_Face(ft_library, filename, 0, &face); 849 if(ftrc) 850 goto done; 851 have_face = 1; 852 853 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 854 855 if(!isBitmap) { 856 /* Workaround for bitmap-only SFNT fonts */ 857 if(FT_IS_SFNT(face) && face->num_fixed_sizes > 0 && 858 strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) { 859 TT_MaxProfile *maxp; 860 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 861 if(maxp != NULL && maxp->maxContours == 0) 862 isBitmap = 1; 863 } 864 } 865 866 if(isBitmap) { 867 if(!doBitmaps) 868 goto done; 869 } else { 870 if(!doScalable) 871 goto done; 872 } 873 874 if(isBitmap) { 875 BDF_PropertyRec prop; 876 rc = FT_Get_BDF_Property(face, "FONT", &prop); 877 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 878 xlfd_name = malloc(strlen(prop.u.atom) + 1); 879 if(xlfd_name == NULL) 880 goto done; 881 strcpy(xlfd_name, prop.u.atom); 882 } 883 } 884 } 885 886 if(xlfd_name) { 887 /* We know it's a bitmap font, and we know its XLFD */ 888 int n = strlen(xlfd_name); 889 if(reencodeLegacy && 890 n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) { 891 char *s; 892 893 s = malloc(n - 10); 894 memcpy(s, xlfd_name, n - 11); 895 s[n - 11] = '\0'; 896 xlfd = listCons(s, xlfd); 897 } else { 898 /* Not a reencodable font -- skip all the rest of the loop body */ 899 putHash(entries, xlfd_name, entry->d_name, filePrio(entry->d_name)); 900 goto done; 901 } 902 } 903 904 if(!have_face) { 905 ftrc = FT_New_Face(ft_library, filename, 0, &face); 906 if(ftrc) 907 goto done; 908 have_face = 1; 909 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 910 911 if(!isBitmap) { 912 if(face->num_fixed_sizes > 0) { 913 TT_MaxProfile *maxp; 914 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 915 if(maxp != NULL && maxp->maxContours == 0) 916 isBitmap = 1; 917 } 918 } 919 } 920 921 if(xlfd == NULL) 922 xlfd = makeXLFD(entry->d_name, face, isBitmap); 923 924 found = 0; 925 926 for(lp = xlfd; lp; lp = lp->next) { 927 char buf[MAXFONTNAMELEN]; 928 for(encoding = encodings; encoding; encoding = encoding->next) { 929 if(checkEncoding(face, encoding->value)) { 930 found = 1; 931 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 932 lp->value, encoding->value); 933 putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); 934 } 935 } 936 for(encoding = extra_encodings; encoding; 937 encoding = encoding->next) { 938 if(checkExtraEncoding(face, encoding->value, found)) { 939 /* Do not set found! */ 940 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 941 lp->value, encoding->value); 942 putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); 943 } 944 } 945 } 946 done: 947 if(have_face) 948 FT_Done_Face(face); 949 deepDestroyList(xlfd); 950 xlfd = NULL; 951 free(filename); 952 } 953 954 closedir(dirp); 955 n = hashElements(entries); 956 fprintf(fontscale, "%d\n", n); 957 array = hashArray(entries, 1); 958 for(i = 0; i < n; i++) 959 fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key); 960 destroyHashArray(array); 961 entries = NULL; 962 if(fontscale_name) { 963 fclose(fontscale); 964 free(fontscale_name); 965 } 966 967 encodings: 968 encdir = dsprintf("%s%s", dirname, "encodings.dir"); 969 970 if(encdir == NULL) { 971 perror("encodings"); 972 exit(1); 973 } 974 unlink(encdir); 975 976 if (numEncodings) { 977 encfile = fopen(encdir, "w"); 978 if(encfile == NULL) { 979 perror("open(encodings.dir)"); 980 exit(1); 981 } 982 fprintf(encfile, "%d\n", numEncodings); 983 encodingsToDo = sortList(encodingsToDo); 984 for(lp = encodingsToDo; lp; lp = lp->next) { 985 fprintf(encfile, "%s\n", lp->value); 986 } 987 fclose (encfile); 988 } 989 990 free(dirname); 991 return 1; 992} 993 994#define CODE_IGNORED(c) ((c) < 0x20 || \ 995 ((c) >= 0x7F && (c) <= 0xA0) || \ 996 (c) == 0xAD || (c) == 0xF71B) 997 998static int 999checkEncoding(FT_Face face, char *encoding_name) 1000{ 1001 FontEncPtr encoding; 1002 FontMapPtr mapping; 1003 int i, j, c, koi8; 1004 char *n; 1005 1006 encoding = FontEncFind(encoding_name, NULL); 1007 if(!encoding) 1008 return 0; 1009 1010 /* An encoding is ``small'' if one of the following is true: 1011 - it is linear and has no more than 256 codepoints; or 1012 - it is a matrix encoding and has no more than one column. 1013 1014 For small encodings using Unicode indices, we require perfect 1015 coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility. 1016 1017 For large encodings, we require coverage up to bigEncodingFuzz. 1018 1019 For encodings using PS names (currently Adobe Standard and 1020 Adobe Symbol only), we require perfect coverage. */ 1021 1022 1023 if(FT_Has_PS_Glyph_Names(face)) { 1024 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1025 if(mapping->type == FONT_ENCODING_POSTSCRIPT) { 1026 if(encoding->row_size > 0) { 1027 for(i = encoding->first; i < encoding->size; i++) { 1028 for(j = encoding->first_col; 1029 j < encoding->row_size; 1030 j++) { 1031 n = FontEncName((i<<8) | j, mapping); 1032 if(n && FT_Get_Name_Index(face, n) == 0) { 1033 return 0; 1034 } 1035 } 1036 } 1037 return 1; 1038 } else { 1039 for(i = encoding->first; i < encoding->size; i++) { 1040 n = FontEncName(i, mapping); 1041 if(n && FT_Get_Name_Index(face, n) == 0) { 1042 return 0; 1043 } 1044 } 1045 return 1; 1046 } 1047 } 1048 } 1049 } 1050 1051 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1052 if(find_cmap(mapping->type, mapping->pid, mapping->eid, face)) { 1053 int total = 0, failed = 0; 1054 if(encoding->row_size > 0) { 1055 int estimate = 1056 (encoding->size - encoding->first) * 1057 (encoding->row_size - encoding->first_col); 1058 for(i = encoding->first; i < encoding->size; i++) { 1059 for(j = encoding->first_col; 1060 j < encoding->row_size; 1061 j++) { 1062 c = FontEncRecode((i<<8) | j, mapping); 1063 if(CODE_IGNORED(c)) { 1064 continue; 1065 } else { 1066 if(FT_Get_Char_Index(face, c) == 0) { 1067 failed++; 1068 } 1069 total++; 1070 if((encoding->size <= 1 && failed > 0) || 1071 ((float)failed >= bigEncodingFuzz * estimate)) { 1072 return 0; 1073 } 1074 } 1075 } 1076 } 1077 if((float)failed >= total * bigEncodingFuzz) 1078 return 0; 1079 else 1080 return 1; 1081 } else { 1082 int estimate = encoding->size - encoding->first; 1083 /* For the KOI8 encodings, we ignore the lack of 1084 linedrawing and pseudo-math characters */ 1085 if(strncmp(encoding->name, "koi8-", 5) == 0) 1086 koi8 = 1; 1087 else 1088 koi8 = 0; 1089 for(i = encoding->first; i < encoding->size; i++) { 1090 c = FontEncRecode(i, mapping); 1091 if(CODE_IGNORED(c) || 1092 (koi8 && ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) { 1093 continue; 1094 } else { 1095 if(FT_Get_Char_Index(face, c) == 0) { 1096 failed++; 1097 } 1098 total++; 1099 if((encoding->size <= 256 && failed > 0) || 1100 ((float)failed >= bigEncodingFuzz * estimate)) { 1101 return 0; 1102 } 1103 } 1104 } 1105 if((float)failed >= total * bigEncodingFuzz) 1106 return 0; 1107 else 1108 return 1; 1109 } 1110 } 1111 } 1112 return 0; 1113} 1114 1115static int 1116find_cmap(int type, int pid, int eid, FT_Face face) 1117{ 1118 int i, n, rc; 1119 FT_CharMap cmap = NULL; 1120 1121 n = face->num_charmaps; 1122 1123 switch(type) { 1124 case FONT_ENCODING_TRUETYPE: /* specific cmap */ 1125 for(i=0; i<n; i++) { 1126 cmap = face->charmaps[i]; 1127 if(cmap->platform_id == pid && cmap->encoding_id == eid) { 1128 rc = FT_Set_Charmap(face, cmap); 1129 if(rc == 0) 1130 return 1; 1131 } 1132 } 1133 break; 1134 case FONT_ENCODING_UNICODE: /* any Unicode cmap */ 1135 /* prefer Microsoft Unicode */ 1136 for(i=0; i<n; i++) { 1137 cmap = face->charmaps[i]; 1138 if(cmap->platform_id == TT_PLATFORM_MICROSOFT && 1139 cmap->encoding_id == TT_MS_ID_UNICODE_CS) { 1140 rc = FT_Set_Charmap(face, cmap); 1141 if(rc == 0) 1142 return 1; 1143 } 1144 } 1145 /* Try Apple Unicode */ 1146 for(i=0; i<n; i++) { 1147 cmap = face->charmaps[i]; 1148 if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) { 1149 rc = FT_Set_Charmap(face, cmap); 1150 if(rc == 0) 1151 return 1; 1152 } 1153 } 1154 /* ISO Unicode? */ 1155 for(i=0; i<n; i++) { 1156 cmap = face->charmaps[i]; 1157 if(cmap->platform_id == TT_PLATFORM_ISO) { 1158 rc = FT_Set_Charmap(face, cmap); 1159 if(rc == 0) 1160 return 1; 1161 } 1162 } 1163 break; 1164 default: 1165 return 0; 1166 } 1167 return 0; 1168} 1169 1170static int 1171checkExtraEncoding(FT_Face face, char *encoding_name, int found) 1172{ 1173 int c; 1174 1175 if(strcasecmp(encoding_name, "iso10646-1") == 0) { 1176 if(doISO10646_1_encoding && find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) { 1177 int found = 0; 1178 /* Export as Unicode if there are at least 15 BMP 1179 characters that are not a space or ignored. */ 1180 for(c = 0x21; c < 0x10000; c++) { 1181 if(CODE_IGNORED(c)) 1182 continue; 1183 if(FT_Get_Char_Index(face, c) > 0) 1184 found++; 1185 if(found >= 15) 1186 return 1; 1187 } 1188 return 0; 1189 } else 1190 return 0; 1191 } else if(strcasecmp(encoding_name, "microsoft-symbol") == 0) { 1192 if(find_cmap(FONT_ENCODING_TRUETYPE, 1193 TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, 1194 face)) 1195 return 1; 1196 else 1197 return 0; 1198 } else if(strcasecmp(encoding_name, "adobe-fontspecific") == 0) { 1199 if(!found) { 1200 if(FT_Has_PS_Glyph_Names(face)) 1201 return 1; 1202 else 1203 return 0; 1204 } else 1205 return 0; 1206 } else { 1207 fprintf(stderr, "Unknown extra encoding %s\n", encoding_name); 1208 return 0; 1209 } 1210} 1211 1212static const char* 1213notice_foundry(const char *notice) 1214{ 1215 int i; 1216 for(i = 0; i < countof(notice_foundries); i++) 1217 if(notice && strstr(notice, notice_foundries[i][0])) 1218 return notice_foundries[i][1]; 1219 return NULL; 1220} 1221 1222static int 1223vendor_match(const signed char *vendor, const char *vendor_string) 1224{ 1225 /* vendor is not necessarily NUL-terminated. */ 1226 int i, len; 1227 len = strlen(vendor_string); 1228 if(memcmp(vendor, vendor_string, len) != 0) 1229 return 0; 1230 for(i = len; i < 4; i++) 1231 if(vendor[i] != ' ' && vendor[i] != '\0') 1232 return 0; 1233 return 1; 1234} 1235 1236static const char* 1237vendor_foundry(const signed char *vendor) 1238{ 1239 int i; 1240 for(i = 0; i < countof(vendor_foundries); i++) 1241 if(vendor_match(vendor, vendor_foundries[i][0])) 1242 return vendor_foundries[i][1]; 1243 return NULL; 1244} 1245 1246static int 1247readEncodings(ListPtr encodings, char *dirname) 1248{ 1249 char *fullname; 1250 DIR *dirp; 1251 struct dirent *file; 1252 char **names, **name; 1253 1254 if(strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/') 1255 dirname[strlen(dirname) - 1] = '\0'; 1256 1257 dirp = opendir(dirname); 1258 if(dirp == NULL) { 1259 perror("opendir"); 1260 return -1; 1261 } 1262 1263 while((file = readdir(dirp)) != NULL) { 1264 fullname = dsprintf("%s/%s", dirname, file->d_name); 1265 if(fullname == NULL) { 1266 fprintf(stderr, "Couldn't allocate fullname\n"); 1267 closedir(dirp); 1268 return -1; 1269 } 1270 1271 names = FontEncIdentify(fullname); 1272 if(!names) 1273 continue; 1274 1275 for(name = names; *name; name++) { 1276 if(fullname[0] != '/' && !relative) { 1277 char *n; 1278 n = dsprintf("%s%s", encodingPrefix, fullname); 1279 if(n == NULL) { 1280 fprintf(stderr, "Couldn't allocate name\n"); 1281 closedir(dirp); 1282 return -1; 1283 } 1284 encodingsToDo = listConsF(encodingsToDo, "%s %s", *name, n); 1285 free(n); 1286 } else { 1287 encodingsToDo = 1288 listConsF(encodingsToDo, "%s %s", *name, fullname); 1289 } 1290 if(encodingsToDo == NULL) { 1291 fprintf(stderr, "Couldn't allocate encodings\n"); 1292 closedir(dirp); 1293 return -1; 1294 } 1295 } 1296 free(names); /* only the spine */ 1297 } 1298 closedir(dirp); 1299 return 0; 1300} 1301