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