~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/utils/fonts/fontconfig.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
:mod:`fontconfig` -- Pythonic interface to fontconfig
 
3
=====================================================
 
4
 
 
5
.. module:: fontconfig
 
6
    :platform: All
 
7
    :synopsis: Pythonic interface to the fontconfig library
 
8
 
 
9
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net> Copyright 2009
 
10
 
 
11
*/
 
12
 
 
13
#define PY_SSIZE_T_CLEAN
 
14
#include <Python.h>
 
15
#include <stdio.h>
 
16
#include <string.h>
 
17
#include <fontconfig.h>
 
18
 
 
19
static PyObject *
 
20
fontconfig_initialize(PyObject *self, PyObject *args) {
 
21
    char *path;
 
22
    FcBool ok;
 
23
    FcConfig *config;
 
24
    PyThreadState *_save;
 
25
 
 
26
    if (!PyArg_ParseTuple(args, "z", &path))
 
27
                return NULL;
 
28
    if (path == NULL) {
 
29
        _save = PyEval_SaveThread();
 
30
        ok = FcInit();
 
31
        PyEval_RestoreThread(_save);
 
32
    } else {
 
33
        config = FcConfigCreate();
 
34
        if (config == NULL) return PyErr_NoMemory();
 
35
        _save = PyEval_SaveThread();
 
36
        ok = FcConfigParseAndLoad(config, path, FcTrue);
 
37
        if (ok) ok = FcConfigBuildFonts(config);
 
38
        if (ok) ok = FcConfigSetCurrent(config);
 
39
        PyEval_RestoreThread(_save);
 
40
        if (!ok) return PyErr_NoMemory();     
 
41
        ok = 1;
 
42
    }
 
43
    if (ok) Py_RETURN_TRUE;
 
44
    Py_RETURN_FALSE;
 
45
}
 
46
 
 
47
static
 
48
fontconfig_cleanup_find(FcPattern *p, FcObjectSet *oset, FcFontSet *fs) {
 
49
    if (p != NULL) FcPatternDestroy(p);
 
50
    if (oset != NULL) FcObjectSetDestroy(oset);
 
51
    if (fs != NULL) FcFontSetDestroy(fs);
 
52
}
 
53
 
 
54
 
 
55
static PyObject *
 
