~pygame/pygame/trunk

« back to all changes in this revision

Viewing changes to src/_freetype.c

  • Committer: pygame
  • Date: 2017-01-10 00:31:42 UTC
  • Revision ID: git-v1:2eea4f299a2e791f884608d7ed601558634af73c
commit 1639c41a8cb3433046882ede92c80ce69d59016b
Author: Thomas Kluyver <takowl@gmail.com>
Date:   Sun Jan 8 18:46:46 2017 +0000

    Build newer versions of libogg and libvorbis into Linux base images

    Closes #317
    Closes #323

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  pygame - Python Game Library
 
3
  Copyright (C) 2009 Vicent Marti
 
4
 
 
5
  This library is free software; you can redistribute it and/or
 
6
  modify it under the terms of the GNU Library General Public
 
7
  License as published by the Free Software Foundation; either
 
8
  version 2 of the License, or (at your option) any later version.
 
9
 
 
10
  This library is distributed in the hope that it will be useful,
 
11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
  Library General Public License for more details.
 
14
 
 
15
  You should have received a copy of the GNU Library General Public
 
16
  License along with this library; if not, write to the Free
 
17
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 
 
19
*/
 
20
 
 
21
#define PYGAME_FREETYPE_INTERNAL
 
22
#define PYGAME_FREETYPE_FONT_INTERNAL
 
23
 
 
24
#include "freetype.h"
 
25
#include "freetype/ft_wrap.h"
 
26
#include "doc/freetype_doc.h"
 
27
 
 
28
#define MODULE_NAME "_freetype"
 
29
#define FONT_TYPE_NAME "Font"
 
30
 
 
31
/*
 
32
 * FreeType module declarations
 
33
 */
 
34
static const Scale_t FACE_SIZE_NONE = {0, 0};
 
35
 
 
36
#if PY3
 
37
static int _ft_traverse(PyObject *, visitproc, void *);
 
38
static int _ft_clear(PyObject *);
 
39
#endif
 
40
 
 
41
static PyObject *_ft_quit(PyObject *);
 
42
static PyObject *_ft_init(PyObject *, PyObject *, PyObject *);
 
43
static PyObject *_ft_get_version(PyObject *);
 
44
static PyObject *_ft_get_error(PyObject *);
 
45
static PyObject *_ft_was_init(PyObject *);
 
46
static PyObject *_ft_autoinit(PyObject *);
 
47
static void _ft_autoquit(void);
 
48
static PyObject *_ft_get_cache_size(PyObject *);
 
49
static PyObject *_ft_get_default_resolution(PyObject *);
 
50
static PyObject *_ft_set_default_resolution(PyObject *, PyObject *);
 
51
static PyObject *_ft_get_default_font(PyObject* self);
 
52
 
 
53
/*
 
54
 * Constructor/init/destructor
 
55
 */
 
56
static PyObject *_ftfont_new(PyTypeObject *, PyObject *, PyObject *);
 
57
static void _ftfont_dealloc(PgFontObject *);
 
58
static PyObject *_ftfont_repr(PgFontObject *);
 
59
static int _ftfont_init(PgFontObject *, PyObject *, PyObject *);
 
60
 
 
61
/*
 
62
 * Main methods
 
63
 */
 
64
static PyObject *_ftfont_getrect(PgFontObject *, PyObject *, PyObject *);
 
65
static PyObject *_ftfont_getmetrics(PgFontObject *, PyObject *, PyObject *);
 
66
static PyObject *_ftfont_render(PgFontObject *, PyObject *, PyObject *);
 
67
static PyObject *_ftfont_render_to(PgFontObject *, PyObject *, PyObject *);
 
68
static PyObject *_ftfont_render_raw(PgFontObject *, PyObject *, PyObject *);
 
69
static PyObject *_ftfont_render_raw_to(PgFontObject *, PyObject *, PyObject *);
 
70
static PyObject *_ftfont_getsizedascender(PgFontObject *, PyObject *);
 
71
static PyObject *_ftfont_getsizeddescender(PgFontObject *, PyObject *);
 
72
static PyObject *_ftfont_getsizedheight(PgFontObject *, PyObject *);
 
73
static PyObject *_ftfont_getsizedglyphheight(PgFontObject *, PyObject *);
 
74
static PyObject *_ftfont_getsizes(PgFontObject *);
 
75
 
 
76
/* static PyObject *_ftfont_copy(PgFontObject *); */
 
77
 
 
78
/*
 
79
 * Getters/setters
 
80
 */
 
81
static PyObject *_ftfont_getsize(PgFontObject *, void *);
 
82
static int _ftfont_setsize(PgFontObject *, PyObject *, void *);
 
83
static PyObject *_ftfont_getstyle(PgFontObject *, void *);
 
84
static int _ftfont_setstyle(PgFontObject *, PyObject *, void *);
 
85
static PyObject *_ftfont_getname(PgFontObject *, void *);
 
86
static PyObject *_ftfont_getpath(PgFontObject *, void *);
 
87
static PyObject *_ftfont_getscalable(PgFontObject *, void *);
 
88
static PyObject *_ftfont_getfixedwidth(PgFontObject *, void *);
 
89
static PyObject *_ftfont_getfixedsizes(PgFontObject *, void *);
 
90
static PyObject *_ftfont_getstrength(PgFontObject *, void *);
 
91
static int _ftfont_setstrength(PgFontObject *, PyObject *, void *);
 
92
static PyObject *_ftfont_getunderlineadjustment(PgFontObject *, void *);
 
93
static int _ftfont_setunderlineadjustment(PgFontObject *, PyObject *, void *);
 
94
static PyObject *_ftfont_getrotation(PgFontObject *, void *);
 
95
static int _ftfont_setrotation(PgFontObject *, PyObject *, void *);
 
96
static PyObject *_ftfont_getfgcolor(PgFontObject *, void *);
 
97
static int _ftfont_setfgcolor(PgFontObject *, PyObject *, void *);
 
98
 
 
99
static PyObject *_ftfont_getresolution(PgFontObject *, void *);
 
100
 
 
101
static PyObject *_ftfont_getfontmetric(PgFontObject *, void *);
 
102
 
 
103
static PyObject *_ftfont_getstyle_flag(PgFontObject *, void *);
 
104
static int _ftfont_setstyle_flag(PgFontObject *, PyObject *, void *);
 
105
 
 
106
static PyObject *_ftfont_getrender_flag(PgFontObject *, void *);
 
107
static int _ftfont_setrender_flag(PgFontObject *, PyObject *, void *);
 
108
 
 
109
#if defined(PGFT_DEBUG_CACHE)
 
110
static PyObject *_ftfont_getdebugcachestats(PgFontObject *, void *);
 
111
#endif
 
112
 
 
113
/*
 
114
 * Internal helpers
 
115
 */
 
116
static PyObject *get_metrics(FontRenderMode *, PgFontObject *, PGFT_String *);
 
117
static PyObject *load_font_res(const char *);
 
118
static int parse_dest(PyObject *, int *, int *);
 
119
static int obj_to_scale(PyObject *, void *);
 
120
static int objs_to_scale(PyObject *, PyObject *, Scale_t *);
 
121
static int numbers_to_scale(PyObject *, PyObject *, Scale_t *);
 
122
static int build_scale(PyObject *, PyObject *, Scale_t *);
 
123
static FT_UInt number_to_FX6_unsigned(PyObject *);
 
124
static int obj_to_rotation(PyObject *, void *);
 
125
static void free_string(PGFT_String *);
 
126
 
 
127
/*
 
128
 * Auxiliar defines
 
129
 */
 
130
#define ASSERT_SELF_IS_ALIVE(s)                     \
 
131
if (!PgFont_IS_ALIVE(s)) {                  \
 
132
    return RAISE(PyExc_RuntimeError,                \
 
133
        MODULE_NAME "." FONT_TYPE_NAME              \
 
134
        " instance is not initialized");            \
 
135
}
 
136
 
 
137
#define PGFT_CHECK_BOOL(_pyobj, _var)               \
 
