aboutsummaryrefslogtreecommitdiff
path: root/libXfont/src/fontfile/catalogue.c
diff options
context:
space:
mode:
Diffstat (limited to 'libXfont/src/fontfile/catalogue.c')
-rw-r--r--libXfont/src/fontfile/catalogue.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/libXfont/src/fontfile/catalogue.c b/libXfont/src/fontfile/catalogue.c
new file mode 100644
index 000000000..d49423617
--- /dev/null
+++ b/libXfont/src/fontfile/catalogue.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright © 2007 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <X11/fonts/fntfilst.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+
+static const char CataloguePrefix[] = "catalogue:";
+
+static int CatalogueFreeFPE (FontPathElementPtr fpe);
+
+static int
+CatalogueNameCheck (char *name)
+{
+ return strncmp(name, CataloguePrefix, sizeof(CataloguePrefix) - 1) == 0;
+}
+
+typedef struct _CatalogueRec {
+ time_t mtime;
+ int fpeCount, fpeAlloc;
+ FontPathElementPtr *fpeList;
+} CatalogueRec, *CataloguePtr;
+
+static int
+CatalogueAddFPE (CataloguePtr cat, FontPathElementPtr fpe)
+{
+ FontPathElementPtr *new;
+
+ if (cat->fpeCount >= cat->fpeAlloc)
+ {
+ if (cat->fpeAlloc == 0)
+ cat->fpeAlloc = 16;
+ else
+ cat->fpeAlloc *= 2;
+
+ new = xrealloc(cat->fpeList,
+ cat->fpeAlloc * sizeof(FontPathElementPtr));
+ if (new == NULL)
+ return AllocError;
+
+ cat->fpeList = new;
+ }
+
+ cat->fpeList[cat->fpeCount++] = fpe;
+
+ return Successful;
+}
+
+static const char PriorityAttribute[] = "pri=";
+
+static int
+ComparePriority(const void *p1, const void *p2)
+{
+ FontDirectoryPtr dir1 = (*(FontPathElementPtr*) p1)->private;
+ FontDirectoryPtr dir2 = (*(FontPathElementPtr*) p2)->private;
+ const char *pri1 = NULL;
+ const char *pri2 = NULL;
+
+ if (dir1->attributes != NULL)
+ pri1 = strstr(dir1->attributes, PriorityAttribute);
+ if (dir2->attributes != NULL)
+ pri2 = strstr(dir2->attributes, PriorityAttribute);
+
+ if (pri1 == NULL && pri2 == NULL)
+ return 0;
+ else if (pri1 == NULL)
+ return 1;
+ else if (pri2 == NULL)
+ return -1;
+ else
+ return
+ atoi(pri1 + strlen(PriorityAttribute)) -
+ atoi(pri2 + strlen(PriorityAttribute));
+}
+
+static void
+CatalogueUnrefFPEs (FontPathElementPtr fpe)
+{
+ CataloguePtr cat = fpe->private;
+ FontPathElementPtr subfpe;
+ int i;
+
+ for (i = 0; i < cat->fpeCount; i++)
+ {
+ subfpe = cat->fpeList[i];
+ subfpe->refcount--;
+ if (subfpe->refcount == 0)
+ {
+ FontFileFreeFPE (subfpe);
+ xfree(subfpe->name);
+ xfree(subfpe);
+ }
+ }
+
+ cat->fpeCount = 0;
+}
+
+/* Rescan catalogue directory if modified timestamp has changed or
+ * the forceScan argument says to do it anyway (like on first load). */
+static int
+CatalogueRescan (FontPathElementPtr fpe, Bool forceScan)
+{
+ CataloguePtr cat = fpe->private;
+ char link[MAXFONTFILENAMELEN];
+ char dest[MAXFONTFILENAMELEN];
+ char *attrib;
+ FontPathElementPtr subfpe;
+ struct stat statbuf;
+ const char *path;
+ DIR *dir;
+ struct dirent *entry;
+ int len;
+ int pathlen;
+
+ path = fpe->name + strlen(CataloguePrefix);
+ if (stat(path, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
+ return BadFontPath;
+
+ if ((forceScan == FALSE) && (statbuf.st_mtime <= cat->mtime))
+ return Successful;
+
+ dir = opendir(path);
+ if (dir == NULL)
+ {
+ xfree(cat);
+ return BadFontPath;
+ }
+
+ CatalogueUnrefFPEs (fpe);
+ while (entry = readdir(dir), entry != NULL)
+ {
+ snprintf(link, sizeof link, "%s/%s", path, entry->d_name);
+ len = readlink(link, dest, sizeof dest - 1);
+ if (len < 0)
+ continue;
+
+ dest[len] = '\0';
+
+ if (dest[0] != '/')
+ {
+ pathlen = strlen(path);
+ memmove(dest + pathlen + 1, dest, sizeof dest - pathlen - 1);
+ memcpy(dest, path, pathlen);
+ memcpy(dest + pathlen, "/", 1);
+ len += pathlen + 1;
+ }
+
+ attrib = strchr(link, ':');
+ if (attrib && len + strlen(attrib) < sizeof dest)
+ {
+ memcpy(dest + len, attrib, strlen(attrib));
+ len += strlen(attrib);
+ }
+
+ subfpe = xalloc(sizeof *subfpe);
+ if (subfpe == NULL)
+ continue;
+
+ /* The fonts returned by OpenFont will point back to the
+ * subfpe they come from. So set the type of the subfpe to
+ * what the catalogue fpe was assigned, so calls to CloseFont
+ * (which uses font->fpe->type) goes to CatalogueCloseFont. */
+ subfpe->type = fpe->type;
+ subfpe->name_length = len;
+ subfpe->name = xalloc (len + 1);
+ if (subfpe == NULL)
+ {
+ xfree(subfpe);
+ continue;
+ }
+
+ memcpy(subfpe->name, dest, len);
+ subfpe->name[len] = '\0';
+
+ /* The X server will manipulate the subfpe ref counts
+ * associated with the font in OpenFont and CloseFont, so we
+ * have to make sure it's valid. */
+ subfpe->refcount = 1;
+
+ if (FontFileInitFPE (subfpe) != Successful)
+ {
+ xfree(subfpe->name);
+ xfree(subfpe);
+ continue;
+ }
+
+ if (CatalogueAddFPE(cat, subfpe) != Successful)
+ {
+ FontFileFreeFPE (subfpe);
+ xfree(subfpe);
+ continue;
+ }
+ }
+
+ closedir(dir);
+
+ qsort(cat->fpeList,
+ cat->fpeCount, sizeof cat->fpeList[0], ComparePriority);
+
+ cat->mtime = statbuf.st_mtime;
+
+ return Successful;
+}
+
+static int
+CatalogueInitFPE (FontPathElementPtr fpe)
+{
+ CataloguePtr cat;
+
+ cat = (CataloguePtr) xalloc(sizeof *cat);
+ if (cat == NULL)
+ return AllocError;
+
+ fpe->private = (pointer) cat;
+ cat->fpeCount = 0;
+ cat->fpeAlloc = 0;
+ cat->fpeList = NULL;
+ cat->mtime = 0;
+
+ return CatalogueRescan (fpe, TRUE);
+}
+
+static int
+CatalogueResetFPE (FontPathElementPtr fpe)
+{
+ /* Always just tell the caller to close and re-open */
+ return FPEResetFailed;
+}
+
+static int
+CatalogueFreeFPE (FontPathElementPtr fpe)
+{
+ CataloguePtr cat = fpe->private;
+
+ /* If the catalogue is modified while the xserver has fonts open
+ * from the previous subfpes, we'll unref the old subfpes when we
+ * reload the catalogue, and the xserver will the call FreeFPE on
+ * them once it drops its last reference. Thus, the FreeFPE call
+ * for the subfpe ends up here and we just forward it to
+ * FontFileFreeFPE. */
+
+ if (!CatalogueNameCheck (fpe->name))
+ return FontFileFreeFPE (fpe);
+
+ CatalogueUnrefFPEs (fpe);
+ xfree(cat->fpeList);
+ xfree(cat);
+
+ return Successful;
+}
+
+static int
+CatalogueOpenFont (pointer client, FontPathElementPtr fpe, Mask flags,
+ char *name, int namelen,
+ fsBitmapFormat format, fsBitmapFormatMask fmask,
+ XID id, FontPtr *pFont, char **aliasName,
+ FontPtr non_cachable_font)
+{
+ CataloguePtr cat = fpe->private;
+ FontPathElementPtr subfpe;
+ FontDirectoryPtr dir;
+ int i, status;
+
+ CatalogueRescan (fpe, FALSE);
+
+ for (i = 0; i < cat->fpeCount; i++)
+ {
+ subfpe = cat->fpeList[i];
+ dir = subfpe->private;
+ status = FontFileOpenFont(client, subfpe, flags,
+ name, namelen, format, fmask, id,
+ pFont, aliasName, non_cachable_font);
+ if (status == Successful || status == FontNameAlias)
+ return status;
+ }
+
+ return BadFontName;
+}
+
+static void
+CatalogueCloseFont (FontPathElementPtr fpe, FontPtr pFont)
+{
+ /* Note: this gets called with the actual subfpe where we found
+ * the font, not the catalogue fpe. */
+
+ FontFileCloseFont(fpe, pFont);
+}
+
+static int
+CatalogueListFonts (pointer client, FontPathElementPtr fpe, char *pat,
+ int len, int max, FontNamesPtr names)
+{
+ CataloguePtr cat = fpe->private;
+ FontPathElementPtr subfpe;
+ FontDirectoryPtr dir;
+ int i;
+
+ CatalogueRescan (fpe, FALSE);
+
+ for (i = 0; i < cat->fpeCount; i++)
+ {
+ subfpe = cat->fpeList[i];
+ dir = subfpe->private;
+ FontFileListFonts(client, subfpe, pat, len, max, names);
+ }
+
+ return Successful;
+}
+
+int
+FontFileStartListFonts(pointer client, FontPathElementPtr fpe,
+ char *pat, int len, int max,
+ pointer *privatep, int mark_aliases);
+
+typedef struct _LFWIData {
+ pointer *privates;
+ int current;
+} LFWIDataRec, *LFWIDataPtr;
+
+static int
+CatalogueStartListFonts(pointer client, FontPathElementPtr fpe,
+ char *pat, int len, int max, pointer *privatep,
+ int mark_aliases)
+{
+ CataloguePtr cat = fpe->private;
+ LFWIDataPtr data;
+ int ret, i, j;
+
+ CatalogueRescan (fpe, FALSE);
+
+ data = (LFWIDataPtr) xalloc (sizeof *data +
+ sizeof data->privates[0] * cat->fpeCount);
+ if (!data)
+ return AllocError;
+ data->privates = (pointer *) (data + 1);
+
+ for (i = 0; i < cat->fpeCount; i++)
+ {
+ ret = FontFileStartListFonts(client, cat->fpeList[i], pat, len,
+ max, &data->privates[i], mark_aliases);
+ if (ret != Successful)
+ goto bail;
+ }
+
+ data->current = 0;
+ *privatep = (pointer) data;
+ return Successful;
+
+ bail:
+ for (j = 0; j < i; j++)
+ /* FIXME: we have no way to free the per-fpe privates. */;
+ xfree (data);
+
+ return AllocError;
+}
+
+static int
+CatalogueStartListFontsWithInfo(pointer client, FontPathElementPtr fpe,
+ char *pat, int len, int max,
+ pointer *privatep)
+{
+ return CatalogueStartListFonts(client, fpe, pat, len, max, privatep, 0);
+}
+
+static int
+CatalogueListNextFontWithInfo(pointer client, FontPathElementPtr fpe,
+ char **namep, int *namelenp,
+ FontInfoPtr *pFontInfo,
+ int *numFonts, pointer private)
+{
+ LFWIDataPtr data = private;
+ CataloguePtr cat = fpe->private;
+ int ret;
+
+ if (data->current == cat->fpeCount)
+ {
+ xfree(data);
+ return BadFontName;
+ }
+
+ ret = FontFileListNextFontWithInfo(client, cat->fpeList[data->current],
+ namep, namelenp,
+ pFontInfo, numFonts,
+ data->privates[data->current]);
+ if (ret == BadFontName)
+ {
+ data->current++;
+ return CatalogueListNextFontWithInfo(client, fpe, namep, namelenp,
+ pFontInfo, numFonts, private);
+ }
+
+ return ret;
+}
+
+static int
+CatalogueStartListFontsAndAliases(pointer client, FontPathElementPtr fpe,
+ char *pat, int len, int max,
+ pointer *privatep)
+{
+ return CatalogueStartListFonts(client, fpe, pat, len, max, privatep, 1);
+}
+
+static int
+CatalogueListNextFontOrAlias(pointer client, FontPathElementPtr fpe,
+ char **namep, int *namelenp, char **resolvedp,
+ int *resolvedlenp, pointer private)
+{
+ LFWIDataPtr data = private;
+ CataloguePtr cat = fpe->private;
+ int ret;
+
+ if (data->current == cat->fpeCount)
+ {
+ xfree(data);
+ return BadFontName;
+ }
+
+ ret = FontFileListNextFontOrAlias(client, cat->fpeList[data->current],
+ namep, namelenp,
+ resolvedp, resolvedlenp,
+ data->privates[data->current]);
+ if (ret == BadFontName)
+ {
+ data->current++;
+ return CatalogueListNextFontOrAlias(client, fpe, namep, namelenp,
+ resolvedp, resolvedlenp, private);
+ }
+
+ return ret;
+}
+
+void
+CatalogueRegisterLocalFpeFunctions (void)
+{
+ RegisterFPEFunctions(CatalogueNameCheck,
+ CatalogueInitFPE,
+ CatalogueFreeFPE,
+ CatalogueResetFPE,
+ CatalogueOpenFont,
+ CatalogueCloseFont,
+ CatalogueListFonts,
+ CatalogueStartListFontsWithInfo,
+ CatalogueListNextFontWithInfo,
+ NULL,
+ NULL,
+ NULL,
+ CatalogueStartListFontsAndAliases,
+ CatalogueListNextFontOrAlias,
+ FontFileEmptyBitmapSource);
+}