1
/* $XdotOrg: xc/lib/font/fontfile/fontdir.c,v 1.4 2005/07/03 07:01:00 daniels Exp $ */
2
/* $Xorg: fontdir.c,v 1.4 2001/02/09 02:04:03 xorgcvs Exp $ */
6
Copyright 1991, 1998 The Open Group
8
Permission to use, copy, modify, distribute, and sell this software and its
9
documentation for any purpose is hereby granted without fee, provided that
10
the above copyright notice appear in all copies and that both that
11
copyright notice and this permission notice appear in supporting
14
The above copyright notice and this permission notice shall be included in
15
all copies or substantial portions of the Software.
17
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
Except as contained in this notice, the name of The Open Group shall not be
25
used in advertising or otherwise to promote the sale, use or other dealings
26
in this Software without prior written authorization from The Open Group.
29
/* $XFree86: xc/lib/font/fontfile/fontdir.c,v 3.22 2003/07/07 16:40:11 eich Exp $ */
32
* Author: Keith Packard, MIT X Consortium
38
#include <X11/fonts/fntfilst.h>
39
#include <X11/keysym.h>
42
FontFileInitTable (FontTablePtr table, int size)
46
table->entries = (FontEntryPtr) xalloc(sizeof(FontEntryRec) * size);
54
table->sorted = FALSE;
59
FontFileFreeEntry (FontEntryPtr entry)
61
FontScalableExtraPtr extra;
65
xfree(entry->name.name);
66
entry->name.name = NULL;
70
case FONT_ENTRY_SCALABLE:
71
xfree (entry->u.scalable.fileName);
72
extra = entry->u.scalable.extra;
73
for (i = 0; i < extra->numScaled; i++)
74
if (extra->scaled[i].vals.ranges)
75
xfree (extra->scaled[i].vals.ranges);
76
xfree (extra->scaled);
79
case FONT_ENTRY_BITMAP:
80
xfree (entry->u.bitmap.fileName);
81
entry->u.bitmap.fileName = NULL;
83
case FONT_ENTRY_ALIAS:
84
xfree (entry->u.alias.resolved);
85
entry->u.alias.resolved = NULL;
95
FontFileFreeTable (FontTablePtr table)
99
for (i = 0; i < table->used; i++)
100
FontFileFreeEntry (&table->entries[i]);
101
xfree (table->entries);
105
FontFileMakeDir(char *dirName, int size)
107
FontDirectoryPtr dir;
116
#if !defined(__UNIXOS2__) && !defined(WIN32)
117
attrib = strchr(dirName, ':');
119
/* OS/2 uses the colon in the drive letter descriptor, skip this */
120
attrib = strchr(dirName+2, ':');
123
dirlen = attrib - dirName;
124
attriblen = strlen(attrib);
126
dirlen = strlen(dirName);
130
dirlen = strlen(dirName);
132
if (dirName[dirlen - 1] != '/')
134
if (dirlen) /* leave out slash for builtins */
138
dir = (FontDirectoryPtr) xalloc(sizeof *dir + dirlen + needslash + 1 +
139
(attriblen ? attriblen + 1 : 0));
141
dir = (FontDirectoryPtr) xalloc(sizeof *dir + dirlen + needslash + 1);
144
return (FontDirectoryPtr)0;
145
if (!FontFileInitTable (&dir->scalable, 0))
148
return (FontDirectoryPtr)0;
150
if (!FontFileInitTable (&dir->nonScalable, size))
152
FontFileFreeTable (&dir->scalable);
154
return (FontDirectoryPtr)0;
156
dir->directory = (char *) (dir + 1);
158
dir->alias_mtime = 0;
161
dir->attributes = dir->directory + dirlen + needslash + 1;
163
dir->attributes = NULL;
164
strncpy(dir->directory, dirName, dirlen);
165
dir->directory[dirlen] = '\0';
167
strcpy(dir->attributes, attrib);
169
strcpy(dir->directory, dirName);
172
strcat(dir->directory, "/");
177
FontFileFreeDir (FontDirectoryPtr dir)
179
FontFileFreeTable (&dir->scalable);
180
FontFileFreeTable (&dir->nonScalable);
185
FontFileAddEntry(FontTablePtr table, 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
* Compare two strings just like strcmp, but preserve decimal integer
215
* sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" <
216
* "iso10646-1". Strings are sorted as if sequences of digits were
217
* prefixed by a length indicator (i.e., does not ignore leading zeroes).
219
* Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>
221
#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071')
223
static int strcmpn(const char *s1, const char *s2)
225
int digits, predigits = 0;
226
const char *ss1, *ss2;
229
if (*s1 == 0 && *s2 == 0)
231
digits = Xisdigit(*s1) && Xisdigit(*s2);
232
if (digits && !predigits) {
235
while (Xisdigit(*ss1) && Xisdigit(*ss2))
237
if (!Xisdigit(*ss1) && Xisdigit(*ss2))
239
if (Xisdigit(*ss1) && !Xisdigit(*ss2))
242
if ((unsigned char)*s1 < (unsigned char)*s2)
244
if ((unsigned char)*s1 > (unsigned char)*s2)
253
FontFileNameCompare(const void* a, const void* b)
255
FontEntryPtr a_name = (FontEntryPtr) a,
256
b_name = (FontEntryPtr) b;
258
return strcmpn(a_name->name.name, b_name->name.name);
262
FontFileSortTable (FontTablePtr table)
264
if (!table->sorted) {
265
qsort((char *) table->entries, table->used, sizeof(FontEntryRec),
266
FontFileNameCompare);
267
table->sorted = TRUE;
272
FontFileSortDir(FontDirectoryPtr dir)
274
FontFileSortTable (&dir->scalable);
275
FontFileSortTable (&dir->nonScalable);
276
/* now that the table is fixed in size, swizzle the pointers */
277
FontFileSwitchStringsToBitmapPointers (dir);
281
Given a Font Table, SetupWildMatch() sets up various pointers and state
282
information so the table can be searched for name(s) that match a given
283
fontname pattern -- which may contain wildcards. Under certain
284
circumstances, SetupWildMatch() will find the one table entry that
285
matches the pattern. If those circumstances do not pertain,
286
SetupWildMatch() returns a range within the the table that should be
287
searched for matching name(s). With the information established by
288
SetupWildMatch(), including state information in "private", the
289
PatternMatch() procedure is then used to test names in the range for a
293
#define isWild(c) ((c) == XK_asterisk || (c) == XK_question)
294
#define isDigit(c) (XK_0 <= (c) && (c) <= XK_9)
297
SetupWildMatch(FontTablePtr table, FontNamePtr pat,
298
int *leftp, int *rightp, int *privatep)
313
nDashes = pat->ndashes;
333
if (!table->sorted) {
337
} else if (firstWild) {
338
if (firstDigit && firstDigit < firstWild)
339
first = firstDigit - name;
341
first = firstWild - name;
342
while (left < right) {
343
center = (left + right) / 2;
344
result = strncmp(name, table->entries[center].name.name, first);
356
while (left < right) {
357
center = (left + right) / 2;
358
result = strcmpn(name, table->entries[center].name.name);
373
PatternMatch(char *pat, int patdashes, char *string, int stringdashes)
378
if (stringdashes < patdashes)
381
switch (c = *pat++) {
388
while ((t = *string++) != XK_minus)
392
if (PatternMatch(pat, patdashes, string, stringdashes))
394
if (stringdashes == patdashes)
399
while ((t = *string++) != c) {
403
if (stringdashes-- < patdashes)
407
if (PatternMatch(pat, patdashes, string, stringdashes))
412
if (*string++ == XK_minus)
416
return (*string == '\0');
418
if (*string++ == XK_minus) {
433
FontFileCountDashes (char *name, int namelen)
438
if (*name++ == '\055') /* avoid non ascii systems */
444
FontFileSaveString (char *s)
448
n = (char *) xalloc (strlen (s) + 1);
456
FontFileFindNameInScalableDir(FontTablePtr table, FontNamePtr pat,
457
FontScalablePtr vals)
466
if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0)
467
return &table->entries[i];
468
for (i = start; i < stop; i++) {
469
name = &table->entries[i].name;
470
res = PatternMatch(pat->name, private, name->name, name->ndashes);
473
/* Check to see if enhancements requested are available */
476
int vs = vals->values_supplied;
479
if (table->entries[i].type == FONT_ENTRY_SCALABLE)
480
cap = table->entries[i].u.scalable.renderer->capabilities;
481
else if (table->entries[i].type == FONT_ENTRY_ALIAS)
482
cap = ~0; /* Calling code will have to see if true */
485
if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
486
(vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
487
!(cap & CAP_MATRIX)) ||
488
((vs & CHARSUBSET_SPECIFIED) &&
489
!(cap & CAP_CHARSUBSETTING)))
492
return &table->entries[i];
497
return (FontEntryPtr)0;
501
FontFileFindNameInDir(FontTablePtr table, FontNamePtr pat)
503
return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
507
FontFileFindNamesInScalableDir(FontTablePtr table, FontNamePtr pat, int max,
508
FontNamesPtr names, FontScalablePtr vals,
509
int alias_behavior, int *newmax)
516
int ret = Successful;
522
if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0) {
523
if (alias_behavior == NORMAL_ALIAS_BEHAVIOR ||
524
table->entries[i].type != FONT_ENTRY_ALIAS)
526
name = &table->entries[i].name;
527
if (newmax) *newmax = max - 1;
528
return AddFontNamesName(names, name->name, name->length);
533
for (i = start, fname = &table->entries[start]; i < stop; i++, fname++) {
534
res = PatternMatch(pat->name, private, fname->name.name, fname->name.ndashes);
538
int vs = vals->values_supplied;
541
if (fname->type == FONT_ENTRY_SCALABLE)
542
cap = fname->u.scalable.renderer->capabilities;
543
else if (fname->type == FONT_ENTRY_ALIAS)
544
cap = ~0; /* Calling code will have to see if true */
547
if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
548
(vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
549
!(cap & CAP_MATRIX)) ||
550
((vs & CHARSUBSET_SPECIFIED) &&
551
!(cap & CAP_CHARSUBSETTING)))
555
if ((alias_behavior & IGNORE_SCALABLE_ALIASES) &&
556
fname->type == FONT_ENTRY_ALIAS)
558
FontScalableRec tmpvals;
559
if (FontParseXLFDName (fname->name.name, &tmpvals,
560
FONT_XLFD_REPLACE_NONE) &&
561
!(tmpvals.values_supplied & SIZE_SPECIFY_MASK))
565
ret = AddFontNamesName(names, fname->name.name, fname->name.length);
566
if (ret != Successful)
569
/* If alias_behavior is LIST_ALIASES_AND_TARGET_NAMES, mark
570
this entry as an alias by negating its length and follow
571
it by the resolved name */
572
if ((alias_behavior & LIST_ALIASES_AND_TARGET_NAMES) &&
573
fname->type == FONT_ENTRY_ALIAS)
575
names->length[names->nnames - 1] =
576
-names->length[names->nnames - 1];
577
ret = AddFontNamesName(names, fname->u.alias.resolved,
578
strlen(fname->u.alias.resolved));
579
if (ret != Successful)
589
if (newmax) *newmax = max;
594
FontFileFindNamesInDir(FontTablePtr table, FontNamePtr pat,
595
int max, FontNamesPtr names)
597
return FontFileFindNamesInScalableDir(table, pat, max, names,
599
NORMAL_ALIAS_BEHAVIOR, (int *)0);
603
FontFileMatchName(char *name, int length, FontNamePtr pat)
605
/* Perform a fontfile-type name match on a single name */
607
FontEntryRec entries[1];
609
/* Dummy up a table */
613
table.entries = entries;
614
entries[0].name.name = name;
615
entries[0].name.length = length;
616
entries[0].name.ndashes = FontFileCountDashes(name, length);
618
return FontFileFindNameInDir(&table, pat) != (FontEntryPtr)0;
622
* Add a font file to a directory. This handles bitmap and
623
* scalable names both
627
FontFileAddFontFile (FontDirectoryPtr dir, char *fontName, char *fileName)
630
FontScalableRec vals, zeroVals;
631
FontRendererPtr renderer;
632
FontEntryPtr existing;
633
FontScalableExtraPtr extra;
634
FontEntryPtr bitmap = 0, scalable;
640
renderer = FontFileMatchRenderer (fileName);
643
entry.name.length = strlen (fontName);
644
if (entry.name.length > MAXFONTNAMELEN)
645
entry.name.length = MAXFONTNAMELEN;
646
entry.name.name = fontName;
647
CopyISOLatin1Lowered (entry.name.name, fontName, entry.name.length);
648
entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
649
entry.name.name[entry.name.length] = '\0';
651
* Add a bitmap name if the incoming name isn't an XLFD name, or
652
* if it isn't a scalable name (i.e. non-zero scalable fields)
654
* If name of bitmapped font contains XLFD enhancements, do not add
655
* a scalable version of the name... this can lead to confusion and
656
* ambiguity between the font name and the field enhancements.
658
isscale = entry.name.ndashes == 14 &&
659
FontParseXLFDName(entry.name.name,
660
&vals, FONT_XLFD_REPLACE_NONE) &&
661
(vals.values_supplied & PIXELSIZE_MASK) != PIXELSIZE_ARRAY &&
662
(vals.values_supplied & POINTSIZE_MASK) != POINTSIZE_ARRAY &&
663
!(vals.values_supplied & ENHANCEMENT_SPECIFY_MASK);
665
#define UNSCALED_ATTRIB "unscaled"
666
scalable_xlfd = (isscale &&
667
(((vals.values_supplied & PIXELSIZE_MASK) == 0) ||
668
((vals.values_supplied & POINTSIZE_MASK) == 0)));
670
* For scalable fonts without a scalable XFLD, check if the "unscaled"
671
* attribute is present.
673
if (isscale && !scalable_xlfd &&
674
dir->attributes && dir->attributes[0] == ':') {
675
char *ptr1 = dir->attributes + 1;
678
int uslength = strlen(UNSCALED_ATTRIB);
681
ptr2 = strchr(ptr1, ':');
683
length = ptr2 - ptr1;
685
length = dir->attributes + strlen(dir->attributes) - ptr1;
686
if (length == uslength && !strncmp(ptr1, UNSCALED_ATTRIB, uslength))
693
if (!isscale || (vals.values_supplied & SIZE_SPECIFY_MASK))
696
* If the renderer doesn't support OpenBitmap, FontFileOpenFont
697
* will still do the right thing.
699
entry.type = FONT_ENTRY_BITMAP;
700
entry.u.bitmap.renderer = renderer;
701
entry.u.bitmap.pFont = NullFont;
702
if (!(entry.u.bitmap.fileName = FontFileSaveString (fileName)))
704
if (!(bitmap = FontFileAddEntry (&dir->nonScalable, &entry)))
706
xfree (entry.u.bitmap.fileName);
711
* Parse out scalable fields from XLFD names - a scalable name
712
* just gets inserted, a scaled name has more things to do.
716
if (vals.values_supplied & SIZE_SPECIFY_MASK)
718
bzero((char *)&zeroVals, sizeof(zeroVals));
721
zeroVals.values_supplied = PIXELSIZE_SCALAR | POINTSIZE_SCALAR;
722
FontParseXLFDName (entry.name.name, &zeroVals,
723
FONT_XLFD_REPLACE_VALUE);
724
entry.name.length = strlen (entry.name.name);
725
existing = FontFileFindNameInDir (&dir->scalable, &entry.name);
728
if ((vals.values_supplied & POINTSIZE_MASK) ==
730
(int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
732
existing->u.scalable.extra->defaults = vals;
734
xfree (existing->u.scalable.fileName);
735
if (!(existing->u.scalable.fileName = FontFileSaveString (fileName)))
740
FontFileCompleteXLFD(&vals, &vals);
741
FontFileAddScaledInstance (existing, &vals, NullFont,
747
if (!(entry.u.scalable.fileName = FontFileSaveString (fileName)))
749
extra = (FontScalableExtraPtr) xalloc (sizeof (FontScalableExtraRec));
752
xfree (entry.u.scalable.fileName);
755
bzero((char *)&extra->defaults, sizeof(extra->defaults));
756
if ((vals.values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR &&
757
(int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
758
extra->defaults = vals;
761
FontResolutionPtr resolution;
764
extra->defaults.point_matrix[0] =
765
extra->defaults.point_matrix[3] =
766
(double)GetDefaultPointSize() / 10.0;
767
extra->defaults.point_matrix[1] =
768
extra->defaults.point_matrix[2] = 0.0;
769
extra->defaults.values_supplied =
770
POINTSIZE_SCALAR | PIXELSIZE_UNDEFINED;
771
extra->defaults.width = -1;
772
if (vals.x <= 0 || vals.y <= 0)
774
resolution = GetClientResolutions (&num);
775
if (resolution && num > 0)
777
extra->defaults.x = resolution->x_resolution;
778
extra->defaults.y = resolution->y_resolution;
782
extra->defaults.x = 75;
783
extra->defaults.y = 75;
788
extra->defaults.x = vals.x;
789
extra->defaults.y = vals.y;
791
FontFileCompleteXLFD (&extra->defaults, &extra->defaults);
793
extra->numScaled = 0;
794
extra->sizeScaled = 0;
797
entry.type = FONT_ENTRY_SCALABLE;
798
entry.u.scalable.renderer = renderer;
799
entry.u.scalable.extra = extra;
800
if (!(scalable = FontFileAddEntry (&dir->scalable, &entry)))
803
xfree (entry.u.scalable.fileName);
806
if (vals.values_supplied & SIZE_SPECIFY_MASK)
810
FontFileCompleteXLFD(&vals, &vals);
811
FontFileAddScaledInstance (scalable, &vals, NullFont,
820
FontFileAddFontAlias (FontDirectoryPtr dir, char *aliasName, char *fontName)
824
entry.name.length = strlen (aliasName);
825
CopyISOLatin1Lowered (aliasName, aliasName, entry.name.length);
826
entry.name.name = aliasName;
827
entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
828
entry.type = FONT_ENTRY_ALIAS;
829
if (!(entry.u.alias.resolved = FontFileSaveString (fontName)))
831
if (!FontFileAddEntry (&dir->nonScalable, &entry))
833
xfree (entry.u.alias.resolved);