1 /* $XConsortium: fontdir.c /main/24 1996/09/28 16:49:04 rws $ */
2 /* $XFree86: xc/lib/font/fontfile/fontdir.c,v 3.7 1996/12/23 06:02:21 dawes Exp $ */
6 Copyright (c) 1991 X Consortium
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of the X Consortium shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings
27 in this Software without prior written authorization from the X Consortium.
32 * Author: Keith Packard, MIT X Consortium
36 #include <X11/keysym.h>
39 FontFileInitTable (table, size)
45 table->entries = (FontEntryPtr) xalloc(sizeof(FontEntryRec) * size);
53 table->sorted = FALSE;
57 FontFileFreeEntry (entry)
60 FontScalableExtraPtr extra;
64 xfree(entry->name.name);
68 case FONT_ENTRY_SCALABLE:
69 xfree (entry->u.scalable.fileName);
70 extra = entry->u.scalable.extra;
71 for (i = 0; i < extra->numScaled; i++)
72 if (extra->scaled[i].vals.ranges)
73 xfree (extra->scaled[i].vals.ranges);
74 xfree (extra->scaled);
77 case FONT_ENTRY_BITMAP:
78 xfree (entry->u.bitmap.fileName);
80 case FONT_ENTRY_ALIAS:
81 xfree (entry->u.alias.resolved);
90 FontFileFreeTable (table)
95 for (i = 0; i < table->used; i++)
96 FontFileFreeEntry (&table->entries[i]);
97 xfree (table->entries);
101 FontFileMakeDir(dirName, size)
105 FontDirectoryPtr dir;
115 attrib = strchr(dirName, ':');
117 /* OS/2 uses the colon in the drive letter descriptor, skip this */
118 attrib = strchr(dirName+2, ':');
121 dirlen = attrib - dirName;
122 attriblen = strlen(attrib);
124 dirlen = strlen(dirName);
128 dirlen = strlen(dirName);
130 if (dirName[dirlen - 1] != '/')
132 if (dirlen) /* leave out slash for builtins */
136 dir = (FontDirectoryPtr) xalloc(sizeof *dir + dirlen + needslash + 1 +
137 (attriblen ? attriblen + 1 : 0));
139 dir = (FontDirectoryPtr) xalloc(sizeof *dir + dirlen + needslash + 1);
142 return (FontDirectoryPtr)0;
143 if (!FontFileInitTable (&dir->scalable, 0))
146 return (FontDirectoryPtr)0;
148 if (!FontFileInitTable (&dir->nonScalable, size))
150 FontFileFreeTable (&dir->scalable);
152 return (FontDirectoryPtr)0;
154 dir->directory = (char *) (dir + 1);
156 dir->alias_mtime = 0;
159 dir->attributes = dir->directory + dirlen + needslash + 1;
161 dir->attributes = NULL;
162 strncpy(dir->directory, dirName, dirlen);
163 dir->directory[dirlen] = '\0';
165 strcpy(dir->attributes, attrib);
167 strcpy(dir->directory, dirName);
170 strcat(dir->directory, "/");
174 FontFileFreeDir (dir)
175 FontDirectoryPtr dir;
177 FontFileFreeTable (&dir->scalable);
178 FontFileFreeTable (&dir->nonScalable);
183 FontFileAddEntry(table, prototype)
185 FontEntryPtr prototype;
190 /* can't add entries to a sorted table, pointers get broken! */
192 return (FontEntryPtr) 0; /* "cannot" happen */
193 if (table->used == table->size) {
194 newsize = table->size + 100;
195 entry = (FontEntryPtr) xrealloc(table->entries,
196 newsize * sizeof(FontEntryRec));
198 return (FontEntryPtr)0;
199 table->size = newsize;
200 table->entries = entry;
202 entry = &table->entries[table->used];
204 entry->name.name = (char *) xalloc(prototype->name.length + 1);
205 if (!entry->name.name)
206 return (FontEntryPtr)0;
207 memcpy (entry->name.name, prototype->name.name, prototype->name.length);
208 entry->name.name[entry->name.length] = '\0';
214 FontFileNameCompare(a, b)
218 FontEntryPtr a_name = (FontEntryPtr) a,
219 b_name = (FontEntryPtr) b;
221 return strcmp(a_name->name.name, b_name->name.name);
224 FontFileSortTable (table)
227 if (!table->sorted) {
228 qsort((char *) table->entries, table->used, sizeof(FontEntryRec),
229 FontFileNameCompare);
230 table->sorted = TRUE;
235 FontDirectoryPtr dir;
237 FontFileSortTable (&dir->scalable);
238 FontFileSortTable (&dir->nonScalable);
239 /* now that the table is fixed in size, swizzle the pointers */
240 FontFileSwitchStringsToBitmapPointers (dir);
244 Given a Font Table, SetupWildMatch() sets up various pointers and state
245 information so the table can be searched for name(s) that match a given
246 fontname pattern -- which may contain wildcards. Under certain
247 circumstances, SetupWildMatch() will find the one table entry that
248 matches the pattern. If those circumstances do not pertain,
249 SetupWildMatch() returns a range within the the table that should be
250 searched for matching name(s). With the information established by
251 SetupWildMatch(), including state information in "private", the
252 PatternMatch() procedure is then used to test names in the range for a
256 #define isWild(c) ((c) == XK_asterisk || (c) == XK_question)
259 SetupWildMatch(table, pat, leftp, rightp, privatep)
278 nDashes = pat->ndashes;
293 if (!table->sorted) {
297 } else if (firstWild) {
298 first = firstWild - name;
299 while (left < right) {
300 center = (left + right) / 2;
301 result = strncmp(name, table->entries[center].name.name, first);
313 while (left < right) {
314 center = (left + right) / 2;
315 result = strcmp(name, table->entries[center].name.name);
330 PatternMatch(pat, patdashes, string, stringdashes)
337 if (stringdashes < patdashes)
340 switch (c = *pat++) {
347 while ((t = *string++) != XK_minus)
351 if (PatternMatch(pat, patdashes, string, stringdashes))
353 if (stringdashes == patdashes)
358 while ((t = *string++) != c) {
362 if (stringdashes-- < patdashes)
366 if (PatternMatch(pat, patdashes, string, stringdashes))
371 if (*string++ == XK_minus)
375 return (*string == '\0');
377 if (*string++ == XK_minus) {
392 FontFileCountDashes (name, namelen)
399 if (*name++ == '\055') /* avoid non ascii systems */
405 FontFileSaveString (s)
410 n = (char *) xalloc (strlen (s) + 1);
418 FontFileFindNameInScalableDir(table, pat, vals)
421 FontScalablePtr vals;
430 if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0)
431 return &table->entries[i];
432 for (i = start; i < stop; i++) {
433 name = &table->entries[i].name;
434 res = PatternMatch(pat->name, private, name->name, name->ndashes);
437 /* Check to see if enhancements requested are available */
440 int vs = vals->values_supplied;
443 if (table->entries[i].type == FONT_ENTRY_SCALABLE)
444 cap = table->entries[i].u.scalable.renderer->capabilities;
445 else if (table->entries[i].type == FONT_ENTRY_ALIAS)
446 cap = ~0; /* Calling code will have to see if true */
449 if (((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
450 (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
451 !(cap & CAP_MATRIX) ||
452 (vs & CHARSUBSET_SPECIFIED) &&
453 !(cap & CAP_CHARSUBSETTING))
456 return &table->entries[i];
461 return (FontEntryPtr)0;
465 FontFileFindNameInDir(table, pat)
469 return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
472 FontFileFindNamesInScalableDir(table, pat, max, names, vals,
473 alias_behavior, newmax)
478 FontScalablePtr vals;
487 int ret = Successful;
493 if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0) {
494 if (alias_behavior == NORMAL_ALIAS_BEHAVIOR ||
495 table->entries[i].type != FONT_ENTRY_ALIAS)
497 name = &table->entries[i].name;
498 if (newmax) *newmax = max - 1;
499 return AddFontNamesName(names, name->name, name->length);
504 for (i = start, fname = &table->entries[start]; i < stop; i++, fname++) {
505 res = PatternMatch(pat->name, private, fname->name.name, fname->name.ndashes);
509 int vs = vals->values_supplied;
512 if (fname->type == FONT_ENTRY_SCALABLE)
513 cap = fname->u.scalable.renderer->capabilities;
514 else if (fname->type == FONT_ENTRY_ALIAS)
515 cap = ~0; /* Calling code will have to see if true */
518 if (((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
519 (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
520 !(cap & CAP_MATRIX) ||
521 (vs & CHARSUBSET_SPECIFIED) &&
522 !(cap & CAP_CHARSUBSETTING))
526 if ((alias_behavior & IGNORE_SCALABLE_ALIASES) &&
527 fname->type == FONT_ENTRY_ALIAS)
529 FontScalableRec tmpvals;
530 if (FontParseXLFDName (fname->name.name, &tmpvals,
531 FONT_XLFD_REPLACE_NONE) &&
532 !(tmpvals.values_supplied & SIZE_SPECIFY_MASK))
536 ret = AddFontNamesName(names, fname->name.name, fname->name.length);
537 if (ret != Successful)
540 /* If alias_behavior is LIST_ALIASES_AND_TARGET_NAMES, mark
541 this entry as an alias by negating its length and follow
542 it by the resolved name */
543 if ((alias_behavior & LIST_ALIASES_AND_TARGET_NAMES) &&
544 fname->type == FONT_ENTRY_ALIAS)
546 names->length[names->nnames - 1] =
547 -names->length[names->nnames - 1];
548 ret = AddFontNamesName(names, fname->u.alias.resolved,
549 strlen(fname->u.alias.resolved));
550 if (ret != Successful)
560 if (newmax) *newmax = max;
565 FontFileFindNamesInDir(table, pat, max, names)
571 return FontFileFindNamesInScalableDir(table, pat, max, names,
573 NORMAL_ALIAS_BEHAVIOR, (int *)0);
577 FontFileMatchName(name, length, pat)
582 /* Perform a fontfile-type name match on a single name */
584 FontEntryRec entries[1];
586 /* Dummy up a table */
590 table.entries = entries;
591 entries[0].name.name = name;
592 entries[0].name.length = length;
593 entries[0].name.ndashes = FontFileCountDashes(name, length);
595 return FontFileFindNameInDir(&table, pat) != (FontEntryPtr)0;
599 * Add a font file to a directory. This handles bitmap and
600 * scalable names both
604 FontFileAddFontFile (dir, fontName, fileName)
605 FontDirectoryPtr dir;
610 FontScalableRec vals, zeroVals;
611 FontRendererPtr renderer;
612 FontEntryPtr existing;
613 FontScalableExtraPtr extra;
614 FontEntryPtr bitmap, scalable;
617 renderer = FontFileMatchRenderer (fileName);
620 entry.name.length = strlen (fontName);
621 if (entry.name.length > MAXFONTNAMELEN)
622 entry.name.length = MAXFONTNAMELEN;
623 entry.name.name = fontName;
624 CopyISOLatin1Lowered (entry.name.name, fontName, entry.name.length);
625 entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
626 entry.name.name[entry.name.length] = '\0';
628 * Add a bitmap name if the incoming name isn't an XLFD name, or
629 * if it isn't a scalable name (i.e. non-zero scalable fields)
631 * If name of bitmapped font contains XLFD enhancements, do not add
632 * a scalable version of the name... this can lead to confusion and
633 * ambiguity between the font name and the field enhancements.
635 isscale = entry.name.ndashes == 14 &&
636 FontParseXLFDName(entry.name.name,
637 &vals, FONT_XLFD_REPLACE_NONE) &&
638 (vals.values_supplied & PIXELSIZE_MASK) != PIXELSIZE_ARRAY &&
639 (vals.values_supplied & POINTSIZE_MASK) != POINTSIZE_ARRAY &&
640 !(vals.values_supplied & ENHANCEMENT_SPECIFY_MASK);
642 #define UNSCALED_ATTRIB "unscaled"
643 /* For scalable fonts, check if the "unscaled" attribute is present */
644 if (isscale && dir->attributes && dir->attributes[0] == ':') {
645 char *ptr1 = dir->attributes + 1;
648 int uslength = strlen(UNSCALED_ATTRIB);
651 ptr2 = strchr(ptr1, ':');
653 length = ptr2 - ptr1;
655 length = dir->attributes + strlen(dir->attributes) - ptr1;
656 if (length == uslength && !strncmp(ptr1, UNSCALED_ATTRIB, uslength))
663 if (!isscale || (vals.values_supplied & SIZE_SPECIFY_MASK))
665 /* If the fontname says it is nonScalable, make sure that the
666 * renderer supports OpenBitmap and GetInfoBitmap.
668 if (renderer->OpenBitmap && renderer->GetInfoBitmap)
670 entry.type = FONT_ENTRY_BITMAP;
671 entry.u.bitmap.renderer = renderer;
672 entry.u.bitmap.pFont = NullFont;
673 if (!(entry.u.bitmap.fileName = FontFileSaveString (fileName)))
675 if (!(bitmap = FontFileAddEntry (&dir->nonScalable, &entry)))
677 xfree (entry.u.bitmap.fileName);
683 * Parse out scalable fields from XLFD names - a scalable name
684 * just gets inserted, a scaled name has more things to do.
688 /* If the fontname says it is scalable, make sure that the
689 * renderer supports OpenScalable and GetInfoScalable.
691 if (renderer->OpenScalable && renderer->GetInfoScalable)
693 if (vals.values_supplied & SIZE_SPECIFY_MASK)
695 bzero((char *)&zeroVals, sizeof(zeroVals));
698 zeroVals.values_supplied = PIXELSIZE_SCALAR | POINTSIZE_SCALAR;
699 FontParseXLFDName (entry.name.name, &zeroVals,
700 FONT_XLFD_REPLACE_VALUE);
701 entry.name.length = strlen (entry.name.name);
702 existing = FontFileFindNameInDir (&dir->scalable, &entry.name);
705 if ((vals.values_supplied & POINTSIZE_MASK) ==
707 (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
709 existing->u.scalable.extra->defaults = vals;
711 xfree (existing->u.scalable.fileName);
712 if (!(existing->u.scalable.fileName = FontFileSaveString (fileName)))
715 FontFileCompleteXLFD(&vals, &vals);
716 FontFileAddScaledInstance (existing, &vals, NullFont,
721 if (!(entry.u.scalable.fileName = FontFileSaveString (fileName)))
723 extra = (FontScalableExtraPtr) xalloc (sizeof (FontScalableExtraRec));
726 xfree (entry.u.scalable.fileName);
729 bzero((char *)&extra->defaults, sizeof(extra->defaults));
730 if ((vals.values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR &&
731 (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
732 extra->defaults = vals;
735 FontResolutionPtr resolution;
738 extra->defaults.point_matrix[0] =
739 extra->defaults.point_matrix[3] =
740 (double)GetDefaultPointSize() / 10.0;
741 extra->defaults.point_matrix[1] =
742 extra->defaults.point_matrix[2] = 0.0;
743 extra->defaults.values_supplied =
744 POINTSIZE_SCALAR | PIXELSIZE_UNDEFINED;
745 extra->defaults.width = -1;
746 if (vals.x <= 0 || vals.y <= 0)
748 resolution = GetClientResolutions (&num);
749 if (resolution && num > 0)
751 extra->defaults.x = resolution->x_resolution;
752 extra->defaults.y = resolution->y_resolution;
756 extra->defaults.x = 75;
757 extra->defaults.y = 75;
762 extra->defaults.x = vals.x;
763 extra->defaults.y = vals.y;
765 FontFileCompleteXLFD (&extra->defaults, &extra->defaults);
767 extra->numScaled = 0;
768 extra->sizeScaled = 0;
771 entry.type = FONT_ENTRY_SCALABLE;
772 entry.u.scalable.renderer = renderer;
773 entry.u.scalable.extra = extra;
774 if (!(scalable = FontFileAddEntry (&dir->scalable, &entry)))
777 xfree (entry.u.scalable.fileName);
780 if (vals.values_supplied & SIZE_SPECIFY_MASK)
782 FontFileCompleteXLFD(&vals, &vals);
783 FontFileAddScaledInstance (scalable, &vals, NullFont,
792 FontFileAddFontAlias (dir, aliasName, fontName)
793 FontDirectoryPtr dir;
799 entry.name.length = strlen (aliasName);
800 CopyISOLatin1Lowered (aliasName, aliasName, entry.name.length);
801 entry.name.name = aliasName;
802 entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
803 entry.type = FONT_ENTRY_ALIAS;
804 if (!(entry.u.alias.resolved = FontFileSaveString (fontName)))
806 if (!FontFileAddEntry (&dir->nonScalable, &entry))
808 xfree (entry.u.alias.resolved);