Author: jch Date: 2003-06-05 11:54:39 -0500 (Thu, 05 Jun 2003) New Revision: 147
Added: people/jch/xc/programs/mkfontscale/hash.c people/jch/xc/programs/mkfontscale/hash.h people/jch/xc/programs/mkfontscale/ident.c people/jch/xc/programs/mkfontscale/ident.h Modified: people/jch/xc/programs/mkfontscale/Imakefile people/jch/xc/programs/mkfontscale/list.c people/jch/xc/programs/mkfontscale/list.h people/jch/xc/programs/mkfontscale/mkfontscale.c people/jch/xc/programs/mkfontscale/mkfontscale.man Log: Modified mkfontscale to process bitmap fonts, both legacy formats (BDF, PCF) and formats supported by FreeType (such as bitmap-only TTF fonts). Mkfontscale -b -s -l should now be a drop-in replacement for mkfontdir. Modified: people/jch/xc/programs/mkfontscale/mkfontscale.man ============================================================================== --- people/jch/xc/programs/mkfontscale/mkfontscale.man 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/mkfontscale.man 2003-06-05 16:54:39 UTC (rev 147) @@ -6,16 +6,27 @@ .SH SYNOPSIS .B mkfontscale [ +.B \-b +] [ +.B \-s +] [ .B \-o .I filename -] -[ -.B \-e +] [ +.B \-x .I encoding ] \|.\|.\|. [ .B \-f .I fuzz ] [ +.B \-l +] [ +.B \-e +.I directory +] [ +.B \-p +.I prefix +] [ .B \-\- ] [ .I directory @@ -37,19 +48,30 @@ program. .SH OPTIONS .TP +.B \-b +read bitmap fonts. By default, bitmap fonts are ignored. +.TP +.B \-s +ignore scalable fonts. By default, scalable fonts are read. If +.B \-b +is set, this flag has the side effect of enabling the reading of +.B fonts.scale +files. .BI \-o " filename" send program output to .IR filename ; default is -.BR fonts.scale . -If +.B fonts.scale +if bitmap fonts are not being read, and +.B fonts.dir +if they are. If .I filename is relative, it is created in the directory being processed. If it is the special value .BR \- , output is written to standard output. .TP -.BI \-e " encoding" +.BI \-x " encoding" add .I encoding to the list of encodings searched for. @@ -59,15 +81,44 @@ .I fuzz percent. Defaults to 2%. .TP +.B \-l +Write +.B fonts.dir +files suitable for implementations that cannot reencode legacy fonts +(BDF and PCF). By default, it is assumed that the implementation can +reencode Unicode-encoded legacy fonts. +.TP +.B -e +specifies a directory with encoding files. Every such +directory is scanned for encoding files, the list of which is then +written to an "encodings.dir" file in every font directory. +.TP +.B -p +Specifies a prefix that is prepended to the encoding file path names +when they are written to the "encodings.dir" file. The prefix is +prepended litterally: if a `/' is required between the prefix and the path +names, it must be supplied explicitly as part of the prefix. +.TP .B \-\- end of options. .SH SEE ALSO X(__miscmansuffix__), Xserver(1), mkfontdir(1), ttmkfdir(1), xfs(1), xset(1) .SH NOTES +The format of the +.BR fonts.scale , +.B fonts.dir +and +.B encodings.dir +files is documented in the mkfontdir(1) manual page. + .B Mkfontscale will overwrite any .B fonts.scale file even if it has been hand-edited. + +.B mkfontscale -b -l +is equivalent to +.BR mkfontdir . .SH AUTHOR .B Mkfontscale was written by Juliusz Chroboczek <[EMAIL PROTECTED]> for the XFree86 Modified: people/jch/xc/programs/mkfontscale/list.h ============================================================================== --- people/jch/xc/programs/mkfontscale/list.h 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/list.h 2003-06-05 16:54:39 UTC (rev 147) @@ -40,16 +40,3 @@ void destroyList(ListPtr old); void deepDestroyList(ListPtr old); -typedef struct _Acell { - char *key; - char *value; - int prio; -} AcellRec, *AcellPtr; - -AcellPtr acell(ListPtr alist); -AcellPtr assoc(char *key, ListPtr alist); -ListPtr acons(char *key, char *value, ListPtr alist); -ListPtr aconsPrio(char *key, char *value, int prio, ListPtr alist); - -void destroyAlist(ListPtr old); -void deepDestroyAlist(ListPtr old); Added: people/jch/xc/programs/mkfontscale/ident.c ============================================================================== --- people/jch/xc/programs/mkfontscale/ident.c 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/ident.c 2003-06-05 16:54:39 UTC (rev 147) @@ -0,0 +1,330 @@ +/* + Copyright (c) 2003 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* The function identifyBitmap returns -1 if filename is definitively not + a font file, 1 if it is a single-face bitmap font with a XLFD name, + and 0 if it should be processed normally. identifyBitmap is + much faster than parsing the whole font. */ + +#include <stdlib.h> +#include "zlib.h" + +#define PCF_VERSION (('p'<<24)|('c'<<16)|('f'<<8)|1) +#define PCF_PROPERTIES (1 << 0) + +typedef struct _Prop { + unsigned name; + int isString; + unsigned value; +} PropRec, *PropPtr; + +static int pcfIdentify(gzFile f, char **name); +static int bdfIdentify(gzFile f, char **name); + +static int +getLSB32(gzFile f) +{ + int rc; + unsigned char c[4]; + + rc = gzread(f, c, 4); + if(rc != 4) + return -1; + return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); +} + +static int +getInt8(gzFile f, int format) +{ + unsigned char c; + int rc; + + rc = gzread(f, &c, 1); + if(rc != 1) + return -1; + return c; +} + +static int +getInt32(gzFile f, int format) +{ + int rc; + unsigned char c[4]; + + rc = gzread(f, c, 4); + if(rc != 4) + return -1; + + if(format & (1 << 2)) { + return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3]); + } else { + return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); + } +} + +static int +pcfskip(gzFile f, int n) +{ + char buf[32]; + int i, rc; + while(n > 0) { + i = (n > 32 ? 32 : n); + rc = gzread(f, buf, i); + if(rc != i) + return -1; + n -= rc; + } + return 1; +} + +int +bitmapIdentify(char *filename, char **name) +{ + gzFile f; + int magic; + + f = gzopen(filename, "rb"); + if(f == NULL) + return -1; + + magic = getLSB32(f); + if(magic == PCF_VERSION) + return pcfIdentify(f, name); + else if(magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24)) + return bdfIdentify(f, name); + + gzclose(f); + return 0; +} + +static int +pcfIdentify(gzFile f, char **name) +{ + int prop_position; + PropPtr props = NULL; + int version, format, count, prop_size, nprops, i, string_size, rc; + char *strings = NULL, *s; + char buf[4]; + + count = getLSB32(f); + if(count <= 0) + goto fail; + + prop_position = -1; + for(i = 0; i < count; i++) { + int type, format, size, offset; + type = getLSB32(f); + format = getLSB32(f); + size = getLSB32(f); + offset = getLSB32(f); + if(type == PCF_PROPERTIES) { + prop_position = offset; + prop_size = size; + break; + } + } + if(prop_position < 0) + goto fail; + + rc = gzseek(f, prop_position, SEEK_SET); + if(rc < 0) + goto fail; + + format = getLSB32(f); + if((format & 0xFFFFFF00) != 0) + goto fail; + nprops = getInt32(f, format); + if(nprops <= 0 || nprops > 1000) + goto fail; + props = malloc(nprops * sizeof(PropRec)); + if(props == NULL) + goto fail; + + for(i = 0; i < nprops; i++) { + props[i].name = getInt32(f, format); + props[i].isString = getInt8(f, format); + props[i].value = getInt32(f, format); + } + if(nprops & 3) { + rc = pcfskip(f, 4 - (nprops & 3)); + if(rc < 0) + goto fail; + } + + string_size = getInt32(f, format); + if(string_size < 0 || string_size > 100000) + goto fail; + strings = malloc(string_size); + if(!strings) + goto fail; + + rc = gzread(f, strings, string_size); + if(rc != string_size) + goto fail; + + for(i = 0; i < nprops; i++) { + if(!props[i].isString || + props[i].name >= string_size - 4 || + props[i].value >= string_size) + continue; + if(strcmp(strings + props[i].name, "FONT") == 0) + break; + } + + if(i >= nprops) + goto fail; + + s = malloc(strlen(strings + props[i].value) + 1); + if(s == NULL) + goto fail; + strcpy(s, strings + props[i].value); + *name = s; + free(strings); + free(props); + gzclose(f); + return 1; + + fail: + if(strings) free(strings); + if(props) free(props); + gzclose(f); + return 0; +} + +#define NKEY 20 + +static char* +getKeyword(gzFile *f, int *eol) +{ + static char keyword[NKEY + 1]; + int c, i; + i = 0; + while(i < NKEY) { + c = gzgetc(f); + if(c == ' ' || c == '\n') { + if(i <= 0) + return NULL; + if(eol) + *eol = (c == '\n'); + keyword[i] = '\0'; + return keyword; + } + if(c < 'A' || c > 'Z') + return NULL; + keyword[i++] = c; + } + return NULL; +} + +static int +bdfskip(gzFile *f) +{ + int c; + do { + c = gzgetc(f); + } while(c >= 0 && c != '\n'); + if(c < 0) + return -1; + return 1; +} + +static char * +bdfend(gzFile *f) +{ + int c; + char *buf = NULL; + int bufsize = 0; + int i = 0; + + do { + c = gzgetc(f); + } while (c == ' '); + + while(i < 1000) { + if(c < 0 || (c == '\n' && i == 0)) { + goto fail; + } + if(bufsize < i + 1) { + char *newbuf; + if(bufsize == 0) { + bufsize = 20; + newbuf = malloc(bufsize); + } else { + bufsize = 2 * bufsize; + newbuf = realloc(buf, bufsize); + } + if(newbuf == NULL) + goto fail; + buf = newbuf; + } + if(c == '\n') { + buf[i] = '\0'; + return buf; + } + buf[i++] = c; + c = gzgetc(f); + } + + fail: + if(buf) + free(buf); + return NULL; +} + +static int +bdfIdentify(gzFile f, char **name) +{ + char *k; + int rc; + int eol; + /* bitmapIdentify already read "STAR", so we need to check for + "TFONT" */ + k = getKeyword(f, &eol); + if(k == NULL || eol) + goto fail; + if(strcmp(k, "TFONT") != 0) + goto fail; + while(1) { + if(!eol) { + rc = bdfskip(f); + if(rc < 0) + goto fail; + } + k = getKeyword(f, &eol); + if(k == NULL) + goto fail; + else if(strcmp(k, "FONT") == 0) { + if(eol) + goto fail; + k = bdfend(f); + if(k == NULL) + goto fail; + *name = k; + gzclose(f); + return 1; + } else if(strcmp(k, "CHARS") == 0) + goto fail; + } + fail: + gzclose(f); + return 0; +} Added: people/jch/xc/programs/mkfontscale/hash.c ============================================================================== --- people/jch/xc/programs/mkfontscale/hash.c 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/hash.c 2003-06-05 16:54:39 UTC (rev 147) @@ -0,0 +1,236 @@ +/* + Copyright (c) 2003 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include "hash.h" +#include "list.h" + +#define LOG2_NUMBUCKETS 10 +#define NUMBUCKETS (1 << LOG2_NUMBUCKETS) + +static unsigned +hash(char *string) +{ + int i; + unsigned u = 0; + for(i = 0; string[i] != '\0'; i++) + u = (u<<5) + (u >> (LOG2_NUMBUCKETS - 5)) + (unsigned char)string[i]; + return (u & (NUMBUCKETS - 1)); +} + +static char +lwr(char a) +{ + if(a >= 'A' && a <= 'Z') + return a | 0x20; + else + return a; +} + +static void +strcpy_lwr(char *dst, char *src) +{ + while(1) { + *dst = lwr(*src); + if(*src == '\0') + break; + src++; + dst++; + } +} + +static int +strcmp_lwr(char *a, char *b) +{ + while(*a != '\0' && *b != '\0') { + if(lwr(*a) != lwr(*b)) { + if(lwr(*a) < lwr(*b)) + return -1; + if(lwr(*a) > lwr(*b)) + return 1; + } + a++; + b++; + } + if (*a != '\0') + return -1; + else if(*b == '\0') + return 1; + else + return 0; +} + +HashTablePtr +makeHashTable() +{ + return calloc(NUMBUCKETS, sizeof(HashBucketPtr)); +} + +void +destroyHashTable(HashTablePtr table) +{ + int i; + HashBucketPtr bp; + + for(i = 0; i < NUMBUCKETS; i++) { + while(table[i]) { + bp = table[i]; + table[i] = table[i]->next; + free(bp->key); + free(bp->value); + free(bp); + } + } + free(table); +} + +char * +getHash(HashTablePtr table, char *key) +{ + int i = hash(key); + HashBucketPtr bp; + for(bp = table[i]; bp; bp = bp->next) { + if(strcmp_lwr(bp->key, key) == 0) + return bp->value; + } + return NULL; +} + +int +putHash(HashTablePtr table, char *key, char *value, int prio) +{ + int i = hash(key); + char *keycopy = NULL, *valuecopy = NULL; + HashBucketPtr bp; + for(bp = table[i]; bp; bp = bp->next) { + if(strcmp_lwr(bp->key, key) == 0) { + if(prio > bp->prio) { + keycopy = malloc(strlen(key) + 1); + if(keycopy == NULL) goto fail; + strcpy_lwr(keycopy, key); + valuecopy = malloc(strlen(value) + 1); + if(valuecopy == NULL) goto fail; + strcpy(valuecopy, value); + free(bp->key); + free(bp->value); + bp->key = keycopy; + bp->value = valuecopy; + } + return 1; + } + } + keycopy = malloc(strlen(key) + 1); + if(keycopy == NULL) + goto fail; + strcpy_lwr(keycopy, key); + valuecopy = malloc(strlen(value) + 1); + if(valuecopy == NULL) + goto fail; + strcpy(valuecopy, value); + bp = malloc(sizeof(HashBucketRec)); + if(bp == NULL) + goto fail; + bp->key = keycopy; + bp->value = valuecopy; + bp->prio = prio; + bp->next = table[i]; + table[i] = bp; + return 1; + + fail: + if(keycopy) free(keycopy); + if(valuecopy) free(valuecopy); + return -1; +} + +int +hashElements(HashTablePtr table) +{ + int i, n; + HashBucketPtr bp; + + n = 0; + for(i = 0; i < NUMBUCKETS; i++) { + for(bp = table[i]; bp; bp = bp->next) { + n++; + } + } + return n; +} + +static int +key_first_cmp(void *v1, void *v2) +{ + HashBucketPtr *b1 = v1, *b2 = v2; + int c1 = strcmp_lwr((*b1)->key, (*b2)->key); + if(c1 != 0) return c1; + return strcmp((*b1)->value, (*b2)->value); +} + +static int +value_first_cmp(void *v1, void *v2) +{ + HashBucketPtr *b1 = v1, *b2 = v2; + int c1 = strcmp((*b1)->value, (*b2)->value); + if(c1 != 0) return c1; + return strcmp_lwr((*b1)->key, (*b2)->key); +} + +HashBucketPtr * +hashArray(HashTablePtr table, int value_first) +{ + int i, j, n; + HashBucketPtr *dst; + + n = hashElements(table); + dst = malloc((n + 1) * sizeof(HashBucketPtr)); + if(dst == NULL) + return NULL; + + j = 0; + for(i = 0; i < NUMBUCKETS; i++) { + while(table[i]) { + dst[j++] = table[i]; + table[i] = table[i]->next; + } + } + qsort(dst, j, sizeof(HashBucketPtr), + value_first ? value_first_cmp : key_first_cmp); + dst[j++] = NULL; + free(table); + + return dst; +} + +void +destroyHashArray(HashBucketPtr *array) +{ + int i = 0; + while(array[i]) { + free(array[i]->key); + free(array[i]->value); + free(array[i]); + i++; + } + free(array); +} Modified: people/jch/xc/programs/mkfontscale/Imakefile ============================================================================== --- people/jch/xc/programs/mkfontscale/Imakefile 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/Imakefile 2003-06-05 16:54:39 UTC (rev 147) @@ -5,9 +5,9 @@ SYS_LIBRARIES = GzipLibrary -SRCS = mkfontscale.c list.c +SRCS = mkfontscale.c list.c hash.c ident.c -OBJS = mkfontscale.o list.o +OBJS = mkfontscale.o list.o hash.o ident.o #if !HasSnprintf SNPRINTF_DEFINES = -DNEED_SNPRINTF Modified: people/jch/xc/programs/mkfontscale/mkfontscale.c ============================================================================== --- people/jch/xc/programs/mkfontscale/mkfontscale.c 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/mkfontscale.c 2003-06-05 16:54:39 UTC (rev 147) @@ -28,6 +28,7 @@ #include <sys/types.h> #include <dirent.h> #include <unistd.h> +#include <errno.h> #include <X11/fonts/fontenc.h> #include <freetype/freetype.h> @@ -35,12 +36,23 @@ #include <freetype/tttables.h> #include <freetype/ttnameid.h> #include <freetype/t1tables.h> +#include <freetype/ftbdf.h> +#include <freetype/tttables.h> #include "list.h" +#include "hash.h" #include "data.h" +#include "ident.h" #define NPREFIX 1024 +#ifndef MAXFONTFILENAMELEN +#define MAXFONTFILENAMELEN 1024 +#endif +#ifndef MAXFONTNAMELEN +#define MAXFONTNAMELEN 1024 +#endif + char *encodings_array[] = { "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5", "iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10", @@ -68,6 +80,8 @@ static int find_cmap(int type, int pid, int eid, FT_Face face); static char* notice_foundry(char *notice); static char* vendor_foundry(signed char *vendor); +int readFontScale(HashTablePtr entries, char *dirname); +ListPtr makeXLFD(char *filename, FT_Face face, int); static FT_Library ft_library; static float bigEncodingFuzz = 0.02; @@ -83,8 +97,10 @@ usage(void) { fprintf(stderr, - "mkfontscale [ -o filename ] [ -e encoding ] [ -f fuzz ] " - "[ directory ]\n"); + "mkfontscale [ -b ] [ -s ] [ -o filename ] \n" + " [ -x encoding ] [ -f fuzz ] [ -l ] " + "[ -e directory ] [ -p prefix ]\n" + " [ directory ]...\n"); } int @@ -93,7 +109,7 @@ int argn; FT_Error ftrc; int rc; - char prefix[NPREFIX + 1]; + char prefix[NPREFIX]; if(getcwd(prefix, NPREFIX - 1) == NULL) { perror("Couldn't get cwd"); @@ -101,7 +117,6 @@ } if(prefix[strlen(prefix) - 1] != '/') strcat(prefix, "/"); - encodingPrefix = prefix; outfilename = NULL; @@ -123,14 +138,14 @@ if(argv[argn][1] == '-') { argn++; break; - } else if(argv[argn][1] == 'e') { + } else if(strcmp(argv[argn], "-x") == 0) { if(argn >= argc - 1) { usage(); exit(1); } makeList(&argv[argn + 1], 1, encodings, 0); argn += 2; - } else if(argv[argn][1] == 'p') { + } else if(strcmp(argv[argn], "-p") == 0) { if(argn >= argc - 1) { usage(); exit(1); @@ -140,10 +155,8 @@ exit(1); } strcpy(prefix, argv[argn + 1]); - if(prefix[strlen(prefix) - 1] != '/') - strcat(prefix, "/"); argn += 2; - } else if(argv[argn][1] == 'E') { + } else if(strcmp(argv[argn], "-e") == 0) { if(argn >= argc - 1) { usage(); exit(1); @@ -153,23 +166,23 @@ if(rc < 0) exit(1); argn += 2; - } else if(argv[argn][1] == 'b') { - doBitmaps = !doBitmaps; + } else if(strcmp(argv[argn], "-b") == 0) { + doBitmaps = 1; argn++; - } else if(argv[argn][1] == 's') { - doScalable = !doScalable; + } else if(strcmp(argv[argn], "-s") == 0) { + doScalable = 0; argn++; - } else if(argv[argn][1] == 'r') { + } else if(strcmp(argv[argn], "-l") == 0) { reencodeLegacy = !reencodeLegacy; argn++; - } else if(argv[argn][1] == 'o') { + } else if(strcmp(argv[argn], "-o") == 0) { if(argn >= argc - 1) { usage(); exit(1); } outfilename = argv[argn + 1]; argn += 2; - } else if(argv[argn][1] == 'f') { + } else if(strcmp(argv[argn], "-f") == 0) { if(argn >= argc - 1) { usage(); exit(1); @@ -182,6 +195,8 @@ } } + encodingPrefix = dsprintf("%s", prefix); + if(outfilename == NULL) { if(doBitmaps) outfilename = "fonts.dir"; @@ -432,7 +447,251 @@ return t; } +ListPtr +makeXLFD(char *filename, FT_Face face, int isBitmap) +{ + ListPtr xlfd = NULL; + char *foundry, *family, *weight, *slant, *sWidth, *adstyle, + *spacing, *full_name; + TT_Header *head; + TT_HoriHeader *hhea; + TT_OS2 *os2; + TT_Postscript *post; + PS_FontInfoRec *t1info, t1info_rec; + int rc; + + foundry = NULL; + family = NULL; + weight = NULL; + slant = NULL; + sWidth = NULL; + adstyle = NULL; + spacing = NULL; + full_name = NULL; + + head = FT_Get_Sfnt_Table(face, ft_sfnt_head); + hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); + os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); + post = FT_Get_Sfnt_Table(face, ft_sfnt_post); + + rc = FT_Get_PS_Font_Info(face, &t1info_rec); + if(rc == 0) + t1info = &t1info_rec; + else + t1info = NULL; + + if(!family) + family = getName(face, TT_NAME_ID_FONT_FAMILY); + if(!family) + family = getName(face, TT_NAME_ID_FULL_NAME); + if(!family) + family = getName(face, TT_NAME_ID_PS_NAME); + + if(!full_name) + full_name = getName(face, TT_NAME_ID_FULL_NAME); + if(!full_name) + full_name = getName(face, TT_NAME_ID_PS_NAME); + + if(os2 && os2->version != 0xFFFF) { + if(!weight) + weight = os2Weight(os2->usWeightClass); + if(!sWidth) + sWidth = os2Width(os2->usWidthClass); + if(!foundry) + foundry = vendor_foundry(os2->achVendID); + if(!slant) + slant = os2->fsSelection & 1 ? "i" : "r"; + } + + if(post) { + if(!spacing) { + if(post->isFixedPitch) { + if(hhea->min_Left_Side_Bearing >= 0 && + hhea->xMax_Extent <= hhea->advance_Width_Max) { + spacing = "c"; + } else { + spacing = "m"; + } + } else { + spacing = "p"; + } + } + } + + if(t1info) { + if(!family) + family = t1info->family_name; + if(!family) + family = t1info->full_name; + if(!full_name) + full_name = t1info->full_name; + if(!foundry) + foundry = notice_foundry(t1info->notice); + if(!weight) + weight = t1Weight(t1info->weight); + if(!spacing) + spacing = t1info->is_fixed_pitch ? "m" : "p"; + if(!slant) { + /* Bitstream fonts have positive italic angle. */ + slant = + t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ? + "i" : "r"; + } + } + + if(!full_name) { + fprintf(stderr, "Couldn't determine full name for %s\n", filename); + full_name = filename; + } + + if(head) { + if(!slant) + slant = head->Mac_Style & 2 ? "i" : "r"; + if(!weight) + weight = head->Mac_Style & 1 ? "bold" : "medium"; + } + + if(!slant) { + fprintf(stderr, "Couldn't determine slant for %s\n", filename); + slant = "r"; + } + + if(!weight) { + fprintf(stderr, "Couldn't determine weight for %s\n", filename); + weight = "medium"; + } + + if(!foundry) { + char *notice; + notice = getName(face, TT_NAME_ID_TRADEMARK); + if(notice) { + foundry = notice_foundry(notice); + } + if(!foundry) { + notice = getName(face, TT_NAME_ID_MANUFACTURER); + if(notice) { + foundry = notice_foundry(notice); + } + } + } + + if(strcmp(slant, "i") == 0) { + if(strstr(full_name, "Oblique")) + slant = "o"; + if(strstr(full_name, "Slanted")) + slant = "o"; + } + + if(!sWidth) + sWidth = nameWidth(full_name); + + if(!foundry) foundry = "misc"; + if(!family) { + fprintf(stderr, "Couldn't get family name for %s\n", filename); + family = filename; + } + + if(!weight) weight = "medium"; + if(!slant) slant = "r"; + if(!sWidth) sWidth = "normal"; + if(!adstyle) adstyle = ""; + if(!spacing) spacing = "p"; + + /* Yes, it's a memory leak. */ + foundry = safe(foundry); + family = safe(family); + + if(!isBitmap) { + xlfd = listConsF(xlfd, + "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0", + foundry, family, + weight, slant, sWidth, adstyle, spacing); + } else { + int i, w, h, xres, yres; + for(i = 0; i < face->num_fixed_sizes; i++) { + w = face->available_sizes[i].width; + h = face->available_sizes[i].height; + xres = 75; + yres = (double)h / w * xres; + xlfd = listConsF(xlfd, + "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d", + foundry, family, + weight, slant, sWidth, adstyle, + h, ((int)(h / (double)yres + 0.5)) * 10, + xres, yres, + spacing, 60); + } + } + return xlfd; +} + int +readFontScale(HashTablePtr entries, char *dirname) +{ + int n = strlen(dirname); + char *filename; + FILE *in; + int rc, count, i; + char file[MAXFONTFILENAMELEN], font[MAXFONTNAMELEN]; + char format[100]; + + snprintf(format, 100, "%%%ds %%%d[^\n]\n", + MAXFONTFILENAMELEN, MAXFONTNAMELEN); + + if(dirname[n - 1] == '/') + filename = dsprintf("%sfonts.scale", dirname); + else + filename = dsprintf("%s/fonts.scale", dirname); + if(filename == NULL) + return -1; + + in = fopen(filename, "r"); + free(filename); + if(in == NULL) { + if(errno != ENOENT) + perror("open(fonts.scale)"); + return -1; + } + + rc = fscanf(in, "%d\n", &count); + if(rc != 1) { + fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname); + fclose(in); + return -1; + } + + for(i = 0; i < count; i++) { + rc = fscanf(in, format, file, font); + if(rc != 2) + break; + putHash(entries, font, file, 100); + } + fclose(in); + return 1; +} + +static int +filePrio(char *filename) +{ + int n = strlen(filename); + if(n < 4) + return 0; + if(memcmp(filename + n - 4, ".otf", 4) == 0) + return 4; + if(memcmp(filename + n - 4, ".OTF", 4) == 0) + return 4; + if(memcmp(filename + n - 4, ".ttf", 4) == 0) + return 3; + if(memcmp(filename + n - 4, ".TTF", 4) == 0) + return 3; + if(memcmp(filename + n - 3, ".gz", 3) == 0) + return 2; + if(memcmp(filename + n - 2, ".Z", 2) == 0) + return 1; + return 0; +} + +int doDirectory(char *dirname_given, int doEncodings, ListPtr encodingsToDo) { char *dirname, *fontscale_name, *filename; @@ -441,15 +700,11 @@ struct dirent *entry; FT_Error ftrc; FT_Face face; - TT_Header *head; - TT_HoriHeader *hhea; - TT_OS2 *os2; - TT_Postscript *post; - PS_FontInfoRec *t1info, t1info_rec; - char *foundry, *family, *weight, *slant, *sWidth, *adstyle, - *spacing, *full_name; - ListPtr encoding, entries = NULL; - int i, found, rc; + ListPtr encoding, xlfd, lp; + HashTablePtr entries; + HashBucketPtr *array; + int i, n, found, rc; + int isBitmap; i = strlen(dirname_given); if(i == 0) @@ -481,10 +736,15 @@ } fprintf(out, "%d\n", listLength(encodingsToDo)); for(l = encodingsToDo; l; l = l->next) { - fprintf(out, "%s %s\n", acell(l)->key, acell(l)->value); + fprintf(out, "%s\n", l->value); } } + entries = makeHashTable(); + if(doBitmaps && !doScalable) { + readFontScale(entries, dirname); + } + if(strcmp(outfilename, "-") == 0) fontscale_name = NULL; else { @@ -515,191 +775,138 @@ perror("fopen(w)"); return 0; } - - for(;;) { - entry = readdir(dirp); - if(entry == NULL) - break; + + while((entry = readdir(dirp)) != NULL) { + int have_face = 0; + char *xlfd_name = NULL; + xlfd = NULL; filename = dsprintf("%s%s", dirname, entry->d_name); - ftrc = FT_New_Face(ft_library, filename, 0, &face); - if(ftrc) - continue; - if((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) { - if(!doBitmaps) - continue; - } else { - if(!doScalable) - continue; - } + if(doBitmaps) + rc = bitmapIdentify(filename, &xlfd_name); + else + rc = 0; - found = 0; + if(rc < 0) + goto done; - foundry = NULL; - family = NULL; - weight = NULL; - slant = NULL; - sWidth = NULL; - adstyle = NULL; - spacing = NULL; - full_name = NULL; + if(rc == 0) { + ftrc = FT_New_Face(ft_library, filename, 0, &face); + if(ftrc) + goto done; + have_face = 1; - head = FT_Get_Sfnt_Table(face, ft_sfnt_head); - hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); - os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); - post = FT_Get_Sfnt_Table(face, ft_sfnt_post); + isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); - rc = FT_Get_PS_Font_Info(face, &t1info_rec); - if(rc == 0) - t1info = &t1info_rec; - else - t1info = NULL; + if(!isBitmap) { + /* Workaround for bitmap-only TTF fonts */ + if(face->num_fixed_sizes > 0) { + TT_MaxProfile *maxp; + maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); + if(maxp != NULL && maxp->maxContours == 0) + isBitmap = 1; + } + } - if(!family) - family = getName(face, TT_NAME_ID_FONT_FAMILY); - if(!family) - family = getName(face, TT_NAME_ID_FULL_NAME); - if(!family) - family = getName(face, TT_NAME_ID_PS_NAME); + if(isBitmap) { + if(!doBitmaps) + goto done; + } else { + if(!doScalable) + goto done; + } - if(!full_name) - full_name = getName(face, TT_NAME_ID_FULL_NAME); - if(!full_name) - full_name = getName(face, TT_NAME_ID_PS_NAME); - - if(os2 && os2->version != 0xFFFF) { - if(!weight) - weight = os2Weight(os2->usWeightClass); - if(!sWidth) - sWidth = os2Width(os2->usWidthClass); - if(!foundry) - foundry = vendor_foundry(os2->achVendID); - if(!slant) - slant = os2->fsSelection & 1 ? "i" : "r"; - } - - if(post) { - if(!spacing) { - if(post->isFixedPitch) { - if(hhea->min_Left_Side_Bearing >= 0 && - hhea->xMax_Extent <= hhea->advance_Width_Max) { - spacing = "c"; - } else { - spacing = "m"; - } - } else { - spacing = "p"; + if(isBitmap) { + BDF_PropertyRec prop; + int n; + rc = FT_Get_BDF_Property(face, "FONT", &prop); + if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { + n = strlen(prop.u.atom); + xlfd_name = malloc(strlen(prop.u.atom) + 1); + if(xlfd_name == NULL) + goto done; + strcpy(xlfd_name, prop.u.atom); } } } - - if(t1info) { - if(!family) - family = t1info->family_name; - if(!family) - family = t1info->full_name; - if(!full_name) - full_name = t1info->full_name; - if(!foundry) - foundry = notice_foundry(t1info->notice); - if(!weight) - weight = t1Weight(t1info->weight); - if(!spacing) - spacing = t1info->is_fixed_pitch ? "m" : "p"; - if(!slant) { - /* Bitstream fonts have positive italic angle. */ - slant = - t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ? - "i" : "r"; + + if(xlfd_name) { + /* We know it's a bitmap font, and we know its XLFD */ + char *s; + int n = strlen(xlfd_name); + if(reencodeLegacy && + n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) { + s = malloc(n - 10); + memcpy(s, xlfd_name, n - 11); + s[n - 11] = '\0'; + xlfd = listCons(s, xlfd); + } else { + /* Not a reencodable font -- skip all the rest of the loop body */ + putHash(entries, xlfd_name, entry->d_name, filePrio(entry->d_name)); + goto done; } } - if(head) { - if(!slant) - slant = head->Mac_Style & 2 ? "i" : "r"; - if(!weight) - weight = head->Mac_Style & 1 ? "bold" : "medium"; - } + if(!have_face) { + ftrc = FT_New_Face(ft_library, filename, 0, &face); + if(ftrc) + goto done; + have_face = 1; + isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); - if(!slant) { - fprintf(stderr, "Couldn't determine slant for %s\n", filename); - slant = "r"; + if(!isBitmap) { + if(face->num_fixed_sizes > 0) { + TT_MaxProfile *maxp; + maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); + if(maxp != NULL && maxp->maxContours == 0) + isBitmap = 1; + } + } } - if(!weight) { - fprintf(stderr, "Couldn't determine weight for %s\n", filename); - weight = "medium"; - } + if(xlfd == NULL) + xlfd = makeXLFD(entry->d_name, face, isBitmap); - if(!foundry) { - char *notice; - notice = getName(face, TT_NAME_ID_TRADEMARK); - if(notice) { - foundry = notice_foundry(notice); + found = 0; + + for(lp = xlfd; lp; lp = lp->next) { + char buf[MAXFONTNAMELEN]; + for(encoding = encodings; encoding; encoding = encoding->next) { + if(checkEncoding(face, encoding->value)) { + found = 1; + snprintf(buf, MAXFONTNAMELEN, "%s-%s", + lp->value, encoding->value); + putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); + } } - if(!foundry) { - notice = getName(face, TT_NAME_ID_MANUFACTURER); - if(notice) { - foundry = notice_foundry(notice); + for(encoding = extra_encodings; encoding; + encoding = encoding->next) { + if(checkExtraEncoding(face, encoding->value, found)) { + /* Do not set found! */ + snprintf(buf, MAXFONTNAMELEN, "%s-%s", + lp->value, encoding->value); + putHash(entries, buf, entry->d_name, filePrio(entry->d_name)); } } } - - if(strcmp(slant, "i") == 0) { - if(strstr(full_name, "Oblique")) - slant = "o"; - if(strstr(full_name, "Slanted")) - slant = "o"; + done: + if(have_face) { + FT_Done_Face(face); + have_face = 0; } - - if(!sWidth) - sWidth = nameWidth(full_name); - - if(!foundry) foundry = "misc"; - if(!family) { - fprintf(stderr, "Couldn't get family name for %s\n", filename); - family = entry->d_name; - } - - if(!weight) weight = "medium"; - if(!slant) slant = "r"; - if(!sWidth) sWidth = "normal"; - if(!adstyle) adstyle = ""; - if(!spacing) spacing = "p"; - - /* Yes, it's a memory leak. */ - foundry = safe(foundry); - family = safe(family); - - for(encoding = encodings; encoding; encoding = encoding->next) - if(checkEncoding(face, encoding->value)) { - found = 1; - entries = listConsF(entries, - "%s -%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0-%s", - entry->d_name, - foundry, family, - weight, slant, sWidth, adstyle, spacing, - encoding->value); - } - for(encoding = extra_encodings; encoding; encoding = encoding->next) - if(checkExtraEncoding(face, encoding->value, found)) { - /* Do not set found! */ - entries = listConsF(entries, - "%s -%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0-%s", - entry->d_name, - foundry, family, - weight, slant, sWidth, adstyle, spacing, - encoding->value); - } + deepDestroyList(xlfd); + xlfd = NULL; free(filename); } - entries = reverseList(entries); - fprintf(fontscale, "%d\n", listLength(entries)); - while(entries) { - fprintf(fontscale, "%s\n", entries->value); - entries = entries->next; - } - deepDestroyList(entries); + + closedir(dirp); + n = hashElements(entries); + fprintf(fontscale, "%d\n", n); + array = hashArray(entries, 1); + for(i = 0; i < n; i++) + fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key); + destroyHashArray(array); + entries = NULL; if(fontscale_name) { fclose(fontscale); free(fontscale_name); @@ -983,6 +1190,7 @@ fullname = dsprintf("%s/%s", dirname, file->d_name); if(fullname == NULL) { fprintf(stderr, "Couldn't allocate fullname\n"); + closedir(dirp); return -1; } @@ -996,18 +1204,21 @@ n = dsprintf("%s%s", encodingPrefix, fullname); if(n == NULL) { fprintf(stderr, "Couldn't allocate name\n"); + closedir(dirp); return -1; } free(fullname); fullname = n; } - encodingsToDo = acons(fullname, *name, encodingsToDo); + encodingsToDo = listConsF(encodingsToDo, "%s %s", fullname, *name); if(encodingsToDo == NULL) { fprintf(stderr, "Couldn't allocate encodings\n"); + closedir(dirp); return -1; } } free(names); /* only the spine */ } + closedir(dirp); return 0; } Added: people/jch/xc/programs/mkfontscale/hash.h ============================================================================== --- people/jch/xc/programs/mkfontscale/hash.h 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/hash.h 2003-06-05 16:54:39 UTC (rev 147) @@ -0,0 +1,37 @@ +/* + Copyright (c) 2003 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +typedef struct _HashBucket { + char *key; + char *value; + int prio; + struct _HashBucket *next; +} HashBucketRec, *HashBucketPtr; + +typedef HashBucketPtr* HashTablePtr; + +HashTablePtr makeHashTable(void); +void destroyHashTable(HashTablePtr table); +char *getHash(HashTablePtr table, char *key); +int putHash(HashTablePtr table, char *key, char *value, int prio); +int hashElements(HashTablePtr table); +HashBucketPtr *hashArray(HashTablePtr table, int value_first); Added: people/jch/xc/programs/mkfontscale/ident.h ============================================================================== --- people/jch/xc/programs/mkfontscale/ident.h 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/ident.h 2003-06-05 16:54:39 UTC (rev 147) @@ -0,0 +1,26 @@ +/* + Copyright (c) 2003 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +int bitmapIdentify(char *filename, char **xlfd); + + + Modified: people/jch/xc/programs/mkfontscale/list.c ============================================================================== --- people/jch/xc/programs/mkfontscale/list.c 2003-06-05 13:30:06 UTC (rev 146) +++ people/jch/xc/programs/mkfontscale/list.c 2003-06-05 16:54:39 UTC (rev 147) @@ -231,11 +231,10 @@ ListPtr next; if(!old) return; - next = old->next; while(old) { + next = old->next; free(old); old = next; - next = old->next; } } @@ -245,97 +244,10 @@ ListPtr next; if(!old) return; - next = old->next; while(old) { + next = old->next; free(old->value); free(old); old = next; - next = old->next; } } - -AcellPtr -acell(ListPtr alist) -{ - return (AcellPtr)alist->value; -} - -AcellPtr -assoc(char *key, ListPtr alist) -{ - ListPtr l; - AcellPtr acell; - l = alist; - while(l) { - acell = (AcellPtr)l->value; - if(strcmp(acell->key, key) == 0) - return acell; - l = l->next; - } - return NULL; -} - -ListPtr -acons(char *key, char *value, ListPtr alist) -{ - AcellPtr acell; - acell = malloc(sizeof(AcellRec)); - if(acell == NULL) - return NULL; - acell->key = key; - acell->value = value; - acell->prio = 0; - return listCons((char*)acell, alist); -} - -ListPtr -aconsPrio(char *key, char *value, int prio, ListPtr alist) -{ - ListPtr l; - AcellPtr acell; - l = alist; - while(l) { - acell = (AcellPtr)l->value; - if(strcmp(acell->key, key) == 0) - break; - l = l->next; - } - if(l && acell->prio >= prio) - return alist; - - acell = malloc(sizeof(AcellRec)); - if(acell == NULL) - return NULL; - acell->key = key; - acell->value = value; - acell->prio = prio; - return listCons((char*)acell, alist); -} - -void -destroyAlist(ListPtr old) -{ - return deepDestroyList(old); -} - -void -deepDestroyAlist(ListPtr old) -{ - ListPtr next; - AcellPtr acell; - - if(!old) - return; - next = old->next; - while(old) { - acell = (AcellPtr)old->value; - free(acell->key); - free(acell->value); - free(acell); - free(old); - old = next; - next = old->next; - } -} - -