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
FontFileInitTable(FontTablePtr table,int size)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
FontFileFreeEntry(FontEntryPtr entry)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
FontFileFreeTable(FontTablePtr table)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
FontFileMakeDir(const char * dirName,int size)105 FontFileMakeDir(const char *dirName, int size)
106 {
107     FontDirectoryPtr	dir;
108     int			dirlen;
109     int			needslash = 0;
110     const 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
FontFileFreeDir(FontDirectoryPtr dir)163 FontFileFreeDir (FontDirectoryPtr dir)
164 {
165     FontFileFreeTable (&dir->scalable);
166     FontFileFreeTable (&dir->nonScalable);
167     free(dir);
168 }
169 
170 FontEntryPtr
FontFileAddEntry(FontTablePtr table,FontEntryPtr prototype)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 	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 = realloc(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 
strcmpn(const char * s1,const char * s2)213 static 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 
242 static int
FontFileNameCompare(const void * a,const void * b)243 FontFileNameCompare(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 
251 void
FontFileSortTable(FontTablePtr table)252 FontFileSortTable (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 
261 void
FontFileSortDir(FontDirectoryPtr dir)262 FontFileSortDir(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 
286 static int
SetupWildMatch(FontTablePtr table,FontNamePtr pat,int * leftp,int * rightp,int * privatep)287 SetupWildMatch(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 
362 static int
PatternMatch(char * pat,int patdashes,char * string,int stringdashes)363 PatternMatch(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 
424 int
FontFileCountDashes(char * name,int namelen)425 FontFileCountDashes (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> */
436 char *
FontFileSaveString(char * s)437 FontFileSaveString (char *s)
438 {
439     return strdup(s);
440 }
441 #define FontFileSaveString(s) strdup(s)
442 
443 FontEntryPtr
FontFileFindNameInScalableDir(FontTablePtr table,FontNamePtr pat,FontScalablePtr vals)444 FontFileFindNameInScalableDir(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 
490 FontEntryPtr
FontFileFindNameInDir(FontTablePtr table,FontNamePtr pat)491 FontFileFindNameInDir(FontTablePtr table, FontNamePtr pat)
492 {
493     return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
494 }
495 
496 int
FontFileFindNamesInScalableDir(FontTablePtr table,FontNamePtr pat,int max,FontNamesPtr names,FontScalablePtr vals,int alias_behavior,int * newmax)497 FontFileFindNamesInScalableDir(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 AddFontNamesName(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 = AddFontNamesName(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 = AddFontNamesName(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 
583 int
FontFileFindNamesInDir(FontTablePtr table,FontNamePtr pat,int max,FontNamesPtr names)584 FontFileFindNamesInDir(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 
592 Bool
FontFileMatchName(char * name,int length,FontNamePtr pat)593 FontFileMatchName(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 
616 Bool
FontFileAddFontFile(FontDirectoryPtr dir,char * fontName,char * fileName)617 FontFileAddFontFile (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 
806 Bool
FontFileAddFontAlias(FontDirectoryPtr dir,char * aliasName,char * fontName)807 FontFileAddFontAlias (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