138
    if (_pyobj) {                                   \
 
139
        if (!PyBool_Check(_pyobj)) {                \
 
140
            PyErr_SetString(PyExc_TypeError,        \
 
141
                #_var " must be a boolean value");  \
 
142
            return 0;                            \
 
143
        }                                           \
 
144
                                                    \
 
145
        _var = PyObject_IsTrue(_pyobj);             \
 
146
    }
 
147
 
 
148
#define DEFAULT_FONT_NAME   "freesansbold.ttf"
 
149
#define PKGDATA_MODULE_NAME "pygame.pkgdata"
 
150
#define RESOURCE_FUNC_NAME  "getResource"
 
151
 
 
152
static PyObject *
 
153
load_font_res(const char *filename)
 
154
{
 
155
    PyObject *load_basicfunc = 0;
 
156
    PyObject *pkgdatamodule = 0;
 
157
    PyObject *resourcefunc = 0;
 
158
    PyObject *result = 0;
 
159
    PyObject *tmp;
 
160
 
 
161
    pkgdatamodule = PyImport_ImportModule(PKGDATA_MODULE_NAME);
 
162
    if (!pkgdatamodule) {
 
163
        goto font_resource_end;
 
164
    }
 
165
 
 
166
    resourcefunc = PyObject_GetAttrString(pkgdatamodule, RESOURCE_FUNC_NAME);
 
167
    if (!resourcefunc) {
 
168
        goto font_resource_end;
 
169
    }
 
170
 
 
171
    result = PyObject_CallFunction(resourcefunc, "s", filename);
 
172
    if (!result) {
 
173
        goto font_resource_end;
 
174
    }
 
175
 
 
176
#if PY3
 
177
    tmp = PyObject_GetAttrString(result, "name");
 
178
    if (tmp) {
 
179
        Py_DECREF(result);
 
180
        result = tmp;
 
181
    }
 
182
    else  {
 
183
        PyErr_Clear();
 
184
    }
 
185
#else
 
186
    if (PyFile_Check(result)) {
 
187
        tmp = PyFile_Name(result);
 
188
        Py_INCREF(tmp);
 
189
        Py_DECREF(result);
 
190
        result = tmp;
 
191
    }
 
192
#endif
 
193
 
 
194
font_resource_end:
 
195
    Py_XDECREF(pkgdatamodule);
 
196
    Py_XDECREF(resourcefunc);
 
197
    Py_XDECREF(load_basicfunc);
 
198
    return result;
 
199
}
 
200
 
 
201
static int
 
202
parse_dest(PyObject *dest, int *x, int *y)
 
203
{
 
204
    PyObject *oi;
 
205
    PyObject *oj;
 
206
    int i, j;
 
207
 
 
208
    if (!PySequence_Check(dest) ||  /* conditional and */
 
209
        !PySequence_Size(dest) > 1) {
 
210
        PyErr_Format(PyExc_TypeError,
 
211
                     "Expected length 2 sequence for dest argument:"
 
212
                     " got type %.1024s",
 
213
                     Py_TYPE(dest)->tp_name);
 
214
        return -1;
 
215
    }
 
216
    oi = PySequence_GetItem(dest, 0);
 
217
    if (!oi) {
 
218
        return -1;
 
219
    }
 
220
    oj = PySequence_GetItem(dest, 1);
 
221
    if (!oj) {
 
222
        Py_DECREF(oi);
 
223
        return -1;
 
224
    }
 
225
    if (!PyNumber_Check(oi) || !PyNumber_Check(oj)) {
 
226
        PyErr_Format(PyExc_TypeError,
 
227
                     "for dest expected a pair of numbers"
 
228
                     "for elements 1 and 2: got types %.1024s and %1024s",
 
229
                     Py_TYPE(oi)->tp_name, Py_TYPE(oj)->tp_name);
 
230
        Py_DECREF(oi);
 
231
        Py_DECREF(oj);
 
232
        return -1;
 
233
    }
 
234
    i = PyInt_AsLong(oi);
 
235
    Py_DECREF(oi);
 
236
    if (i == -1 && PyErr_Occurred()) {
 
237
        Py_DECREF(oj);
 
238
        return -1;
 
239
    }
 
240
    j = PyInt_AsLong(oj);
 
241
    Py_DECREF(oj);
 
242
    if (j == -1 && PyErr_Occurred()) {
 
243
        return -1;
 
244
    }
 
245
    *x = i;
 
246
    *y = j;
 
247
    return 0;
 
248
}
 
249
 
 
250
/** Point size PyArg_ParseTuple converter: int -> Scale_t */
 
251
static int
 
252
obj_to_scale(PyObject *o, void *p)
 
253
{
 
254
    if (PyTuple_Check(o)) {
 
255
        if (PyTuple_GET_SIZE(o) != 2) {
 
256
            PyErr_Format(PyExc_TypeError,
 
257
                         "expected a 2-tuple for size, got %zd-tuple",
 
258
                         PyTuple_GET_SIZE(o));
 
259
            return 0;
 
260
        }
 
261
        return objs_to_scale(PyTuple_GET_ITEM(o, 0),
 
262
                             PyTuple_GET_ITEM(o, 1),
 
263
                             (Scale_t *)p);
 
264
    }
 
265
    return objs_to_scale(o, 0, (Scale_t *)p);
 
266
}
 
267
 
 
268
static int
 
269
objs_to_scale(PyObject *x, PyObject *y, Scale_t *size)
 
270
{
 
271
    PyObject *o;
 
272
    int do_y;
 
273
 
 
274
    for (o = x, do_y = 1; o; o = (do_y--) ? y : 0) {
 
275
        if (!PyLong_Check(o) &&
 
276
#if PY2
 
277
            !PyInt_Check(o) &&
 
278
#endif
 
279
            !PyFloat_Check(o)) {
 
280
            if (y) {
 
281
                PyErr_Format(PyExc_TypeError,
 
282
                             "expected a (float, float) tuple for size"
 
283
                             ", got (%128s, %128s)",
 
284
                             Py_TYPE(x)->tp_name,
 
285
                             Py_TYPE(y)->tp_name);
 
286
            }
 
287
            else {
 
288
                PyErr_Format(PyExc_TypeError,
 
289
                             "expected a float for size, got %128s",
 
290
                             Py_TYPE(o)->tp_name);
 
291
            }
 
292
            return 0;
 
293
        }
 
294
    }
 
295
 
 
296
    return numbers_to_scale(x, y, size);
 
297
}
 
298
 
 
299
static int
 
300
numbers_to_scale(PyObject *x, PyObject *y, Scale_t *size)
 
301
{
 
302
    PyObject *o;
 
303
    PyObject *min_obj = 0;
 
304
    PyObject *max_obj = 0;
 
305
    int do_y;
 
306
    int cmp_result;
 
307
    int rval = 0;
 
308
 
 
309
    min_obj = PyFloat_FromDouble(0.0);
 
310
    if (!min_obj) goto finish;
 
311
    max_obj = PyFloat_FromDouble(FX6_TO_DBL(FX6_MAX));
 
312
    if (!max_obj) goto finish;
 
313
 
 
314
    for (o = x, do_y = 1; o; o = (do_y--) ? y : 0) {
 
315
        cmp_result = PyObject_RichCompareBool(o, min_obj, Py_LT);
 
316
        if (cmp_result == -1) goto finish;
 
317
        if (cmp_result == 1) {
 
318
            PyErr_Format(PyExc_OverflowError,
 
319
                         "%128s value is negative"
 
320
                         " while size value is zero or positive",
 
321
                         Py_TYPE(o)->tp_name);
 
322
            goto finish;
 
323
        }
 
324
        cmp_result = PyObject_RichCompareBool(o, max_obj, Py_GT);
 
325
        if (cmp_result == -1) goto finish;
 
326
        if (cmp_result == 1) {
 
327
            PyErr_Format(PyExc_OverflowError,
 
328
                         "%128s value too large to convert to a size value",
 
329
                         Py_TYPE(o)->tp_name);
 
330
            goto finish;
 
331
        }
 
332
    }
 
333
 
 
334
    rval = build_scale(x, y, size);
 
335
 
 
336
  finish:
 
337
    Py_XDECREF(min_obj);
 
338
    Py_XDECREF(max_obj);
 
339
    return rval;
 
340
}
 
341
 
 
342
static int
 
343
build_scale(PyObject *x, PyObject *y, Scale_t *size)
 
344
{
 
345
    FT_UInt sz_x = 0, sz_y = 0;
 
346
 
 
347
    sz_x = number_to_FX6_unsigned(x);
 
348
    if (PyErr_Occurred()) {
 
349
        return 0;
 
350
    }
 
351
    if (y) {
 
352
        sz_y = number_to_FX6_unsigned(y);
 
353
        if (PyErr_Occurred()) {
 
354
            return 0;
 
355
        }
 
356
    }
 
357
    if (sz_x == 0 && sz_y != 0) {
 
358
        PyErr_SetString(PyExc_ValueError,
 
359
                        "expected zero size height when width is zero");
 
360
        return 0;
 
361
    }
 
362
    size->x = sz_x;
 
363
    size->y = sz_y;
 
364
    return 1;
 
365
}
 
366
 
 
367
static FT_UInt
 
368
number_to_FX6_unsigned(PyObject *n)
 
369
{
 
370
    PyObject *f_obj = PyNumber_Float(n);
 
371
    double f;
 
372
 
 
373
    if (!f_obj) return 0;
 
374
    f = PyFloat_AsDouble(f_obj);
 
375
    Py_XDECREF(f_obj);
 
376
    if (PyErr_Occurred()) return 0;
 
377
    return DBL_TO_FX6(f);
 
378
}
 
379
 
 
380
/** rotation: int -> Angle_t */
 
381
int
 
382
obj_to_rotation(PyObject *o, void *p)
 
383
{
 
384
    PyObject *full_circle_obj = 0;
 
385
    PyObject *angle_obj = 0;
 
386
    long angle;
 
387
    int rval = 0;
 
388
 
 
389
    if (PyLong_Check(o)) {
 
390
        ;
 
391
    }
 
392
#if PY2
 
393
    else if (PyInt_Check(o)) {
 
394
        ;
 
395
    }
 
396
#endif
 
397
    else {
 
398
        PyErr_Format(PyExc_TypeError, "integer rotation expected, got %s",
 
399
                     Py_TYPE(o)->tp_name);
 
400
        goto finish;
 
401
    }
 
402
    full_circle_obj = PyLong_FromLong(360L);
 
403
    if (!full_circle_obj) goto finish;
 
404
    angle_obj = PyNumber_Remainder(o, full_circle_obj);
 
405
    if (!angle_obj) goto finish;
 
406
    angle = PyLong_AsLong(angle_obj);
 
407
    if (angle == -1) goto finish;
 
408
    *(Angle_t *)p = (Angle_t)INT_TO_FX16(angle);
 
409
    rval = 1;
 
410
 
 
411
  finish:
 
412
    Py_XDECREF(full_circle_obj);
 
413
    Py_XDECREF(angle_obj);
 
414
    return rval;
 
415
}
 
416
 
 
417
/** This accepts a NULL PGFT_String pointer */
 
418
static void
 
419
free_string(PGFT_String *p) {
 
420
    if (p) _PGFT_FreeString(p);
 
421
}
 
422
 
 
423
/*
 
424
 * FREETYPE MODULE METHODS TABLE
 
425
 */
 
426
static PyMethodDef _ft_methods[] = {
 
427
    {
 
428
        "__PYGAMEinit__",
 
429
        (PyCFunction) _ft_autoinit,
 
430
        METH_NOARGS,
 
431
        "auto initialize function for _freetype"
 
432
    },
 
433
    {
 
434
        "init",
 
435
        (PyCFunction) _ft_init,
 
436
        METH_VARARGS | METH_KEYWORDS,
 
437
        DOC_PYGAMEFREETYPEINIT
 
438
    },
 
439
    {
 
440
        "quit",
 
441
        (PyCFunction) _ft_quit,
 
442
        METH_NOARGS,
 
443
        DOC_PYGAMEFREETYPEQUIT
 
444
    },
 
445
    {
 
446
        "was_init",
 
447
        (PyCFunction) _ft_was_init,
 
448
        METH_NOARGS,
 
449
        DOC_PYGAMEFREETYPEWASINIT
 
450
    },
 
451
    {
 
452
        "get_error",
 
453
        (PyCFunction) _ft_get_error,
 
454
        METH_NOARGS,
 
455
        DOC_PYGAMEFREETYPEGETERROR
 
456
    },
 
457
    {
 
458
        "get_version",
 
459
        (PyCFunction) _ft_get_version,
 
460
        METH_NOARGS,
 
461
        DOC_PYGAMEFREETYPEGETVERSION
 
462
    },
 
463
    {
 
464
        "get_cache_size",
 
465
        (PyCFunction) _ft_get_cache_size,
 
466
        METH_NOARGS,
 
467
        DOC_PYGAMEFREETYPEGETCACHESIZE
 
468
    },
 
469
    {
 
470
        "get_default_resolution",
 
471
        (PyCFunction) _ft_get_default_resolution,
 
472
        METH_NOARGS,
 
473
        DOC_PYGAMEFREETYPEGETDEFAULTRESOLUTION
 
474
    },
 
475
    {
 
476
        "set_default_resolution",
 
477
        (PyCFunction) _ft_set_default_resolution,
 
478
        METH_VARARGS,
 
479
        DOC_PYGAMEFREETYPESETDEFAULTRESOLUTION
 
480
    },
 
481
    {
 
482
        "get_default_font",
 
483
        (PyCFunction) _ft_get_default_font,
 
484
        METH_NOARGS,
 
485
        DOC_PYGAMEFREETYPEGETDEFAULTFONT
 
486
    },
 
487
 
 
488
    { 0, 0, 0, 0 }
 
489
};
 
490
 
 
491
 
 
492
/*
 
493
 * FREETYPE FONT METHODS TABLE
 
494
 */
 
495
static PyMethodDef _ftfont_methods[] = {
 
496
    {
 
497
        "get_sized_height",
 
498
        (PyCFunction) _ftfont_getsizedheight,
 
499
        METH_VARARGS,
 
500
        DOC_FONTGETSIZEDHEIGHT
 
501
    },
 
502
    {
 
503
        "get_sized_ascender",
 
504
        (PyCFunction) _ftfont_getsizedascender,
 
505
        METH_VARARGS,
 
506
        DOC_FONTGETSIZEDASCENDER
 
507
    },
 
508
    {
 
509
        "get_sized_descender",
 
510
        (PyCFunction) _ftfont_getsizeddescender,
 
511
        METH_VARARGS,
 
512
        DOC_FONTGETSIZEDDESCENDER
 
513
    },
 
514
    {
 
515
        "get_sized_glyph_height",
 
516
        (PyCFunction) _ftfont_getsizedglyphheight,
 
517
        METH_VARARGS,
 
518
        DOC_FONTGETSIZEDGLYPHHEIGHT
 
519
    },
 
520
    {
 
521
        "get_rect",
 
522
        (PyCFunction) _ftfont_getrect,
 
523
        METH_VARARGS | METH_KEYWORDS,
 
524
        DOC_FONTGETRECT
 
525
    },
 
526
    {
 
527
        "get_metrics",
 
528
        (PyCFunction) _ftfont_getmetrics,
 
529
        METH_VARARGS | METH_KEYWORDS,
 
530
        DOC_FONTGETMETRICS
 
531
    },
 
532
    {
 
533
        "get_sizes",
 
534
        (PyCFunction) _ftfont_getsizes,
 
535
        METH_NOARGS,
 
536
        DOC_FONTGETSIZES
 
537
    },
 
538
    {
 
539
        "render",
 
540
        (PyCFunction)_ftfont_render,
 
541
        METH_VARARGS | METH_KEYWORDS,
 
542
        DOC_FONTRENDER
 
543
    },
 
544
    {
 
545
        "render_to",
 
546
        (PyCFunction)_ftfont_render_to,
 
547
        METH_VARARGS | METH_KEYWORDS,
 
548
        DOC_FONTRENDERTO
 
549
    },
 
550
    {
 
551
        "render_raw",
 
552
        (PyCFunction)_ftfont_render_raw,
 
553
        METH_VARARGS | METH_KEYWORDS,
 
554
        DOC_FONTRENDERRAW
 
555
    },
 
556
    {
 
557
        "render_raw_to",
 
558
        (PyCFunction)_ftfont_render_raw_to,
 
559
        METH_VARARGS | METH_KEYWORDS,
 
560
        DOC_FONTRENDERRAWTO
 
561
    },
 
562
 
 
563
    { 0, 0, 0, 0 }
 
564
};
 
565
 
 
566
/*
 
567
 * FREETYPE FONT GETTERS/SETTERS TABLE
 
568
 */
 
569
static PyGetSetDef _ftfont_getsets[] = {
 
570
    {
 
571
        "size",
 
572
        (getter)_ftfont_getsize,
 
573
        (setter)_ftfont_setsize,
 
574
        DOC_FONTSIZE,
 
575
        0
 
576
    },
 
577
    {
 
578
        "style",
 
579
        (getter)_ftfont_getstyle,
 
580
        (setter)_ftfont_setstyle,
 
581
        DOC_FONTSTYLE,
 
582
        0
 
583
    },
 
584
    {
 
585
        "height",
 
586
        (getter)_ftfont_getfontmetric,
 
587
        0,
 
588
        DOC_FONTHEIGHT,
 
589
        (void *)_PGFT_Font_GetHeight
 
590
    },
 
591
    {
 
592
        "ascender",
 
593
        (getter)_ftfont_getfontmetric,
 
594
        0,
 
595
        DOC_FONTASCENDER,
 
596
        (void *)_PGFT_Font_GetAscender
 
597
    },
 
598
    {
 
599
        "descender",
 
600
        (getter)_ftfont_getfontmetric,
 
601
        0,
 
602
        DOC_FONTASCENDER,
 
603
        (void *)_PGFT_Font_GetDescender
 
604
    },
 
605
    {
 
606
        "name",
 
607
        (getter)_ftfont_getname,
 
608
        0,
 
609
        DOC_FONTNAME,
 
610
        0
 
611
    },
 
612
    {
 
613
        "path",
 
614
        (getter)_ftfont_getpath,
 
615
        0,
 
616
        DOC_FONTPATH,
 
617
        0
 
618
    },
 
619
    {
 
620
        "scalable",
 
621
        (getter)_ftfont_getscalable,
 
622
        0,
 
623
        DOC_FONTSCALABLE,
 
624
        0
 
625
    },
 
626
    {
 
627
        "fixed_width",
 
628
        (getter)_ftfont_getfixedwidth,
 
629
        0,
 
630
        DOC_FONTFIXEDWIDTH,
 
631
        0
 
632
    },
 
633
    {
 
634
        "fixed_sizes",
 
635
        (getter)_ftfont_getfixedsizes,
 
636
        0,
 
637
        DOC_FONTFIXEDSIZES,
 
638
        0
 
639
    },
 
640
    {
 
641
        "antialiased",
 
642
        (getter)_ftfont_getrender_flag,
 
643
        (setter)_ftfont_setrender_flag,
 
644
        DOC_FONTANTIALIASED,
 
645
        (void *)FT_RFLAG_ANTIALIAS
 
646
    },
 
647
    {
 
648
        "kerning",
 
649
        (getter)_ftfont_getrender_flag,
 
650
        (setter)_ftfont_setrender_flag,
 
651
        DOC_FONTKERNING,
 
652
        (void *)FT_RFLAG_KERNING
 
653
    },
 
654
    {
 
655
        "vertical",
 
656
        (getter)_ftfont_getrender_flag,
 
657
        (setter)_ftfont_setrender_flag,
 
658
        DOC_FONTVERTICAL,
 
659
        (void *)FT_RFLAG_VERTICAL
 
660
    },
 
661
    {
 
662
        "pad",
 
663
        (getter)_ftfont_getrender_flag,
 
664
        (setter)_ftfont_setrender_flag,
 
665
        DOC_FONTPAD,
 
666
        (void *)FT_RFLAG_PAD
 
667
    },
 
668
    {
 
669
        "oblique",
 
670
        (getter)_ftfont_getstyle_flag,
 
671
        (setter)_ftfont_setstyle_flag,
 
672
        DOC_FONTOBLIQUE,
 
673
        (void *)FT_STYLE_OBLIQUE
 
674
    },
 
675
    {
 
676
        "strong",
 
677
        (getter)_ftfont_getstyle_flag,
 
678
        (setter)_ftfont_setstyle_flag,
 
679
        DOC_FONTSTRONG,
 
680
        (void *)FT_STYLE_STRONG
 
681
    },
 
682
    {
 
683
        "underline",
 
684
        (getter)_ftfont_getstyle_flag,
 
685
        (setter)_ftfont_setstyle_flag,
 
686
        DOC_FONTUNDERLINE,
 
687
        (void *)FT_STYLE_UNDERLINE
 
688
    },
 
689
    {
 
690
        "wide",
 
691
        (getter)_ftfont_getstyle_flag,
 
692
        (setter)_ftfont_setstyle_flag,
 
693
        DOC_FONTWIDE,
 
694
        (void *)FT_STYLE_WIDE
 
695
    },
 
696
    {
 
697
        "strength",
 
698
        (getter)_ftfont_getstrength,
 
699
        (setter)_ftfont_setstrength,
 
700
        DOC_FONTSTRENGTH,
 
701
        0
 
702
    },
 
703
    {
 
704
        "underline_adjustment",
 
705
        (getter)_ftfont_getunderlineadjustment,
 
706
        (setter)_ftfont_setunderlineadjustment,
 
707
        DOC_FONTUNDERLINEADJUSTMENT,
 
708
        0
 
709
    },
 
710
    {
 
711
        "ucs4",
 
712
        (getter)_ftfont_getrender_flag,
 
713
        (setter)_ftfont_setrender_flag,
 
714
        DOC_FONTUCS4,
 
715
        (void *)FT_RFLAG_UCS4
 
716
    },
 
717
    {
 
718
        "use_bitmap_strikes",
 
719
        (getter)_ftfont_getrender_flag,
 
720
        (setter)_ftfont_setrender_flag,
 
721
        DOC_FONTUSEBITMAPSTRIKES,
 
722
        (void *)FT_RFLAG_USE_BITMAP_STRIKES
 
723
    },
 
724
    {
 
725
        "resolution",
 
726
        (getter)_ftfont_getresolution,
 
727
        0,
 
728
        DOC_FONTRESOLUTION,
 
729
        0
 
730
    },
 
731
    {
 
732
        "rotation",
 
733
        (getter)_ftfont_getrotation,
 
734
        (setter)_ftfont_setrotation,
 
735
        DOC_FONTROTATION,
 
736
        0
 
737
    },
 
738
    {
 
739
        "fgcolor",
 
740
        (getter)_ftfont_getfgcolor,
 
741
        (setter)_ftfont_setfgcolor,
 
742
        DOC_FONTFGCOLOR,
 
743
        0
 
744
    },
 
745
    {
 
746
        "origin",
 
747
        (getter)_ftfont_getrender_flag,
 
748
        (setter)_ftfont_setrender_flag,
 
749
        DOC_FONTORIGIN,
 
750
        (void *)FT_RFLAG_ORIGIN
 
751
    },
 
752
#if defined(PGFT_DEBUG_CACHE)
 
753
    {
 
754
        "_debug_cache_stats",
 
755
        (getter)_ftfont_getdebugcachestats,
 
756
        0,
 
757
        "_debug cache fields as a tuple",
 
758
        0
 
759
    },
 
760
#endif
 
761
 
 
762
    { 0, 0, 0, 0, 0 }
 
763
};
 
764
 
 
765
/*
 
766
 * FREETYPE FONT BASE TYPE TABLE
 
767
 */
 
768
#define FULL_TYPE_NAME MODULE_NAME "." FONT_TYPE_NAME
 
769
 
 
770
PyTypeObject PgFont_Type = {
 
771
    TYPE_HEAD(0,0)
 
772
    FULL_TYPE_NAME,             /* tp_name */
 
773
    sizeof (PgFontObject),      /* tp_basicsize */
 
774
    0,                          /* tp_itemsize */
 
775
    (destructor)_ftfont_dealloc,/* tp_dealloc */
 
776
    0,                          /* tp_print */
 
777
    0,                          /* tp_getattr */
 
778
    0,                          /* tp_setattr */
 
779
    0,                          /* tp_compare */
 
780
    (reprfunc)_ftfont_repr,     /* tp_repr */
 
781
    0,                          /* tp_as_number */
 
782
    0,                          /* tp_as_sequence */
 
783
    0,                          /* tp_as_mapping */
 
784
    0,                          /* tp_hash */
 
785
    0,                          /* tp_call */
 
786
    0,                          /* tp_str */
 
787
    0,                          /* tp_getattro */
 
788
    0,                          /* tp_setattro */
 
789
    0,                          /* tp_as_buffer */
 
790
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
 
791
    DOC_PYGAMEFREETYPEFONT,     /* docstring */
 
792
    0,                          /* tp_traverse */
 
793
    0,                          /* tp_clear */
 
794
    0,                          /* tp_richcompare */
 
795
    0,                          /* tp_weaklistoffset */
 
796
    0,                          /* tp_iter */
 
797
    0,                          /* tp_iternext */
 
798
    _ftfont_methods,            /* tp_methods */
 
799
    0,                          /* tp_members */
 
800
    _ftfont_getsets,            /* tp_getset */
 
801
    0,                          /* tp_base */
 
802
    0,                          /* tp_dict */
 
803
    0,                          /* tp_descr_get */
 
804
    0,                          /* tp_descr_set */
 
805
    0,                          /* tp_dictoffset */
 
806
    (initproc) _ftfont_init,    /* tp_init */
 
807
    0,                          /* tp_alloc */
 
808
    (newfunc) _ftfont_new,      /* tp_new */
 
809
    0,                          /* tp_free */
 
810
    0,                          /* tp_is_gc */
 
811
    0,                          /* tp_bases */
 
812
    0,                          /* tp_mro */
 
813
    0,                          /* tp_cache */
 
814
    0,                          /* tp_subclasses */
 
815
    0,                          /* tp_weaklist */
 
816
    0,                          /* tp_del */
 
817
#if PY_VERSION_HEX >= 0x02060000
 
818
    0                           /* tp_version_tag */
 
819
#endif
 
820
};
 
821
 
 
822
#undef FULL_TYPE_NAME
 
823
 
 
824
 
 
825
/****************************************************
 
826
 * CONSTRUCTOR/INIT/DESTRUCTOR
 
827
 ****************************************************/
 
828
static PyObject *
 
829
_ftfont_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
 
830
{
 
831
    PgFontObject *obj = (PgFontObject *)(subtype->tp_alloc(subtype, 0));
 
832
 
 
833
    if (obj) {
 
834
        obj->id.open_args.flags = 0;
 
835
        obj->id.open_args.pathname = 0;
 
836
        obj->path = 0;
 
837
        obj->resolution = 0;
 
838
        obj->is_scalable = 0;
 
839
        obj->freetype = 0;
 
840
        obj->_internals = 0;
 
841
        obj->face_size = FACE_SIZE_NONE;
 
842
        obj->style = FT_STYLE_NORMAL;
 
843
        obj->render_flags = FT_RFLAG_DEFAULTS;
 
844
        obj->strength = PGFT_DBL_DEFAULT_STRENGTH;
 
845
        obj->underline_adjustment = 1.0;
 
846
        obj->rotation = 0;
 
847
        obj->transform.xx = FX16_ONE;
 
848
        obj->transform.xy = 0;
 
849
        obj->transform.yx = 0;
 
850
        obj->transform.yy = FX16_ONE;
 
851
        obj->fgcolor[0] = 0;  /* rgba opaque black */
 
852
        obj->fgcolor[1] = 0;
 
853
        obj->fgcolor[2] = 0;
 
854
        obj->fgcolor[3] = 255;
 
855
    }
 
856
    return (PyObject *)obj;
 
857
}
 
858
 
 
859
static void
 
860
_ftfont_dealloc(PgFontObject *self)
 
861
{
 
862
    _PGFT_UnloadFont(self->freetype, self);
 
863
    _PGFT_Quit(self->freetype);
 
864
 
 
865
    Py_XDECREF(self->path);
 
866
    ((PyObject *)self)->ob_type->tp_free((PyObject *)self);
 
867
}
 
868
 
 
869
static int
 
870
_ftfont_init(PgFontObject *self, PyObject *args, PyObject *kwds)
 
871
{
 
872
    static char *kwlist[] =  {
 
873
        "file", "size", "font_index", "resolution", "ucs4", 0
 
874
    };
 
875
 
 
876
    PyObject *file, *original_file;
 
877
    long font_index = 0;
 
878
    Scale_t face_size = self->face_size;
 
879
    int ucs4 = self->render_flags & FT_RFLAG_UCS4 ? 1 : 0;
 
880
    unsigned resolution = 0;
 
881
    long size = 0;
 
882
    long height = 0;
 
883
    long width = 0;
 
884
    double x_ppem = 0;
 
885
    double y_ppem = 0;
 
886
    int rval = -1;
 
887
 
 
888
    FreeTypeInstance *ft;
 
889
    ASSERT_GRAB_FREETYPE(ft, -1);
 
890
 
 
891
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&lIi", kwlist,
 
892
                                     &file,
 
893
                                     obj_to_scale, (void *)&face_size,
 
894
                                     &font_index, &resolution, &ucs4)) {
 
895
        return -1;
 
896
    }
 
