2
pygame - Python Game Library
3
Copyright (C) 2009 Vicent Marti
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.
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.
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
21
#define PYGAME_FREETYPE_INTERNAL
22
#define PYGAME_FREETYPE_FONT_INTERNAL
25
#include "freetype/ft_wrap.h"
26
#include "doc/freetype_doc.h"
28
#define MODULE_NAME "_freetype"
29
#define FONT_TYPE_NAME "Font"
32
* FreeType module declarations
34
static const Scale_t FACE_SIZE_NONE = {0, 0};
37
static int _ft_traverse(PyObject *, visitproc, void *);
38
static int _ft_clear(PyObject *);
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);
54
* Constructor/init/destructor
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 *);
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 *);
76
/* static PyObject *_ftfont_copy(PgFontObject *); */
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 *);
99
static PyObject *_ftfont_getresolution(PgFontObject *, void *);
101
static PyObject *_ftfont_getfontmetric(PgFontObject *, void *);
103
static PyObject *_ftfont_getstyle_flag(PgFontObject *, void *);
104
static int _ftfont_setstyle_flag(PgFontObject *, PyObject *, void *);
106
static PyObject *_ftfont_getrender_flag(PgFontObject *, void *);
107
static int _ftfont_setrender_flag(PgFontObject *, PyObject *, void *);
109
#if defined(PGFT_DEBUG_CACHE)
110
static PyObject *_ftfont_getdebugcachestats(PgFontObject *, void *);
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 *);
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"); \
137
#define PGFT_CHECK_BOOL(_pyobj, _var) \
139
if (!PyBool_Check(_pyobj)) { \
140
PyErr_SetString(PyExc_TypeError, \
141
#_var " must be a boolean value"); \
145
_var = PyObject_IsTrue(_pyobj); \
148
#define DEFAULT_FONT_NAME "freesansbold.ttf"
149
#define PKGDATA_MODULE_NAME "pygame.pkgdata"
150
#define RESOURCE_FUNC_NAME "getResource"
153
load_font_res(const char *filename)
155
PyObject *load_basicfunc = 0;
156
PyObject *pkgdatamodule = 0;
157
PyObject *resourcefunc = 0;
158
PyObject *result = 0;
161
pkgdatamodule = PyImport_ImportModule(PKGDATA_MODULE_NAME);
162
if (!pkgdatamodule) {
163
goto font_resource_end;
166
resourcefunc = PyObject_GetAttrString(pkgdatamodule, RESOURCE_FUNC_NAME);
168
goto font_resource_end;
171
result = PyObject_CallFunction(resourcefunc, "s", filename);
173
goto font_resource_end;
177
tmp = PyObject_GetAttrString(result, "name");
186
if (PyFile_Check(result)) {
187
tmp = PyFile_Name(result);
195
Py_XDECREF(pkgdatamodule);
196
Py_XDECREF(resourcefunc);
197
Py_XDECREF(load_basicfunc);
202
parse_dest(PyObject *dest, int *x, int *y)
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:"
213
Py_TYPE(dest)->tp_name);
216
oi = PySequence_GetItem(dest, 0);
220
oj = PySequence_GetItem(dest, 1);
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);
234
i = PyInt_AsLong(oi);
236
if (i == -1 && PyErr_Occurred()) {
240
j = PyInt_AsLong(oj);
242
if (j == -1 && PyErr_Occurred()) {
250
/** Point size PyArg_ParseTuple converter: int -> Scale_t */
252
obj_to_scale(PyObject *o, void *p)
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));
261
return objs_to_scale(PyTuple_GET_ITEM(o, 0),
262
PyTuple_GET_ITEM(o, 1),
265
return objs_to_scale(o, 0, (Scale_t *)p);
269
objs_to_scale(PyObject *x, PyObject *y, Scale_t *size)
274
for (o = x, do_y = 1; o; o = (do_y--) ? y : 0) {
275
if (!PyLong_Check(o) &&
281
PyErr_Format(PyExc_TypeError,
282
"expected a (float, float) tuple for size"
283
", got (%128s, %128s)",
285
Py_TYPE(y)->tp_name);
288
PyErr_Format(PyExc_TypeError,
289
"expected a float for size, got %128s",
290
Py_TYPE(o)->tp_name);
296
return numbers_to_scale(x, y, size);
300
numbers_to_scale(PyObject *x, PyObject *y, Scale_t *size)
303
PyObject *min_obj = 0;
304
PyObject *max_obj = 0;
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;
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);
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);
334
rval = build_scale(x, y, size);
343
build_scale(PyObject *x, PyObject *y, Scale_t *size)
345
FT_UInt sz_x = 0, sz_y = 0;
347
sz_x = number_to_FX6_unsigned(x);
348
if (PyErr_Occurred()) {
352
sz_y = number_to_FX6_unsigned(y);
353
if (PyErr_Occurred()) {
357
if (sz_x == 0 && sz_y != 0) {
358
PyErr_SetString(PyExc_ValueError,
359
"expected zero size height when width is zero");
368
number_to_FX6_unsigned(PyObject *n)
370
PyObject *f_obj = PyNumber_Float(n);
373
if (!f_obj) return 0;
374
f = PyFloat_AsDouble(f_obj);
376
if (PyErr_Occurred()) return 0;
377
return DBL_TO_FX6(f);
380
/** rotation: int -> Angle_t */
382
obj_to_rotation(PyObject *o, void *p)
384
PyObject *full_circle_obj = 0;
385
PyObject *angle_obj = 0;
389
if (PyLong_Check(o)) {
393
else if (PyInt_Check(o)) {
398
PyErr_Format(PyExc_TypeError, "integer rotation expected, got %s",
399
Py_TYPE(o)->tp_name);
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);
412
Py_XDECREF(full_circle_obj);
413
Py_XDECREF(angle_obj);
417
/** This accepts a NULL PGFT_String pointer */
419
free_string(PGFT_String *p) {
420
if (p) _PGFT_FreeString(p);
424
* FREETYPE MODULE METHODS TABLE
426
static PyMethodDef _ft_methods[] = {
429
(PyCFunction) _ft_autoinit,
431
"auto initialize function for _freetype"
435
(PyCFunction) _ft_init,
436
METH_VARARGS | METH_KEYWORDS,
437
DOC_PYGAMEFREETYPEINIT
441
(PyCFunction) _ft_quit,
443
DOC_PYGAMEFREETYPEQUIT
447
(PyCFunction) _ft_was_init,
449
DOC_PYGAMEFREETYPEWASINIT
453
(PyCFunction) _ft_get_error,
455
DOC_PYGAMEFREETYPEGETERROR
459
(PyCFunction) _ft_get_version,
461
DOC_PYGAMEFREETYPEGETVERSION
465
(PyCFunction) _ft_get_cache_size,
467
DOC_PYGAMEFREETYPEGETCACHESIZE
470
"get_default_resolution",
471
(PyCFunction) _ft_get_default_resolution,
473
DOC_PYGAMEFREETYPEGETDEFAULTRESOLUTION
476
"set_default_resolution",
477
(PyCFunction) _ft_set_default_resolution,
479
DOC_PYGAMEFREETYPESETDEFAULTRESOLUTION
483
(PyCFunction) _ft_get_default_font,
485
DOC_PYGAMEFREETYPEGETDEFAULTFONT
493
* FREETYPE FONT METHODS TABLE
495
static PyMethodDef _ftfont_methods[] = {
498
(PyCFunction) _ftfont_getsizedheight,
500
DOC_FONTGETSIZEDHEIGHT
503
"get_sized_ascender",
504
(PyCFunction) _ftfont_getsizedascender,
506
DOC_FONTGETSIZEDASCENDER
509
"get_sized_descender",
510
(PyCFunction) _ftfont_getsizeddescender,
512
DOC_FONTGETSIZEDDESCENDER
515
"get_sized_glyph_height",
516
(PyCFunction) _ftfont_getsizedglyphheight,
518
DOC_FONTGETSIZEDGLYPHHEIGHT
522
(PyCFunction) _ftfont_getrect,
523
METH_VARARGS | METH_KEYWORDS,
528
(PyCFunction) _ftfont_getmetrics,
529
METH_VARARGS | METH_KEYWORDS,
534
(PyCFunction) _ftfont_getsizes,
540
(PyCFunction)_ftfont_render,
541
METH_VARARGS | METH_KEYWORDS,
546
(PyCFunction)_ftfont_render_to,
547
METH_VARARGS | METH_KEYWORDS,
552
(PyCFunction)_ftfont_render_raw,
553
METH_VARARGS | METH_KEYWORDS,
558
(PyCFunction)_ftfont_render_raw_to,
559
METH_VARARGS | METH_KEYWORDS,
567
* FREETYPE FONT GETTERS/SETTERS TABLE
569
static PyGetSetDef _ftfont_getsets[] = {
572
(getter)_ftfont_getsize,
573
(setter)_ftfont_setsize,
579
(getter)_ftfont_getstyle,
580
(setter)_ftfont_setstyle,
586
(getter)_ftfont_getfontmetric,
589
(void *)_PGFT_Font_GetHeight
593
(getter)_ftfont_getfontmetric,
596
(void *)_PGFT_Font_GetAscender
600
(getter)_ftfont_getfontmetric,
603
(void *)_PGFT_Font_GetDescender
607
(getter)_ftfont_getname,
614
(getter)_ftfont_getpath,
621
(getter)_ftfont_getscalable,
628
(getter)_ftfont_getfixedwidth,
635
(getter)_ftfont_getfixedsizes,
642
(getter)_ftfont_getrender_flag,
643
(setter)_ftfont_setrender_flag,
645
(void *)FT_RFLAG_ANTIALIAS
649
(getter)_ftfont_getrender_flag,
650
(setter)_ftfont_setrender_flag,
652
(void *)FT_RFLAG_KERNING
656
(getter)_ftfont_getrender_flag,
657
(setter)_ftfont_setrender_flag,
659
(void *)FT_RFLAG_VERTICAL
663
(getter)_ftfont_getrender_flag,
664
(setter)_ftfont_setrender_flag,
670
(getter)_ftfont_getstyle_flag,
671
(setter)_ftfont_setstyle_flag,
673
(void *)FT_STYLE_OBLIQUE
677
(getter)_ftfont_getstyle_flag,
678
(setter)_ftfont_setstyle_flag,
680
(void *)FT_STYLE_STRONG
684
(getter)_ftfont_getstyle_flag,
685
(setter)_ftfont_setstyle_flag,
687
(void *)FT_STYLE_UNDERLINE
691
(getter)_ftfont_getstyle_flag,
692
(setter)_ftfont_setstyle_flag,
694
(void *)FT_STYLE_WIDE
698
(getter)_ftfont_getstrength,
699
(setter)_ftfont_setstrength,
704
"underline_adjustment",
705
(getter)_ftfont_getunderlineadjustment,
706
(setter)_ftfont_setunderlineadjustment,
707
DOC_FONTUNDERLINEADJUSTMENT,
712
(getter)_ftfont_getrender_flag,
713
(setter)_ftfont_setrender_flag,
715
(void *)FT_RFLAG_UCS4
718
"use_bitmap_strikes",
719
(getter)_ftfont_getrender_flag,
720
(setter)_ftfont_setrender_flag,
721
DOC_FONTUSEBITMAPSTRIKES,
722
(void *)FT_RFLAG_USE_BITMAP_STRIKES
726
(getter)_ftfont_getresolution,
733
(getter)_ftfont_getrotation,
734
(setter)_ftfont_setrotation,
740
(getter)_ftfont_getfgcolor,
741
(setter)_ftfont_setfgcolor,
747
(getter)_ftfont_getrender_flag,
748
(setter)_ftfont_setrender_flag,
750
(void *)FT_RFLAG_ORIGIN
752
#if defined(PGFT_DEBUG_CACHE)
754
"_debug_cache_stats",
755
(getter)_ftfont_getdebugcachestats,
757
"_debug cache fields as a tuple",
766
* FREETYPE FONT BASE TYPE TABLE
768
#define FULL_TYPE_NAME MODULE_NAME "." FONT_TYPE_NAME
770
PyTypeObject PgFont_Type = {
772
FULL_TYPE_NAME, /* tp_name */
773
sizeof (PgFontObject), /* tp_basicsize */
775
(destructor)_ftfont_dealloc,/* tp_dealloc */
780
(reprfunc)_ftfont_repr, /* tp_repr */
781
0, /* tp_as_number */
782
0, /* tp_as_sequence */
783
0, /* tp_as_mapping */
789
0, /* tp_as_buffer */
790
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
791
DOC_PYGAMEFREETYPEFONT, /* docstring */
794
0, /* tp_richcompare */
795
0, /* tp_weaklistoffset */
798
_ftfont_methods, /* tp_methods */
800
_ftfont_getsets, /* tp_getset */
803
0, /* tp_descr_get */
804
0, /* tp_descr_set */
805
0, /* tp_dictoffset */
806
(initproc) _ftfont_init, /* tp_init */
808
(newfunc) _ftfont_new, /* tp_new */
814
0, /* tp_subclasses */
817
#if PY_VERSION_HEX >= 0x02060000
818
0 /* tp_version_tag */
822
#undef FULL_TYPE_NAME
825
/****************************************************
826
* CONSTRUCTOR/INIT/DESTRUCTOR
827
****************************************************/
829
_ftfont_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
831
PgFontObject *obj = (PgFontObject *)(subtype->tp_alloc(subtype, 0));
834
obj->id.open_args.flags = 0;
835
obj->id.open_args.pathname = 0;
838
obj->is_scalable = 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;
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 */
854
obj->fgcolor[3] = 255;
856
return (PyObject *)obj;
860
_ftfont_dealloc(PgFontObject *self)
862
_PGFT_UnloadFont(self->freetype, self);
863
_PGFT_Quit(self->freetype);
865
Py_XDECREF(self->path);
866
((PyObject *)self)->ob_type->tp_free((PyObject *)self);
870
_ftfont_init(PgFontObject *self, PyObject *args, PyObject *kwds)
872
static char *kwlist[] = {
873
"file", "size", "font_index", "resolution", "ucs4", 0
876
PyObject *file, *original_file;
878
Scale_t face_size = self->face_size;
879
int ucs4 = self->render_flags & FT_RFLAG_UCS4 ? 1 : 0;
880
unsigned resolution = 0;
888
FreeTypeInstance *ft;
889
ASSERT_GRAB_FREETYPE(ft, -1);
891
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&lIi", kwlist,
893
obj_to_scale, (void *)&face_size,
894
&font_index, &resolution, &ucs4)) {
898
original_file = file;
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);
906
Py_XDECREF(self->path);
908
self->is_scalable = 0;
910
self->face_size = face_size;
912
self->render_flags |= FT_RFLAG_UCS4;
915
self->render_flags &= ~FT_RFLAG_UCS4;
918
self->resolution = (FT_UInt)resolution;
921
self->resolution = FREETYPE_STATE->resolution;
923
if (file == Py_None) {
924
file = load_font_res(DEFAULT_FONT_NAME);
927
PyErr_SetString(PyExc_RuntimeError, "Failed to find default font");
932
file = RWopsEncodeFilePath(file, 0);
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.
942
self->path = Object_Unicode(original_file);
945
self->path = PyUnicode_FromEncodedObject(file, UNICODE_DEF_FS_CODEC,
952
if (_PGFT_TryLoadFont_Filename(ft, self,
953
Bytes_AS_STRING(file), font_index)) {
958
SDL_RWops *source = RWopsFromFileObjectThreaded(original_file);
966
path = PyObject_GetAttrString(original_file, "name");
969
str = Bytes_FromFormat("<%s instance at %p>",
970
Py_TYPE(file)->tp_name, (void *)file);
972
self->path = PyUnicode_FromEncodedObject(str,
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.
982
self->path = Object_Unicode(path);
984
else if (Bytes_Check(path)) {
985
self->path = PyUnicode_FromEncodedObject(path, UNICODE_DEF_FS_CODEC,
989
self->path = Object_Unicode(path);
996
if (_PGFT_TryLoadFont_RWops(ft, self, source, font_index)) {
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);
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
1016
self->freetype = ft;
1022
if (file != original_file) {
1030
_ftfont_repr(PgFontObject *self)
1032
if (PgFont_IS_ALIVE(self)) {
1034
return PyUnicode_FromFormat("Font('%.1024U')", self->path);
1036
PyObject *str = PyUnicode_AsEncodedString(self->path,
1037
"raw_unicode_escape",
1042
rval = PyString_FromFormat("Font('%.1024s')",
1043
PyString_AS_STRING(str));
1049
return Text_FromFormat("<uninitialized Font object at %p>", (void *)self);
1053
/****************************************************
1055
****************************************************/
1057
/** Generic style attributes */
1059
_ftfont_getstyle_flag(PgFontObject *self, void *closure)
1061
const int style_flag = (int)closure;
1063
return PyBool_FromLong(self->style & style_flag);
1067
_ftfont_setstyle_flag(PgFontObject *self, PyObject *value, void *closure)
1069
const int style_flag = (int)closure;
1071
if (!PyBool_Check(value)) {
1072
PyErr_SetString(PyExc_TypeError,
1073
"The style value must be a boolean");
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");
1083
PyErr_SetString(PyExc_RuntimeError,
1084
MODULE_NAME "." FONT_TYPE_NAME
1085
" instance is not initialized");
1089
if (PyObject_IsTrue(value)) {
1090
self->style |= (FT_UInt16)style_flag;
1093
self->style &= (FT_UInt16)(~style_flag);
1100
/** Style attribute */
1102
_ftfont_getstyle (PgFontObject *self, void *closure)
1104
return PyInt_FromLong(self->style);
1108
_ftfont_setstyle(PgFontObject *self, PyObject *value, void *closure)
1112
if (!PyInt_Check(value)) {
1113
PyErr_SetString(PyExc_TypeError,
1114
"The style value must be an integer"
1115
" from the FT constants module");
1119
style = (FT_UInt32)PyInt_AsLong(value);
1121
if (style == FT_STYLE_DEFAULT) {
1122
/* The Font object's style property is the Font's default style,
1123
* so leave unchanged.
1127
if (_PGFT_CheckStyle(style)) {
1128
PyErr_Format(PyExc_ValueError,
1129
"Invalid style value %x", (int)style);
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");
1138
PyErr_SetString(PyExc_RuntimeError,
1139
MODULE_NAME "." FONT_TYPE_NAME
1140
" instance is not initialized");
1145
self->style = (FT_UInt16)style;
1150
_ftfont_getstrength(PgFontObject *self, void *closure)
1152
return PyFloat_FromDouble(self->strength);
1156
_ftfont_setstrength(PgFontObject *self, PyObject *value, void *closure)
1158
PyObject *strengthobj = PyNumber_Float(value);
1164
strength = PyFloat_AS_DOUBLE(strengthobj);
1165
Py_DECREF(strengthobj);
1166
if (strength < 0.0 || strength > 1.0) {
1169
sprintf(msg, "strength value %.4e is outside range [0, 1]", strength);
1170
PyErr_SetString(PyExc_ValueError, msg);
1173
self->strength = strength;
1178
_ftfont_getsize(PgFontObject *self, void *closure)
1180
if (self->face_size.y == 0) {
1181
return PyFloat_FromDouble(FX6_TO_DBL(self->face_size.x));
1183
return Py_BuildValue("dd",
1184
FX6_TO_DBL(self->face_size.x),
1185
FX6_TO_DBL(self->face_size.y));
1189
_ftfont_setsize(PgFontObject *self, PyObject *value, void *closure)
1193
if (!obj_to_scale(value, &face_size)) goto error;
1194
self->face_size = face_size;
1202
_ftfont_getunderlineadjustment(PgFontObject *self, void *closure)
1204
return PyFloat_FromDouble(self->underline_adjustment);
1208
_ftfont_setunderlineadjustment(PgFontObject *self, PyObject *value,
1211
PyObject *adjustmentobj = PyNumber_Float(value);
1214
if (!adjustmentobj) {
1217
adjustment = PyFloat_AS_DOUBLE(adjustmentobj);
1218
Py_DECREF(adjustmentobj);
1219
if (adjustment < -2.0 || adjustment > 2.0) {
1223
"underline adjustment value %.4e is outside range [-2.0, 2.0]",
1225
PyErr_SetString(PyExc_ValueError, msg);
1228
self->underline_adjustment = adjustment;
1233
/** general font attributes */
1236
_ftfont_getfontmetric(PgFontObject *self, void *closure)
1238
typedef long (*getter)(FreeTypeInstance *, PgFontObject *);
1241
ASSERT_SELF_IS_ALIVE(self);
1242
height = ((getter)closure)(self->freetype, self);
1243
if (!height && PyErr_Occurred()) {
1246
return PyInt_FromLong(height);
1250
_ftfont_getname(PgFontObject *self, void *closure)
1254
if (PgFont_IS_ALIVE(self)) {
1255
name = _PGFT_Font_GetName(self->freetype, self);
1256
return name ? Text_FromUTF8(name) : 0;
1258
return PyObject_Repr((PyObject *)self);
1262
_ftfont_getpath(PgFontObject *self, void *closure)
1264
PyObject *path = ((PgFontObject *)self)->path;
1267
PyErr_SetString(PyExc_AttributeError, "path unavailable");
1275
_ftfont_getscalable(PgFontObject *self, void *closure)
1277
ASSERT_SELF_IS_ALIVE(self)
1278
return PyBool_FromLong(self->is_scalable);
1282
_ftfont_getfixedwidth(PgFontObject *self, void *closure)
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;
1292
_ftfont_getfixedsizes(PgFontObject *self, void *closure)
1294
long num_fixed_sizes;
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;
1302
/** Generic render flag attributes */
1304
_ftfont_getrender_flag(PgFontObject *self, void *closure)
1306
const int render_flag = (int)closure;
1308
return PyBool_FromLong(self->render_flags & render_flag);
1312
_ftfont_setrender_flag(PgFontObject *self, PyObject *value, void *closure)
1314
const int render_flag = (int)closure;
1316
if (!PyBool_Check(value)) {
1317
PyErr_SetString(PyExc_TypeError,
1318
"The style value must be a boolean");
1322
if (PyObject_IsTrue(value)) {
1323
self->render_flags |= (FT_UInt16)render_flag;
1326
self->render_flags &= (FT_UInt16)(~render_flag);
1333
/** resolution pixel size attribute */
1335
_ftfont_getresolution(PgFontObject *self, void *closure)
1337
return PyLong_FromUnsignedLong((unsigned long)self->resolution);
1341
/** text rotation attribute */
1343
_ftfont_getrotation(PgFontObject *self, void *closure)
1345
return PyLong_FromLong((long)FX16_ROUND_TO_INT(self->rotation));
1349
_ftfont_setrotation(PgFontObject *self, PyObject *value, void *closure)
1351
if (!self->is_scalable) {
1352
if (PgFont_IS_ALIVE(self)) {
1353
PyErr_SetString(PyExc_AttributeError,
1354
"rotation is unsupported for a bitmap font");
1357
PyErr_SetString(PyExc_RuntimeError,
1358
MODULE_NAME "." FONT_TYPE_NAME
1359
" instance is not initialized");
1363
return obj_to_rotation(value, &self->rotation) ? 0 : -1;
1366
/** default glyph color */
1368
_ftfont_getfgcolor(PgFontObject *self, void *closure)
1370
return PyColor_New(self->fgcolor);
1374
_ftfont_setfgcolor(PgFontObject *self, PyObject *value, void *closure)
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);
1385
/** testing and debugging */
1386
#if defined(PGFT_DEBUG_CACHE)
1388
_ftfont_getdebugcachestats(PgFontObject *self, void *closure)
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.)
1396
const FontCache *cache = &PGFT_FONT_CACHE(self);
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);
1407
/****************************************************
1409
****************************************************/
1411
_ftfont_getrect(PgFontObject *self, PyObject *args, PyObject *kwds)
1416
static char *kwlist[] = {
1417
"text", "style", "rotation", "size", 0
1421
PGFT_String *text = 0;
1422
Scale_t face_size = FACE_SIZE_NONE;
1425
FontRenderMode render;
1426
Angle_t rotation = self->rotation;
1427
int style = FT_STYLE_DEFAULT;
1429
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O&", kwlist,
1431
obj_to_rotation, (void *)&rotation,
1432
obj_to_scale, (void *)&face_size))
1436
if (textobj != Py_None) {
1437
text = _PGFT_EncodePyString(textobj,
1438
self->render_flags & FT_RFLAG_UCS4);
1439
if (!text) goto error;
1442
ASSERT_SELF_IS_ALIVE(self);
1444
/* Build rendering mode, always anti-aliased by default */
1445
if (_PGFT_BuildRenderMode(self->freetype, self, &render,
1446
face_size, style, rotation)) goto error;
1448
if (_PGFT_GetTextRect(self->freetype, self, &render, text, &r)) goto error;
1451
return PyRect_New(&r);
1459
get_metrics(FontRenderMode *render, PgFontObject *font, PGFT_String *text)
1461
Py_ssize_t length = PGFT_String_GET_LENGTH(text);
1462
PGFT_char *data = PGFT_String_GET_DATA(text);
1463
PyObject *list, *item;
1471
if (!_PGFT_GetFontSized(font->freetype, font, render->face_size)) {
1472
PyErr_SetString(PyExc_SDLError, _PGFT_GetError(font->freetype));
1475
list = PyList_New(length);
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) {
1488
item = Py_BuildValue("lllldd", minx, maxx, miny, maxy,
1489
advance_x, advance_y);
1500
PyList_SET_ITEM(list, i, item);
1507
_ftfont_getmetrics(PgFontObject *self, PyObject *args, PyObject *kwds)
1510
static char *kwlist[] = {
1514
FontRenderMode render;
1519
PGFT_String *text = 0;
1520
Scale_t face_size = FACE_SIZE_NONE;
1523
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&", kwlist, &textobj,
1524
obj_to_scale, (void *)&face_size))
1528
text = _PGFT_EncodePyString(textobj,
1529
self->render_flags & FT_RFLAG_UCS4);
1530
if (!text) goto error;
1532
ASSERT_SELF_IS_ALIVE(self);
1535
* Build the render mode with the given size and no
1536
* rotation/styles/vertical text
1538
if (_PGFT_BuildRenderMode(self->freetype, self, &render,
1539
face_size, FT_STYLE_NORMAL, 0)) goto error;
1542
list = get_metrics(&render, self, text);
1543
if (!list) goto error;
1555
_ftfont_getsizedascender(PgFontObject *self, PyObject *args)
1557
Scale_t face_size = FACE_SIZE_NONE;
1560
if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
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");
1572
face_size = self->face_size;
1574
value = (long)_PGFT_Font_GetAscenderSized(self->freetype, self, face_size);
1575
if (!value && PyErr_Occurred()) {
1578
return PyInt_FromLong(value);
1582
_ftfont_getsizeddescender(PgFontObject *self, PyObject *args)
1584
Scale_t face_size = FACE_SIZE_NONE;
1587
if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
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");
1599
face_size = self->face_size;
1601
value = (long)_PGFT_Font_GetDescenderSized(self->freetype, self, face_size);
1602
if (!value && PyErr_Occurred()) {
1605
return PyInt_FromLong(value);
1609
_ftfont_getsizedheight(PgFontObject *self, PyObject *args)
1611
Scale_t face_size = FACE_SIZE_NONE;
1614
if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
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");
1626
face_size = self->face_size;
1628
value = _PGFT_Font_GetHeightSized(self->freetype, self, face_size);
1629
if (!value && PyErr_Occurred()) {
1632
return PyInt_FromLong(value);
1636
_ftfont_getsizedglyphheight(PgFontObject *self, PyObject *args)
1638
Scale_t face_size = FACE_SIZE_NONE;
1641
if (!PyArg_ParseTuple(args, "|O&", obj_to_scale, (void *)&face_size)) {
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");
1653
face_size = self->face_size;
1655
value = (long)_PGFT_Font_GetGlyphHeightSized(self->freetype, self,
1657
if (!value && PyErr_Occurred()) {
1660
return PyInt_FromLong(value);
1664
_ftfont_getsizes(PgFontObject *self)
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;
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,
1683
if (rc < 0) goto error;
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);
1693
Py_XDECREF(size_list);
1698
_ftfont_render_raw(PgFontObject *self, PyObject *args, PyObject *kwds)
1701
static char *kwlist[] = {
1702
"text", "style", "rotation", "size", "invert", 0
1705
FontRenderMode mode;
1707
/* input arguments */
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;
1715
/* output arguments */
1716
PyObject *rbuffer = 0;
1717
PyObject *rtuple = 0;
1720
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O&i", kwlist,
1723
obj_to_rotation, (void *)&rotation,
1724
obj_to_scale, (void *)&face_size,
1729
if (textobj != Py_None) {
1730
text = _PGFT_EncodePyString(textobj,
1731
self->render_flags & FT_RFLAG_UCS4);
1732
if (!text) goto error;
1735
ASSERT_SELF_IS_ALIVE(self);
1738
* Build the render mode with the given size and no
1739
* rotation/styles/vertical text
1741
if (_PGFT_BuildRenderMode(self->freetype, self,
1742
&mode, face_size, style, rotation))
1745
rbuffer = _PGFT_Render_PixelArray(self->freetype, self,
1746
&mode, text, invert,
1748
if (!rbuffer) goto error;
1750
rtuple = Py_BuildValue("O(ii)", rbuffer, width, height);
1751
if (!rtuple) goto error;
1758
Py_XDECREF(rbuffer);
1764
_ftfont_render_raw_to(PgFontObject *self, PyObject *args, PyObject *kwds)
1767
static char *kwlist[] = {
1768
"array", "text", "dest", "style", "rotation", "size", "invert", 0
1771
FontRenderMode mode;
1773
/* input arguments */
1776
PGFT_String *text = 0;
1780
int style = FT_STYLE_DEFAULT;
1781
Angle_t rotation = self->rotation;
1782
Scale_t face_size = FACE_SIZE_NONE;
1785
/* output arguments */
1788
ASSERT_SELF_IS_ALIVE(self);
1790
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OiO&O&i", kwlist,
1791
&arrayobj, &textobj,
1793
obj_to_rotation, (void *)&rotation,
1794
obj_to_scale, (void *)&face_size,
1798
if (dest && dest != Py_None) {
1799
if (parse_dest(dest, &xpos, &ypos)) goto error;
1803
if (textobj != Py_None) {
1804
text = _PGFT_EncodePyString(textobj,
1805
self->render_flags & FT_RFLAG_UCS4);
1806
if (!text) goto error;
1810
* Build the render mode with the given size and no
1811
* rotation/styles/vertical text
1813
if (_PGFT_BuildRenderMode(self->freetype, self,
1814
&mode, face_size, style, rotation))
1817
if (_PGFT_Render_Array(self->freetype, self, &mode,
1818
arrayobj, text, invert, xpos, ypos, &r)) goto error;
1821
return PyRect_New(&r);
1829
_ftfont_render(PgFontObject *self, PyObject *args, PyObject *kwds)
1831
#ifndef HAVE_PYGAME_SDL_VIDEO
1833
PyErr_SetString(PyExc_RuntimeError,
1834
"SDL support is missing. Cannot render on surfonts");
1839
static char *kwlist[] = {
1840
"text", "fgcolor", "bgcolor", "style", "rotation", "size", 0
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;
1852
/* output arguments */
1853
SDL_Surface *surface = 0;
1854
PyObject *surface_obj = 0;
1855
PyObject *rtuple = 0;
1857
PyObject *rect_obj = 0;
1861
FontRenderMode render;
1863
ASSERT_SELF_IS_ALIVE(self);
1865
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOiO&O&", kwlist,
1869
&fg_color_obj, &bg_color_obj, &style,
1870
obj_to_rotation, (void *)&rotation,
1871
obj_to_scale, (void *)&face_size))
1874
if (fg_color_obj == Py_None) {
1877
if (bg_color_obj == Py_None) {
1882
if (!RGBAFromColorObj(fg_color_obj, (Uint8 *)&fg_color)) {
1883
PyErr_SetString(PyExc_TypeError, "fgcolor must be a Color");
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];
1894
if (!RGBAFromColorObj(bg_color_obj, (Uint8 *)&bg_color)) {
1895
PyErr_SetString(PyExc_TypeError, "bgcolor must be a Color");
1901
if (textobj != Py_None) {
1902
text = _PGFT_EncodePyString(textobj,
1903
self->render_flags & FT_RFLAG_UCS4);
1904
if (!text) goto error;
1907
if (_PGFT_BuildRenderMode(self->freetype, self,
1908
&render, face_size, style, rotation))
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;
1916
surface_obj = PySurface_New(surface);
1917
if (!surface_obj) goto error;
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);
1931
Py_DECREF(surface_obj);
1934
SDL_FreeSurface(surface);
1936
Py_XDECREF(rect_obj);
1940
#endif // HAVE_PYGAME_SDL_VIDEO
1944
_ftfont_render_to(PgFontObject *self, PyObject *args, PyObject *kwds)
1946
#ifndef HAVE_PYGAME_SDL_VIDEO
1948
PyErr_SetString(PyExc_RuntimeError,
1949
"SDL support is missing. Cannot render on surfaces");
1954
static char *kwlist[] = {
1955
"surf", "dest", "text", "fgcolor", "bgcolor",
1956
"style", "rotation", "size", 0
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;
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;
1973
/* output arguments */
1978
FontRenderMode render;
1980
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!OO|OOiO&O&", kwlist,
1982
&PySurface_Type, &surface_obj, &dest,
1983
&textobj, &fg_color_obj,
1985
&bg_color_obj, &style,
1986
obj_to_rotation, (void *)&rotation,
1987
obj_to_scale, (void *)&face_size))
1990
if (fg_color_obj == Py_None) {
1993
if (bg_color_obj == Py_None) {
1997
if (parse_dest(dest, &xpos, &ypos)) goto error;
1999
if (!RGBAFromColorObj(fg_color_obj, (Uint8 *)&fg_color)) {
2000
PyErr_SetString(PyExc_TypeError, "fgcolor must be a Color");
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];
2011
if (!RGBAFromColorObj(bg_color_obj, (Uint8 *)&bg_color)) {
2012
PyErr_SetString(PyExc_TypeError, "bgcolor must be a Color");
2017
ASSERT_SELF_IS_ALIVE(self);
2020
if (textobj != Py_None) {
2021
text = _PGFT_EncodePyString(textobj,
2022
self->render_flags & FT_RFLAG_UCS4);
2023
if (!text) goto error;
2026
if (_PGFT_BuildRenderMode(self->freetype, self,
2027
&render, face_size, style, rotation))
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))
2038
return PyRect_New(&r);
2043
#endif // HAVE_PYGAME_SDL_VIDEO
2046
/****************************************************
2048
****************************************************/
2050
PgFont_New(const char *filename, long font_index)
2054
FreeTypeInstance *ft;
2055
ASSERT_GRAB_FREETYPE(ft, 0);
2061
font = (PgFontObject *)PgFont_Type.tp_new(
2062
&PgFont_Type, 0, 0);
2068
if (_PGFT_TryLoadFont_Filename(ft, font, filename, font_index)) {
2072
return (PyObject *) font;
2076
/****************************************************
2077
* FREETYPE MODULE METHODS
2078
****************************************************/
2080
/***************************************************************
2082
* Bindings for initialization/cleanup functions
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
2089
* TODO: These bindings can be removed once proper threading
2090
* support is in place.
2092
***************************************************************/
2095
_ft_autoinit(PyObject *self)
2097
int cache_size = FREETYPE_MOD_STATE(self)->cache_size;
2098
FT_Error result = 1;
2100
if (!FREETYPE_MOD_STATE(self)->freetype) {
2101
PyGame_RegisterQuit(_ft_autoquit);
2103
if (cache_size == 0) {
2104
cache_size = PGFT_DEFAULT_CACHE_SIZE;
2106
if (_PGFT_Init(&(FREETYPE_MOD_STATE(self)->freetype), cache_size)) {
2109
FREETYPE_MOD_STATE(self)->cache_size = cache_size;
2112
return PyInt_FromLong(result);
2118
_FreeTypeState *state = FREETYPE_STATE;
2120
if (state->freetype) {
2121
_PGFT_Quit(state->freetype);
2122
state->cache_size = 0;
2123
state->freetype = 0;
2128
_ft_quit(PyObject *self)
2135
_ft_init(PyObject *self, PyObject *args, PyObject *kwds)
2137
static char *kwlist[] = {
2138
"cache_size", "resolution", 0
2142
unsigned cache_size = 0;
2143
unsigned resolution = 0;
2144
_FreeTypeState *state = FREETYPE_MOD_STATE(self);
2146
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|II", kwlist,
2147
&cache_size, &resolution)) {
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);
2159
PyErr_SetString(PyExc_RuntimeError,
2160
"Failed to initialize the FreeType2 library");
2171
_ft_get_error(PyObject *self)
2173
FreeTypeInstance *ft;
2174
ASSERT_GRAB_FREETYPE(ft, 0);
2176
if (ft->_error_msg[0]) {
2177
return Text_FromUTF8(ft->_error_msg);
2184
_ft_get_version(PyObject *self)
2186
/* Return the linked FreeType2 version */
2187
return Py_BuildValue("iii", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
2191
_ft_get_cache_size(PyObject *self)
2193
return PyLong_FromUnsignedLong((unsigned long)(FREETYPE_STATE->cache_size));
2197
_ft_get_default_resolution(PyObject *self)
2199
return PyLong_FromUnsignedLong((unsigned long)(FREETYPE_STATE->resolution));
2203
_ft_set_default_resolution(PyObject *self, PyObject *args)
2205
unsigned resolution = 0;
2206
_FreeTypeState *state = FREETYPE_MOD_STATE(self);
2208
if (!PyArg_ParseTuple(args, "|I", &resolution)) {
2212
state->resolution = (resolution ?
2213
(FT_UInt)resolution : PGFT_DEFAULT_RESOLUTION);
2218
_ft_was_init(PyObject *self)
2220
return PyBool_FromLong(FREETYPE_MOD_STATE(self)->freetype ? 1 : 0);
2224
_ft_get_default_font(PyObject* self)
2226
return Text_FromUTF8(DEFAULT_FONT_NAME);
2231
_ft_traverse (PyObject *mod, visitproc visit, void *arg)
2237
_ft_clear (PyObject *mod)
2239
if (FREETYPE_MOD_STATE(mod)->freetype) {
2240
_PGFT_Quit(FREETYPE_MOD_STATE(mod)->freetype);
2241
FREETYPE_MOD_STATE(mod)->freetype = 0;
2249
/****************************************************
2250
* FREETYPE MODULE DECLARATION
2251
****************************************************/
2253
struct PyModuleDef _freetypemodule =
2255
PyModuleDef_HEAD_INIT,
2258
sizeof(_FreeTypeState),
2266
_FreeTypeState _modstate;
2269
MODINIT_DEFINE (_freetype)
2271
PyObject *module, *apiobj;
2272
static void* c_api[PYGAMEAPI_FREETYPE_NUMSLOTS];
2274
import_pygame_base();
2275
if (PyErr_Occurred()) {
2279
import_pygame_surface();
2280
if (PyErr_Occurred()) {
2284
import_pygame_color();
2285
if (PyErr_Occurred()) {
2289
import_pygame_rwobject();
2290
if (PyErr_Occurred()) {
2294
import_pygame_rect();
2295
if (PyErr_Occurred()) {
2299
/* type preparation */
2300
if (PyType_Ready(&PgFont_Type) < 0) {
2305
module = PyModule_Create(&_freetypemodule);
2308
module = Py_InitModule3(MODULE_NAME, _ft_methods, DOC_PYGAMEFREETYPE);
2315
FREETYPE_MOD_STATE(module)->freetype = 0;
2316
FREETYPE_MOD_STATE(module)->cache_size = 0;
2317
FREETYPE_MOD_STATE(module)->resolution = PGFT_DEFAULT_RESOLUTION;
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);
2327
# define DEC_CONST(x) PyModule_AddIntConstant(module, #x, (int)FT_##x)
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);
2336
DEC_CONST(BBOX_EXACT);
2337
DEC_CONST(BBOX_EXACT_GRIDFIT);
2338
DEC_CONST(BBOX_PIXEL);
2339
DEC_CONST(BBOX_PIXEL_GRIDFIT);
2341
/* export the c api */
2342
# if PYGAMEAPI_FREETYPE_NUMSLOTS != 2
2343
# error Mismatch between number of api slots and actual exports.
2345
c_api[0] = &PgFont_Type;
2346
c_api[1] = &PgFont_New;
2348
apiobj = encapsulate_api(c_api, "freetype");
2354
if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj) == -1) {
2360
MODINIT_RETURN(module);