fontfile.c revision 7f7f5e4e
1/* $XdotOrg: xc/lib/font/fontfile/fontfile.c,v 1.4 2005/07/03 07:01:00 daniels Exp $ */
2/* $Xorg: fontfile.c,v 1.4 2001/02/09 02:04:03 xorgcvs Exp $ */
3
4/*
5
6Copyright 1991, 1998  The Open Group
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28*/
29/* $XFree86: xc/lib/font/fontfile/fontfile.c,v 3.21 2003/12/02 19:50:40 dawes Exp $ */
30
31/*
32 * Author:  Keith Packard, MIT X Consortium
33 */
34/* $NCDXorg: @(#)fontfile.c,v 1.6 1991/07/02 17:00:46 lemke Exp $ */
35
36#ifdef HAVE_CONFIG_H
37#include <config.h>
38#endif
39#include <X11/fonts/fntfilst.h>
40#include <X11/keysym.h>
41#ifdef WIN32
42#include <ctype.h>
43#endif
44
45static unsigned char
46ISOLatin1ToLower(unsigned char source)
47{
48    if (source >= XK_A && source <= XK_Z)
49	return source + (XK_a - XK_A);
50    if (source >= XK_Agrave && source <= XK_Odiaeresis)
51	return source + (XK_agrave - XK_Agrave);
52    if (source >= XK_Ooblique && source <= XK_Thorn)
53	return source + (XK_oslash - XK_Ooblique);
54    return source;
55}
56
57_X_HIDDEN void
58CopyISOLatin1Lowered(char *dest, char *source, int length)
59{
60    int i;
61    for (i = 0; i < length; i++, source++, dest++)
62	*dest = ISOLatin1ToLower(*source);
63    *dest = '\0';
64}
65
66/*
67 * Map FPE functions to renderer functions
68 */
69
70static int FontFileOpenBitmapNCF (FontPathElementPtr fpe, FontPtr *pFont,
71				  int flags, FontEntryPtr entry,
72				  fsBitmapFormat format,
73				  fsBitmapFormatMask fmask,
74				  FontPtr non_cachable_font);
75
76int
77FontFileNameCheck (char *name)
78{
79#ifndef NCD
80#if defined(WIN32)
81    /* OS/2 uses D:/... as a path name for fonts, so accept this as a valid
82     * path if it starts with a letter and a colon. Same applies for WIN32
83     */
84    if (isalpha(*name) && name[1]==':')
85        return TRUE;
86#endif
87    return *name == '/';
88#else
89    return ((strcmp(name, "built-ins") == 0) || (*name == '/'));
90#endif
91}
92
93int
94FontFileInitFPE (FontPathElementPtr fpe)
95{
96    int			status;
97    FontDirectoryPtr	dir;
98
99    status = FontFileReadDirectory (fpe->name, &dir);
100    if (status == Successful)
101    {
102	if (dir->nonScalable.used > 0)
103	    if (!FontFileRegisterBitmapSource (fpe))
104	    {
105		FontFileFreeFPE (fpe);
106		return AllocError;
107	    }
108	fpe->private = (pointer) dir;
109    }
110    return status;
111}
112
113/* ARGSUSED */
114int
115FontFileResetFPE (FontPathElementPtr fpe)
116{
117    FontDirectoryPtr	dir;
118
119    dir = (FontDirectoryPtr) fpe->private;
120    /*
121     * The reset must fail for bitmap fonts because they get cleared when
122     * the path is set.
123     */
124    if (FontFileDirectoryChanged (dir))
125    {
126	/* can't do it, so tell the caller to close and re-open */
127	return FPEResetFailed;
128    }
129    else
130    {
131	if (dir->nonScalable.used > 0)
132	    if (!FontFileRegisterBitmapSource (fpe))
133	    {
134	        return FPEResetFailed;
135	    }
136        return Successful;
137    }
138}
139
140int
141FontFileFreeFPE (FontPathElementPtr fpe)
142{
143    FontFileUnregisterBitmapSource (fpe);
144    FontFileFreeDir ((FontDirectoryPtr) fpe->private);
145    return Successful;
146}
147
148static int
149transfer_values_to_alias(char *entryname, int entrynamelength,
150			 char *resolvedname,
151			 char **aliasName, FontScalablePtr vals)
152{
153    static char		aliasname[MAXFONTNAMELEN];
154    int			nameok = 1, len;
155    char		lowerName[MAXFONTNAMELEN];
156
157    *aliasName = resolvedname;
158    if ((len = strlen(*aliasName)) <= MAXFONTNAMELEN &&
159	(entrynamelength < MAXFONTNAMELEN) &&
160	FontFileCountDashes (*aliasName, len) == 14)
161    {
162	FontScalableRec tmpVals;
163	FontScalableRec tmpVals2;
164
165	tmpVals2 = *vals;
166
167	/* If we're aliasing a scalable name, transfer values
168	   from the name into the destination alias, multiplying
169	   by matrices that appear in the alias. */
170
171	CopyISOLatin1Lowered (lowerName, entryname,
172			      entrynamelength);
173	lowerName[entrynamelength] = '\0';
174
175	if (FontParseXLFDName(lowerName, &tmpVals,
176			      FONT_XLFD_REPLACE_NONE) &&
177	    !tmpVals.values_supplied &&
178	    FontParseXLFDName(*aliasName, &tmpVals,
179			      FONT_XLFD_REPLACE_NONE))
180	{
181	    double *matrix = 0, tempmatrix[4];
182
183	    /* Use a matrix iff exactly one is defined */
184	    if ((tmpVals.values_supplied & PIXELSIZE_MASK) ==
185		PIXELSIZE_ARRAY &&
186		!(tmpVals.values_supplied & POINTSIZE_MASK))
187		matrix = tmpVals.pixel_matrix;
188	    else if ((tmpVals.values_supplied & POINTSIZE_MASK) ==
189		     POINTSIZE_ARRAY &&
190		     !(tmpVals.values_supplied & PIXELSIZE_MASK))
191		matrix = tmpVals.point_matrix;
192
193	    /* If matrix given in the alias, compute new point
194	       and/or pixel matrices */
195	    if (matrix)
196	    {
197		/* Complete the XLFD name to avoid potential
198		   gotchas */
199		if (FontFileCompleteXLFD(&tmpVals2, &tmpVals2))
200		{
201		    tempmatrix[0] =
202			matrix[0] * tmpVals2.point_matrix[0] +
203			matrix[1] * tmpVals2.point_matrix[2];
204		    tempmatrix[1] =
205			matrix[0] * tmpVals2.point_matrix[1] +
206			matrix[1] * tmpVals2.point_matrix[3];
207		    tempmatrix[2] =
208			matrix[2] * tmpVals2.point_matrix[0] +
209			matrix[3] * tmpVals2.point_matrix[2];
210		    tempmatrix[3] =
211			matrix[2] * tmpVals2.point_matrix[1] +
212			matrix[3] * tmpVals2.point_matrix[3];
213		    tmpVals2.point_matrix[0] = tempmatrix[0];
214		    tmpVals2.point_matrix[1] = tempmatrix[1];
215		    tmpVals2.point_matrix[2] = tempmatrix[2];
216		    tmpVals2.point_matrix[3] = tempmatrix[3];
217
218		    tempmatrix[0] =
219			matrix[0] * tmpVals2.pixel_matrix[0] +
220			matrix[1] * tmpVals2.pixel_matrix[2];
221		    tempmatrix[1] =
222			matrix[0] * tmpVals2.pixel_matrix[1] +
223			matrix[1] * tmpVals2.pixel_matrix[3];
224		    tempmatrix[2] =
225			matrix[2] * tmpVals2.pixel_matrix[0] +
226			matrix[3] * tmpVals2.pixel_matrix[2];
227		    tempmatrix[3] =
228			matrix[2] * tmpVals2.pixel_matrix[1] +
229			matrix[3] * tmpVals2.pixel_matrix[3];
230		    tmpVals2.pixel_matrix[0] = tempmatrix[0];
231		    tmpVals2.pixel_matrix[1] = tempmatrix[1];
232		    tmpVals2.pixel_matrix[2] = tempmatrix[2];
233		    tmpVals2.pixel_matrix[3] = tempmatrix[3];
234
235		    tmpVals2.values_supplied =
236			(tmpVals2.values_supplied &
237			 ~(PIXELSIZE_MASK | POINTSIZE_MASK)) |
238			PIXELSIZE_ARRAY | POINTSIZE_ARRAY;
239		}
240		else
241		    nameok = 0;
242	    }
243
244	    CopyISOLatin1Lowered (aliasname, *aliasName, len + 1);
245	    if (nameok && FontParseXLFDName(aliasname, &tmpVals2,
246				  FONT_XLFD_REPLACE_VALUE))
247		/* Return a version of the aliasname that has
248		   had the vals stuffed into it.  To avoid
249		   memory leak, this alias name lives in a
250		   static buffer.  The caller needs to be done
251		   with this buffer before this procedure is
252		   called again to avoid reentrancy problems. */
253		    *aliasName = aliasname;
254	}
255    }
256    return nameok;
257}
258
259/* ARGSUSED */
260int
261FontFileOpenFont (pointer client, FontPathElementPtr fpe, Mask flags,
262		  char *name, int namelen,
263		  fsBitmapFormat format, fsBitmapFormatMask fmask,
264		  XID id, FontPtr *pFont, char **aliasName,
265		  FontPtr non_cachable_font)
266{
267    FontDirectoryPtr	dir;
268    char		lowerName[MAXFONTNAMELEN];
269    char		fileName[MAXFONTFILENAMELEN*2 + 1];
270    FontNameRec		tmpName;
271    FontEntryPtr	entry;
272    FontScalableRec	vals;
273    FontScalableEntryPtr   scalable;
274    FontScaledPtr	scaled;
275    FontBitmapEntryPtr	bitmap;
276    int			ret;
277    Bool		noSpecificSize;
278    int			nranges;
279    fsRange		*ranges;
280
281    if (namelen >= MAXFONTNAMELEN)
282	return AllocError;
283    dir = (FontDirectoryPtr) fpe->private;
284
285    /* Match non-scalable pattern */
286    CopyISOLatin1Lowered (lowerName, name, namelen);
287    lowerName[namelen] = '\0';
288    ranges = FontParseRanges(lowerName, &nranges);
289    tmpName.name = lowerName;
290    tmpName.length = namelen;
291    tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
292    if (!FontParseXLFDName(lowerName, &vals, FONT_XLFD_REPLACE_NONE))
293	bzero(&vals, sizeof(vals));
294    if (!(entry = FontFileFindNameInDir (&dir->nonScalable, &tmpName)) &&
295	tmpName.ndashes == 14 &&
296	FontParseXLFDName (lowerName, &vals, FONT_XLFD_REPLACE_ZERO))
297    {
298        tmpName.length = strlen(lowerName);
299	entry = FontFileFindNameInDir (&dir->nonScalable, &tmpName);
300    }
301
302    if (entry)
303    {
304	switch (entry->type) {
305	case FONT_ENTRY_BITMAP:
306	    bitmap = &entry->u.bitmap;
307	    if (bitmap->pFont)
308	    {
309	    	*pFont = bitmap->pFont;
310		(*pFont)->fpe = fpe;
311	    	ret = Successful;
312	    }
313	    else
314	    {
315		ret = FontFileOpenBitmapNCF (fpe, pFont, flags, entry, format,
316					     fmask, non_cachable_font);
317		if (ret == Successful && *pFont)
318		    (*pFont)->fpe = fpe;
319	    }
320	    break;
321	case FONT_ENTRY_ALIAS:
322	    vals.nranges = nranges;
323	    vals.ranges = ranges;
324	    transfer_values_to_alias(entry->name.name, entry->name.length,
325				     entry->u.alias.resolved, aliasName, &vals);
326	    ret = FontNameAlias;
327	    break;
328	default:
329	    ret = BadFontName;
330	}
331    }
332    else
333    {
334	ret = BadFontName;
335    }
336
337    if (ret != BadFontName)
338    {
339	if (ranges) free(ranges);
340	return ret;
341    }
342
343    /* Match XLFD patterns */
344    CopyISOLatin1Lowered (lowerName, name, namelen);
345    lowerName[namelen] = '\0';
346    tmpName.name = lowerName;
347    tmpName.length = namelen;
348    tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
349    if (!FontParseXLFDName (lowerName, &vals, FONT_XLFD_REPLACE_ZERO) ||
350	!(tmpName.length = strlen (lowerName),
351	  entry = FontFileFindNameInScalableDir (&dir->scalable, &tmpName,
352						 &vals))) {
353	CopyISOLatin1Lowered (lowerName, name, namelen);
354	lowerName[namelen] = '\0';
355	tmpName.name = lowerName;
356	tmpName.length = namelen;
357	tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
358	entry = FontFileFindNameInScalableDir (&dir->scalable, &tmpName, &vals);
359	if (entry)
360	{
361	    strcpy(lowerName, entry->name.name);
362	    tmpName.name = lowerName;
363	    tmpName.length = entry->name.length;
364	    tmpName.ndashes = entry->name.ndashes;
365	}
366    }
367
368    if (entry)
369    {
370	noSpecificSize = FALSE;	/* TRUE breaks XLFD enhancements */
371    	if (entry->type == FONT_ENTRY_SCALABLE &&
372	    FontFileCompleteXLFD (&vals, &entry->u.scalable.extra->defaults))
373	{
374	    scalable = &entry->u.scalable;
375	    if ((vals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
376		(vals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY ||
377		(vals.values_supplied &
378		 ~SIZE_SPECIFY_MASK & ~CHARSUBSET_SPECIFIED))
379		scaled = 0;
380	    else
381	        scaled = FontFileFindScaledInstance (entry, &vals,
382						     noSpecificSize);
383	    /*
384	     * A scaled instance can occur one of two ways:
385	     *
386	     *  Either the font has been scaled to this
387	     *   size already, in which case scaled->pFont
388	     *   will point at that font.
389	     *
390	     *  Or a bitmap instance in this size exists,
391	     *   which is handled as if we got a pattern
392	     *   matching the bitmap font name.
393	     */
394	    if (scaled)
395	    {
396		if (scaled->pFont)
397		{
398		    *pFont = scaled->pFont;
399		    (*pFont)->fpe = fpe;
400		    ret = Successful;
401		}
402		else if (scaled->bitmap)
403		{
404		    entry = scaled->bitmap;
405		    bitmap = &entry->u.bitmap;
406		    if (bitmap->pFont)
407		    {
408			*pFont = bitmap->pFont;
409			(*pFont)->fpe = fpe;
410			ret = Successful;
411		    }
412		    else
413		    {
414			ret = FontFileOpenBitmapNCF (fpe, pFont, flags, entry,
415						     format, fmask,
416						     non_cachable_font);
417			if (ret == Successful && *pFont)
418			    (*pFont)->fpe = fpe;
419		    }
420		}
421		else /* "cannot" happen */
422		{
423		    ret = BadFontName;
424		}
425	    }
426	    else
427	    {
428		ret = FontFileMatchBitmapSource (fpe, pFont, flags, entry, &tmpName, &vals, format, fmask, noSpecificSize);
429		if (ret != Successful)
430		{
431		    char origName[MAXFONTNAMELEN];
432
433		    CopyISOLatin1Lowered (origName, name, namelen);
434		    origName[namelen] = '\0';
435
436		    /* Pass the original XLFD name in the vals
437		       structure; the rasterizer is free to examine it
438		       for hidden meanings.  This information will not
439		       be saved in the scaled-instances table.  */
440
441		    vals.xlfdName = origName;
442		    vals.ranges = ranges;
443		    vals.nranges = nranges;
444
445		    if (strlen(dir->directory) + strlen(scalable->fileName) >=
446			sizeof(fileName)) {
447			ret = BadFontName;
448		    } else {
449			strcpy (fileName, dir->directory);
450			strcat (fileName, scalable->fileName);
451                        if (scalable->renderer->OpenScalable) {
452			    ret = (*scalable->renderer->OpenScalable) (fpe, pFont,
453			       flags, entry, fileName, &vals, format, fmask,
454			       non_cachable_font);
455                        }
456                        else if (scalable->renderer->OpenBitmap) {
457                            ret = (*scalable->renderer->OpenBitmap) (fpe, pFont,
458                               flags, entry, fileName, format, fmask,
459                               non_cachable_font);
460                        }
461		    }
462
463		    /* In case rasterizer does something bad because of
464		       charset subsetting... */
465		    if (ret == Successful &&
466			((*pFont)->info.firstCol > (*pFont)->info.lastCol ||
467			 (*pFont)->info.firstRow > (*pFont)->info.lastRow))
468		    {
469			(*(*pFont)->unload_font)(*pFont);
470			ret = BadFontName;
471		    }
472		    /* Save the instance */
473		    if (ret == Successful)
474		    {
475		    	if (FontFileAddScaledInstance (entry, &vals,
476						    *pFont, (char *) 0))
477			    ranges = 0;
478			else
479			    (*pFont)->fpePrivate = (pointer) 0;
480			(*pFont)->fpe = fpe;
481		    }
482		}
483	    }
484	}
485    }
486    else
487	ret = BadFontName;
488
489    if (ranges)
490	free(ranges);
491    return ret;
492}
493
494/* ARGSUSED */
495void
496FontFileCloseFont (FontPathElementPtr fpe, FontPtr pFont)
497{
498    FontEntryPtr    entry;
499
500    if ((entry = (FontEntryPtr) pFont->fpePrivate)) {
501	switch (entry->type) {
502	case FONT_ENTRY_SCALABLE:
503	    FontFileRemoveScaledInstance (entry, pFont);
504	    break;
505	case FONT_ENTRY_BITMAP:
506	    entry->u.bitmap.pFont = 0;
507	    break;
508	default:
509	    /* "cannot" happen */
510	    break;
511	}
512	pFont->fpePrivate = 0;
513    }
514    (*pFont->unload_font) (pFont);
515}
516
517static int
518FontFileOpenBitmapNCF (FontPathElementPtr fpe, FontPtr *pFont,
519		       int flags, FontEntryPtr entry,
520		       fsBitmapFormat format, fsBitmapFormatMask fmask,
521		       FontPtr non_cachable_font)
522{
523    FontBitmapEntryPtr	bitmap;
524    char		fileName[MAXFONTFILENAMELEN*2+1];
525    int			ret;
526    FontDirectoryPtr	dir;
527
528    dir = (FontDirectoryPtr) fpe->private;
529    bitmap = &entry->u.bitmap;
530    if(!bitmap || !bitmap->renderer->OpenBitmap)
531        return BadFontName;
532    if (strlen(dir->directory) + strlen(bitmap->fileName) >= sizeof(fileName))
533	return BadFontName;
534    strcpy (fileName, dir->directory);
535    strcat (fileName, bitmap->fileName);
536    ret = (*bitmap->renderer->OpenBitmap)
537			(fpe, pFont, flags, entry, fileName, format, fmask,
538			 non_cachable_font);
539    if (ret == Successful)
540    {
541	bitmap->pFont = *pFont;
542	(*pFont)->fpePrivate = (pointer) entry;
543    }
544    return ret;
545}
546
547int
548FontFileOpenBitmap (FontPathElementPtr fpe, FontPtr *pFont,
549		    int flags, FontEntryPtr entry,
550		    fsBitmapFormat format, fsBitmapFormatMask fmask)
551{
552    return FontFileOpenBitmapNCF (fpe, pFont, flags, entry, format, fmask,
553				  (FontPtr)0);
554}
555
556static int
557FontFileGetInfoBitmap (FontPathElementPtr fpe, FontInfoPtr pFontInfo,
558		       FontEntryPtr entry)
559{
560    FontBitmapEntryPtr	bitmap;
561    char		fileName[MAXFONTFILENAMELEN*2+1];
562    int			ret;
563    FontDirectoryPtr	dir;
564
565    dir = (FontDirectoryPtr) fpe->private;
566    bitmap = &entry->u.bitmap;
567    if (!bitmap || !bitmap->renderer->GetInfoBitmap)
568	return BadFontName;
569    if (strlen(dir->directory) + strlen(bitmap->fileName) >= sizeof(fileName))
570	return BadFontName;
571    strcpy (fileName, dir->directory);
572    strcat (fileName, bitmap->fileName);
573    ret = (*bitmap->renderer->GetInfoBitmap) (fpe, pFontInfo, entry, fileName);
574    return ret;
575}
576
577static void
578_FontFileAddScalableNames(FontNamesPtr names, FontNamesPtr scaleNames,
579			  FontNamePtr nameptr, char *zeroChars,
580			  FontScalablePtr vals, fsRange *ranges,
581			  int nranges, int *max)
582{
583    int i;
584    FontScalableRec	zeroVals, tmpVals;
585    for (i = 0; i < scaleNames->nnames; i++)
586    {
587	char nameChars[MAXFONTNAMELEN];
588	if (!*max)
589	    return;
590	FontParseXLFDName (scaleNames->names[i], &zeroVals,
591			   FONT_XLFD_REPLACE_NONE);
592	tmpVals = *vals;
593	if (FontFileCompleteXLFD (&tmpVals, &zeroVals))
594	{
595	    --*max;
596
597	    strcpy (nameChars, scaleNames->names[i]);
598	    if ((vals->values_supplied & PIXELSIZE_MASK) ||
599		!(vals->values_supplied & PIXELSIZE_WILDCARD) ||
600		vals->y == 0)
601	    {
602		tmpVals.values_supplied =
603		    (tmpVals.values_supplied & ~PIXELSIZE_MASK) |
604		    (vals->values_supplied & PIXELSIZE_MASK);
605		tmpVals.pixel_matrix[0] = vals->pixel_matrix[0];
606		tmpVals.pixel_matrix[1] = vals->pixel_matrix[1];
607		tmpVals.pixel_matrix[2] = vals->pixel_matrix[2];
608		tmpVals.pixel_matrix[3] = vals->pixel_matrix[3];
609	    }
610	    if ((vals->values_supplied & POINTSIZE_MASK) ||
611		!(vals->values_supplied & POINTSIZE_WILDCARD) ||
612		vals->y == 0)
613	    {
614		tmpVals.values_supplied =
615		    (tmpVals.values_supplied & ~POINTSIZE_MASK) |
616		    (vals->values_supplied & POINTSIZE_MASK);
617		tmpVals.point_matrix[0] = vals->point_matrix[0];
618		tmpVals.point_matrix[1] = vals->point_matrix[1];
619		tmpVals.point_matrix[2] = vals->point_matrix[2];
620		tmpVals.point_matrix[3] = vals->point_matrix[3];
621	    }
622	    if (vals->width <= 0)
623		tmpVals.width = 0;
624	    if (vals->x == 0)
625		tmpVals.x = 0;
626	    if (vals->y == 0)
627		tmpVals.y = 0;
628	    tmpVals.ranges = ranges;
629	    tmpVals.nranges = nranges;
630	    FontParseXLFDName (nameChars, &tmpVals,
631			       FONT_XLFD_REPLACE_VALUE);
632	    /* If we're marking aliases with negative lengths, we
633	       need to concoct a valid target name to follow it.
634	       Otherwise we're done.  */
635	    if (scaleNames->length[i] >= 0)
636	    {
637		(void) AddFontNamesName (names, nameChars,
638					 strlen (nameChars));
639		/* If our original pattern matches the name from
640		   the table and that name doesn't duplicate what
641		   we just added, add the name from the table */
642		if (strcmp(nameChars, scaleNames->names[i]) &&
643		    FontFileMatchName(scaleNames->names[i],
644				      scaleNames->length[i],
645				      nameptr) &&
646		    *max)
647		{
648		    --*max;
649		    (void) AddFontNamesName (names, scaleNames->names[i],
650					     scaleNames->length[i]);
651		}
652	    }
653	    else
654	    {
655		char *aliasName;
656		vals->ranges = ranges;
657		vals->nranges = nranges;
658		if (transfer_values_to_alias(zeroChars,
659					     strlen(zeroChars),
660					     scaleNames->names[++i],
661					     &aliasName, vals))
662		{
663		    (void) AddFontNamesName (names, nameChars,
664					     strlen (nameChars));
665		    names->length[names->nnames - 1] =
666			-names->length[names->nnames - 1];
667		    (void) AddFontNamesName (names, aliasName,
668					     strlen (aliasName));
669		    /* If our original pattern matches the name from
670		       the table and that name doesn't duplicate what
671		       we just added, add the name from the table */
672		    if (strcmp(nameChars, scaleNames->names[i - 1]) &&
673			FontFileMatchName(scaleNames->names[i - 1],
674					  -scaleNames->length[i - 1],
675					  nameptr) &&
676			*max)
677		    {
678			--*max;
679			(void) AddFontNamesName (names,
680						 scaleNames->names[i - 1],
681						 -scaleNames->length[i - 1]);
682			names->length[names->nnames - 1] =
683			    -names->length[names->nnames - 1];
684			(void) AddFontNamesName (names, aliasName,
685						 strlen (aliasName));
686		    }
687		}
688	    }
689	}
690    }
691}
692
693/* ARGSUSED */
694static int
695_FontFileListFonts (pointer client, FontPathElementPtr fpe,
696		    char *pat, int len, int max, FontNamesPtr names,
697		    int mark_aliases)
698{
699    FontDirectoryPtr	dir;
700    char		lowerChars[MAXFONTNAMELEN], zeroChars[MAXFONTNAMELEN];
701    FontNameRec		lowerName;
702    FontNameRec		zeroName;
703    FontNamesPtr	scaleNames;
704    FontScalableRec	vals;
705    fsRange		*ranges;
706    int			nranges;
707    int			result = BadFontName;
708
709    if (len >= MAXFONTNAMELEN)
710	return AllocError;
711    dir = (FontDirectoryPtr) fpe->private;
712    CopyISOLatin1Lowered (lowerChars, pat, len);
713    lowerChars[len] = '\0';
714    lowerName.name = lowerChars;
715    lowerName.length = len;
716    lowerName.ndashes = FontFileCountDashes (lowerChars, len);
717
718    /* Match XLFD patterns */
719
720    strcpy (zeroChars, lowerChars);
721    if (lowerName.ndashes == 14 &&
722	FontParseXLFDName (zeroChars, &vals, FONT_XLFD_REPLACE_ZERO))
723    {
724	ranges = FontParseRanges(lowerChars, &nranges);
725        result = FontFileFindNamesInScalableDir (&dir->nonScalable,
726				&lowerName, max, names,
727				(FontScalablePtr)0,
728				(mark_aliases ?
729				 LIST_ALIASES_AND_TARGET_NAMES :
730				 NORMAL_ALIAS_BEHAVIOR) |
731				IGNORE_SCALABLE_ALIASES,
732				&max);
733	zeroName.name = zeroChars;
734	zeroName.length = strlen (zeroChars);
735	zeroName.ndashes = lowerName.ndashes;
736
737	/* Look for scalable names and aliases, adding scaled instances of
738	   them to the output */
739
740	/* Scalable names... */
741	scaleNames = MakeFontNamesRecord (0);
742	if (!scaleNames)
743	{
744	    if (ranges) free(ranges);
745	    return AllocError;
746	}
747	FontFileFindNamesInScalableDir (&dir->scalable, &zeroName, max,
748					scaleNames, &vals,
749					mark_aliases ?
750					LIST_ALIASES_AND_TARGET_NAMES :
751					NORMAL_ALIAS_BEHAVIOR, (int *)0);
752	_FontFileAddScalableNames(names, scaleNames, &lowerName,
753				  zeroChars, &vals, ranges, nranges,
754				  &max);
755	FreeFontNames (scaleNames);
756
757	/* Scalable aliases... */
758	scaleNames = MakeFontNamesRecord (0);
759	if (!scaleNames)
760	{
761	    if (ranges) free(ranges);
762	    return AllocError;
763	}
764	FontFileFindNamesInScalableDir (&dir->nonScalable, &zeroName,
765					max, scaleNames, &vals,
766					mark_aliases ?
767					LIST_ALIASES_AND_TARGET_NAMES :
768					NORMAL_ALIAS_BEHAVIOR, (int *)0);
769	_FontFileAddScalableNames(names, scaleNames, &lowerName,
770				  zeroChars, &vals, ranges, nranges,
771				  &max);
772	FreeFontNames (scaleNames);
773
774	if (ranges) free(ranges);
775    }
776    else
777    {
778        result = FontFileFindNamesInScalableDir (&dir->nonScalable,
779				&lowerName, max, names,
780				(FontScalablePtr)0,
781				mark_aliases ?
782				LIST_ALIASES_AND_TARGET_NAMES :
783				NORMAL_ALIAS_BEHAVIOR,
784				&max);
785	if (result == Successful)
786    	    result = FontFileFindNamesInScalableDir (&dir->scalable,
787				&lowerName, max, names,
788				(FontScalablePtr)0,
789				mark_aliases ?
790				LIST_ALIASES_AND_TARGET_NAMES :
791				NORMAL_ALIAS_BEHAVIOR, (int *)0);
792    }
793    return result;
794}
795
796typedef struct _LFWIData {
797    FontNamesPtr    names;
798    int                   current;
799} LFWIDataRec, *LFWIDataPtr;
800
801int
802FontFileListFonts (pointer client, FontPathElementPtr fpe, char *pat,
803		   int len, int max, FontNamesPtr names)
804{
805    return _FontFileListFonts (client, fpe, pat, len, max, names, 0);
806}
807
808int
809FontFileStartListFonts(pointer client, FontPathElementPtr fpe,
810		       char *pat, int len, int max,
811		       pointer *privatep, int mark_aliases)
812{
813    LFWIDataPtr	data;
814    int		ret;
815
816    data = malloc (sizeof *data);
817    if (!data)
818	return AllocError;
819    data->names = MakeFontNamesRecord (0);
820    if (!data->names)
821    {
822	free (data);
823	return AllocError;
824    }
825    ret = _FontFileListFonts (client, fpe, pat, len,
826			      max, data->names, mark_aliases);
827    if (ret != Successful)
828    {
829	FreeFontNames (data->names);
830	free (data);
831	return ret;
832    }
833    data->current = 0;
834    *privatep = (pointer) data;
835    return Successful;
836}
837
838
839int
840FontFileStartListFontsWithInfo(pointer client, FontPathElementPtr fpe,
841			       char *pat, int len, int max,
842			       pointer *privatep)
843{
844    return FontFileStartListFonts(client, fpe, pat, len, max, privatep, 0);
845}
846
847/* ARGSUSED */
848static int
849FontFileListOneFontWithInfo (pointer client, FontPathElementPtr fpe,
850			     char **namep, int *namelenp,
851			     FontInfoPtr *pFontInfo)
852{
853    FontDirectoryPtr	dir;
854    char		lowerName[MAXFONTNAMELEN];
855    char		fileName[MAXFONTFILENAMELEN*2 + 1];
856    FontNameRec		tmpName;
857    FontEntryPtr	entry;
858    FontScalableRec	vals;
859    FontScalableEntryPtr   scalable;
860    FontScaledPtr	scaled;
861    FontBitmapEntryPtr	bitmap;
862    int			ret;
863    Bool		noSpecificSize;
864    int			nranges;
865    fsRange		*ranges;
866
867    char		*name = *namep;
868    int			namelen = *namelenp;
869
870    if (namelen >= MAXFONTNAMELEN)
871	return AllocError;
872    dir = (FontDirectoryPtr) fpe->private;
873
874    /* Match non-scalable pattern */
875    CopyISOLatin1Lowered (lowerName, name, namelen);
876    lowerName[namelen] = '\0';
877    ranges = FontParseRanges(lowerName, &nranges);
878    tmpName.name = lowerName;
879    tmpName.length = namelen;
880    tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
881    if (!FontParseXLFDName(lowerName, &vals, FONT_XLFD_REPLACE_NONE))
882	bzero(&vals, sizeof(vals));
883    if (!(entry = FontFileFindNameInDir (&dir->nonScalable, &tmpName)) &&
884	tmpName.ndashes == 14 &&
885	FontParseXLFDName (lowerName, &vals, FONT_XLFD_REPLACE_ZERO))
886    {
887        tmpName.length = strlen(lowerName);
888	entry = FontFileFindNameInDir (&dir->nonScalable, &tmpName);
889    }
890
891    if (entry)
892    {
893	switch (entry->type) {
894	case FONT_ENTRY_BITMAP:
895	    bitmap = &entry->u.bitmap;
896	    if (bitmap->pFont)
897	    {
898	    	*pFontInfo = &bitmap->pFont->info;
899	    	ret = Successful;
900	    }
901	    else
902	    {
903		ret = FontFileGetInfoBitmap (fpe, *pFontInfo, entry);
904	    }
905	    break;
906	case FONT_ENTRY_ALIAS:
907	    vals.nranges = nranges;
908	    vals.ranges = ranges;
909	    transfer_values_to_alias(entry->name.name, entry->name.length,
910				     entry->u.alias.resolved, namep, &vals);
911	    *namelenp = strlen (*namep);
912	    ret = FontNameAlias;
913	    break;
914	default:
915	    ret = BadFontName;
916	}
917    }
918    else
919    {
920      ret = BadFontName;
921    }
922
923    if (ret != BadFontName)
924    {
925	if (ranges) free(ranges);
926	return ret;
927    }
928
929    /* Match XLFD patterns */
930    CopyISOLatin1Lowered (lowerName, name, namelen);
931    lowerName[namelen] = '\0';
932    tmpName.name = lowerName;
933    tmpName.length = namelen;
934    tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
935    if (!FontParseXLFDName (lowerName, &vals, FONT_XLFD_REPLACE_ZERO) ||
936	!(tmpName.length = strlen (lowerName),
937	  entry = FontFileFindNameInScalableDir (&dir->scalable, &tmpName,
938						 &vals))) {
939	CopyISOLatin1Lowered (lowerName, name, namelen);
940	lowerName[namelen] = '\0';
941	tmpName.name = lowerName;
942	tmpName.length = namelen;
943	tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
944	entry = FontFileFindNameInScalableDir (&dir->scalable, &tmpName, &vals);
945	if (entry)
946	{
947	    strcpy(lowerName, entry->name.name);
948	    tmpName.name = lowerName;
949	    tmpName.length = entry->name.length;
950	    tmpName.ndashes = entry->name.ndashes;
951	}
952    }
953
954    if (entry)
955    {
956	noSpecificSize = FALSE;	/* TRUE breaks XLFD enhancements */
957    	if (entry && entry->type == FONT_ENTRY_SCALABLE &&
958	    FontFileCompleteXLFD (&vals, &entry->u.scalable.extra->defaults))
959	{
960	    scalable = &entry->u.scalable;
961	    scaled = FontFileFindScaledInstance (entry, &vals, noSpecificSize);
962	    /*
963	     * A scaled instance can occur one of two ways:
964	     *
965	     *  Either the font has been scaled to this
966	     *   size already, in which case scaled->pFont
967	     *   will point at that font.
968	     *
969	     *  Or a bitmap instance in this size exists,
970	     *   which is handled as if we got a pattern
971	     *   matching the bitmap font name.
972	     */
973	    if (scaled)
974	    {
975		if (scaled->pFont)
976		{
977		    *pFontInfo = &scaled->pFont->info;
978		    ret = Successful;
979		}
980		else if (scaled->bitmap)
981		{
982		    entry = scaled->bitmap;
983		    bitmap = &entry->u.bitmap;
984		    if (bitmap->pFont)
985		    {
986			*pFontInfo = &bitmap->pFont->info;
987			ret = Successful;
988		    }
989		    else
990		    {
991			ret = FontFileGetInfoBitmap (fpe, *pFontInfo, entry);
992		    }
993		}
994		else /* "cannot" happen */
995		{
996		    ret = BadFontName;
997		}
998	    }
999	    else
1000	    {
1001		{
1002		    char origName[MAXFONTNAMELEN];
1003
1004		    CopyISOLatin1Lowered (origName, name, namelen);
1005		    origName[namelen] = '\0';
1006		    vals.xlfdName = origName;
1007		    vals.ranges = ranges;
1008		    vals.nranges = nranges;
1009
1010		    /* Make a new scaled instance */
1011		    if (strlen(dir->directory) + strlen(scalable->fileName) >=
1012			sizeof(fileName)) {
1013			ret = BadFontName;
1014		    } else {
1015			strcpy (fileName, dir->directory);
1016			strcat (fileName, scalable->fileName);
1017                        if (scalable->renderer->GetInfoScalable)
1018			    ret = (*scalable->renderer->GetInfoScalable)
1019			        (fpe, *pFontInfo, entry, &tmpName, fileName,
1020                                 &vals);
1021                        else if (scalable->renderer->GetInfoBitmap)
1022                            ret = (*scalable->renderer->GetInfoBitmap)
1023                                (fpe, *pFontInfo, entry, fileName);
1024		    }
1025		    if (ranges) {
1026			free(ranges);
1027			ranges = NULL;
1028		    }
1029		}
1030	    }
1031	    if (ret == Successful) return ret;
1032	}
1033	CopyISOLatin1Lowered (lowerName, name, namelen);
1034	tmpName.length = namelen;
1035    }
1036    else
1037	ret = BadFontName;
1038
1039    if (ranges)
1040	free(ranges);
1041    return ret;
1042}
1043
1044int
1045FontFileListNextFontWithInfo(pointer client, FontPathElementPtr fpe,
1046			     char **namep, int *namelenp,
1047			     FontInfoPtr *pFontInfo,
1048			     int *numFonts, pointer private)
1049{
1050    LFWIDataPtr	data = (LFWIDataPtr) private;
1051    int		ret;
1052    char	*name;
1053    int		namelen;
1054
1055    if (data->current == data->names->nnames)
1056    {
1057	FreeFontNames (data->names);
1058	free (data);
1059	return BadFontName;
1060    }
1061    name = data->names->names[data->current];
1062    namelen = data->names->length[data->current];
1063    ret = FontFileListOneFontWithInfo (client, fpe, &name, &namelen, pFontInfo);
1064    if (ret == BadFontName)
1065	ret = AllocError;
1066    *namep = name;
1067    *namelenp = namelen;
1068    ++data->current;
1069    *numFonts = data->names->nnames - data->current;
1070    return ret;
1071}
1072
1073int
1074FontFileStartListFontsAndAliases(pointer client, FontPathElementPtr fpe,
1075				 char *pat, int len, int max,
1076				 pointer *privatep)
1077{
1078    return FontFileStartListFonts(client, fpe, pat, len, max, privatep, 1);
1079}
1080
1081int
1082FontFileListNextFontOrAlias(pointer client, FontPathElementPtr fpe,
1083			    char **namep, int *namelenp, char **resolvedp,
1084			    int *resolvedlenp, pointer private)
1085{
1086    LFWIDataPtr	data = (LFWIDataPtr) private;
1087    int		ret;
1088    char	*name;
1089    int		namelen;
1090
1091    if (data->current == data->names->nnames)
1092    {
1093	FreeFontNames (data->names);
1094	free (data);
1095	return BadFontName;
1096    }
1097    name = data->names->names[data->current];
1098    namelen = data->names->length[data->current];
1099
1100    /* If this is a real font name... */
1101    if (namelen >= 0)
1102    {
1103	*namep = name;
1104	*namelenp = namelen;
1105	ret = Successful;
1106    }
1107    /* Else if an alias */
1108    else
1109    {
1110	/* Tell the caller that this is an alias... let him resolve it to
1111	   see if it's valid */
1112	*namep = name;
1113	*namelenp = -namelen;
1114	*resolvedp = data->names->names[++data->current];
1115	*resolvedlenp = data->names->length[data->current];
1116	ret = FontNameAlias;
1117    }
1118
1119    ++data->current;
1120    return ret;
1121}
1122
1123void
1124FontFileRegisterLocalFpeFunctions (void)
1125{
1126    RegisterFPEFunctions(FontFileNameCheck,
1127			 FontFileInitFPE,
1128			 FontFileFreeFPE,
1129			 FontFileResetFPE,
1130			 FontFileOpenFont,
1131			 FontFileCloseFont,
1132			 FontFileListFonts,
1133			 FontFileStartListFontsWithInfo,
1134			 FontFileListNextFontWithInfo,
1135			 NULL,
1136			 NULL,
1137			 NULL,
1138			 FontFileStartListFontsAndAliases,
1139			 FontFileListNextFontOrAlias,
1140			 FontFileEmptyBitmapSource);
1141}
1142