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