897
 
 
898
    original_file = file;
 
899
 
 
900
    if (self->freetype) {
 
901
        /* Font.__init__ was previously called on this object. Reset */
 
902
        _PGFT_UnloadFont(self->freetype, self);
 
903
        _PGFT_Quit(self->freetype);
 
904
        self->freetype = 0;
 
905
    }
 
906
    Py_XDECREF(self->path);
 
907
    self->path = 0;
 
908
    self->is_scalable = 0;
 
909
 
 
910
    self->face_size = face_size;
 
911
    if (ucs4) {
 
912
        self->render_flags |= FT_RFLAG_UCS4;
 
913
    }
 
914
    else {
 
915
        self->render_flags &= ~FT_RFLAG_UCS4;
 
916
    }
 
917
    if (resolution) {
 
918
        self->resolution = (FT_UInt)resolution;
 
919
    }
 
920
    else {
 
921
        self->resolution = FREETYPE_STATE->resolution;
 
922
    }
 
923
    if (file == Py_None) {
 
924
        file = load_font_res(DEFAULT_FONT_NAME);
 
925
 
 
926
        if (!file) {
 
927
            PyErr_SetString(PyExc_RuntimeError, "Failed to find default font");
 
928
            goto end;
 
929
        }
 
930
    }
 
931
 
 
932
    file = RWopsEncodeFilePath(file, 0);
 
