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