56
fontconfig_find_font_families(PyObject *self, PyObject *args) {
 
57
    int i; 
 
58
    size_t flen;
 
59
    char *ext;
 
60
    Py_ssize_t l, j, extlen;
 
61
    FcBool ok;
 
62
    FcPattern *pat, *temp;
 
63
    FcObjectSet *oset;
 
64
    FcFontSet *fs;
 
65
    FcValue v, w;
 
66
    PyObject *ans, *exts, *t;
 
67
 
 
68
    ans = PyList_New(0);
 
69
    fs = NULL; oset = NULL; pat = NULL;
 
70
 
 
71
    if (ans == NULL) return PyErr_NoMemory();
 
72
 
 
73
    if (!PyArg_ParseTuple(args, "O", &exts))
 
74
                return NULL;
 
75
 
 
76
    if (!PySequence_Check(exts)) { 
 
77
        PyErr_SetString(PyExc_ValueError, "Must pass sequence of extensions");
 
78
        return NULL;
 
79
    }
 
80
    l = PySequence_Size(exts);
 
81
 
 
82
 
 
83
    pat = FcPatternCreate();
 
84
    if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
85
 
 
86
    oset = FcObjectSetCreate();
 
87
    if (oset == NULL)  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
88
    if (!FcObjectSetAdd(oset, FC_FILE))  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
89
    if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
90
 
 
91
    fs = FcFontList(FcConfigGetCurrent(), pat, oset);
 
92
    if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
93
 
 
94
    for (i = 0; i < fs->nfont; i++) {
 
95
        temp = fs->fonts[i];
 
96
 
 
97
        if (temp == NULL) continue;
 
98
        if (FcPatternGet(temp, FC_FILE, 0, &v) != FcResultMatch) continue;
 
99
 
 
100
        if (v.type == FcTypeString) {
 
101
            flen = strlen((char *)v.u.s);
 
102
            ok = FcFalse;
 
103
            if (l == 0) ok = FcTrue;
 
104
            for ( j = 0; j < l && !ok; j++) {
 
105
                ext = PyBytes_AS_STRING(PySequence_ITEM(exts, j));
 
106
                extlen = PyBytes_GET_SIZE(PySequence_ITEM(exts, j));
 
107
                ok = flen > extlen && extlen > 0 && 
 
108
                    PyOS_strnicmp(ext, v.u.s + (flen - extlen), extlen) == 0;
 
109
            }
 
110
 
 
111
            if (ok) {
 
112
                if (FcPatternGet(temp, FC_FAMILY, 0, &w) != FcResultMatch) continue;
 
113
                if (w.type != FcTypeString) continue;
 
114
                t = PyString_FromString(w.u.s);
 
115
                if (t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
116
                if (PyList_Append(ans, t) != 0)
 
117
                    { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
118
            }
 
119
        }
 
120
 
 
121
    }
 
122
    fontconfig_cleanup_find(pat, oset, fs);
 
123
    Py_INCREF(ans);
 
124
    return ans;
 
125
}
 
126
 
 
127
static PyObject *
 
128
fontconfig_files_for_family(PyObject *self, PyObject *args) {
 
129
    char *family; int i;
 
130
    FcPattern *pat, *tp;
 
131
    FcObjectSet *oset;
 
132
    FcFontSet *fs;
 
133
    FcValue file, weight, fullname, style, slant, family2;
 
134
    PyObject *ans, *temp, *t;
 
135
 
 
136
    if (!PyArg_ParseTuple(args, "s", &family))
 
137
                return NULL;
 
138
 
 
139
    ans = PyList_New(0);
 
140
    if (ans == NULL) return PyErr_NoMemory();
 
141
 
 
142
    fs = NULL; oset = NULL; pat = NULL;
 
143
 
 
144
    pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, family, (char *) 0);
 
145
    if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
146
 
 
147
    oset = FcObjectSetCreate();
 
148
    if (oset == NULL)  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
149
    if (!FcObjectSetAdd(oset, FC_FILE))  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
150
    if (!FcObjectSetAdd(oset, FC_STYLE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
151
    if (!FcObjectSetAdd(oset, FC_SLANT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
152
    if (!FcObjectSetAdd(oset, FC_WEIGHT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
153
    if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
154
    if (!FcObjectSetAdd(oset, "fullname")) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
155
 
 
156
    fs = FcFontList(FcConfigGetCurrent(), pat, oset);
 
157
    if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
158
 
 
159
    for (i = 0; i < fs->nfont; i++) {
 
160
        tp = fs->fonts[i];
 
161
 
 
162
        if (tp == NULL) continue;
 
163
        if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
 
164
        if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
 
165
        if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
 
166
        if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
 
167
        if (FcPatternGet(tp, FC_FAMILY, 0, &family2) != FcResultMatch) continue;
 
168
        if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
 
169
 
 
170
        temp = PyTuple_New(6);
 
171
        if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
172
        t = PyBytes_FromString(fullname.u.s);
 
173
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
174
        PyTuple_SET_ITEM(temp, 0, t);
 
175
        t = PyBytes_FromString(file.u.s);
 
176
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
177
        PyTuple_SET_ITEM(temp, 1, t);
 
178
        t = PyBytes_FromString(style.u.s);
 
179
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
180
        PyTuple_SET_ITEM(temp, 2, t);
 
181
        t = PyBytes_FromString(family2.u.s);
 
182
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
183
        PyTuple_SET_ITEM(temp, 3, t);
 
184
        t = PyInt_FromLong((long)weight.u.i);
 
185
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
186
        PyTuple_SET_ITEM(temp, 4, t);
 
187
        t = PyInt_FromLong((long)slant.u.i);
 
188
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
189
        PyTuple_SET_ITEM(temp, 5, t);
 
190
        if (PyList_Append(ans, temp) != 0)
 
191
            { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
192
    }
 
193
    fontconfig_cleanup_find(pat, oset, fs);
 
194
    Py_INCREF(ans);
 
195
    return ans;
 
196
}
 
197
 
 
198
static PyObject *
 
199
fontconfig_match(PyObject *self, PyObject *args) {
 
200
    char *namespec; int i;
 
201
    FcPattern *pat, *tp;
 
202
    FcObjectSet *oset;
 
203
    FcFontSet *fs, *fs2;
 
204
    FcValue file, weight, fullname, style, slant, family;
 
205
    FcResult res;
 
206
    PyObject *ans, *temp, *t, *all, *verbose;
 
207
 
 
208
    if (!PyArg_ParseTuple(args, "sOO", &namespec, &all, &verbose))
 
209
                return NULL;
 
210
 
 
211
    ans = PyList_New(0);
 
212
    if (ans == NULL) return PyErr_NoMemory();
 
213
 
 
214
    fs = NULL; oset = NULL; pat = NULL; fs2 = NULL;
 
215
 
 
216
    pat = FcNameParse(namespec);
 
217
    if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
218
    if (PyObject_IsTrue(verbose)) FcPatternPrint(pat);
 
219
 
 
220
    if (!FcConfigSubstitute(FcConfigGetCurrent(), pat, FcMatchPattern)) 
 
221
        { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 
222
    FcDefaultSubstitute(pat);
 
223
 
 
224
    fs = FcFontSetCreate();
 
225
    if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
226
    if (PyObject_IsTrue(all)) {
 
227
        fs2 = FcFontSort(FcConfigGetCurrent(), pat, FcTrue, NULL, &res);
 
228
        if (fs2 == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
229
 
 
230
        for (i = 0; i < fs2->nfont; i++) {
 
231
            tp = fs2->fonts[i];
 
232
            if (tp == NULL) continue;
 
233
            tp = FcFontRenderPrepare(FcConfigGetCurrent(), pat, tp);
 
234
            if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
235
            if (!FcFontSetAdd(fs, tp)) 
 
236
                { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
237
        }
 
238
        if (fs2 != NULL) FcFontSetDestroy(fs2);
 
239
    } else {
 
240
        tp = FcFontMatch(FcConfigGetCurrent(), pat, &res);
 
241
        if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
242
        if (!FcFontSetAdd(fs, tp)) 
 
243
            { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
244
    }
 
245
 
 
246
    for (i = 0; i < fs->nfont; i++) {
 
247
        tp = fs->fonts[i];
 
248
        if (tp == NULL) continue;
 
249
        if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
 
250
        if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
 
251
        if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
 
252
        if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
 
253
        if (FcPatternGet(tp, FC_FAMILY, 0, &family) != FcResultMatch) continue;
 
254
        if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
 
255
 
 
256
        temp = PyTuple_New(6);
 
257
        if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
258
        t = PyBytes_FromString(fullname.u.s);
 
259
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
260
        PyTuple_SET_ITEM(temp, 0, t);
 
261
        t = PyBytes_FromString(file.u.s);
 
262
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
263
        PyTuple_SET_ITEM(temp, 1, t);
 
264
        t = PyBytes_FromString(style.u.s);
 
265
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
266
        PyTuple_SET_ITEM(temp, 2, t);
 
267
        t = PyBytes_FromString(family.u.s);
 
268
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
269
        PyTuple_SET_ITEM(temp, 3, t);
 
270
        t = PyInt_FromLong((long)weight.u.i);
 
271
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
272
        PyTuple_SET_ITEM(temp, 4, t);
 
273
        t = PyInt_FromLong((long)slant.u.i);
 
274
        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
275
        PyTuple_SET_ITEM(temp, 5, t);
 
276
        if (PyList_Append(ans, temp) != 0)
 
277
            { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 
278
 
 
279
    }
 
280
    fontconfig_cleanup_find(pat, oset, fs);
 
281
    Py_INCREF(ans);
 
282
    return ans;
 
283
}
 
284
 
 
285
 
 
286
 
 
287
static 
 
288
PyMethodDef fontconfig_methods[] = {
 
289
    {"initialize", fontconfig_initialize, METH_VARARGS,
 
290
    "initialize(path_to_config_file)\n\n"
 
291
                "Initialize the library. If path to config file is specified it is used instead of the "
 
292
            "default configuration. Returns True iff the initialization succeeded."
 
293
    },
 
294
 
 
295
    {"find_font_families", fontconfig_find_font_families, METH_VARARGS,
 
296
    "find_font_families(allowed_extensions)\n\n"
 
297
                "Find all font families on the system for fonts of the specified types. If no "
 
298
            "types are specified all font families are returned."
 
299
    },
 
300
 
 
301
    {"files_for_family", fontconfig_files_for_family, METH_VARARGS,
 
302
    "files_for_family(family, normalize)\n\n"
 
303
                "Find all the variants in the font family `family`. "
 
304
            "Returns a list of tuples. Each tuple is of the form "
 
305
            "(fullname, path, style, family, weight, slant). "
 
306
    },
 
307
 
 
308
    {"match", fontconfig_match, METH_VARARGS,
 
309
    "match(namespec,all,verbose)\n\n"
 
310
                "Find all system fonts that match namespec, in decreasing order "
 
311
            "of closeness. "
 
312
            "Returns a list of tuples. Each tuple is of the form "
 
313
            "(fullname, path, style, family, weight, slant). "
 
314
 
 
315
    },
 
316
 
 
317
    {NULL, NULL, 0, NULL}
 
318
};
 
319
 
 
320
 
 
321
 
 
322
PyMODINIT_FUNC
 
323
initfontconfig(void) {
 
324
    PyObject *m;
 
325
    m = Py_InitModule3(
 
326
            "fontconfig", fontconfig_methods,
 
327
            "Find fonts."
 
328
    );
 
329
    if (m == NULL) return;
 
330
}
 
331