mkfontscale.c revision ea6ae205
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 if(strcmp(filename + n - 2, ".Z") == 0) 744 return 2; 745 if(strcmp(filename + n - 4, ".bdf") == 0) 746 return 1; 747 if(strcmp(filename + n - 4, ".BDF") == 0) 748 return 1; 749 return 0; 750} 751 752static int 753doDirectory(char *dirname_given, int numEncodings, ListPtr encodingsToDo) 754{ 755 char *dirname, *fontscale_name, *filename, *encdir; 756 FILE *fontscale, *encfile; 757 DIR *dirp; 758 struct dirent *entry; 759 FT_Error ftrc; 760 FT_Face face; 761 ListPtr encoding, xlfd, lp; 762 HashTablePtr entries; 763 HashBucketPtr *array; 764 int i, n, found, rc; 765 int isBitmap=0,xl=0; 766 767 if (exclusionSuffix) 768 xl = strlen (exclusionSuffix); 769 770 i = strlen(dirname_given); 771 if(i == 0) 772 dirname = dsprintf("./"); 773 else if(dirname_given[i - 1] != '/') 774 dirname = dsprintf("%s/", dirname_given); 775 else 776 dirname = dsprintf("%s", dirname_given); 777 778 if(dirname == NULL) { 779 perror("dirname"); 780 exit(1); 781 } 782 783 if (onlyEncodings) 784 goto encodings; 785 786 entries = makeHashTable(); 787 if(doBitmaps && !doScalable) { 788 readFontScale(entries, dirname); 789 } 790 791 if(strcmp(outfilename, "-") == 0) 792 fontscale_name = NULL; 793 else { 794 if(outfilename[0] == '/') 795 fontscale_name = dsprintf("%s", outfilename); 796 else 797 fontscale_name = dsprintf("%s%s", dirname, outfilename); 798 if(fontscale_name == NULL) { 799 perror("fontscale_name"); 800 exit(1); 801 } 802 } 803 804 dirp = opendir(dirname); 805 if(dirp == NULL) { 806 fprintf(stderr, "%s: ", dirname); 807 perror("opendir"); 808 return 0; 809 } 810 811 if(fontscale_name == NULL) 812 fontscale = stdout; 813 else 814 fontscale = fopen(fontscale_name, "wb"); 815 816 if(fontscale == NULL) { 817 fprintf(stderr, "%s: ", fontscale_name); 818 perror("fopen(w)"); 819 return 0; 820 } 821 822 while((entry = readdir(dirp)) != NULL) { 823 int have_face = 0; 824 char *xlfd_name = NULL; 825 xlfd = NULL; 826 827 if (xl) { 828 int dl = strlen (entry->d_name); 829 if (strcmp (entry->d_name + dl - xl, exclusionSuffix) == 0) 830 continue; 831 } 832 833 filename = dsprintf("%s%s", dirname, entry->d_name); 834 835 if(doBitmaps) 836 rc = bitmapIdentify(filename, &xlfd_name); 837 else 838 rc = 0; 839 840 if(rc < 0) 841 goto done; 842 843 if(rc == 0) { 844 ftrc = FT_New_Face(ft_library, filename, 0, &face); 845 if(ftrc) 846 goto done; 847 have_face = 1; 848 849 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 850 851 if(!isBitmap) { 852 /* Workaround for bitmap-only SFNT fonts */ 853 if(FT_IS_SFNT(face) && face->num_fixed_sizes > 0 && 854 strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) { 855 TT_MaxProfile *maxp; 856 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 857 if(maxp != NULL && maxp->maxContours == 0) 858 isBitmap = 1; 859 } 860 } 861 862 if(isBitmap) { 863 if(!doBitmaps) 864 goto done; 865 } else { 866 if(!doScalable) 867 goto done; 868 } 869 870 if(isBitmap) { 871 BDF_PropertyRec prop; 872 rc = FT_Get_BDF_Property(face, "FONT", &prop); 873 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 874 xlfd_name = malloc(strlen(prop.u.atom) + 1); 875 if(xlfd_name == NULL) 876 goto done; 877 strcpy(xlfd_name, prop.u.atom); 878 } 879 } 880 } 881 882 if(xlfd_name) { 883 /* We know it's a bitmap font, and we know its XLFD */ 884 int n = strlen(xlfd_name); 885 if(reencodeLegacy && 886 n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) { 887 char *s; 888 889 s = malloc(n - 10); 890 memcpy(s, xlfd_name, n - 11); 891 s[n - 11] = '\0'; 892 xlfd = listCons(s, xlfd); 893 } else { 894 /* Not a reencodable font -- skip all the rest of the loop body */ 895 putHash(entries, xlfd_name, entry->d_name, filePrio(entry->d_name)); 896 goto done; 897 } 898 } 899 900 if(!have_face) { 901 ftrc = FT_New_Face(ft_library, filename, 0, &face); 902 if(ftrc) 903 goto done; 904 have_face = 1; 905 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 906 907 if(!isBitmap) { 908 if(face->num_fixed_sizes > 0) { 909 TT_MaxProfile *maxp; 910 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 911 if(maxp != NULL && maxp->maxContours == 0) 912 isBitmap = 1; 913 } 914 } 915 } 916 917 if(xlfd == NULL) 918 xlfd = makeXLFD(entry->d_name, face, isBitmap); 919 920 found = 0; 921 922 for(lp = xlfd; lp; lp = lp->next) { 923 char buf[MAXFONTNAMELEN]; 924 for(encoding = encodings; encoding; encoding = encoding->next) { 925 if(checkEncoding(face, encoding->value)) { 926 found = 1; 927 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 928 lp->value, encoding->value); 929 putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); 930 } 931 } 932 for(encoding = extra_encodings; encoding; 933 encoding = encoding->next) { 934 if(checkExtraEncoding(face, encoding->value, found)) { 935 /* Do not set found! */ 936 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 937 lp->value, encoding->value); 938 putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); 939 } 940 } 941 } 942 done: 943 if(have_face) { 944 FT_Done_Face(face); 945 have_face = 0; 946 } 947 deepDestroyList(xlfd); 948 xlfd = NULL; 949 free(filename); 950 } 951 952 closedir(dirp); 953 n = hashElements(entries); 954 fprintf(fontscale, "%d\n", n); 955 array = hashArray(entries, 1); 956 for(i = 0; i < n; i++) 957 fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key); 958 destroyHashArray(array); 959 entries = NULL; 960 if(fontscale_name) { 961 fclose(fontscale); 962 free(fontscale_name); 963 } 964 965 encodings: 966 encdir = dsprintf("%s%s", dirname, "encodings.dir"); 967 968 if(encdir == NULL) { 969 perror("encodings"); 970 exit(1); 971 } 972 unlink(encdir); 973 974 if (numEncodings) { 975 encfile = fopen(encdir, "w"); 976 if(encfile == NULL) { 977 perror("open(encodings.dir)"); 978 exit(1); 979 } 980 fprintf(encfile, "%d\n", numEncodings); 981 for(lp = encodingsToDo; lp; lp = lp->next) { 982 fprintf(encfile, "%s\n", lp->value); 983 } 984 fclose (encfile); 985 } 986 987 free(dirname); 988 return 1; 989} 990 991#define CODE_IGNORED(c) ((c) < 0x20 || \ 992 ((c) >= 0x7F && (c) <= 0xA0) || \ 993 (c) == 0xAD || (c) == 0xF71B) 994 995static int 996checkEncoding(FT_Face face, char *encoding_name) 997{ 998 FontEncPtr encoding; 999 FontMapPtr mapping; 1000 int i, j, c, koi8; 1001 char *n; 1002 1003 encoding = FontEncFind(encoding_name, NULL); 1004 if(!encoding) 1005 return 0; 1006 1007 /* An encoding is ``small'' if one of the following is true: 1008 - it is linear and has no more than 256 codepoints; or 1009 - it is a matrix encoding and has no more than one column. 1010 1011 For small encodings using Unicode indices, we require perfect 1012 coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility. 1013 1014 For large encodings, we require coverage up to bigEncodingFuzz. 1015 1016 For encodings using PS names (currently Adobe Standard and 1017 Adobe Symbol only), we require perfect coverage. */ 1018 1019 1020 if(FT_Has_PS_Glyph_Names(face)) { 1021 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1022 if(mapping->type == FONT_ENCODING_POSTSCRIPT) { 1023 if(encoding->row_size > 0) { 1024 for(i = encoding->first; i < encoding->size; i++) { 1025 for(j = encoding->first_col; 1026 j < encoding->row_size; 1027 j++) { 1028 n = FontEncName((i<<8) | j, mapping); 1029 if(n && FT_Get_Name_Index(face, n) == 0) { 1030 return 0; 1031 } 1032 } 1033 } 1034 return 1; 1035 } else { 1036 for(i = encoding->first; i < encoding->size; i++) { 1037 n = FontEncName(i, mapping); 1038 if(n && FT_Get_Name_Index(face, n) == 0) { 1039 return 0; 1040 } 1041 } 1042 return 1; 1043 } 1044 } 1045 } 1046 } 1047 1048 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1049 if(find_cmap(mapping->type, mapping->pid, mapping->eid, face)) { 1050 int total = 0, failed = 0; 1051 if(encoding->row_size > 0) { 1052 int estimate = 1053 (encoding->size - encoding->first) * 1054 (encoding->row_size - encoding->first_col); 1055 for(i = encoding->first; i < encoding->size; i++) { 1056 for(j = encoding->first_col; 1057 j < encoding->row_size; 1058 j++) { 1059 c = FontEncRecode((i<<8) | j, mapping); 1060 if(CODE_IGNORED(c)) { 1061 continue; 1062 } else { 1063 if(FT_Get_Char_Index(face, c) == 0) { 1064 failed++; 1065 } 1066 total++; 1067 if((encoding->size <= 1 && failed > 0) || 1068 ((float)failed >= bigEncodingFuzz * estimate)) { 1069 return 0; 1070 } 1071 } 1072 } 1073 } 1074 if((float)failed >= total * bigEncodingFuzz) 1075 return 0; 1076 else 1077 return 1; 1078 } else { 1079 int estimate = encoding->size - encoding->first; 1080 /* For the KOI8 encodings, we ignore the lack of 1081 linedrawing and pseudo-math characters */ 1082 if(strncmp(encoding->name, "koi8-", 5) == 0) 1083 koi8 = 1; 1084 else 1085 koi8 = 0; 1086 for(i = encoding->first; i < encoding->size; i++) { 1087 c = FontEncRecode(i, mapping); 1088 if(CODE_IGNORED(c) || 1089 (koi8 && ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) { 1090 continue; 1091 } else { 1092 if(FT_Get_Char_Index(face, c) == 0) { 1093 failed++; 1094 } 1095 total++; 1096 if((encoding->size <= 256 && failed > 0) || 1097 ((float)failed >= bigEncodingFuzz * estimate)) { 1098 return 0; 1099 } 1100 } 1101 } 1102 if((float)failed >= total * bigEncodingFuzz) 1103 return 0; 1104 else 1105 return 1; 1106 } 1107 } 1108 } 1109 return 0; 1110} 1111 1112static int 1113find_cmap(int type, int pid, int eid, FT_Face face) 1114{ 1115 int i, n, rc; 1116 FT_CharMap cmap = NULL; 1117 1118 n = face->num_charmaps; 1119 1120 switch(type) { 1121 case FONT_ENCODING_TRUETYPE: /* specific cmap */ 1122 for(i=0; i<n; i++) { 1123 cmap = face->charmaps[i]; 1124 if(cmap->platform_id == pid && cmap->encoding_id == eid) { 1125 rc = FT_Set_Charmap(face, cmap); 1126 if(rc == 0) 1127 return 1; 1128 } 1129 } 1130 break; 1131 case FONT_ENCODING_UNICODE: /* any Unicode cmap */ 1132 /* prefer Microsoft Unicode */ 1133 for(i=0; i<n; i++) { 1134 cmap = face->charmaps[i]; 1135 if(cmap->platform_id == TT_PLATFORM_MICROSOFT && 1136 cmap->encoding_id == TT_MS_ID_UNICODE_CS) { 1137 rc = FT_Set_Charmap(face, cmap); 1138 if(rc == 0) 1139 return 1; 1140 } 1141 } 1142 /* Try Apple Unicode */ 1143 for(i=0; i<n; i++) { 1144 cmap = face->charmaps[i]; 1145 if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) { 1146 rc = FT_Set_Charmap(face, cmap); 1147 if(rc == 0) 1148 return 1; 1149 } 1150 } 1151 /* ISO Unicode? */ 1152 for(i=0; i<n; i++) { 1153 cmap = face->charmaps[i]; 1154 if(cmap->platform_id == TT_PLATFORM_ISO) { 1155 rc = FT_Set_Charmap(face, cmap); 1156 if(rc == 0) 1157 return 1; 1158 } 1159 } 1160 break; 1161 default: 1162 return 0; 1163 } 1164 return 0; 1165} 1166 1167static int 1168checkExtraEncoding(FT_Face face, char *encoding_name, int found) 1169{ 1170 int c; 1171 1172 if(strcasecmp(encoding_name, "iso10646-1") == 0) { 1173 if(doISO10646_1_encoding && find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) { 1174 int found = 0; 1175 /* Export as Unicode if there are at least 15 BMP 1176 characters that are not a space or ignored. */ 1177 for(c = 0x21; c < 0x10000; c++) { 1178 if(CODE_IGNORED(c)) 1179 continue; 1180 if(FT_Get_Char_Index(face, c) > 0) 1181 found++; 1182 if(found >= 15) 1183 return 1; 1184 } 1185 return 0; 1186 } else 1187 return 0; 1188 } else if(strcasecmp(encoding_name, "microsoft-symbol") == 0) { 1189 if(find_cmap(FONT_ENCODING_TRUETYPE, 1190 TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, 1191 face)) 1192 return 1; 1193 else 1194 return 0; 1195 } else if(strcasecmp(encoding_name, "adobe-fontspecific") == 0) { 1196 if(!found) { 1197 if(FT_Has_PS_Glyph_Names(face)) 1198 return 1; 1199 else 1200 return 0; 1201 } else 1202 return 0; 1203 } else { 1204 fprintf(stderr, "Unknown extra encoding %s\n", encoding_name); 1205 return 0; 1206 } 1207} 1208 1209static char* 1210notice_foundry(char *notice) 1211{ 1212 int i; 1213 for(i = 0; i < countof(notice_foundries); i++) 1214 if(notice && strstr(notice, notice_foundries[i][0])) 1215 return notice_foundries[i][1]; 1216 return NULL; 1217} 1218 1219static int 1220vendor_match(signed char *vendor, char *vendor_string) 1221{ 1222 /* vendor is not necessarily NUL-terminated. */ 1223 int i, len; 1224 len = strlen(vendor_string); 1225 if(memcmp(vendor, vendor_string, len) != 0) 1226 return 0; 1227 for(i = len; i < 4; i++) 1228 if(vendor[i] != ' ' && vendor[i] != '\0') 1229 return 0; 1230 return 1; 1231} 1232 1233static char* 1234vendor_foundry(signed char *vendor) 1235{ 1236 int i; 1237 for(i = 0; i < countof(vendor_foundries); i++) 1238 if(vendor_match(vendor, vendor_foundries[i][0])) 1239 return vendor_foundries[i][1]; 1240 return NULL; 1241} 1242 1243static int 1244readEncodings(ListPtr encodings, char *dirname) 1245{ 1246 char *fullname; 1247 DIR *dirp; 1248 struct dirent *file; 1249 char **names, **name; 1250 1251 if(strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/') 1252 dirname[strlen(dirname) - 1] = '\0'; 1253 1254 dirp = opendir(dirname); 1255 if(dirp == NULL) { 1256 perror("opendir"); 1257 return -1; 1258 } 1259 1260 while((file = readdir(dirp)) != NULL) { 1261 fullname = dsprintf("%s/%s", dirname, file->d_name); 1262 if(fullname == NULL) { 1263 fprintf(stderr, "Couldn't allocate fullname\n"); 1264 closedir(dirp); 1265 return -1; 1266 } 1267 1268 names = FontEncIdentify(fullname); 1269 if(!names) 1270 continue; 1271 1272 for(name = names; *name; name++) { 1273 if(fullname[0] != '/' && !relative) { 1274 char *n; 1275 n = dsprintf("%s%s", encodingPrefix, fullname); 1276 if(n == NULL) { 1277 fprintf(stderr, "Couldn't allocate name\n"); 1278 closedir(dirp); 1279 return -1; 1280 } 1281 encodingsToDo = listConsF(encodingsToDo, "%s %s", *name, n); 1282 free(n); 1283 } else { 1284 encodingsToDo = 1285 listConsF(encodingsToDo, "%s %s", *name, fullname); 1286 } 1287 if(encodingsToDo == NULL) { 1288 fprintf(stderr, "Couldn't allocate encodings\n"); 1289 closedir(dirp); 1290 return -1; 1291 } 1292 } 1293 free(names); /* only the spine */ 1294 } 1295 closedir(dirp); 1296 return 0; 1297} 1298