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 "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 
45 Bool
FontFileInitTable(FontTablePtr table,int size)46 FontFileInitTable (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 
64 void
FontFileFreeEntry(FontEntryPtr entry)65 FontFileFreeEntry (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 
96 void
FontFileFreeTable(FontTablePtr table)97 FontFileFreeTable (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 
106 FontDirectoryPtr
FontFileMakeDir(const char * dirName,int size)107 FontFileMakeDir(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 
161 void
FontFileFreeDir(FontDirectoryPtr dir)162 FontFileFreeDir (FontDirectoryPtr dir)
163 {
164     FontFileFreeTable (&dir->scalable);
165     FontFileFreeTable (&dir->nonScalable);
166     free(dir);
167 }
168 
169 FontEntryPtr
FontFileAddEntry(FontTablePtr table,FontEntryPtr prototype)170 FontFileAddEntry(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 
strcmpn(const char * s1,const char * s2)212 static 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 
241 static int
FontFileNameCompare(const void * a,const void * b)242 FontFileNameCompare(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 
250 void
FontFileSortTable(FontTablePtr table)251 FontFileSortTable (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 
260 void
FontFileSortDir(FontDirectoryPtr dir)261 FontFileSortDir(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 
285 static int
SetupWildMatch(FontTablePtr table,FontNamePtr pat,int * leftp,int * rightp,int * privatep)286 SetupWildMatch(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 
361 static int
PatternMatch(char * pat,int patdashes,char * string,int stringdashes)362 PatternMatch(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 
423 int
FontFileCountDashes(char * name,int namelen)424 FontFileCountDashes (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> */
435 char *
FontFileSaveString(char * s)436 FontFileSaveString (char *s)
437 {
438     return strdup(s);
439 }
440 #define FontFileSaveString(s) strdup(s)
441 
442 FontEntryPtr
FontFileFindNameInScalableDir(FontTablePtr table,FontNamePtr pat,FontScalablePtr vals)443 FontFileFindNameInScalableDir(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 
489 FontEntryPtr
FontFileFindNameInDir(FontTablePtr table,FontNamePtr pat)490 FontFileFindNameInDir(FontTablePtr table, FontNamePtr pat)
491 {
492     return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
493 }
494 
495 int
FontFileFindNamesInScalableDir(FontTablePtr table,FontNamePtr pat,int max,FontNamesPtr names,FontScalablePtr vals,int alias_behavior,int * newmax)496 FontFileFindNamesInScalableDir(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 
582 int
FontFileFindNamesInDir(FontTablePtr table,FontNamePtr pat,int max,FontNamesPtr names)583 FontFileFindNamesInDir(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 
591 Bool
FontFileMatchName(char * name,int length,FontNamePtr pat)592 FontFileMatchName(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 
615 Bool
FontFileAddFontFile(FontDirectoryPtr dir,char * fontName,char * fileName)616 FontFileAddFontFile (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 
805 Bool
FontFileAddFontAlias(FontDirectoryPtr dir,char * aliasName,char * fontName)806 FontFileAddFontAlias (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