933
    if (!file) {
 
934
        return -1;
 
935
    }
 
936
    if (Bytes_Check(file)) {
 
937
        if (PyUnicode_Check(original_file)) {
 
938
            /* Make sure to save a pure Unicode object to prevent possible
 
939
             * cycles from a derived class. This means no tp_traverse or
 
940
             * tp_clear for the PyFreetypeFont type.
 
941
             */
 
942
            self->path = Object_Unicode(original_file);
 
943
        }
 
944
        else {
 
945
            self->path = PyUnicode_FromEncodedObject(file, UNICODE_DEF_FS_CODEC,
 
946
                                                     "replace");
 
947
        }
 
948
        if (!self->path) {
 
949
            goto end;
 
950
        }
 
951
 
 
952
        if (_PGFT_TryLoadFont_Filename(ft, self,
 
953
                                       Bytes_AS_STRING(file), font_index)) {
 
954
            goto end;
 
955
        }
 
956
    }
 
957
    else {
 
958
        SDL_RWops *source = RWopsFromFileObjectThreaded(original_file);
 
959
        PyObject *str = 0;
 
960
        PyObject *path = 0;
 
961
 
 
962
        if (!source) {
 
963
            goto end;
 
964
        }
 
965
 
 
966
        path = PyObject_GetAttrString(original_file, "name");
 
967
        if (!path) {
 
968
            PyErr_Clear();
 
969
            str = Bytes_FromFormat("<%s instance at %p>",
 
970
                                   Py_TYPE(file)->tp_name, (void *)file);
 
971
            if (str) {
 
972
                self->path = PyUnicode_FromEncodedObject(str,
 
973
                                                         "ascii", "strict");
 
974
                Py_DECREF(str);
 
975
            }
 
976
        }
 
977
        else if (PyUnicode_Check(path)) {
 
978
            /* Make sure to save a pure Unicode object to prevent possible
 
979
             * cycles from a derived class. This means no tp_traverse or
 
980
             * tp_clear for the PyFreetypeFont type.
 
981
             */
 
982
            self->path = Object_Unicode(path);
 
983
        }
 
984
        else if (Bytes_Check(path)) {
 
985
            self->path = PyUnicode_FromEncodedObject(path, UNICODE_DEF_FS_CODEC,
 
986
                                                     "replace");
 
987
        }
 
988
        else {
 
989
            self->path = Object_Unicode(path);
 
990
        }
 
991
        Py_XDECREF(path);
 
992
        if (!self->path) {
 
993
            goto end;
 
994
        }
 
995
 
 
996
        if (_PGFT_TryLoadFont_RWops(ft, self, source, font_index)) {
 
997
            goto end;
 
998
        }
 
999
    }
 
1000
 
 
1001
    if (!self->is_scalable && self->face_size.x == 0) {
 
1002
        if (_PGFT_Font_GetAvailableSize(ft, self, 0, &size, &height, &width,
 
1003
                                        &x_ppem, &y_ppem)) {
 
1004
            self->face_size.x = DBL_TO_FX6(x_ppem);
 
1005
            self->face_size.y = DBL_TO_FX6(y_ppem);
 
1006
        }
 
1007
        else {
 
1008
            PyErr_Clear();
 
1009
        }
 
1010
    }
 
1011
    
 
1012
    /* Keep the current freetype 2 connection open while this object exists.
 
1013
       Otherwise, the freetype library may be closed before the object frees
 
1014
       its local resources. See Pygame issue #187
 
1015
    */
 
1016
    self->freetype = ft;
 
1017
    ++ft->ref_count;
 
1018
    
 
1019
    rval = 0;
 
1020
 
 
1021
end:
 
1022
    if (file != original_file) {
 
1023
        Py_XDECREF(file);
 
1024
    }
 
1025
 
 
1026
    return rval;
 
1027
}
 
1028
 
 
1029
static PyObject *
 
1030
_ftfont_repr(PgFontObject *self)
 
1031
{
 
1032
    if (PgFont_IS_ALIVE(self)) {
 
1033
#if PY3
 
1034
        return PyUnicode_FromFormat("Font('%.1024U')", self->path);
 
1035
#else
 
1036
        PyObject *str = PyUnicode_AsEncodedString(self->path,
 
1037
                                                  "raw_unicode_escape",
 
1038
                                                  "replace");
 
1039
        PyObject *rval = 0;
 
1040
 
 
1041
        if (str) {
 
1042
            rval = PyString_FromFormat("Font('%.1024s')",
 
1043
                                       PyString_AS_STRING(str));
 
1044
            Py_DECREF(str);
 
1045
        }
 
1046
        return rval;
 
1047
#endif
 
1048
    }
 
1049
    return Text_FromFormat("<uninitialized Font object at %p>", (void *)self);
 
1050
}
 
1051
 
 
1052
 
 
1053
/****************************************************
 
1054
 * GETTERS/SETTERS
 
1055
 ****************************************************/
 
1056
 
 
1057
/** Generic style attributes */
 
1058
static PyObject *
 
1059
_ftfont_getstyle_flag(PgFontObject *self, void *closure)
 
1060
{
 
1061
    const int style_flag = (int)closure;
 
1062
 
 
1063
    return PyBool_FromLong(self->style & style_flag);
 
1064
}
 
1065
 
 
1066
static int
 
1067
_ftfont_setstyle_flag(PgFontObject *self, PyObject *value, void *closure)
 
1068
{
 
1069
    const int style_flag = (int)closure;
 
1070
 
 
1071
    if (!PyBool_Check(value)) {
 
1072
        PyErr_SetString(PyExc_TypeError,
 
1073
                "The style value must be a boolean");
 
1074
        return -1;
 
1075
    }
 
1076
 
 
1077
    if ((style_flag & FT_STYLES_SCALABLE_ONLY) && !self->is_scalable) {
 
1078
        if (PgFont_IS_ALIVE(self)) {
 
1079
            PyErr_SetString(PyExc_AttributeError,
 
1080
                            "this style is unsupported for a bitmap font");
 
1081
        }
 
1082
        else {
 
1083
            PyErr_SetString(PyExc_RuntimeError,
 
1084
                            MODULE_NAME "." FONT_TYPE_NAME
 
1085
                            " instance is not initialized");
 
1086
        }
 
1087
        return -1;
 
1088
    }
 
1089
    if (PyObject_IsTrue(value)) {
 
1090
        self->style |= (FT_UInt16)style_flag;
 
1091
    }
 
1092
    else {
 
1093
        self->style &= (FT_UInt16)(~style_flag);
 
1094
    }
 
1095
 
 
1096
    return 0;
 
1097
}
 
1098
 
 
1099
 
 
1100
/** Style attribute */
 
1101
static PyObject *
 
1102
_ftfont_getstyle (PgFontObject *self, void *closure)
 
1103
{
 
1104
    return PyInt_FromLong(self->style);
 
1105
}
 
1106
 
 
1107
static int
 
1108
_ftfont_setstyle(PgFontObject *self, PyObject *value, void *closure)
 
1109
{
 
1110
    FT_UInt32 style;
 
1111
 
 
1112
    if (!PyInt_Check(value)) {
 
1113
        PyErr_SetString(PyExc_TypeError,
 
1114
                "The style value must be an integer"
 
1115
                " from the FT constants module");
 
1116
        return -1;
 
1117
    }
 
1118
 
 
1119
    style = (FT_UInt32)PyInt_AsLong(value);
 
1120
 
 
1121
    if (style == FT_STYLE_DEFAULT) {
 
1122
        /* The Font object's style property is the Font's default style,
 
1123
         * so leave unchanged.
 
1124
         */
 
1125
        return 0;
 
1126
    }
 
1127
    if (_PGFT_CheckStyle(style)) {
 
1128
        PyErr_Format(PyExc_ValueError,
 
1129
                     "Invalid style value %x", (int)style);
 
1130
        return -1;
 
1131
    }
 
1132
    if ((style & FT_STYLES_SCALABLE_ONLY) && !self->is_scalable) {
 
1133
        if (PgFont_IS_ALIVE(self)) {
 
1134
            PyErr_SetString(PyExc_AttributeError,
 
1135
                            "this style is unsupported for a bitmap font");
 
1136
        }
 
1137
        else {
 
1138
            PyErr_SetString(PyExc_RuntimeError,
 
1139
                            MODULE_NAME "." FONT_TYPE_NAME
 
1140
                            " instance is not initialized");
 
1141
        }
 
1142
        return -1;
 
1143
    }
 
1144
 
 
1145
    self->style = (FT_UInt16)style;
 
1146
    return 0;
 
1147
}
 
1148
 
 
1149
static PyObject *
 
1150
_ftfont_getstrength(PgFontObject *self, void *closure)
 
1151
{
 
1152
    return PyFloat_FromDouble(self->strength);
 
1153
}
 
1154
 
 
1155
static int
 
1156
_ftfont_setstrength(PgFontObject *self, PyObject *value, void *closure)
 
1157
{
 
1158
    PyObject *strengthobj = PyNumber_Float(value);
 
1159
    double strength;
 
1160
 
 
1161
    if (!strengthobj) {
 
1162
        return -1;
 
1163
    }
 
1164
    strength = PyFloat_AS_DOUBLE(strengthobj);
 
1165
    Py_DECREF(strengthobj);
 
1166
    if (strength < 0.0 || strength > 1.0) {
 
1167
        char msg[80];
 
1168
 
 
1169
        sprintf(msg, "strength value %.4e is outside range [0, 1]", strength);
 
1170
        PyErr_SetString(PyExc_ValueError, msg);
 
1171
        return -1;
 
1172
    }
 
1173
    self->strength = strength;
 
1174
    return 0;
 
1175
}
 
