Git init
[framework/uifw/xorg/lib/libxfont.git] / src / fontfile / fontfile.c
1 /*
2
3 Copyright 1991, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 */
26
27 /*
28  * Author:  Keith Packard, MIT X Consortium
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 #include <X11/fonts/fntfilst.h>
35 #include <X11/keysym.h>
36 #ifdef WIN32
37 #include <ctype.h>
38 #endif
39
40 static unsigned char
41 ISOLatin1ToLower(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
53 CopyISOLatin1Lowered(char *dest, 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
65 static int FontFileOpenBitmapNCF (FontPathElementPtr fpe, FontPtr *pFont, 
66                                   int flags, FontEntryPtr entry, 
67                                   fsBitmapFormat format, 
68                                   fsBitmapFormatMask fmask,
69                                   FontPtr non_cachable_font);
70
71 int
72 FontFileNameCheck (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
88 int
89 FontFileInitFPE (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 */
109 int
110 FontFileResetFPE (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
135 int
136 FontFileFreeFPE (FontPathElementPtr fpe)
137 {
138     FontFileUnregisterBitmapSource (fpe);
139     FontFileFreeDir ((FontDirectoryPtr) fpe->private);
140     return Successful;
141 }
142
143 static int
144 transfer_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 */
255 int
256 FontFileOpenFont (pointer client, FontPathElementPtr fpe, Mask flags, 
257                   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 */
490 void
491 FontFileCloseFont (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
512 static int
513 FontFileOpenBitmapNCF (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
542 int
543 FontFileOpenBitmap (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
551 static int
552 FontFileGetInfoBitmap (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
572 static 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 */
689 static int
690 _FontFileListFonts (pointer client, FontPathElementPtr fpe, 
691                     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
791 typedef struct _LFWIData {
792     FontNamesPtr    names;
793     int                   current;
794 } LFWIDataRec, *LFWIDataPtr;
795
796 int
797 FontFileListFonts (pointer client, FontPathElementPtr fpe, char *pat, 
798                    int len, int max, FontNamesPtr names)
799 {
800     return _FontFileListFonts (client, fpe, pat, len, max, names, 0);
801 }
802
803 int
804 FontFileStartListFonts(pointer client, FontPathElementPtr fpe, 
805                        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
834 int
835 FontFileStartListFontsWithInfo(pointer client, FontPathElementPtr fpe, 
836                                char *pat, int len, int max, 
837                                pointer *privatep)
838 {
839     return FontFileStartListFonts(client, fpe, pat, len, max, privatep, 0);
840 }
841
842 /* ARGSUSED */
843 static int
844 FontFileListOneFontWithInfo (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
1039 int
1040 FontFileListNextFontWithInfo(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
1068 int
1069 FontFileStartListFontsAndAliases(pointer client, FontPathElementPtr fpe, 
1070                                  char *pat, int len, int max, 
1071                                  pointer *privatep)
1072 {
1073     return FontFileStartListFonts(client, fpe, pat, len, max, privatep, 1);
1074 }
1075
1076 int
1077 FontFileListNextFontOrAlias(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
1118 void
1119 FontFileRegisterLocalFpeFunctions (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 }