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