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