1/*
2
3Copyright 1991, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * Author:  Keith Packard, MIT X Consortium
29 */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include "libxfontint.h"
35#include    <X11/fonts/fntfilst.h>
36#include    <X11/keysym.h>
37#include "src/util/replace.h"
38
39#if HAVE_STDINT_H
40#include <stdint.h>
41#elif !defined(INT32_MAX)
42#define INT32_MAX 0x7fffffff
43#endif
44
45Bool
46FontFileInitTable (FontTablePtr table, int size)
47{
48    if (size < 0 || (size > INT32_MAX/sizeof(FontEntryRec)))
49	return FALSE;
50    if (size)
51    {
52	table->entries = mallocarray(size, sizeof(FontEntryRec));
53	if (!table->entries)
54	    return FALSE;
55    }
56    else
57	table->entries = 0;
58    table->used = 0;
59    table->size = size;
60    table->sorted = FALSE;
61    return TRUE;
62}
63
64void
65FontFileFreeEntry (FontEntryPtr entry)
66{
67    FontScalableExtraPtr   extra;
68    int i;
69
70    if (entry->name.name)
71	free(entry->name.name);
72    entry->name.name = NULL;
73
74    switch (entry->type)
75    {
76    case FONT_ENTRY_SCALABLE:
77	free (entry->u.scalable.fileName);
78	extra = entry->u.scalable.extra;
79	for (i = 0; i < extra->numScaled; i++)
80	    if (extra->scaled[i].vals.ranges)
81		free (extra->scaled[i].vals.ranges);
82	free (extra->scaled);
83	free (extra);
84	break;
85    case FONT_ENTRY_BITMAP:
86	free (entry->u.bitmap.fileName);
87	entry->u.bitmap.fileName = NULL;
88	break;
89    case FONT_ENTRY_ALIAS:
90	free (entry->u.alias.resolved);
91	entry->u.alias.resolved = NULL;
92	break;
93    }
94}
95
96void
97FontFileFreeTable (FontTablePtr table)
98{
99    int	i;
100
101    for (i = 0; i < table->used; i++)
102	FontFileFreeEntry (&table->entries[i]);
103    free (table->entries);
104}
105
106FontDirectoryPtr
107FontFileMakeDir(const char *dirName, int size)
108{
109    FontDirectoryPtr	dir;
110    int			dirlen;
111    int			needslash = 0;
112    const char		*attrib;
113    int			attriblen;
114
115    attrib = strchr(dirName, ':');
116#if defined(WIN32)
117    if (attrib && attrib - dirName == 1) {
118	/* WIN32 uses the colon in the drive letter descriptor, skip this */
119	attrib = strchr(dirName + 2, ':');
120    }
121#endif
122    if (attrib) {
123	dirlen = attrib - dirName;
124	attriblen = strlen(attrib);
125    } else {
126	dirlen = strlen(dirName);
127	attriblen = 0;
128    }
129    if (dirlen && dirName[dirlen - 1] != '/')
130	needslash = 1;
131    dir = malloc(sizeof *dir + dirlen + needslash + 1 +
132		 (attriblen ? attriblen + 1 : 0));
133    if (!dir)
134	return (FontDirectoryPtr)0;
135    if (!FontFileInitTable (&dir->scalable, 0))
136    {
137	free (dir);
138	return (FontDirectoryPtr)0;
139    }
140    if (!FontFileInitTable (&dir->nonScalable, size))
141    {
142	FontFileFreeTable (&dir->scalable);
143	free (dir);
144	return (FontDirectoryPtr)0;
145    }
146    dir->directory = (char *) (dir + 1);
147    dir->dir_mtime = 0;
148    dir->alias_mtime = 0;
149    if (attriblen)
150	dir->attributes = dir->directory + dirlen + needslash + 1;
151    else
152	dir->attributes = NULL;
153    strncpy(dir->directory, dirName, dirlen);
154    if (needslash)
155	dir->directory[dirlen] = '/';
156    dir->directory[dirlen + needslash] = '\0';
157    if (dir->attributes)
158	strlcpy(dir->attributes, attrib, attriblen + 1);
159    return dir;
160}
161
162void
163FontFileFreeDir (FontDirectoryPtr dir)
164{
165    FontFileFreeTable (&dir->scalable);
166    FontFileFreeTable (&dir->nonScalable);
167    free(dir);
168}
169
170FontEntryPtr
171FontFileAddEntry(FontTablePtr table, FontEntryPtr prototype)
172{
173    FontEntryPtr    entry;
174    int		    newsize;
175
176    /* can't add entries to a sorted table, pointers get broken! */
177    if (table->sorted)
178	return (FontEntryPtr) 0;    /* "cannot" happen */
179    if (table->used == table->size) {
180	if (table->size >= ((INT32_MAX / sizeof(FontEntryRec)) - 100))
181	    /* If we've read so many entries we're going to ask for 2gb
182	       or more of memory, something is so wrong with this font
183	       directory that we should just give up before we overflow. */
184	    return NULL;
185	newsize = table->size + 100;
186	entry = reallocarray(table->entries, newsize, sizeof(FontEntryRec));
187	if (!entry)
188	    return (FontEntryPtr)0;
189	table->size = newsize;
190	table->entries = entry;
191    }
192    entry = &table->entries[table->used];
193    *entry = *prototype;
194    entry->name.name = malloc(prototype->name.length + 1);
195    if (!entry->name.name)
196	return (FontEntryPtr)0;
197    memcpy (entry->name.name, prototype->name.name, prototype->name.length);
198    entry->name.name[entry->name.length] = '\0';
199    table->used++;
200    return entry;
201}
202
203/*
204 * Compare two strings just like strcmp, but preserve decimal integer
205 * sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" <
206 * "iso10646-1". Strings are sorted as if sequences of digits were
207 * prefixed by a length indicator (i.e., does not ignore leading zeroes).
208 *
209 * Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>
210 */
211#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071')
212
213static int strcmpn(const char *s1, const char *s2)
214{
215    int digits, predigits = 0;
216    const char *ss1, *ss2;
217
218    while (1) {
219	if (*s1 == 0 && *s2 == 0)
220	    return 0;
221	digits = Xisdigit(*s1) && Xisdigit(*s2);
222	if (digits && !predigits) {
223	    ss1 = s1;
224	    ss2 = s2;
225	    while (Xisdigit(*ss1) && Xisdigit(*ss2))
226		ss1++, ss2++;
227	    if (!Xisdigit(*ss1) && Xisdigit(*ss2))
228		return -1;
229	    if (Xisdigit(*ss1) && !Xisdigit(*ss2))
230		return 1;
231	}
232	if ((unsigned char)*s1 < (unsigned char)*s2)
233	    return -1;
234	if ((unsigned char)*s1 > (unsigned char)*s2)
235	    return 1;
236	predigits = digits;
237	s1++, s2++;
238    }
239}
240
241
242static int
243FontFileNameCompare(const void* a, const void* b)
244{
245    FontEntryPtr    a_name = (FontEntryPtr) a,
246		    b_name = (FontEntryPtr) b;
247
248    return strcmpn(a_name->name.name, b_name->name.name);
249}
250
251void
252FontFileSortTable (FontTablePtr table)
253{
254    if (!table->sorted) {
255	qsort((char *) table->entries, table->used, sizeof(FontEntryRec),
256	      FontFileNameCompare);
257	table->sorted = TRUE;
258    }
259}
260
261void
262FontFileSortDir(FontDirectoryPtr dir)
263{
264    FontFileSortTable (&dir->scalable);
265    FontFileSortTable (&dir->nonScalable);
266    /* now that the table is fixed in size, swizzle the pointers */
267    FontFileSwitchStringsToBitmapPointers (dir);
268}
269
270/*
271  Given a Font Table, SetupWildMatch() sets up various pointers and state
272  information so the table can be searched for name(s) that match a given
273  fontname pattern -- which may contain wildcards.  Under certain
274  circumstances, SetupWildMatch() will find the one table entry that
275  matches the pattern.  If those circumstances do not pertain,
276  SetupWildMatch() returns a range within the the table that should be
277  searched for matching name(s).  With the information established by
278  SetupWildMatch(), including state information in "private", the
279  PatternMatch() procedure is then used to test names in the range for a
280  match.
281*/
282
283#define isWild(c)   ((c) == XK_asterisk || (c) == XK_question)
284#define isDigit(c)  (XK_0 <= (c) && (c) <= XK_9)
285
286static int
287SetupWildMatch(FontTablePtr table, FontNamePtr pat,
288	       int *leftp, int *rightp, int *privatep)
289{
290    int         nDashes;
291    char        c;
292    char       *t;
293    char       *firstWild;
294    char       *firstDigit;
295    int         first;
296    int         center,
297                left,
298                right;
299    int         result;
300    char	*name;
301
302    name = pat->name;
303    nDashes = pat->ndashes;
304    firstWild = 0;
305    firstDigit = 0;
306    t = name;
307    while ((c = *t++)) {
308	if (isWild(c)) {
309	    if (!firstWild)
310		firstWild = t - 1;
311	}
312	if (isDigit(c)) {
313	    if (!firstDigit)
314		firstDigit = t - 1;
315	}
316    }
317    left = 0;
318    right = table->used;
319    if (firstWild)
320	*privatep = nDashes;
321    else
322	*privatep = -1;
323    if (!table->sorted) {
324	*leftp = left;
325	*rightp = right;
326	return -1;
327    } else if (firstWild) {
328	if (firstDigit && firstDigit < firstWild)
329	    first = firstDigit - name;
330	else
331	    first = firstWild - name;
332	while (left < right) {
333	    center = (left + right) / 2;
334	    result = strncmp(name, table->entries[center].name.name, first);
335	    if (result == 0)
336		break;
337	    if (result < 0)
338		right = center;
339	    else
340		left = center + 1;
341	}
342	*leftp = left;
343	*rightp = right;
344	return -1;
345    } else {
346	while (left < right) {
347	    center = (left + right) / 2;
348	    result = strcmpn(name, table->entries[center].name.name);
349	    if (result == 0)
350		return center;
351	    if (result < 0)
352		right = center;
353	    else
354		left = center + 1;
355	}
356	*leftp = 1;
357	*rightp = 0;
358	return -1;
359    }
360}
361
362static int
363PatternMatch(char *pat, int patdashes, char *string, int stringdashes)
364{
365    char        c,
366                t;
367
368    if (stringdashes < patdashes)
369	return 0;
370    for (;;) {
371	switch (c = *pat++) {
372	case '*':
373	    if (!(c = *pat++))
374		return 1;
375	    if (c == XK_minus) {
376		patdashes--;
377		for (;;) {
378		    while ((t = *string++) != XK_minus)
379			if (!t)
380			    return 0;
381		    stringdashes--;
382		    if (PatternMatch(pat, patdashes, string, stringdashes))
383			return 1;
384		    if (stringdashes == patdashes)
385			return 0;
386		}
387	    } else {
388		for (;;) {
389		    while ((t = *string++) != c) {
390			if (!t)
391			    return 0;
392			if (t == XK_minus) {
393			    if (stringdashes-- < patdashes)
394				return 0;
395			}
396		    }
397		    if (PatternMatch(pat, patdashes, string, stringdashes))
398			return 1;
399		}
400	    }
401	case '?':
402	    if ((t = *string++) == XK_minus)
403		stringdashes--;
404	    if (!t)
405		return 0;
406	    break;
407	case '\0':
408	    return (*string == '\0');
409	case XK_minus:
410	    if (*string++ == XK_minus) {
411		patdashes--;
412		stringdashes--;
413		break;
414	    }
415	    return 0;
416	default:
417	    if (c == *string++)
418		break;
419	    return 0;
420	}
421    }
422}
423
424int
425FontFileCountDashes (char *name, int namelen)
426{
427    int	ndashes = 0;
428
429    while (namelen--)
430	if (*name++ == '\055')	/* avoid non ascii systems */
431	    ++ndashes;
432    return ndashes;
433}
434
435/* exported in public API in <X11/fonts/fntfil.h> */
436char *
437FontFileSaveString (char *s)
438{
439    return strdup(s);
440}
441#define FontFileSaveString(s) strdup(s)
442
443FontEntryPtr
444FontFileFindNameInScalableDir(FontTablePtr table, FontNamePtr pat,
445			      FontScalablePtr vals)
446{
447    int         i,
448                start,
449                stop,
450                res,
451                private;
452    FontNamePtr	name;
453
454    if (!table->entries)
455	return NULL;
456    if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0)
457	return &table->entries[i];
458    for (i = start; i < stop; i++) {
459	name = &table->entries[i].name;
460	res = PatternMatch(pat->name, private, name->name, name->ndashes);
461	if (res > 0)
462	{
463	    /* Check to see if enhancements requested are available */
464	    if (vals)
465	    {
466		int vs = vals->values_supplied;
467		int cap;
468
469		if (table->entries[i].type == FONT_ENTRY_SCALABLE)
470		    cap = table->entries[i].u.scalable.renderer->capabilities;
471		else if (table->entries[i].type == FONT_ENTRY_ALIAS)
472		    cap = ~0;	/* Calling code will have to see if true */
473		else
474		    cap = 0;
475		if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
476		      (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
477		     !(cap & CAP_MATRIX)) ||
478		    ((vs & CHARSUBSET_SPECIFIED) &&
479		     !(cap & CAP_CHARSUBSETTING)))
480		    continue;
481	    }
482	    return &table->entries[i];
483	}
484	if (res < 0)
485	    break;
486    }
487    return (FontEntryPtr)0;
488}
489
490FontEntryPtr
491FontFileFindNameInDir(FontTablePtr table, FontNamePtr pat)
492{
493    return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
494}
495
496int
497FontFileFindNamesInScalableDir(FontTablePtr table, FontNamePtr pat, int max,
498			       FontNamesPtr names, FontScalablePtr vals,
499			       int alias_behavior, int *newmax)
500{
501    int		    i,
502		    start,
503		    stop,
504		    res,
505		    private;
506    int		    ret = Successful;
507    FontEntryPtr    fname;
508    FontNamePtr	    name;
509
510    if (max <= 0)
511	return Successful;
512    if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0) {
513	if (alias_behavior == NORMAL_ALIAS_BEHAVIOR ||
514	    table->entries[i].type != FONT_ENTRY_ALIAS)
515	{
516	    name = &table->entries[i].name;
517	    if (newmax) *newmax = max - 1;
518	    return xfont2_add_font_names_name(names, name->name, name->length);
519	}
520	start = i;
521	stop = i + 1;
522    }
523    for (i = start, fname = &table->entries[start]; i < stop; i++, fname++) {
524	res = PatternMatch(pat->name, private, fname->name.name, fname->name.ndashes);
525	if (res > 0) {
526	    if (vals)
527	    {
528		int vs = vals->values_supplied;
529		int cap;
530
531		if (fname->type == FONT_ENTRY_SCALABLE)
532		    cap = fname->u.scalable.renderer->capabilities;
533		else if (fname->type == FONT_ENTRY_ALIAS)
534		    cap = ~0;	/* Calling code will have to see if true */
535		else
536		    cap = 0;
537		if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
538		     (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
539		    !(cap & CAP_MATRIX)) ||
540		    ((vs & CHARSUBSET_SPECIFIED) &&
541		    !(cap & CAP_CHARSUBSETTING)))
542		    continue;
543	    }
544
545	    if ((alias_behavior & IGNORE_SCALABLE_ALIASES) &&
546		fname->type == FONT_ENTRY_ALIAS)
547	    {
548		FontScalableRec	tmpvals;
549		if (FontParseXLFDName (fname->name.name, &tmpvals,
550				       FONT_XLFD_REPLACE_NONE) &&
551		    !(tmpvals.values_supplied & SIZE_SPECIFY_MASK))
552		    continue;
553	    }
554
555	    ret = xfont2_add_font_names_name(names, fname->name.name, fname->name.length);
556	    if (ret != Successful)
557		goto bail;
558
559	    /* If alias_behavior is LIST_ALIASES_AND_TARGET_NAMES, mark
560	       this entry as an alias by negating its length and follow
561	       it by the resolved name */
562	    if ((alias_behavior & LIST_ALIASES_AND_TARGET_NAMES) &&
563		fname->type == FONT_ENTRY_ALIAS)
564	    {
565		names->length[names->nnames - 1] =
566		    -names->length[names->nnames - 1];
567		ret = xfont2_add_font_names_name(names, fname->u.alias.resolved,
568				       strlen(fname->u.alias.resolved));
569		if (ret != Successful)
570		    goto bail;
571	    }
572
573	    if (--max <= 0)
574		break;
575	} else if (res < 0)
576	    break;
577    }
578  bail: ;
579    if (newmax) *newmax = max;
580    return ret;
581}
582
583int
584FontFileFindNamesInDir(FontTablePtr table, FontNamePtr pat,
585		       int max, FontNamesPtr names)
586{
587    return FontFileFindNamesInScalableDir(table, pat, max, names,
588					  (FontScalablePtr)0,
589					  NORMAL_ALIAS_BEHAVIOR, (int *)0);
590}
591
592Bool
593FontFileMatchName(char *name, int length, FontNamePtr pat)
594{
595    /* Perform a fontfile-type name match on a single name */
596    FontTableRec table;
597    FontEntryRec entries[1];
598
599    /* Dummy up a table */
600    table.used = 1;
601    table.size = 1;
602    table.sorted = TRUE;
603    table.entries = entries;
604    entries[0].name.name = name;
605    entries[0].name.length = length;
606    entries[0].name.ndashes = FontFileCountDashes(name, length);
607
608    return FontFileFindNameInDir(&table, pat) != (FontEntryPtr)0;
609}
610
611/*
612 * Add a font file to a directory.  This handles bitmap and
613 * scalable names both
614 */
615
616Bool
617FontFileAddFontFile (FontDirectoryPtr dir, char *fontName, char *fileName)
618{
619    FontEntryRec	    entry;
620    FontScalableRec	    vals, zeroVals;
621    FontRendererPtr	    renderer;
622    FontEntryPtr	    existing;
623    FontScalableExtraPtr    extra;
624    FontEntryPtr	    bitmap = 0, scalable;
625    Bool		    isscale;
626    Bool		    scalable_xlfd;
627
628    renderer = FontFileMatchRenderer (fileName);
629    if (!renderer)
630	return FALSE;
631    entry.name.length = strlen (fontName);
632    if (entry.name.length > MAXFONTNAMELEN)
633	entry.name.length = MAXFONTNAMELEN;
634    entry.name.name = fontName;
635    CopyISOLatin1Lowered (entry.name.name, fontName, entry.name.length);
636    entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
637    entry.name.name[entry.name.length] = '\0';
638    /*
639     * Add a bitmap name if the incoming name isn't an XLFD name, or
640     * if it isn't a scalable name (i.e. non-zero scalable fields)
641     *
642     * If name of bitmapped font contains XLFD enhancements, do not add
643     * a scalable version of the name... this can lead to confusion and
644     * ambiguity between the font name and the field enhancements.
645     */
646    isscale = entry.name.ndashes == 14 &&
647	      FontParseXLFDName(entry.name.name,
648				&vals, FONT_XLFD_REPLACE_NONE) &&
649	      (vals.values_supplied & PIXELSIZE_MASK) != PIXELSIZE_ARRAY &&
650	      (vals.values_supplied & POINTSIZE_MASK) != POINTSIZE_ARRAY &&
651	      !(vals.values_supplied & ENHANCEMENT_SPECIFY_MASK);
652#define UNSCALED_ATTRIB "unscaled"
653    scalable_xlfd = (isscale &&
654		(((vals.values_supplied & PIXELSIZE_MASK) == 0) ||
655		 ((vals.values_supplied & POINTSIZE_MASK) == 0)));
656    /*
657     * For scalable fonts without a scalable XFLD, check if the "unscaled"
658     * attribute is present.
659     */
660    if (isscale && !scalable_xlfd &&
661	    dir->attributes && dir->attributes[0] == ':') {
662	char *ptr1 = dir->attributes + 1;
663	char *ptr2;
664	int length;
665	int uslength = strlen(UNSCALED_ATTRIB);
666
667	do {
668	    ptr2 = strchr(ptr1, ':');
669	    if (ptr2)
670		length = ptr2 - ptr1;
671	    else
672		length = dir->attributes + strlen(dir->attributes) - ptr1;
673	    if (length == uslength && !strncmp(ptr1, UNSCALED_ATTRIB, uslength))
674		isscale = FALSE;
675	    if (ptr2)
676		ptr1 = ptr2 + 1;
677	} while (ptr2);
678    }
679    if (!isscale || (vals.values_supplied & SIZE_SPECIFY_MASK))
680    {
681      /*
682       * If the renderer doesn't support OpenBitmap, FontFileOpenFont
683       * will still do the right thing.
684       */
685	entry.type = FONT_ENTRY_BITMAP;
686	entry.u.bitmap.renderer = renderer;
687	entry.u.bitmap.pFont = NullFont;
688	if (!(entry.u.bitmap.fileName = FontFileSaveString (fileName)))
689	    return FALSE;
690	if (!(bitmap = FontFileAddEntry (&dir->nonScalable, &entry)))
691	{
692	    free (entry.u.bitmap.fileName);
693	    return FALSE;
694	}
695    }
696    /*
697     * Parse out scalable fields from XLFD names - a scalable name
698     * just gets inserted, a scaled name has more things to do.
699     */
700    if (isscale)
701    {
702	if (vals.values_supplied & SIZE_SPECIFY_MASK)
703	{
704	    bzero((char *)&zeroVals, sizeof(zeroVals));
705	    zeroVals.x = vals.x;
706	    zeroVals.y = vals.y;
707	    zeroVals.values_supplied = PIXELSIZE_SCALAR | POINTSIZE_SCALAR;
708	    FontParseXLFDName (entry.name.name, &zeroVals,
709			       FONT_XLFD_REPLACE_VALUE);
710	    entry.name.length = strlen (entry.name.name);
711	    existing = FontFileFindNameInDir (&dir->scalable, &entry.name);
712	    if (existing)
713	    {
714		if ((vals.values_supplied & POINTSIZE_MASK) ==
715			POINTSIZE_SCALAR &&
716		    (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
717		{
718		    existing->u.scalable.extra->defaults = vals;
719
720		    free (existing->u.scalable.fileName);
721		    if (!(existing->u.scalable.fileName = FontFileSaveString (fileName)))
722			return FALSE;
723		}
724                if(bitmap)
725                {
726                    FontFileCompleteXLFD(&vals, &vals);
727                    FontFileAddScaledInstance (existing, &vals, NullFont,
728                                               bitmap->name.name);
729                    return TRUE;
730                }
731	    }
732	}
733	if (!(entry.u.scalable.fileName = FontFileSaveString (fileName)))
734	    return FALSE;
735	extra = malloc (sizeof (FontScalableExtraRec));
736	if (!extra)
737	{
738	    free (entry.u.scalable.fileName);
739	    return FALSE;
740	}
741	bzero((char *)&extra->defaults, sizeof(extra->defaults));
742	if ((vals.values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR &&
743	    (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
744	    extra->defaults = vals;
745	else
746	{
747	    FontResolutionPtr resolution;
748	    int num;
749	    int default_point_size = GetDefaultPointSize();
750
751	    extra->defaults.point_matrix[0] =
752		extra->defaults.point_matrix[3] =
753	            (double)default_point_size / 10.0;
754	    extra->defaults.point_matrix[1] =
755		extra->defaults.point_matrix[2] = 0.0;
756	    extra->defaults.values_supplied =
757		POINTSIZE_SCALAR | PIXELSIZE_UNDEFINED;
758	    extra->defaults.width = -1;
759	    if (vals.x <= 0 || vals.y <= 0)
760	    {
761	        resolution = GetClientResolutions (&num);
762	        if (resolution && num > 0)
763	        {
764	    	    extra->defaults.x = resolution->x_resolution;
765	    	    extra->defaults.y = resolution->y_resolution;
766	        }
767	        else
768	        {
769		    extra->defaults.x = 75;
770		    extra->defaults.y = 75;
771	        }
772	     }
773	     else
774	     {
775		extra->defaults.x = vals.x;
776		extra->defaults.y = vals.y;
777	     }
778	     FontFileCompleteXLFD (&extra->defaults, &extra->defaults);
779	}
780	extra->numScaled = 0;
781	extra->sizeScaled = 0;
782	extra->scaled = 0;
783	extra->private = 0;
784	entry.type = FONT_ENTRY_SCALABLE;
785	entry.u.scalable.renderer = renderer;
786	entry.u.scalable.extra = extra;
787	if (!(scalable = FontFileAddEntry (&dir->scalable, &entry)))
788	{
789	    free (extra);
790	    free (entry.u.scalable.fileName);
791	    return FALSE;
792	}
793	if (vals.values_supplied & SIZE_SPECIFY_MASK)
794	{
795            if(bitmap)
796            {
797                FontFileCompleteXLFD(&vals, &vals);
798                FontFileAddScaledInstance (scalable, &vals, NullFont,
799                                           bitmap->name.name);
800            }
801	}
802    }
803    return TRUE;
804}
805
806Bool
807FontFileAddFontAlias (FontDirectoryPtr dir, char *aliasName, char *fontName)
808{
809    FontEntryRec	entry;
810
811    if (strcmp(aliasName,fontName) == 0) {
812        /* Don't allow an alias to point to itself and create a loop */
813        return FALSE;
814    }
815    entry.name.length = strlen (aliasName);
816    CopyISOLatin1Lowered (aliasName, aliasName, entry.name.length);
817    entry.name.name = aliasName;
818    entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
819    entry.type = FONT_ENTRY_ALIAS;
820    if (!(entry.u.alias.resolved = FontFileSaveString (fontName)))
821	return FALSE;
822    if (!FontFileAddEntry (&dir->nonScalable, &entry))
823    {
824	free (entry.u.alias.resolved);
825	return FALSE;
826    }
827    return TRUE;
828}
829