1176
 
 
1177
static PyObject *
 
1178
_ftfont_getsize(PgFontObject *self, void *closure)
 
1179
{
 
1180
    if (self->face_size.y == 0) {
 
1181
        return PyFloat_FromDouble(FX6_TO_DBL(self->face_size.x));
 
1182
    }
 
1183
    return Py_BuildValue("dd",
 
1184
                         FX6_TO_DBL(self->face_size.x),
 
1185
                         FX6_TO_DBL(self->face_size.y));
 
1186
}
 
1187
 
 
1188
static int
 
1189
_ftfont_setsize(PgFontObject *self, PyObject *value, void *closure)
 
1190
{
 
1191
    Scale_t face_size;
 
1192
 
 
1193
    if (!obj_to_scale(value, &face_size)) goto error;
 
1194
    self->face_size = face_size;
 
1195
    return 0;
 
1196
 
 
1197
  error:
 
1198
    return -1;
 
1199
}
 
1200
 
 
1201
static PyObject *
 
1202
_ftfont_getunderlineadjustment(PgFontObject *self, void *closure)
 
1203
{
 
1204
    return PyFloat_FromDouble(self->underline_adjustment);
 
1205
}
 
1206
 
 
1207
static int
 
1208
_ftfont_setunderlineadjustment(PgFontObject *self, PyObject *value,
 
1209
                               void *closure)
 
1210
{
 
1211
    PyObject *adjustmentobj = PyNumber_Float(value);
 
1212
    double adjustment;
 
1213
 
 
1214
    if (!adjustmentobj) {
 
1215
        return -1;
 
1216
    }
 
1217
    adjustment = PyFloat_AS_DOUBLE(adjustmentobj);
 
1218
    Py_DECREF(adjustmentobj);
 
1219
    if (adjustment < -2.0 || adjustment > 2.0) {
 
1220
        char msg[100];
 
1221
 
 
1222
        sprintf(msg,
 
1223
                "underline adjustment value %.4e is outside range [-2.0, 2.0]",
 
1224
                adjustment);
 
1225
        PyErr_SetString(PyExc_ValueError, msg);
 
1226
        return -1;
 
1227
    }
 
1228
    self->underline_adjustment = adjustment;
 
1229
    return 0;
 
1230
}
 
1231
 
 
1232
 
 
1233
/** general font attributes */
 
1234
 
 
1235
static PyObject *
 
1236
_ftfont_getfontmetric(PgFontObject *self, void *closure)
 
1237
{
 
1238
    typedef long (*getter)(FreeTypeInstance *, PgFontObject *);
 
1239
    long height;
 
1240
 
 
1241
    ASSERT_SELF_IS_ALIVE(self);
 
1242
    height = ((getter)closure)(self->freetype, self);
 
1243
    if (!height && PyErr_Occurred()) {
 
1244
        return 0;
 
1245
    }
 
1246
    return PyInt_FromLong(height);
 
1247
}
 
1248
 
 
1249
static PyObject *
 
1250
_ftfont_getname(PgFontObject *self, void *closure)
 
1251
{
 
1252
    const char *name;
 
1253
 
 
1254
    if (PgFont_IS_ALIVE(self)) {
 
1255
        name = _PGFT_Font_GetName(self->freetype, self);
 
1256
        return name ? Text_FromUTF8(name) : 0;
 
1257
    }
 
1258
    return PyObject_Repr((PyObject *)self);
 
1259
}
 
1260
 
 
1261
static PyObject *
 
1262
_ftfont_getpath(PgFontObject *self, void *closure)
 
1263
{
 
1264
    PyObject *path = ((PgFontObject *)self)->path;
 
1265
 
 
1266
    if (!path) {
 
1267
        PyErr_SetString(PyExc_AttributeError, "path unavailable");
 
1268
        return 0;
 
1269
    }
 
1270
    Py_INCREF(path);
 
1271
    return path;
 
1272
}
 
1273
 
 
1274
static PyObject *
 
1275
_ftfont_getscalable(PgFontObject *self, void *closure)
 
1276
{
 
1277
    ASSERT_SELF_IS_ALIVE(self)
 
1278
    return PyBool_FromLong(self->is_scalable);
 
1279
}
 
1280
 
 
1281
static PyObject *
 
1282
_ftfont_getfixedwidth(PgFontObject *self, void *closure)
 
1283
{
 
1284
    long fixed_width;
 
1285
 
 
1286
    ASSERT_SELF_IS_ALIVE(self);
 
1287
    fixed_width = _PGFT_Font_IsFixedWidth(self->freetype, (PgFontObject *)self);
 
1288
    return fixed_width >= 0 ? PyBool_FromLong(fixed_width) : 0;
 
1289
}
 
1290
 
 
1291
static PyObject *
 
1292
_ftfont_getfixedsizes(PgFontObject *self, void *closure)
 
1293
{
 
1294
    long num_fixed_sizes;
 
1295
 
 
1296
    ASSERT_SELF_IS_ALIVE(self);
 
1297
    num_fixed_sizes = _PGFT_Font_NumFixedSizes(self->freetype, self);
 
1298
    return num_fixed_sizes >= 0 ? PyInt_FromLong(num_fixed_sizes) : 0;
 
1299
}
 
1300
 
 
1301
 
 
1302
/** Generic render flag attributes */
 
1303
static PyObject *
 
1304
_ftfont_getrender_flag(PgFontObject *self, void *closure)
 
1305
{
 
1306
    const int render_flag = (int)closure;
 
1307
 
 
1308
    return PyBool_FromLong(self->render_flags & render_flag);
 
1309
}
 
1310
 
 
1311
static int
 
1312
_ftfont_setrender_flag(PgFontObject *self, PyObject *value, void *closure)
 
1313
{
 
1314
    const int render_flag = (int)closure;
 
1315
 
 
1316
    if (!PyBool_Check(value)) {
 
1317
        PyErr_SetString(PyExc_TypeError,
 
1318
                "The style value must be a boolean");
 
1319
        return -1;
 
1320
    }
 
1321
 
 
1322
    if (PyObject_IsTrue(value)) {
 
1323
        self->render_flags |= (FT_UInt16)render_flag;
 
1324
    }
 
1325
    else {
 
1326
        self->render_flags &= (FT_UInt16)(~render_flag);
 
1327
    }
 
1328
 
 
1329
    return 0;
 
1330
}
 
1331
 
 
1332
 
 
1333
/** resolution pixel size attribute */
 
1334
static PyObject *
 
1335
_ftfont_getresolution(PgFontObject *self, void *closure)
 
1336
{
 
1337
    return PyLong_FromUnsignedLong((unsigned long)self->resolution);
 
1338
}
 
1339
 
 
1340
 
 
1341
/** text rotation attribute */
 
1342
static PyObject *
 
1343
_ftfont_getrotation(PgFontObject *self, void *closure)
 
1344
{
 
1345
    return PyLong_FromLong((long)FX16_ROUND_TO_INT(self->rotation));
 
1346
}
 
1347
 
 
1348
static int
 
1349
_ftfont_setrotation(PgFontObject *self, PyObject *value, void *closure)
 
1350
{
 
1351
    if (!self->is_scalable) {
 
1352
        if (PgFont_IS_ALIVE(self)) {
 
1353
            PyErr_SetString(PyExc_AttributeError,
 
1354
                            "rotation is unsupported for a bitmap font");
 
1355
        }
 
1356
        else {
 
1357
            PyErr_SetString(PyExc_RuntimeError,
 
1358
                            MODULE_NAME "." FONT_TYPE_NAME
 
1359
                            " instance is not initialized");
 
1360
        }
 
1361
        return -1;
 
1362
    }
 
1363
    return obj_to_rotation(value, &self->rotation) ? 0 : -1;
 
1364
}
 
1365
 
 
1366
/** default glyph color */
 
1367
static PyObject *
 
1368
_ftfont_getfgcolor(PgFontObject *self, void *closure)
 
1369
{
 
1370
    return PyColor_New(self->fgcolor);
 
1371
}
 
1372
 
 
1373
static int
 
1374
_ftfont_setfgcolor(PgFontObject *self, PyObject *value, void *closure)
 
1375
{
 
1376
    if (!RGBAFromObj(value, self->fgcolor)) {
 
1377
        PyErr_Format(PyExc_AttributeError,
 
1378
                     "unable to convert %128s object to a color",
 
1379
                     Py_TYPE(value)->tp_name);
 
1380
        return -1;
 
1381
    }
 
1382
    return 0;
 
1383
}
 
1384
 
 
1385
/** testing and debugging */
 
1386
#if defined(PGFT_DEBUG_CACHE)
 
1387
static PyObject *
 
1388
_ftfont_getdebugcachestats(PgFontObject *self, void *closure)
 
1389
{
 
1390
    /* Yes, this kind of breaches the boundary between the top level
 
1391
     * freetype.c and the lower level ft_text.c. But it is built
 
1392
     * conditionally, and it keeps some of the Python api out
 
1393
     * of ft_text.c and ft_cache.c (hoping to remove the Python
 
1394
     * api completely from ft_text.c and support C modules at some point.)
 
1395
     */
 
1396
    const FontCache *cache = &PGFT_FONT_CACHE(self);
 
1397
 
 
1398
    return Py_BuildValue("kkkkk",
 
1399
                         (unsigned long)cache->_debug_count,
 
1400
                         (unsigned long)cache->_debug_delete_count,
 
1401
                         (unsigned long)cache->_debug_access,
 
1402
                         (unsigned long)cache->_debug_hit,
 
1403
                         (unsigned long)cache->_debug_miss);
 
1404
}
 
1405
#endif
 
1406
 
 
1407
/****************************************************
 
1408
 * MAIN METHODS
 
1409
 ****************************************************/
 
1410
static PyObject *
 
1411
_ftfont_getrect(PgFontObject *self, PyObject *args, PyObject *kwds)
 
1412
{
 
1413
/* MODIFIED
 
1414
 */
 
1415
    /* keyword list */
 
1416
    static char *kwlist[] =  {
 
1417
        "text", "style", "rotation", "size", 0
 
1418
    };
 
1419
 
 
1420
    PyObject *textobj;
 
1421
    PGFT_String *text = 0;
 
1422
    Scale_t face_size = FACE_SIZE_NONE;
 
1423
    SDL_Rect r;
 
1424
 
 
1425
    FontRenderMode render;
 
1426
    Angle_t rotation = self->rotation;
 
1427
    int style = FT_STYLE_DEFAULT;
 
1428
 
 
1429
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O&", kwlist,
 
1430
                                     &textobj, &style,
 
1431
                                     obj_to_rotation, (void *)&rotation,
 
1432
                                     obj_to_scale, (void *)&face_size))
 
1433
        goto error;
 
1434
 
 
1435
    /* Encode text */
 
1436
    if (textobj != Py_None) {
 
1437
        text = _PGFT_EncodePyString(textobj,
 
1438
                                    self->render_flags & FT_RFLAG_UCS4);
 
1439
        if (!text) goto error;
 
1440
    }
 
1441
 
 
1442
    ASSERT_SELF_IS_ALIVE(self);
 
1443
 
 
1444
    /* Build rendering mode, always anti-aliased by default */
 
1445
    if (_PGFT_BuildRenderMode(self->freetype, self, &render,
 
1446
                              face_size, style, rotation)) goto error;
 
1447
 
 
1448
    if (_PGFT_GetTextRect(self->freetype, self, &render, text, &r)) goto error;
 
1449
    free_string(text);
 
1450
 
 
1451
    return PyRect_New(&r);
 
1452
 
 
1453
  error:
 
1454
    free_string(text);
 
1455
    return 0;
 
1456
}
 
1457
 
 
1458
static PyObject *
 
1459
get_metrics(FontRenderMode *render, PgFontObject *font, PGFT_String *text)
 
