3 Copyright 1991, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
28 * Author: Keith Packard, MIT X Consortium
34 #include <X11/fonts/fntfilst.h>
35 #include <X11/keysym.h>
39 #elif !defined(INT32_MAX)
40 #define INT32_MAX 0x7fffffff
44 FontFileInitTable (FontTablePtr table, int size)
46 if (size < 0 || (size > INT32_MAX/sizeof(FontEntryRec)))
50 table->entries = malloc(sizeof(FontEntryRec) * size);
58 table->sorted = FALSE;
63 FontFileFreeEntry (FontEntryPtr entry)
65 FontScalableExtraPtr extra;
69 free(entry->name.name);
70 entry->name.name = NULL;
74 case FONT_ENTRY_SCALABLE:
75 free (entry->u.scalable.fileName);
76 extra = entry->u.scalable.extra;
77 for (i = 0; i < extra->numScaled; i++)
78 if (extra->scaled[i].vals.ranges)
79 free (extra->scaled[i].vals.ranges);
83 case FONT_ENTRY_BITMAP:
84 free (entry->u.bitmap.fileName);
85 entry->u.bitmap.fileName = NULL;
87 case FONT_ENTRY_ALIAS:
88 free (entry->u.alias.resolved);
89 entry->u.alias.resolved = NULL;
95 FontFileFreeTable (FontTablePtr table)
99 for (i = 0; i < table->used; i++)
100 FontFileFreeEntry (&table->entries[i]);
101 free (table->entries);
105 FontFileMakeDir(const char *dirName, int size)
107 FontDirectoryPtr dir;
114 attrib = strchr(dirName, ':');
116 /* OS/2 uses the colon in the drive letter descriptor, skip this */
117 attrib = strchr(dirName+2, ':');
120 dirlen = attrib - dirName;
121 attriblen = strlen(attrib);
123 dirlen = strlen(dirName);
126 if (dirName[dirlen - 1] != '/')
128 if (dirlen) /* leave out slash for builtins */
131 dir = malloc(sizeof *dir + dirlen + needslash + 1 +
132 (attriblen ? attriblen + 1 : 0));
134 return (FontDirectoryPtr)0;
135 if (!FontFileInitTable (&dir->scalable, 0))
138 return (FontDirectoryPtr)0;
140 if (!FontFileInitTable (&dir->nonScalable, size))
142 FontFileFreeTable (&dir->scalable);
144 return (FontDirectoryPtr)0;
146 dir->directory = (char *) (dir + 1);
148 dir->alias_mtime = 0;
150 dir->attributes = dir->directory + dirlen + needslash + 1;
152 dir->attributes = NULL;
153 strncpy(dir->directory, dirName, dirlen);
154 dir->directory[dirlen] = '\0';
156 strcpy(dir->attributes, attrib);
158 strcat(dir->directory, "/");
163 FontFileFreeDir (FontDirectoryPtr dir)
165 FontFileFreeTable (&dir->scalable);
166 FontFileFreeTable (&dir->nonScalable);
171 FontFileAddEntry(FontTablePtr table, FontEntryPtr prototype)
176 /* can't add entries to a sorted table, pointers get broken! */
178 return (FontEntryPtr) 0; /* "cannot" happen */
179 if (table->used == table->size) {
180 newsize = table->size + 100;
181 entry = realloc(table->entries, newsize * sizeof(FontEntryRec));
183 return (FontEntryPtr)0;
184 table->size = newsize;
185 table->entries = entry;
187 entry = &table->entries[table->used];
189 entry->name.name = malloc(prototype->name.length + 1);
190 if (!entry->name.name)
191 return (FontEntryPtr)0;
192 memcpy (entry->name.name, prototype->name.name, prototype->name.length);
193 entry->name.name[entry->name.length] = '\0';
199 * Compare two strings just like strcmp, but preserve decimal integer
200 * sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" <
201 * "iso10646-1". Strings are sorted as if sequences of digits were
202 * prefixed by a length indicator (i.e., does not ignore leading zeroes).
204 * Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>
206 #define Xisdigit(c) ('\060' <= (c) && (c) <= '\071')
208 static int strcmpn(const char *s1, const char *s2)
210 int digits, predigits = 0;
211 const char *ss1, *ss2;
214 if (*s1 == 0 && *s2 == 0)
216 digits = Xisdigit(*s1) && Xisdigit(*s2);
217 if (digits && !predigits) {
220 while (Xisdigit(*ss1) && Xisdigit(*ss2))
222 if (!Xisdigit(*ss1) && Xisdigit(*ss2))
224 if (Xisdigit(*ss1) && !Xisdigit(*ss2))
227 if ((unsigned char)*s1 < (unsigned char)*s2)
229 if ((unsigned char)*s1 > (unsigned char)*s2)
238 FontFileNameCompare(const void* a, const void* b)
240 FontEntryPtr a_name = (FontEntryPtr) a,
241 b_name = (FontEntryPtr) b;
243 return strcmpn(a_name->name.name, b_name->name.name);
247 FontFileSortTable (FontTablePtr table)
249 if (!table->sorted) {
250 qsort((char *) table->entries, table->used, sizeof(FontEntryRec),
251 FontFileNameCompare);
252 table->sorted = TRUE;
257 FontFileSortDir(FontDirectoryPtr dir)
259 FontFileSortTable (&dir->scalable);
260 FontFileSortTable (&dir->nonScalable);
261 /* now that the table is fixed in size, swizzle the pointers */
262 FontFileSwitchStringsToBitmapPointers (dir);
266 Given a Font Table, SetupWildMatch() sets up various pointers and state
267 information so the table can be searched for name(s) that match a given
268 fontname pattern -- which may contain wildcards. Under certain
269 circumstances, SetupWildMatch() will find the one table entry that
270 matches the pattern. If those circumstances do not pertain,
271 SetupWildMatch() returns a range within the the table that should be
272 searched for matching name(s). With the information established by
273 SetupWildMatch(), including state information in "private", the
274 PatternMatch() procedure is then used to test names in the range for a
278 #define isWild(c) ((c) == XK_asterisk || (c) == XK_question)
279 #define isDigit(c) (XK_0 <= (c) && (c) <= XK_9)
282 SetupWildMatch(FontTablePtr table, FontNamePtr pat,
283 int *leftp, int *rightp, int *privatep)
298 nDashes = pat->ndashes;
318 if (!table->sorted) {
322 } else if (firstWild) {
323 if (firstDigit && firstDigit < firstWild)
324 first = firstDigit - name;
326 first = firstWild - name;
327 while (left < right) {
328 center = (left + right) / 2;
329 result = strncmp(name, table->entries[center].name.name, first);
341 while (left < right) {
342 center = (left + right) / 2;
343 result = strcmpn(name, table->entries[center].name.name);
358 PatternMatch(char *pat, int patdashes, char *string, int stringdashes)
363 if (stringdashes < patdashes)
366 switch (c = *pat++) {
373 while ((t = *string++) != XK_minus)
377 if (PatternMatch(pat, patdashes, string, stringdashes))
379 if (stringdashes == patdashes)
384 while ((t = *string++) != c) {
388 if (stringdashes-- < patdashes)
392 if (PatternMatch(pat, patdashes, string, stringdashes))
397 if (*string++ == XK_minus)
401 return (*string == '\0');
403 if (*string++ == XK_minus) {
418 FontFileCountDashes (char *name, int namelen)
423 if (*name++ == '\055') /* avoid non ascii systems */
429 FontFileSaveString (char *s)
433 n = malloc (strlen (s) + 1);
441 FontFileFindNameInScalableDir(FontTablePtr table, FontNamePtr pat,
442 FontScalablePtr vals)
453 if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0)
454 return &table->entries[i];
455 for (i = start; i < stop; i++) {
456 name = &table->entries[i].name;
457 res = PatternMatch(pat->name, private, name->name, name->ndashes);
460 /* Check to see if enhancements requested are available */
463 int vs = vals->values_supplied;
466 if (table->entries[i].type == FONT_ENTRY_SCALABLE)
467 cap = table->entries[i].u.scalable.renderer->capabilities;
468 else if (table->entries[i].type == FONT_ENTRY_ALIAS)
469 cap = ~0; /* Calling code will have to see if true */
472 if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
473 (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
474 !(cap & CAP_MATRIX)) ||
475 ((vs & CHARSUBSET_SPECIFIED) &&
476 !(cap & CAP_CHARSUBSETTING)))
479 return &table->entries[i];
484 return (FontEntryPtr)0;
488 FontFileFindNameInDir(FontTablePtr table, FontNamePtr pat)
490 return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
494 FontFileFindNamesInScalableDir(FontTablePtr table, FontNamePtr pat, int max,
495 FontNamesPtr names, FontScalablePtr vals,
496 int alias_behavior, int *newmax)
503 int ret = Successful;
509 if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0) {
510 if (alias_behavior == NORMAL_ALIAS_BEHAVIOR ||
511 table->entries[i].type != FONT_ENTRY_ALIAS)
513 name = &table->entries[i].name;
514 if (newmax) *newmax = max - 1;
515 return AddFontNamesName(names, name->name, name->length);
520 for (i = start, fname = &table->entries[start]; i < stop; i++, fname++) {
521 res = PatternMatch(pat->name, private, fname->name.name, fname->name.ndashes);
525 int vs = vals->values_supplied;
528 if (fname->type == FONT_ENTRY_SCALABLE)
529 cap = fname->u.scalable.renderer->capabilities;
530 else if (fname->type == FONT_ENTRY_ALIAS)
531 cap = ~0; /* Calling code will have to see if true */
534 if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
535 (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
536 !(cap & CAP_MATRIX)) ||
537 ((vs & CHARSUBSET_SPECIFIED) &&
538 !(cap & CAP_CHARSUBSETTING)))
542 if ((alias_behavior & IGNORE_SCALABLE_ALIASES) &&
543 fname->type == FONT_ENTRY_ALIAS)
545 FontScalableRec tmpvals;
546 if (FontParseXLFDName (fname->name.name, &tmpvals,
547 FONT_XLFD_REPLACE_NONE) &&
548 !(tmpvals.values_supplied & SIZE_SPECIFY_MASK))
552 ret = AddFontNamesName(names, fname->name.name, fname->name.length);
553 if (ret != Successful)
556 /* If alias_behavior is LIST_ALIASES_AND_TARGET_NAMES, mark
557 this entry as an alias by negating its length and follow
558 it by the resolved name */
559 if ((alias_behavior & LIST_ALIASES_AND_TARGET_NAMES) &&
560 fname->type == FONT_ENTRY_ALIAS)
562 names->length[names->nnames - 1] =
563 -names->length[names->nnames - 1];
564 ret = AddFontNamesName(names, fname->u.alias.resolved,
565 strlen(fname->u.alias.resolved));
566 if (ret != Successful)
576 if (newmax) *newmax = max;
581 FontFileFindNamesInDir(FontTablePtr table, FontNamePtr pat,
582 int max, FontNamesPtr names)
584 return FontFileFindNamesInScalableDir(table, pat, max, names,
586 NORMAL_ALIAS_BEHAVIOR, (int *)0);
590 FontFileMatchName(char *name, int length, FontNamePtr pat)
592 /* Perform a fontfile-type name match on a single name */
594 FontEntryRec entries[1];
596 /* Dummy up a table */
600 table.entries = entries;
601 entries[0].name.name = name;
602 entries[0].name.length = length;
603 entries[0].name.ndashes = FontFileCountDashes(name, length);
605 return FontFileFindNameInDir(&table, pat) != (FontEntryPtr)0;
609 * Add a font file to a directory. This handles bitmap and
610 * scalable names both
614 FontFileAddFontFile (FontDirectoryPtr dir, char *fontName, char *fileName)
617 FontScalableRec vals, zeroVals;
618 FontRendererPtr renderer;
619 FontEntryPtr existing;
620 FontScalableExtraPtr extra;
621 FontEntryPtr bitmap = 0, scalable;
625 renderer = FontFileMatchRenderer (fileName);
628 entry.name.length = strlen (fontName);
629 if (entry.name.length > MAXFONTNAMELEN)
630 entry.name.length = MAXFONTNAMELEN;
631 entry.name.name = fontName;
632 CopyISOLatin1Lowered (entry.name.name, fontName, entry.name.length);
633 entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
634 entry.name.name[entry.name.length] = '\0';
636 * Add a bitmap name if the incoming name isn't an XLFD name, or
637 * if it isn't a scalable name (i.e. non-zero scalable fields)
639 * If name of bitmapped font contains XLFD enhancements, do not add
640 * a scalable version of the name... this can lead to confusion and
641 * ambiguity between the font name and the field enhancements.
643 isscale = entry.name.ndashes == 14 &&
644 FontParseXLFDName(entry.name.name,
645 &vals, FONT_XLFD_REPLACE_NONE) &&
646 (vals.values_supplied & PIXELSIZE_MASK) != PIXELSIZE_ARRAY &&
647 (vals.values_supplied & POINTSIZE_MASK) != POINTSIZE_ARRAY &&
648 !(vals.values_supplied & ENHANCEMENT_SPECIFY_MASK);
649 #define UNSCALED_ATTRIB "unscaled"
650 scalable_xlfd = (isscale &&
651 (((vals.values_supplied & PIXELSIZE_MASK) == 0) ||
652 ((vals.values_supplied & POINTSIZE_MASK) == 0)));
654 * For scalable fonts without a scalable XFLD, check if the "unscaled"
655 * attribute is present.
657 if (isscale && !scalable_xlfd &&
658 dir->attributes && dir->attributes[0] == ':') {
659 char *ptr1 = dir->attributes + 1;
662 int uslength = strlen(UNSCALED_ATTRIB);
665 ptr2 = strchr(ptr1, ':');
667 length = ptr2 - ptr1;
669 length = dir->attributes + strlen(dir->attributes) - ptr1;
670 if (length == uslength && !strncmp(ptr1, UNSCALED_ATTRIB, uslength))
676 if (!isscale || (vals.values_supplied & SIZE_SPECIFY_MASK))
679 * If the renderer doesn't support OpenBitmap, FontFileOpenFont
680 * will still do the right thing.
682 entry.type = FONT_ENTRY_BITMAP;
683 entry.u.bitmap.renderer = renderer;
684 entry.u.bitmap.pFont = NullFont;
685 if (!(entry.u.bitmap.fileName = FontFileSaveString (fileName)))
687 if (!(bitmap = FontFileAddEntry (&dir->nonScalable, &entry)))
689 free (entry.u.bitmap.fileName);
694 * Parse out scalable fields from XLFD names - a scalable name
695 * just gets inserted, a scaled name has more things to do.
699 if (vals.values_supplied & SIZE_SPECIFY_MASK)
701 bzero((char *)&zeroVals, sizeof(zeroVals));
704 zeroVals.values_supplied = PIXELSIZE_SCALAR | POINTSIZE_SCALAR;
705 FontParseXLFDName (entry.name.name, &zeroVals,
706 FONT_XLFD_REPLACE_VALUE);
707 entry.name.length = strlen (entry.name.name);
708 existing = FontFileFindNameInDir (&dir->scalable, &entry.name);
711 if ((vals.values_supplied & POINTSIZE_MASK) ==
713 (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
715 existing->u.scalable.extra->defaults = vals;
717 free (existing->u.scalable.fileName);
718 if (!(existing->u.scalable.fileName = FontFileSaveString (fileName)))
723 FontFileCompleteXLFD(&vals, &vals);
724 FontFileAddScaledInstance (existing, &vals, NullFont,
730 if (!(entry.u.scalable.fileName = FontFileSaveString (fileName)))
732 extra = malloc (sizeof (FontScalableExtraRec));
735 free (entry.u.scalable.fileName);
738 bzero((char *)&extra->defaults, sizeof(extra->defaults));
739 if ((vals.values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR &&
740 (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
741 extra->defaults = vals;
744 FontResolutionPtr resolution;
746 int default_point_size = GetDefaultPointSize();
748 extra->defaults.point_matrix[0] =
749 extra->defaults.point_matrix[3] =
750 (double)default_point_size / 10.0;
751 extra->defaults.point_matrix[1] =
752 extra->defaults.point_matrix[2] = 0.0;
753 extra->defaults.values_supplied =
754 POINTSIZE_SCALAR | PIXELSIZE_UNDEFINED;
755 extra->defaults.width = -1;
756 if (vals.x <= 0 || vals.y <= 0)
758 resolution = GetClientResolutions (&num);
759 if (resolution && num > 0)
761 extra->defaults.x = resolution->x_resolution;
762 extra->defaults.y = resolution->y_resolution;
766 extra->defaults.x = 75;
767 extra->defaults.y = 75;
772 extra->defaults.x = vals.x;
773 extra->defaults.y = vals.y;
775 FontFileCompleteXLFD (&extra->defaults, &extra->defaults);
777 extra->numScaled = 0;
778 extra->sizeScaled = 0;
781 entry.type = FONT_ENTRY_SCALABLE;
782 entry.u.scalable.renderer = renderer;
783 entry.u.scalable.extra = extra;
784 if (!(scalable = FontFileAddEntry (&dir->scalable, &entry)))
787 free (entry.u.scalable.fileName);
790 if (vals.values_supplied & SIZE_SPECIFY_MASK)
794 FontFileCompleteXLFD(&vals, &vals);
795 FontFileAddScaledInstance (scalable, &vals, NullFont,
804 FontFileAddFontAlias (FontDirectoryPtr dir, char *aliasName, char *fontName)
808 if (strcmp(aliasName,fontName) == 0) {
809 /* Don't allow an alias to point to itself and create a loop */
812 entry.name.length = strlen (aliasName);
813 CopyISOLatin1Lowered (aliasName, aliasName, entry.name.length);
814 entry.name.name = aliasName;
815 entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
816 entry.type = FONT_ENTRY_ALIAS;
817 if (!(entry.u.alias.resolved = FontFileSaveString (fontName)))
819 if (!FontFileAddEntry (&dir->nonScalable, &entry))
821 free (entry.u.alias.resolved);