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