1460
{
 
1461
    Py_ssize_t length = PGFT_String_GET_LENGTH(text);
 
1462
    PGFT_char *data = PGFT_String_GET_DATA(text);
 
1463
    PyObject *list, *item;
 
1464
    FT_UInt gindex;
 
1465
    long minx, miny;
 
1466
    long maxx, maxy;
 
1467
    double advance_x;
 
1468
    double advance_y;
 
1469
    Py_ssize_t i;
 
1470
 
 
1471
    if (!_PGFT_GetFontSized(font->freetype, font, render->face_size)) {
 
1472
        PyErr_SetString(PyExc_SDLError, _PGFT_GetError(font->freetype));
 
1473
        return 0;
 
1474
    }
 
1475
    list = PyList_New(length);
 
1476
    if (!list) {
 
1477
        return 0;
 
1478
    }
 
1479
    for (i = 0; i < length; ++i) {
 
1480
        if (_PGFT_GetMetrics(font->freetype, font, data[i], render,
 
1481
                             &gindex, &minx, &maxx, &miny, &maxy,
 
1482
                             &advance_x, &advance_y) == 0) {
 
1483
            if (gindex == 0) {
 
1484
                Py_INCREF(Py_None);
 
1485
                item = Py_None;
 
1486
            }
 
1487
            else {
 
1488
                item = Py_BuildValue("lllldd", minx, maxx, miny, maxy,
 
1489
                                     advance_x, advance_y);
 
1490
            }
 
1491
            if (!item) {
 
1492
                Py_DECREF(list);
 
1493
                return 0;
 
1494
            }
 
1495
        }
 
1496
        else {
 
1497
            Py_INCREF(Py_None);
 
1498
            item = Py_None;
 
1499
        }
 
1500
        PyList_SET_ITEM(list, i, item);
 
1501
    }
 
1502
 
 
1503
    return list;
 
1504
}
 
1505
 
 
1506
static PyObject *
 
1507
_ftfont_getmetrics(PgFontObject *self, PyObject *args, PyObject *kwds)
 
1508
{
 
1509
    /* keyword list */
 
1510
    static char *kwlist[] =  {
 
1511
        "text", "size", 0
 
1512
    };
 
1513
 
 
1514
    FontRenderMode render;
 
1515
    PyObject *list = 0;
 
1516
 
 
1517
    /* arguments */
 
1518
    PyObject *textobj;
 
1519
    PGFT_String *text = 0;
 
1520
    Scale_t face_size = FACE_SIZE_NONE;
 
1521
 
 
1522
    /* parse args */
 
1523
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&", kwlist, &textobj,
 
1524
                                     obj_to_scale, (void *)&face_size))
 
1525
        goto error;
 
1526
 
 
1527
    /* Encode text */
 
1528
    text = _PGFT_EncodePyString(textobj,
 
1529
                                self->render_flags & FT_RFLAG_UCS4);
 
1530
    if (!text) goto error;
 
1531
 
 
1532
    ASSERT_SELF_IS_ALIVE(self);
 
1533
 
 
1534
    /*
 
1535
     * Build the render mode with the given size and no
 
1536
     * rotation/styles/vertical text
 
1537
     */
 
1538
    if (_PGFT_BuildRenderMode(self->freetype, self, &render,
 
1539
                              face_size, FT_STYLE_NORMAL, 0)) goto error;
 
1540
 
 
1541
    /* get metrics */
 
1542
    list = get_metrics(&render, self, text);
 
1543
    if (!list) goto error;
 
1544
    free_string(text);
 
1545
 
 
1546
    return list;
 
1547
 
 
1548
  error:
 
1549
    free_string(text);
 
1550
    Py_XDECREF(list);
 
1551
    return 0;
 
1552
}
 
1553
 
 
1554
static PyObject *
 
1555
_ftfont_getsizedascender(PgFontObject *self, PyObject *args)
 
1556
{
 
1557
    Scale_t face_size = FACE_SIZE_NONE;
 
1558
    long value;
 
1559
 
 
1560
    if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
 
1561
        return 0;
 
1562
    }
 
1563
 
 
1564
    if (face_size.x == 0) {
 
1565
        if (self->face_size.x == 0) {
 
1566
            RAISE(PyExc_ValueError,
 
1567
                  "No font point size specified"
 
1568
                  " and no default font size in typefont");
 
1569
            return 0;
 
1570
        }
 
1571
 
 
1572
        face_size = self->face_size;
 
1573
    }
 
1574
    value = (long)_PGFT_Font_GetAscenderSized(self->freetype, self, face_size);
 
1575
    if (!value && PyErr_Occurred()) {
 
1576
        return 0;
 
1577
    }
 
1578
    return PyInt_FromLong(value);
 
1579
}
 
1580
 
 
1581
static PyObject *
 
1582
_ftfont_getsizeddescender(PgFontObject *self, PyObject *args)
 
1583
{
 
1584
    Scale_t face_size = FACE_SIZE_NONE;
 
1585
    long value;
 
1586
 
 
1587
    if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
 
1588
        return 0;
 
1589
    }
 
1590
 
 
1591
    if (face_size.x == 0) {
 
1592
        if (self->face_size.x == 0) {
 
1593
            RAISE(PyExc_ValueError,
 
1594
                  "No font point size specified"
 
1595
                  " and no default font size in typefont");
 
1596
            return 0;
 
1597
        }
 
1598
 
 
1599
        face_size = self->face_size;
 
1600
    }
 
1601
    value = (long)_PGFT_Font_GetDescenderSized(self->freetype, self, face_size);
 
1602
    if (!value && PyErr_Occurred()) {
 
1603
        return 0;
 
1604
    }
 
1605
    return PyInt_FromLong(value);
 
1606
}
 
1607
 
 
1608
static PyObject *
 
1609
_ftfont_getsizedheight(PgFontObject *self, PyObject *args)
 
1610
{
 
1611
    Scale_t face_size = FACE_SIZE_NONE;
 
1612
    long value;
 
1613
 
 
1614
    if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
 
1615
        return 0;
 
1616
    }
 
1617
 
 
1618
    if (face_size.x == 0) {
 
1619
        if (self->face_size.x == 0) {
 
1620
            RAISE(PyExc_ValueError,
 
1621
                  "No font point size specified"
 
1622
                  " and no default font size in typeface");
 
1623
            return 0;
 
1624
        }
 
1625
 
 
1626
        face_size = self->face_size;
 
1627
    }
 
1628
    value = _PGFT_Font_GetHeightSized(self->freetype, self, face_size);
 
1629
    if (!value && PyErr_Occurred()) {
 
1630
        return 0;
 
1631
    }
 
1632
    return PyInt_FromLong(value);
 
1633
}
 
1634
 
 
1635
static PyObject *
 
1636
_ftfont_getsizedglyphheight(PgFontObject *self, PyObject *args)
 
1637
{
 
1638
    Scale_t face_size = FACE_SIZE_NONE;
 
1639
    long value;
 
1640
 
 
1641
    if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
 
1642
        return 0;
 
1643
    }
 
1644
 
 
1645
    if (face_size.x == 0) {
 
1646
        if (self->face_size.x == 0) {
 
1647
            RAISE(PyExc_ValueError,
 
1648
                  "No font point size specified"
 
1649
                  " and no default font size in typeface");
 
1650
            return 0;
 
1651
        }
 
1652
 
 
1653
        face_size = self->face_size;
 
1654
    }
 
1655
    value = (long)_PGFT_Font_GetGlyphHeightSized(self->freetype, self,
 
1656
                                                 face_size);
 
1657
    if (!value && PyErr_Occurred()) {
 
1658
        return 0;
 
1659
    }
 
1660
    return PyInt_FromLong(value);
 
1661
}
 
1662
 
 
1663
static PyObject *
 
1664
_ftfont_getsizes(PgFontObject *self)
 
1665
{
 
1666
    int nsizes;
 
1667
    unsigned i;
 
1668
    int rc;
 
1669
    long size = 0;
 
1670
    long height = 0, width = 0;
 
1671
    double x_ppem = 0.0, y_ppem = 0.0;
 
1672
    PyObject *size_list = 0;
 
1673
    PyObject *size_item;
 
1674
 
 
1675
    nsizes = _PGFT_Font_NumFixedSizes(self->freetype, self);
 
1676
    if (nsizes < 0) goto error;
 
1677
    size_list = PyList_New(nsizes);
 
1678
    if (!size_list) goto error;
 
1679
    for (i = 0; i < nsizes; ++i) {
 
1680
        rc = _PGFT_Font_GetAvailableSize(self->freetype, self, i,
 
1681
                                         &size, &height, &width,
 
1682
                                         &x_ppem, &y_ppem);
 
1683
        if (rc < 0) goto error;
 
1684
        assert(rc > 0);
 
1685
        size_item = Py_BuildValue("llldd",
 
1686
                                  size, height, width, x_ppem, y_ppem);
 
1687
        if (!size_item) goto error;
 
1688
        PyList_SET_ITEM(size_list, i, size_item);
 
1689
    }
 
1690
    return size_list;
 
1691
 
 
1692
  error:
 
1693
    Py_XDECREF(size_list);
 
1694
    return 0;
 
1695
}
 
1696
 
 
1697
static PyObject *
 
1698
_ftfont_render_raw(PgFontObject *self, PyObject *args, PyObject *kwds)
 
1699
{
 
1700
    /* keyword list */
 
1701
    static char *kwlist[] =  {
 
1702
        "text", "style", "rotation", "size", "invert", 0
 
1703
    };
 
1704
 
 
1705
    FontRenderMode mode;
 
1706
 
 
1707
    /* input arguments */
 
1708
    PyObject *textobj;
 
1709
    PGFT_String *text = 0;
 
1710
    int style = FT_STYLE_DEFAULT;
 
1711
    Angle_t rotation = self->rotation;
 
1712
    Scale_t face_size = FACE_SIZE_NONE;
 
1713
    int invert = 0;
 
1714
 
 
1715
    /* output arguments */
 
1716
    PyObject *rbuffer = 0;
 
1717
    PyObject *rtuple = 0;
 
1718
    int width, height;
 
1719
 
 
1720
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O&i", kwlist,
 
1721
                                     &textobj,
 
1722
                                     &style,
 
1723
                                     obj_to_rotation, (void *)&rotation,
 
1724
                                     obj_to_scale, (void *)&face_size,
 
1725
                                     &invert))
 
1726
        goto error;
 
1727
 
 
1728
    /* Encode text */
 
1729
    if (textobj != Py_None) {
 
1730
        text = _PGFT_EncodePyString(textobj,
 
1731
                                    self->render_flags & FT_RFLAG_UCS4);
 
1732
        if (!text) goto error;
 
1733
    }
 
1734
 
 
1735
    ASSERT_SELF_IS_ALIVE(self);
 
1736
 
 
1737
    /*
 
1738
     * Build the render mode with the given size and no
 
1739
     * rotation/styles/vertical text
 
1740
     */
 
1741
    if (_PGFT_BuildRenderMode(self->freetype, self,
 
1742
                              &mode, face_size, style, rotation))
 
1743
        goto error;
 
1744
 
 
1745
    rbuffer = _PGFT_Render_PixelArray(self->freetype, self,
 
1746
                                      &mode, text, invert,
 
1747
                                      &width, &height);
 
1748
    if (!rbuffer) goto error;
 
1749
    free_string(text);
 
1750
    rtuple = Py_BuildValue("O(ii)", rbuffer, width, height);
 
1751
    if (!rtuple) goto error;
 
1752
    Py_DECREF(rbuffer);
 
1753
 
 
1754
    return rtuple;
 
1755
 
 
1756
  error:
 
1757
    free_string(text);
 
1758
    Py_XDECREF(rbuffer);
 
1759
    Py_XDECREF(rtuple);
 
1760
    return 0;
 
1761
}
 
1762
 
 
1763
static PyObject *
 
1764
_ftfont_render_raw_to(PgFontObject *self, PyObject *args, PyObject *kwds)
 
