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