upload tizen2.0 source
[framework/uifw/xorg/lib/libxfont.git] / src / fontfile / catalogue.c
1 /*
2  * Copyright © 2007 Red Hat, Inc
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author:
24  *   Kristian Høgsberg <krh@redhat.com>
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <X11/fonts/fntfilst.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <dirent.h>
34 #include <unistd.h>
35
36 static const char CataloguePrefix[] = "catalogue:";
37
38 static int CatalogueFreeFPE (FontPathElementPtr fpe);
39
40 static int
41 CatalogueNameCheck (char *name)
42 {
43     return strncmp(name, CataloguePrefix, sizeof(CataloguePrefix) - 1) == 0;
44 }
45
46 typedef struct _CatalogueRec {
47     time_t mtime;
48     int fpeCount, fpeAlloc;
49     FontPathElementPtr *fpeList;
50 } CatalogueRec, *CataloguePtr;
51
52 static int
53 CatalogueAddFPE (CataloguePtr cat, FontPathElementPtr fpe)
54 {
55     FontPathElementPtr *new;
56
57     if (cat->fpeCount >= cat->fpeAlloc)
58     {
59         if (cat->fpeAlloc == 0)
60             cat->fpeAlloc = 16;
61         else
62             cat->fpeAlloc *= 2;
63
64         new = realloc(cat->fpeList, cat->fpeAlloc * sizeof(FontPathElementPtr));
65         if (new == NULL)
66             return AllocError;
67
68         cat->fpeList = new;
69     }
70
71     cat->fpeList[cat->fpeCount++] = fpe;
72
73     return Successful;
74 }
75
76 static const char PriorityAttribute[] = "pri=";
77
78 static int
79 ComparePriority(const void *p1, const void *p2)
80 {
81     FontDirectoryPtr dir1 = (*(FontPathElementPtr*) p1)->private;
82     FontDirectoryPtr dir2 = (*(FontPathElementPtr*) p2)->private;
83     const char *pri1 = NULL;
84     const char *pri2 = NULL;
85
86     if (dir1->attributes != NULL)
87         pri1 = strstr(dir1->attributes, PriorityAttribute);
88     if (dir2->attributes != NULL)
89         pri2 = strstr(dir2->attributes, PriorityAttribute);
90
91     if (pri1 == NULL && pri2 == NULL)
92         return 0;
93     else if (pri1 == NULL)
94         return 1;
95     else if (pri2 == NULL)
96         return -1;
97     else
98         return
99             atoi(pri1 + strlen(PriorityAttribute)) -
100             atoi(pri2 + strlen(PriorityAttribute));
101 }
102
103 static void
104 CatalogueUnrefFPEs (FontPathElementPtr fpe)
105 {
106     CataloguePtr        cat = fpe->private;
107     FontPathElementPtr  subfpe;
108     int                 i;
109
110     for (i = 0; i < cat->fpeCount; i++)
111     {
112         subfpe = cat->fpeList[i];
113         subfpe->refcount--;
114         if (subfpe->refcount == 0)
115         {
116             FontFileFreeFPE (subfpe);
117             free(subfpe->name);
118             free(subfpe);
119         }
120     }
121
122     cat->fpeCount = 0;
123 }
124
125 /* Rescan catalogue directory if modified timestamp has changed or
126  * the forceScan argument says to do it anyway (like on first load). */
127 static int
128 CatalogueRescan (FontPathElementPtr fpe, Bool forceScan)
129 {
130     CataloguePtr        cat = fpe->private;
131     char                link[MAXFONTFILENAMELEN];
132     char                dest[MAXFONTFILENAMELEN];
133     char                *attrib;
134     FontPathElementPtr  subfpe;
135     struct stat         statbuf;
136     const char          *path;
137     DIR                 *dir;
138     struct dirent       *entry;
139     int                 len;
140     int                 pathlen;
141
142     path = fpe->name + strlen(CataloguePrefix);
143     if (stat(path, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
144         return BadFontPath;
145
146     if ((forceScan == FALSE) && (statbuf.st_mtime <= cat->mtime))
147         return Successful;
148
149     dir = opendir(path);
150     if (dir == NULL)
151     {
152         free(cat);
153         return BadFontPath;
154     }
155
156     CatalogueUnrefFPEs (fpe);
157     while (entry = readdir(dir), entry != NULL)
158     {
159         snprintf(link, sizeof link, "%s/%s", path, entry->d_name);
160         len = readlink(link, dest, sizeof dest - 1);
161         if (len < 0)
162             continue;
163
164         dest[len] = '\0';
165
166         if (dest[0] != '/')
167         {
168            pathlen = strlen(path);
169            memmove(dest + pathlen + 1, dest, sizeof dest - pathlen - 1);
170            memcpy(dest, path, pathlen);
171            memcpy(dest + pathlen, "/", 1);
172            len += pathlen + 1;
173         }
174
175         attrib = strchr(link, ':');
176         if (attrib && len + strlen(attrib) < sizeof dest)
177         {
178             memcpy(dest + len, attrib, strlen(attrib));
179             len += strlen(attrib);
180         }
181
182         subfpe = malloc(sizeof *subfpe);
183         if (subfpe == NULL)
184             continue;
185
186         /* The fonts returned by OpenFont will point back to the
187          * subfpe they come from.  So set the type of the subfpe to
188          * what the catalogue fpe was assigned, so calls to CloseFont
189          * (which uses font->fpe->type) goes to CatalogueCloseFont. */
190         subfpe->type = fpe->type;
191         subfpe->name_length = len;
192         subfpe->name = malloc (len + 1);
193         if (subfpe == NULL)
194         {
195             free(subfpe);
196             continue;
197         }
198
199         memcpy(subfpe->name, dest, len);
200         subfpe->name[len] = '\0';
201
202         /* The X server will manipulate the subfpe ref counts
203          * associated with the font in OpenFont and CloseFont, so we
204          * have to make sure it's valid. */
205         subfpe->refcount = 1;
206
207         if (FontFileInitFPE (subfpe) != Successful)
208         {
209             free(subfpe->name);
210             free(subfpe);
211             continue;
212         }
213
214         if (CatalogueAddFPE(cat, subfpe) != Successful)
215         {
216             FontFileFreeFPE (subfpe);
217             free(subfpe);
218             continue;
219         }
220     }
221
222     closedir(dir);
223
224     qsort(cat->fpeList,
225           cat->fpeCount, sizeof cat->fpeList[0], ComparePriority);
226
227     cat->mtime = statbuf.st_mtime;
228
229     return Successful;
230 }
231
232 static int
233 CatalogueInitFPE (FontPathElementPtr fpe)
234 {
235     CataloguePtr        cat;
236
237     cat = malloc(sizeof *cat);
238     if (cat == NULL)
239         return AllocError;
240
241     fpe->private = (pointer) cat;
242     cat->fpeCount = 0;
243     cat->fpeAlloc = 0;
244     cat->fpeList = NULL;
245     cat->mtime = 0;
246
247     return CatalogueRescan (fpe, TRUE);
248 }
249
250 static int
251 CatalogueResetFPE (FontPathElementPtr fpe)
252 {
253     /* Always just tell the caller to close and re-open */
254     return FPEResetFailed;
255 }
256
257 static int
258 CatalogueFreeFPE (FontPathElementPtr fpe)
259 {
260     CataloguePtr        cat = fpe->private;
261
262     /* If the catalogue is modified while the xserver has fonts open
263      * from the previous subfpes, we'll unref the old subfpes when we
264      * reload the catalogue, and the xserver will the call FreeFPE on
265      * them once it drops its last reference. Thus, the FreeFPE call
266      * for the subfpe ends up here and we just forward it to
267      * FontFileFreeFPE. */
268
269     if (!CatalogueNameCheck (fpe->name))
270         return FontFileFreeFPE (fpe);
271
272     CatalogueUnrefFPEs (fpe);
273     free(cat->fpeList);
274     free(cat);
275
276     return Successful;
277 }
278
279 static int
280 CatalogueOpenFont (pointer client, FontPathElementPtr fpe, Mask flags,
281                    char *name, int namelen,
282                    fsBitmapFormat format, fsBitmapFormatMask fmask,
283                    XID id, FontPtr *pFont, char **aliasName,
284                    FontPtr non_cachable_font)
285 {
286     CataloguePtr cat = fpe->private;
287     FontPathElementPtr subfpe;
288     FontDirectoryPtr dir;
289     int i, status;
290
291     CatalogueRescan (fpe, FALSE);
292
293     for (i = 0; i < cat->fpeCount; i++)
294     {
295         subfpe = cat->fpeList[i];
296         dir = subfpe->private;
297         status = FontFileOpenFont(client, subfpe, flags,
298                                   name, namelen, format, fmask, id,
299                                   pFont, aliasName, non_cachable_font);
300         if (status == Successful || status == FontNameAlias)
301             return status;
302     }
303
304     return BadFontName;
305 }
306
307 static void
308 CatalogueCloseFont (FontPathElementPtr fpe, FontPtr pFont)
309 {
310     /* Note: this gets called with the actual subfpe where we found
311      * the font, not the catalogue fpe. */
312
313     FontFileCloseFont(fpe, pFont);
314 }
315
316 static int
317 CatalogueListFonts (pointer client, FontPathElementPtr fpe, char *pat,
318                     int len, int max, FontNamesPtr names)
319 {
320     CataloguePtr cat = fpe->private;
321     FontPathElementPtr subfpe;
322     FontDirectoryPtr dir;
323     int i;
324
325     CatalogueRescan (fpe, FALSE);
326
327     for (i = 0; i < cat->fpeCount; i++)
328     {
329         subfpe = cat->fpeList[i];
330         dir = subfpe->private;
331         FontFileListFonts(client, subfpe, pat, len, max, names);
332     }
333
334     return Successful;
335 }
336
337 int
338 FontFileStartListFonts(pointer client, FontPathElementPtr fpe,
339                        char *pat, int len, int max,
340                        pointer *privatep, int mark_aliases);
341
342 typedef struct _LFWIData {
343     pointer             *privates;
344     int                 current;
345 } LFWIDataRec, *LFWIDataPtr;
346
347 static int
348 CatalogueStartListFonts(pointer client, FontPathElementPtr fpe,
349                         char *pat, int len, int max, pointer *privatep,
350                         int mark_aliases)
351 {
352     CataloguePtr        cat = fpe->private;
353     LFWIDataPtr         data;
354     int                 ret, i, j;
355
356     CatalogueRescan (fpe, FALSE);
357
358     data = malloc (sizeof *data + sizeof data->privates[0] * cat->fpeCount);
359     if (!data)
360         return AllocError;
361     data->privates = (pointer *) (data + 1);
362
363     for (i = 0; i < cat->fpeCount; i++)
364     {
365         ret = FontFileStartListFonts(client, cat->fpeList[i], pat, len,
366                                      max, &data->privates[i], mark_aliases);
367         if (ret != Successful)
368             goto bail;
369     }
370
371     data->current = 0;
372     *privatep = (pointer) data;
373     return Successful;
374
375  bail:
376     for (j = 0; j < i; j++)
377         /* FIXME: we have no way to free the per-fpe privates. */;
378     free (data);
379
380     return AllocError;
381 }
382
383 static int
384 CatalogueStartListFontsWithInfo(pointer client, FontPathElementPtr fpe,
385                                 char *pat, int len, int max,
386                                 pointer *privatep)
387 {
388     return CatalogueStartListFonts(client, fpe, pat, len, max, privatep, 0);
389 }
390
391 static int
392 CatalogueListNextFontWithInfo(pointer client, FontPathElementPtr fpe,
393                               char **namep, int *namelenp,
394                               FontInfoPtr *pFontInfo,
395                               int *numFonts, pointer private)
396 {
397     LFWIDataPtr         data = private;
398     CataloguePtr        cat = fpe->private;
399     int                 ret;
400
401     if (data->current == cat->fpeCount)
402     {
403         free(data);
404         return BadFontName;
405     }
406
407     ret = FontFileListNextFontWithInfo(client, cat->fpeList[data->current],
408                                        namep, namelenp,
409                                        pFontInfo, numFonts,
410                                        data->privates[data->current]);
411     if (ret == BadFontName)
412     {
413         data->current++;
414         return CatalogueListNextFontWithInfo(client, fpe, namep, namelenp,
415                                              pFontInfo, numFonts, private);
416     }
417
418     return ret;
419 }
420
421 static int
422 CatalogueStartListFontsAndAliases(pointer client, FontPathElementPtr fpe,
423                                   char *pat, int len, int max,
424                                   pointer *privatep)
425 {
426     return CatalogueStartListFonts(client, fpe, pat, len, max, privatep, 1);
427 }
428
429 static int
430 CatalogueListNextFontOrAlias(pointer client, FontPathElementPtr fpe,
431                              char **namep, int *namelenp, char **resolvedp,
432                              int *resolvedlenp, pointer private)
433 {
434     LFWIDataPtr         data = private;
435     CataloguePtr        cat = fpe->private;
436     int                 ret;
437
438     if (data->current == cat->fpeCount)
439     {
440         free(data);
441         return BadFontName;
442     }
443
444     ret = FontFileListNextFontOrAlias(client, cat->fpeList[data->current],
445                                       namep, namelenp,
446                                       resolvedp, resolvedlenp,
447                                       data->privates[data->current]);
448     if (ret == BadFontName)
449     {
450         data->current++;
451         return CatalogueListNextFontOrAlias(client, fpe, namep, namelenp,
452                                             resolvedp, resolvedlenp, private);
453     }
454
455     return ret;
456 }
457
458 void
459 CatalogueRegisterLocalFpeFunctions (void)
460 {
461     RegisterFPEFunctions(CatalogueNameCheck,
462                          CatalogueInitFPE,
463                          CatalogueFreeFPE,
464                          CatalogueResetFPE,
465                          CatalogueOpenFont,
466                          CatalogueCloseFont,
467                          CatalogueListFonts,
468                          CatalogueStartListFontsWithInfo,
469                          CatalogueListNextFontWithInfo,
470                          NULL,
471                          NULL,
472                          NULL,
473                          CatalogueStartListFontsAndAliases,
474                          CatalogueListNextFontOrAlias,
475                          FontFileEmptyBitmapSource);
476 }