1765
{
 
1766
    /* keyword list */
 
1767
    static char *kwlist[] =  {
 
1768
        "array", "text", "dest", "style", "rotation", "size", "invert", 0
 
1769
    };
 
1770
 
 
1771
    FontRenderMode mode;
 
1772
 
 
1773
    /* input arguments */
 
1774
    PyObject *arrayobj;
 
1775
    PyObject *textobj;
 
1776
    PGFT_String *text = 0;
 
1777
    PyObject *dest = 0;
 
1778
    int xpos = 0;
 
1779
    int ypos = 0;
 
1780
    int style = FT_STYLE_DEFAULT;
 
1781
    Angle_t rotation = self->rotation;
 
1782
    Scale_t face_size = FACE_SIZE_NONE;
 
1783
    int invert = 0;
 
1784
 
 
1785
    /* output arguments */
 
1786
    SDL_Rect r;
 
1787
 
 
1788
    ASSERT_SELF_IS_ALIVE(self);
 
1789
 
 
1790
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OiO&O&i", kwlist,
 
1791
                                     &arrayobj, &textobj,
 
1792
                                     &dest, &style,
 
1793
                                     obj_to_rotation, (void *)&rotation,
 
1794
                                     obj_to_scale, (void *)&face_size,
 
1795
                                     &invert))
 
1796
        goto error;
 
1797
 
 
1798
    if (dest && dest != Py_None) {
 
1799
        if (parse_dest(dest, &xpos, &ypos)) goto error;
 
1800
    }
 
1801
 
 
1802
    /* Encode text */
 
1803
    if (textobj != Py_None) {
 
1804
        text = _PGFT_EncodePyString(textobj,
 
1805
                                    self->render_flags & FT_RFLAG_UCS4);
 
1806
        if (!text) goto error;
 
1807
    }
 
1808
 
 
1809
    /*
 
1810
     * Build the render mode with the given size and no
 
1811
     * rotation/styles/vertical text
 
1812
     */
 
1813
    if (_PGFT_BuildRenderMode(self->freetype, self,
 
1814
                              &mode, face_size, style, rotation))
 
1815
        goto error;
 
1816
 
 
1817
    if (_PGFT_Render_Array(self->freetype, self, &mode,
 
1818
                           arrayobj, text, invert, xpos, ypos, &r)) goto error;
 
1819
    free_string(text);
 
1820
 
 
1821
    return PyRect_New(&r);
 
1822
 
 
1823
  error:
 
1824
    free_string(text);
 
1825
    return 0;
 
1826
}
 
1827
 
 
1828
static PyObject *
 
1829
_ftfont_render(PgFontObject *self, PyObject *args, PyObject *kwds)
 
1830
{
 
1831
#ifndef HAVE_PYGAME_SDL_VIDEO
 
1832
 
 
1833
    PyErr_SetString(PyExc_RuntimeError,
 
1834
                    "SDL support is missing. Cannot render on surfonts");
 
1835
    return 0;
 
1836
 
 
1837
#else
 
1838
    /* keyword list */
 
1839
    static char *kwlist[] =  {
 
1840
        "text", "fgcolor", "bgcolor", "style", "rotation", "size", 0
 
1841
    };
 
1842
 
 
1843
    /* input arguments */
 
1844
    PyObject *textobj = 0;
 
1845
    PGFT_String *text = 0;
 
1846
    Scale_t face_size = FACE_SIZE_NONE;
 
1847
    PyObject *fg_color_obj = 0;
 
1848
    PyObject *bg_color_obj = 0;
 
1849
    Angle_t rotation = self->rotation;
 
1850
    int style = FT_STYLE_DEFAULT;
 
1851
 
 
1852
    /* output arguments */
 
1853
    SDL_Surface *surface = 0;
 
1854
    PyObject *surface_obj = 0;
 
1855
    PyObject *rtuple = 0;
 
1856
    SDL_Rect r;
 
1857
    PyObject *rect_obj = 0;
 
1858
 
 
1859
    FontColor fg_color;
 
1860
    FontColor bg_color;
 
1861
    FontRenderMode render;
 
1862
 
 
1863
    ASSERT_SELF_IS_ALIVE(self);
 
1864
 
 
1865
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOiO&O&", kwlist,
 
1866
                                     /* required */
 
1867
                                     &textobj,
 
1868
                                     /* optional */
 
1869
                                     &fg_color_obj, &bg_color_obj, &style,
 
1870
                                     obj_to_rotation, (void *)&rotation,
 
1871
                                     obj_to_scale, (void *)&face_size))
 
1872
        goto error;
 
1873
 
 
1874
    if (fg_color_obj == Py_None) {
 
1875
        fg_color_obj = 0;
 
1876
    }
 
1877
    if (bg_color_obj == Py_None) {
 
1878
        bg_color_obj = 0;
 
1879
    }
 
1880
 
 
1881
    if (fg_color_obj) {
 
1882
        if (!RGBAFromColorObj(fg_color_obj, (Uint8 *)&fg_color)) {
 
1883
            PyErr_SetString(PyExc_TypeError, "fgcolor must be a Color");
 
1884
            goto error;
 
1885
        }
 
1886
    }
 
1887
    else {
 
1888
        fg_color.r = self->fgcolor[0];
 
1889
        fg_color.g = self->fgcolor[1];
 
1890
        fg_color.b = self->fgcolor[2];
 
1891
        fg_color.a = self->fgcolor[3];
 
1892
    }
 
1893
    if (bg_color_obj) {
 
1894
        if (!RGBAFromColorObj(bg_color_obj, (Uint8 *)&bg_color)) {
 
1895
            PyErr_SetString(PyExc_TypeError, "bgcolor must be a Color");
 
1896
            goto error;
 
1897
        }
 
1898
    }
 
1899
 
 
1900
    /* Encode text */
 
1901
    if (textobj != Py_None) {
 
1902
        text = _PGFT_EncodePyString(textobj,
 
1903
                                    self->render_flags & FT_RFLAG_UCS4);
 
1904
        if (!text) goto error;
 
1905
    }
 
1906
 
 
1907
    if (_PGFT_BuildRenderMode(self->freetype, self,
 
1908
                              &render, face_size, style, rotation))
 
1909
        goto error;
 
1910
 
 
1911
    surface = _PGFT_Render_NewSurface(self->freetype, self,
 
1912
                                      &render, text, &fg_color,
 
1913
                                      bg_color_obj ? &bg_color : 0, &r);
 
1914
    if (!surface) goto error;
 
1915
    free_string(text);
 
1916
    surface_obj = PySurface_New(surface);
 
1917
    if (!surface_obj) goto error;
 
1918
 
 
1919
    rect_obj = PyRect_New(&r);
 
1920
    if (!rect_obj) goto error;
 
1921
    rtuple = PyTuple_Pack(2, surface_obj, rect_obj);
 
1922
    if (!rtuple) goto error;
 
1923
    Py_DECREF(surface_obj);
 
1924
    Py_DECREF(rect_obj);
 
1925
 
 
1926
    return rtuple;
 
1927
 
 
1928
  error:
 
1929
    free_string(text);
 
1930
    if (surface_obj) {
 
1931
        Py_DECREF(surface_obj);
 
1932
    }
 
1933
    else if (surface) {
 
1934
        SDL_FreeSurface(surface);
 
1935
    }
 
1936
    Py_XDECREF(rect_obj);
 
1937
    Py_XDECREF(rtuple);
 
1938
    return 0;
 
1939
 
 
1940
#endif // HAVE_PYGAME_SDL_VIDEO
 
1941
}
 
1942
 
 
1943
static PyObject *
 
1944
_ftfont_render_to(PgFontObject *self, PyObject *args, PyObject *kwds)
 
1945
{
 
1946
#ifndef HAVE_PYGAME_SDL_VIDEO
 
1947
 
 
1948
    PyErr_SetString(PyExc_RuntimeError,
 
1949
                    "SDL support is missing. Cannot render on surfaces");
 
1950
    return 0;
 
1951
 
 
1952
#else
 
1953
    /* keyword list */
 
1954
    static char *kwlist[] =  {
 
1955
        "surf", "dest", "text", "fgcolor", "bgcolor",
 
1956
        "style", "rotation", "size", 0
 
1957
    };
 
1958
 
 
1959
    /* input arguments */
 
1960
    PyObject *surface_obj = 0;
 
1961
    PyObject *textobj = 0;
 
1962
    PGFT_String *text = 0;
 
1963
    Scale_t face_size = FACE_SIZE_NONE;
 
1964
    PyObject *dest = 0;
 
1965
    int xpos = 0;
 
1966
    int ypos = 0;
 
1967
    PyObject *fg_color_obj = 0;
 
1968
    PyObject *bg_color_obj = 0;
 
1969
    Angle_t rotation = self->rotation;
 
1970
    int style = FT_STYLE_DEFAULT;
 
1971
    SDL_Surface *surface = 0;
 
1972
 
 
1973
    /* output arguments */
 
1974
    SDL_Rect r;
 
1975
 
 
1976
    FontColor fg_color;
 
1977
    FontColor bg_color;
 
1978
    FontRenderMode render;
 
1979
 
 
1980
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!OO|OOiO&O&", kwlist,
 
1981
                                     /* required */
 
1982
                                     &PySurface_Type, &surface_obj, &dest,
 
1983
                                     &textobj, &fg_color_obj,
 
1984
                                     /* optional */
 
1985
                                     &bg_color_obj, &style,
 
1986
                                     obj_to_rotation, (void *)&rotation,
 
1987
                                     obj_to_scale, (void *)&face_size))
 
1988
        goto error;
 
1989
 
 
1990
    if (fg_color_obj == Py_None) {
 
1991
        fg_color_obj = 0;
 
1992
    }
 
1993
    if (bg_color_obj == Py_None) {
 
1994
        bg_color_obj = 0;
 
1995
    }
 
1996
 
 
1997
    if (parse_dest(dest, &xpos, &ypos)) goto error;
 
1998
    if (fg_color_obj) {
 
1999
        if (!RGBAFromColorObj(fg_color_obj, (Uint8 *)&fg_color)) {
 
2000
            PyErr_SetString(PyExc_TypeError, "fgcolor must be a Color");
 
2001
            goto error;
 
2002
        }
 
2003
    }
 
2004
    else {
 
2005
        fg_color.r = self->fgcolor[0];
 
2006
        fg_color.g = self->fgcolor[1];
 
2007
        fg_color.b = self->fgcolor[2];
 
2008
        fg_color.a = self->fgcolor[3];
 
2009
    }
 
2010
    if (bg_color_obj) {
 
2011
        if (!RGBAFromColorObj(bg_color_obj, (Uint8 *)&bg_color)) {
 
2012
            PyErr_SetString(PyExc_TypeError, "bgcolor must be a Color");
 
2013
            goto error;
 
2014
        }
 
2015
    }
 
2016
 
 
2017
    ASSERT_SELF_IS_ALIVE(self);
 
2018
 
 
2019
    /* Encode text */
 
2020
    if (textobj != Py_None) {
 
2021
        text = _PGFT_EncodePyString(textobj,
 
2022
                                    self->render_flags & FT_RFLAG_UCS4);
 
2023
        if (!text) goto error;
 
2024
    }
 
2025
 
 
2026
    if (_PGFT_BuildRenderMode(self->freetype, self,
 
2027
                              &render, face_size, style, rotation))
 
2028
        goto error;
 
2029
 
 
2030
    surface = PySurface_AsSurface(surface_obj);
 
2031
    if (_PGFT_Render_ExistingSurface(self->freetype, self,
 
2032
                                     &render, text, surface,
 
2033
                                     xpos, ypos, &fg_color,
 
2034
                                     bg_color_obj ? &bg_color : 0, &r))
 
2035
        goto error;
 
2036
    free_string(text);
 
2037
 
 
2038
    return PyRect_New(&r);
 
2039
 
 
2040
  error:
 
2041
    free_string(text);
 
2042
    return 0;
 
2043
#endif // HAVE_PYGAME_SDL_VIDEO
 
2044
}
 
2045
 
 
2046
/****************************************************
 
2047
 * C API CALLS
 
2048
 ****************************************************/
 
2049
static PyObject *
 
2050
PgFont_New(const char *filename, long font_index)
 
2051
{
 
2052
    PgFontObject *font;
 
2053
 
 
2054
    FreeTypeInstance *ft;
 
2055
    ASSERT_GRAB_FREETYPE(ft, 0);
 
2056
 
 
2057
    if (!filename) {
 
2058
        return 0;
 
2059
    }
 
2060
 
 
2061
    font = (PgFontObject *)PgFont_Type.tp_new(
 
2062
            &PgFont_Type, 0, 0);
 
2063
 
 
2064
    if (!font) {
 
2065
        return 0;
 
2066
    }
 
2067
 
 
2068
    if (_PGFT_TryLoadFont_Filename(ft, font, filename, font_index)) {
 
2069
        return 0;
 
2070
    }
 
2071
 
 
2072
    return (PyObject *) font;
 
2073
}
 
2074
 
 
2075
 
 
2076
/****************************************************
 
2077
 * FREETYPE MODULE METHODS
 
2078
 ****************************************************/
 
2079
 
 
2080
/***************************************************************
 
2081
 *
 
2082
 * Bindings for initialization/cleanup functions
 
2083
 *
 
2084
 * Explicit init/quit functions are required to work around
 
2085
 * some issues regarding module caching and multi-threaded apps.
 
2086
 * It's always good to let the user choose when to initialize
 
2087
 * the module.
 
2088
 *
 
2089
 * TODO: These bindings can be removed once proper threading
 
2090
 * support is in place.
 
2091
 *
 
2092
 ***************************************************************/
 
2093
 
 
2094
static PyObject *
 
2095
_ft_autoinit(PyObject *self)
 
2096
{
 
2097
    int cache_size = FREETYPE_MOD_STATE(self)->cache_size;
 
2098
    FT_Error result = 1;
 
2099
 
 
2100
    if (!FREETYPE_MOD_STATE(self)->freetype) {
 
2101
        PyGame_RegisterQuit(_ft_autoquit);
 
2102
 
 
2103
        if (cache_size == 0) {
 
2104
            cache_size = PGFT_DEFAULT_CACHE_SIZE;
 
2105
        }
 
2106
        if (_PGFT_Init(&(FREETYPE_MOD_STATE(self)->freetype), cache_size)) {
 
2107
            return 0;
 
2108
        }
 
2109
        FREETYPE_MOD_STATE(self)->cache_size = cache_size;
 
2110
    }
 
2111
 
 
2112
    return PyInt_FromLong(result);
 
2113
}
 
2114
 
 
2115
static void
 
2116
_ft_autoquit(void)
 
2117
{
 
2118
    _FreeTypeState *state = FREETYPE_STATE;
 
2119
 
 
2120
    if (state->freetype) {
 
2121
        _PGFT_Quit(state->freetype);
 
2122
        state->cache_size = 0;
 
2123
        state->freetype = 0;
 
2124
    }
 
2125
}
 
2126
 
 
2127
static PyObject *
 
2128
_ft_quit(PyObject *self)
 
2129
{
 
2130
    _ft_autoquit();
 
2131
    Py_RETURN_NONE;
 
2132
}
 
2133
 
 
2134
static PyObject *
 
2135
_ft_init(PyObject *self, PyObject *args, PyObject *kwds)
 
2136
{
 
2137
    static char *kwlist[] =  {
 
2138
        "cache_size", "resolution", 0
 
2139
    };
 
2140
 
 
2141
    PyObject *result;
 
2142
    unsigned cache_size = 0;
 
2143
    unsigned resolution = 0;
 
2144
    _FreeTypeState *state = FREETYPE_MOD_STATE(self);
 
2145
 
 
2146
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|II", kwlist,
 
2147
                                     &cache_size, &resolution)) {
 
2148
        return 0;
 
2149
    }
 
2150
 
 
2151
    if (!state->freetype) {
 
2152
        state->cache_size = cache_size;
 
2153
        state->resolution = (resolution ?
 
2154
                             (FT_UInt)resolution : PGFT_DEFAULT_RESOLUTION);
 
2155
        result = _ft_autoinit(self);
 
2156
 
 
2157
        if (!result) {
 
2158
            PyErr_Clear();
 
2159
            PyErr_SetString(PyExc_RuntimeError,
 
2160
                            "Failed to initialize the FreeType2 library");
 
2161
            return 0;
 
2162
        }
 
2163
        Py_DECREF(result);
 
2164
    }
 
2165
 
 
2166
    Py_RETURN_NONE;
 
2167
}
 
2168
 
 
2169
 
 
2170
static PyObject *
 
2171
_ft_get_error(PyObject *self)
 
2172
{
 
2173
    FreeTypeInstance *ft;
 
2174
    ASSERT_GRAB_FREETYPE(ft, 0);
 
2175
 
 
2176
    if (ft->_error_msg[0]) {
 
2177
        return Text_FromUTF8(ft->_error_msg);
 
2178
    }
 
2179
 
 
2180
    Py_RETURN_NONE;
 
2181
}
 
2182
 
 
2183
static PyObject *
 
2184
_ft_get_version(PyObject *self)
 
2185
{
 
2186
    /* Return the linked FreeType2 version */
 
2187
    return Py_BuildValue("iii", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
 
2188
}
 
2189
 
 
2190
static PyObject *
 
2191
_ft_get_cache_size(PyObject *self)
 
2192
{
 
2193
    return PyLong_FromUnsignedLong((unsigned long)(FREETYPE_STATE->cache_size));
 
2194
}
 
2195
 
 
2196
static PyObject *
 
2197
_ft_get_default_resolution(PyObject *self)
 
2198
{
 
2199
    return PyLong_FromUnsignedLong((unsigned long)(FREETYPE_STATE->resolution));
 
2200
}
 
2201
 
 
2202
static PyObject *
 
2203
_ft_set_default_resolution(PyObject *self, PyObject *args)
 
2204
{
 
2205
    unsigned resolution = 0;
 
2206
    _FreeTypeState *state = FREETYPE_MOD_STATE(self);
 
2207
 
 
2208
    if (!PyArg_ParseTuple(args, "|I", &resolution)) {
 
2209
        return 0;
 
2210
    }
 
2211
 
 
2212
    state->resolution = (resolution ?
 
2213
                         (FT_UInt)resolution : PGFT_DEFAULT_RESOLUTION);
 
2214
    Py_RETURN_NONE;
 
2215
}
 
2216
 
 
2217
static PyObject *
 
2218
_ft_was_init(PyObject *self)
 
2219
{
 
2220
    return PyBool_FromLong(FREETYPE_MOD_STATE(self)->freetype ? 1 : 0);
 
2221
}
 
2222
 
 
2223
static PyObject*
 
2224
_ft_get_default_font(PyObject* self)
 
2225
{
 
2226
    return Text_FromUTF8(DEFAULT_FONT_NAME);
 
2227
}
 
2228
 
 
2229
#if PY3
 
2230
static int
 
2231
_ft_traverse (PyObject *mod, visitproc visit, void *arg)
 
2232
{
 
2233
    return 0;
 
2234
}
 
2235
 
 
2236
static int
 
2237
_ft_clear (PyObject *mod)
 
2238
{
 
2239
    if (FREETYPE_MOD_STATE(mod)->freetype) {
 
2240
        _PGFT_Quit(FREETYPE_MOD_STATE(mod)->freetype);
 
2241
        FREETYPE_MOD_STATE(mod)->freetype = 0;
 
2242
    }
 
2243
    return 0;
 
2244
}
 
2245
#endif
 
2246
 
 
2247
 
 
2248
 
 
2249
/****************************************************
 
2250
 * FREETYPE MODULE DECLARATION
 
2251
 ****************************************************/
 
2252
#if PY3
 
2253
struct PyModuleDef _freetypemodule =
 
2254
{
 
2255
    PyModuleDef_HEAD_INIT,
 
2256
    MODULE_NAME,
 
2257
    DOC_PYGAMEFREETYPE,
 
2258
    sizeof(_FreeTypeState),
 
2259
    _ft_methods,
 
2260
    0,
 
2261
    _ft_traverse,
 
2262
    _ft_clear,
 
2263
    0
 
2264
};
 
2265
#else
 
2266
_FreeTypeState _modstate;
 
2267
#endif
 
2268
 
 
2269
MODINIT_DEFINE (_freetype)
 
2270
{
 
2271
    PyObject *module, *apiobj;
 
2272
    static void* c_api[PYGAMEAPI_FREETYPE_NUMSLOTS];
 
2273
 
 
2274
    import_pygame_base();
 
2275
    if (PyErr_Occurred()) {
 
2276
        MODINIT_ERROR;
 
2277
    }
 
2278
 
 
2279
    import_pygame_surface();
 
2280
    if (PyErr_Occurred())  {
 
2281
        MODINIT_ERROR;
 
2282
    }
 
2283
 
 
2284
    import_pygame_color();
 
2285
    if (PyErr_Occurred())  {
 
2286
        MODINIT_ERROR;
 
2287
    }
 
2288
 
 
2289
    import_pygame_rwobject();
 
2290
    if (PyErr_Occurred())  {
 
2291
        MODINIT_ERROR;
 
2292
    }
 
2293
 
 
2294
    import_pygame_rect();
 
2295
    if (PyErr_Occurred())  {
 
2296
        MODINIT_ERROR;
 
2297
    }
 
2298
 
 
2299
    /* type preparation */
 
2300
    if (PyType_Ready(&PgFont_Type) < 0)  {
 
2301
        MODINIT_ERROR;
 
2302
    }
 
2303
 
 
2304
#if PY3
 
2305
    module = PyModule_Create(&_freetypemodule);
 
2306
#else
 
2307
    /* TODO: DOC */
 
2308
    module = Py_InitModule3(MODULE_NAME, _ft_methods, DOC_PYGAMEFREETYPE);
 
2309
#endif
 
2310
 
 
2311
    if (!module)  {
 
2312
        MODINIT_ERROR;
 
2313
    }
 
2314
 
 
2315
    FREETYPE_MOD_STATE(module)->freetype = 0;
 
2316
    FREETYPE_MOD_STATE(module)->cache_size = 0;
 
2317
    FREETYPE_MOD_STATE(module)->resolution = PGFT_DEFAULT_RESOLUTION;
 
2318
 
 
2319
    Py_INCREF((PyObject *)&PgFont_Type);
 
2320
    if (PyModule_AddObject(module, FONT_TYPE_NAME,
 
2321
                           (PyObject *)&PgFont_Type) == -1)  {
 
2322
        Py_DECREF((PyObject *) &PgFont_Type);
 
2323
        DECREF_MOD(module);
 
2324
        MODINIT_ERROR;
 
2325
    }
 
2326
 
 
2327
#   define DEC_CONST(x)  PyModule_AddIntConstant(module, #x, (int)FT_##x)
 
2328
 
 
2329
    DEC_CONST(STYLE_NORMAL);
 
2330
    DEC_CONST(STYLE_STRONG);
 
2331
    DEC_CONST(STYLE_OBLIQUE);
 
2332
    DEC_CONST(STYLE_UNDERLINE);
 
2333
    DEC_CONST(STYLE_WIDE);
 
2334
    DEC_CONST(STYLE_DEFAULT);
 
2335
 
 
2336
    DEC_CONST(BBOX_EXACT);
 
2337
    DEC_CONST(BBOX_EXACT_GRIDFIT);
 
2338
    DEC_CONST(BBOX_PIXEL);
 
2339
    DEC_CONST(BBOX_PIXEL_GRIDFIT);
 
2340
 
 
2341
    /* export the c api */
 
2342
#   if PYGAMEAPI_FREETYPE_NUMSLOTS != 2
 
2343
#       error Mismatch between number of api slots and actual exports.
 
2344
#   endif
 
2345
    c_api[0] = &PgFont_Type;
 
2346
    c_api[1] = &PgFont_New;
 
2347
 
 
2348
    apiobj = encapsulate_api(c_api, "freetype");
 
2349
    if (!apiobj)  {
 
2350
        DECREF_MOD(module);
 
2351
        MODINIT_ERROR;
 
2352
    }
 
2353
 
 
2354
    if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj) == -1)  {
 
2355
        Py_DECREF(apiobj);
 
2356
        DECREF_MOD(module);
 
2357
        MODINIT_ERROR;
 
2358
    }
 
2359
 
 
2360
    MODINIT_RETURN(module);
 
2361
}