Commits

tanoku  committed 72f5e6e

Created branch for FreeType Module backport.

  • Participants
  • Parent commits f1f7ecf
  • Branches pygame-ftmod

Comments (0)

Files changed (16)

 SCRAP = -lX11
 PORTMIDI = -lportmidi
 PORTTIME = -lporttime
+FREETYPE = -lfreetype 
 #--EndConfig
 
-#DEBUG = -C-W -C-Wall
 DEBUG = 
 
 #the following modules are optional. you will want to compile
 #GFX = src/SDL_gfx/SDL_gfxBlitFunc.c src/SDL_gfx/SDL_gfxPrimitives.c 
 gfxdraw src/gfxdraw.c $(SDL) $(GFX) $(DEBUG)
 
-
+freetype    src/freetype/ft_cache.c \
+            src/freetype/ft_metrics.c \
+            src/freetype/ft_wrap.c \
+            src/freetype/ft_render.c \
+            src/freetype/ft_render_cb.c \
+            src/freetype/ft_text.c \
+            src/freetype/freetype.c \
+            $(SDL) $(FREETYPE) $(DEBUG)
 
 #these modules are required for pygame to run. they only require
 #SDL as a dependency. these should not be altered

File config_unix.py

     return 1
 
 class DependencyProg:
-    def __init__(self, name, envname, exename, minver, defaultlibs):
+    def __init__(self, name, envname, exename, minver, defaultlibs, version_flag="--version"):
         self.name = name
         command = os.environ.get(envname, exename)
         self.lib_dir = ''
         self.libs = []
         self.cflags = ''
         try:
-            config = os.popen(command + ' --version --cflags --libs').readlines()
+            config = os.popen(command + ' ' + version_flag + ' --cflags --libs').readlines()
             flags = ' '.join(config[1:]).split()
 
             # remove this GNU_SOURCE if there... since python has it already,
         Dependency('SCRAP', '', 'libX11', ['X11']),
         Dependency('PORTMIDI', 'portmidi.h', 'libportmidi.so', ['portmidi']),
         Dependency('PORTTIME', 'porttime.h', 'libporttime.so', ['porttime']),
+        DependencyProg('FREETYPE', 'FREETYPE_CONFIG', 'freetype-config', '2.0', ['freetype'], '--ftversion')
         #Dependency('GFX', 'SDL_gfxPrimitives.h', 'libSDL_gfx.so', ['SDL_gfx']),
     ]
     if not DEPS[0].found:

File src/freetype/freetype.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2009 Vicent Marti
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#define PYGAME_FREETYPE_INTERNAL
+#define PYGAME_FREETYPE_FONT_INTERNAL
+
+#include "ft_wrap.h"
+#include "pgfreetype.h"
+
+/*
+ * Auxiliar defines
+ */
+#define PGFT_CHECK_BOOL(_pyobj, _var)               \
+    if (_pyobj)                                     \
+    {                                               \
+        if (!PyBool_Check(_pyobj))                  \
+        {                                           \
+            PyErr_SetString(PyExc_TypeError,        \
+                #_var " must be a boolean value");  \
+            return NULL;                            \
+        }                                           \
+                                                    \
+        _var = PyObject_IsTrue(_pyobj);             \
+    }
+
+#define DEFAULT_FONT_NAME   "freesansbold.ttf"
+#define PKGDATA_MODULE_NAME "pygame.pkgdata"
+#define RESOURCE_FUNC_NAME  "getResource"
+
+static PyObject*
+load_font_res(const char *filename)
+{
+    PyObject *load_basicfunc = NULL;
+    PyObject *pkgdatamodule = NULL;
+    PyObject *resourcefunc = NULL;
+    PyObject *result = NULL;
+    PyObject *tmp;
+
+    pkgdatamodule = PyImport_ImportModule(PKGDATA_MODULE_NAME);
+    if (!pkgdatamodule)
+        goto font_resource_end;
+
+    resourcefunc = PyObject_GetAttrString(pkgdatamodule, RESOURCE_FUNC_NAME);
+    if (!resourcefunc)
+        goto font_resource_end;
+
+    result = PyObject_CallFunction(resourcefunc, "s", filename);
+    if (!result)
+        goto font_resource_end;
+
+#if PY3
+    tmp = PyObject_GetAttrString(result, "name");
+    if (tmp != NULL)
+    {
+        Py_DECREF(result);
+        result = tmp;
+    }
+    else 
+    {
+        PyErr_Clear();
+    }
+#else
+    if (PyFile_Check(result))
+    {		
+        tmp = PyFile_Name(result);        
+        Py_INCREF(tmp);
+        Py_DECREF(result);
+        result = tmp;
+    }
+#endif
+
+font_resource_end:
+    Py_XDECREF(pkgdatamodule);
+    Py_XDECREF(resourcefunc);
+    Py_XDECREF(load_basicfunc);
+    return result;
+}
+
+/*
+ * FreeType module declarations
+ */
+static int _ft_traverse (PyObject *mod, visitproc visit, void *arg);
+static int _ft_clear (PyObject *mod);
+
+static PyObject *_ft_quit(PyObject *self);
+static PyObject *_ft_init(PyObject *self, PyObject *args);
+static PyObject *_ft_get_version(PyObject *self);
+static PyObject *_ft_get_error(PyObject *self);
+static PyObject *_ft_was_init(PyObject *self);
+
+/*
+ * Constructor/init/destructor
+ */
+static void _ftfont_dealloc(PyFreeTypeFont *self);
+static PyObject *_ftfont_repr(PyObject *self);
+static int _ftfont_init(PyObject *self, PyObject *args, PyObject *kwds);
+
+/*
+ * Main methods
+ */
+static PyObject* _ftfont_getsize(PyObject *self, PyObject* args, PyObject *kwds);
+static PyObject* _ftfont_getmetrics(PyObject *self, PyObject* args, PyObject *kwds);
+static PyObject* _ftfont_render(PyObject *self, PyObject* args, PyObject *kwds);
+static PyObject* _ftfont_render_raw(PyObject *self, PyObject* args, PyObject *kwds);
+
+/* static PyObject* _ftfont_copy(PyObject *self); */
+
+/*
+ * Getters/setters
+ */
+static PyObject* _ftfont_getstyle(PyObject *self, void *closure);
+static int _ftfont_setstyle(PyObject *self, PyObject *value, void *closure);
+static PyObject* _ftfont_getheight(PyObject *self, void *closure);
+static PyObject* _ftfont_getname(PyObject *self, void *closure);
+static PyObject* _ftfont_getfixedwidth(PyObject *self, void *closure);
+
+/*
+ * FREETYPE MODULE METHODS TABLE
+ */
+static PyMethodDef _ft_methods[] = 
+{
+    { 
+        "init", 
+        (PyCFunction) _ft_init, 
+        METH_VARARGS, 
+        "TODO"
+    },
+    { 
+        "quit", 
+        (PyCFunction) _ft_quit, 
+        METH_NOARGS, 
+        "TODO"
+    },
+    { 
+        "was_init", 
+        (PyCFunction) _ft_was_init, 
+        METH_NOARGS, 
+        "TODO"
+    },
+    { 
+        "get_error", 
+        (PyCFunction) _ft_get_error, 
+        METH_NOARGS,
+        "TODO"
+    },
+    { 
+        "get_version", 
+        (PyCFunction) _ft_get_version, 
+        METH_NOARGS,
+        "TODO"
+    },
+    { NULL, NULL, 0, NULL },
+};
+
+
+/*
+ * FREETYPE FONT METHODS TABLE
+ */
+static PyMethodDef _ftfont_methods[] = 
+{
+    {
+        "get_size", 
+        (PyCFunction) _ftfont_getsize,
+        METH_VARARGS | METH_KEYWORDS,
+        "TODO" 
+    },
+    {
+        "get_metrics", 
+        (PyCFunction) _ftfont_getmetrics,
+        METH_VARARGS | METH_KEYWORDS,
+        "TODO" 
+    },
+    { 
+        "render", 
+        (PyCFunction)_ftfont_render, 
+        METH_VARARGS | METH_KEYWORDS,
+        "TODO" 
+    },
+    { 
+        "render_raw", 
+        (PyCFunction)_ftfont_render_raw, 
+        METH_VARARGS | METH_KEYWORDS,
+        "TODO"
+    },
+    { NULL, NULL, 0, NULL }
+};
+
+/*
+ * FREETYPE FONT GETTERS/SETTERS TABLE
+ */
+static PyGetSetDef _ftfont_getsets[] = 
+{
+    { 
+        "style",    
+        _ftfont_getstyle,   
+        _ftfont_setstyle, 
+        "TODO",
+        NULL 
+    },
+    { 
+        "height",
+        _ftfont_getheight,  
+        NULL,
+        "TODO",   
+        NULL
+    },
+    { 
+        "name", 
+        _ftfont_getname, 
+        NULL,
+        "TODO", 
+        NULL 
+    },
+    {
+        "fixed_width",
+        _ftfont_getfixedwidth,
+        NULL,
+        "TODO",
+        NULL
+    },
+    { NULL, NULL, NULL, NULL, NULL }
+};
+
+/*
+ * FREETYPE FONT BASE TYPE TABLE
+ */
+PyTypeObject PyFreeTypeFont_Type =
+{
+    TYPE_HEAD(NULL,0)
+    "freetype.Font",            /* tp_name */
+    sizeof (PyFreeTypeFont),    /* tp_basicsize */
+    0,                          /* tp_itemsize */
+    (destructor)_ftfont_dealloc,/* tp_dealloc */
+    0,                          /* tp_print */
+    0,                          /* tp_getattr */
+    0,                          /* tp_setattr */
+    0,                          /* tp_compare */
+    (reprfunc)_ftfont_repr,     /* tp_repr */
+    0,                          /* tp_as_number */
+    0,                          /* tp_as_sequence */
+    0,                          /* tp_as_mapping */
+    0,                          /* tp_hash */
+    0,                          /* tp_call */
+    0,                          /* tp_str */
+    0,                          /* tp_getattro */
+    0,                          /* tp_setattro */
+    0,                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+    "TODO",                     /* docstring */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    _ftfont_methods,            /* tp_methods */
+    0,                          /* tp_members */
+    _ftfont_getsets,            /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    (initproc) _ftfont_init,    /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+    0,                          /* tp_del */
+#if PY_VERSION_HEX >= 0x02060000
+    0                           /* tp_version_tag */
+#endif
+};
+
+
+
+/****************************************************
+ * CONSTRUCTOR/INIT/DESTRUCTOR
+ ****************************************************/
+static void
+_ftfont_dealloc(PyFreeTypeFont *self)
+{
+    /* Always try to unload the font even if we cannot grab
+     * a freetype instance. */
+    PGFT_UnloadFont(FREETYPE_STATE->freetype, self);
+
+    ((PyObject*)self)->ob_type->tp_free((PyObject *)self);
+}
+
+static int
+_ftfont_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = 
+    { 
+        "font", "ptsize", "style", "face_index", NULL
+    };
+
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    
+    PyObject *file, *original_file;
+    int face_index = 0;
+    int ptsize = -1;
+    int font_style = FT_STYLE_NORMAL;
+
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, -1);
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iii", kwlist, 
+                &file, &ptsize, &font_style, &face_index))
+        return -1;
+
+    original_file = file;
+
+    if (face_index < 0)
+    {
+        PyErr_SetString(PyExc_ValueError, "Face index cannot be negative");
+        goto end;
+    }
+
+    font->default_ptsize = (ptsize <= 0) ? -1 : ptsize;
+    font->default_style = font_style;
+
+    if (file == Py_None)
+    {
+        file = load_font_res(DEFAULT_FONT_NAME);
+
+        if (file == NULL)
+        {
+            PyErr_SetString(PyExc_RuntimeError, "Failed to find default font");
+            goto end;
+        }
+    }
+
+    if (PyUnicode_Check(file)) 
+    {
+        file = PyUnicode_AsASCIIString(file);
+
+        if (file == NULL)
+        {
+            PyErr_SetString(PyExc_ValueError, "Failed to decode filename");
+            goto end;
+        }
+    }
+
+    if (Bytes_Check(file))
+    {
+        char *filename;
+        filename = Bytes_AsString(file);
+
+        if (filename == NULL)
+        {
+            PyErr_SetString(PyExc_ValueError, "Failed to decode filename");
+            goto end;
+        }
+
+        if (PGFT_TryLoadFont_Filename(ft, font, filename, face_index) != 0)
+        {
+            PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+            goto end;
+        }
+    }
+    else
+    {
+        SDL_RWops *source;
+        source = RWopsFromPython(file);
+
+        if (source == NULL)
+        {
+            PyErr_SetString(PyExc_ValueError, 
+                    "Invalid 'file' parameter (must be a File object or a file name)");
+            goto end;
+        }
+
+        if (PGFT_TryLoadFont_RWops(ft, font, source, 0, face_index) != 0);
+        {
+            PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+            goto end;
+        }
+
+        Py_INCREF(file);
+        Py_INCREF(file);
+        Py_INCREF(file);
+        Py_INCREF(file);
+        return 0;
+    }
+
+end:
+    if (file != original_file)
+        Py_XDECREF(file);
+
+    return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject*
+_ftfont_repr(PyObject *self)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    return Text_FromFormat("Font('%s')", font->id.open_args.pathname);
+}
+
+
+/****************************************************
+ * GETTERS/SETTERS
+ ****************************************************/
+static PyObject*
+_ftfont_getstyle (PyObject *self, void *closure)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+
+    return PyInt_FromLong(font->default_style);
+}
+
+static int
+_ftfont_setstyle(PyObject *self, PyObject *value, void *closure)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    FT_UInt32 style;
+
+    if (!PyInt_Check(value))
+    {
+        PyErr_SetString(PyExc_TypeError, 
+                "The style value must be an integer"
+                " from the FT constants module");
+        return -1;
+    }
+
+    style = (FT_UInt32)PyInt_AsLong(value);
+
+    if (PGFT_CheckStyle(style) != 0)
+    {
+        PyErr_SetString(PyExc_ValueError, "Invalid style value");
+        return -1;
+    }
+
+    font->default_style = style;
+    return 0;
+}
+
+static PyObject*
+_ftfont_getheight(PyObject *self, void *closure)
+{
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    return PyInt_FromLong(PGFT_Face_GetHeight(ft, (PyFreeTypeFont *)self));
+}
+
+static PyObject*
+_ftfont_getname(PyObject *self, void *closure)
+{
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    return Text_FromUTF8(PGFT_Face_GetName(ft, (PyFreeTypeFont *)self));
+}
+
+static PyObject*
+_ftfont_getfixedwidth(PyObject *self, void *closure)
+{
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    return PyBool_FromLong(PGFT_Face_IsFixedWidth(ft, (PyFreeTypeFont *)self));
+}
+
+
+
+/****************************************************
+ * MAIN METHODS
+ ****************************************************/
+static PyObject*
+_ftfont_getsize(PyObject *self, PyObject* args, PyObject *kwds)
+{
+    /* keyword list */
+    static char *kwlist[] = 
+    { 
+        "text", "style", "vertical", "rotation", "ptsize", NULL
+    };
+
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    PyObject *text, *rtuple = NULL;
+    FT_Error error;
+    int ptsize = -1;
+    int width, height;
+
+    FontRenderMode render;
+    int vertical = 0;
+    int rotation = 0;
+    int style = 0;
+
+    PyObject *vertical_obj = NULL;
+
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iOii", kwlist, 
+                &text, &style, &vertical_obj, &rotation, &ptsize))
+        return NULL;
+
+    PGFT_CHECK_BOOL(vertical_obj, vertical);
+
+    /* Build rendering mode, always anti-aliased by default */
+    if (PGFT_BuildRenderMode(ft, font, 
+            &render, ptsize, style, vertical, 1, rotation) != 0)
+    {
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+        return NULL;
+    }
+
+    error = PGFT_GetTextSize(ft, font, &render,text, &width, &height);
+
+    if (error)
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+    else
+        rtuple = Py_BuildValue ("(ii)", width, height);
+
+    return rtuple;
+}
+
+static PyObject *
+_ftfont_getmetrics(PyObject *self, PyObject* args, PyObject *kwds)
+{
+    /* keyword list */
+    static char *kwlist[] = 
+    { 
+        "text", "ptsize", "bbmode", NULL
+    };
+
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    FontRenderMode render;
+
+    /* aux vars */
+    void *buf = NULL;
+    int char_id, length, i, isunicode = 0;
+
+    /* arguments */
+    PyObject *text, *list;
+    int ptsize = -1;
+    int bbmode = FT_BBOX_PIXEL_GRIDFIT;
+
+    /* grab freetype */
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    /* parse args */
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ii", kwlist,
+                &text, &ptsize, &bbmode))
+        return NULL;
+
+    /*
+     * Build the render mode with the given size and no
+     * rotation/styles/vertical text
+     */
+    if (PGFT_BuildRenderMode(ft, font, 
+                &render, ptsize, FT_STYLE_NORMAL, 0, 1, 0) != 0)
+    {
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+        return NULL;
+    }
+
+    /* check text */
+    if (PyUnicode_Check(text))
+    {
+        buf = PyUnicode_AsUnicode(text);
+        isunicode = 1;
+    }
+    else if (Bytes_Check(text))
+    {
+        buf = Bytes_AS_STRING(text);
+    }
+    else
+    {
+        PyErr_SetString(PyExc_TypeError,
+            "argument must be a string or unicode");
+    }
+
+    if (!buf)
+        return NULL;
+
+    if (isunicode)
+        length = PyUnicode_GetSize(text);
+    else
+        length = Bytes_Size(text);
+
+#define _GET_METRICS(_mt, _tuple_format) {              \
+    for (i = 0; i < length; i++)                        \
+    {                                                   \
+        _mt minx_##_mt, miny_##_mt;                     \
+        _mt maxx_##_mt, maxy_##_mt;                     \
+        _mt advance_##_mt;                              \
+                                                        \
+        if (isunicode) char_id = ((Py_UNICODE *)buf)[i];\
+        else char_id = ((char *)buf)[i];                \
+                                                        \
+        if (PGFT_GetMetrics(ft,                         \
+                (PyFreeTypeFont *)self, char_id,        \
+                &render, bbmode,                        \
+                &minx_##_mt, &maxx_##_mt,               \
+                &miny_##_mt, &maxy_##_mt,               \
+                &advance_##_mt) == 0)                   \
+        {                                               \
+            PyList_SetItem (list, i,                    \
+                    Py_BuildValue(_tuple_format,        \
+                        minx_##_mt, maxx_##_mt,         \
+                        miny_##_mt, maxy_##_mt,         \
+                        advance_##_mt));                \
+        }                                               \
+        else                                            \
+        {                                               \
+            Py_INCREF (Py_None);                        \
+            PyList_SetItem (list, i, Py_None);          \
+        }                                               \
+    }}
+
+    /* get metrics */
+    if (bbmode == FT_BBOX_EXACT || bbmode == FT_BBOX_EXACT_GRIDFIT)
+    {
+        list = PyList_New(length);
+        _GET_METRICS(float, "(fffff)");
+    }
+    else if (bbmode == FT_BBOX_PIXEL || bbmode == FT_BBOX_PIXEL_GRIDFIT)
+    {
+        list = PyList_New(length);
+        _GET_METRICS(int, "(iiiii)");
+    }
+    else
+    {
+        PyErr_SetString(PyExc_ValueError, "Invalid bbox mode specified");
+        return NULL;
+    }
+
+#undef _GET_METRICS
+
+    return list;
+}
+
+static PyObject*
+_ftfont_render_raw(PyObject *self, PyObject* args, PyObject *kwds)
+{
+    /* keyword list */
+    static char *kwlist[] = 
+    { 
+        "text", "ptsize", NULL
+    };
+
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    FontRenderMode render;
+
+    /* input arguments */
+    PyObject *text = NULL;
+    int ptsize = -1;
+
+    /* output arguments */
+    PyObject *rbuffer = NULL;
+    int width, height;
+
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &text, &ptsize))
+        return NULL;
+
+    /*
+     * Build the render mode with the given size and no
+     * rotation/styles/vertical text
+     */
+    if (PGFT_BuildRenderMode(ft, font, 
+                &render, ptsize, FT_STYLE_NORMAL, 0, 1, 0) != 0)
+    {
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+        return NULL;
+    }
+
+    rbuffer = PGFT_Render_PixelArray(ft, font, &render, text, &width, &height);
+
+    if (!rbuffer)
+    {
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+        return NULL;
+    }
+
+    return Py_BuildValue("(iiO)", width, height, rbuffer);
+}
+
+static PyObject*
+_ftfont_render(PyObject *self, PyObject* args, PyObject *kwds)
+{
+#ifndef HAVE_PYGAME_SDL_VIDEO
+
+    PyErr_SetString(PyExc_RuntimeError, "SDL support is missing. Cannot render on surfaces");
+    return NULL;
+
+#else
+    /* keyword list */
+    static char *kwlist[] = 
+    { 
+        "text", "fgcolor", "bgcolor", "dstsurface", 
+        "xpos", "ypos", "style", "vertical", "rotation", "antialias", "ptsize", NULL
+    };
+
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+
+    /* input arguments */
+    PyObject *text = NULL;
+    int ptsize = -1;
+    PyObject *target_surf = NULL;
+    PyObject *fg_color_obj = NULL;
+    PyObject *bg_color_obj = NULL;
+    PyObject *vertical_obj = NULL;
+    PyObject *antialias_obj = NULL;
+    int rotation = 0;
+    int xpos = 0, ypos = 0;
+    int style = FT_STYLE_DEFAULT;
+
+    /* output arguments */
+    PyObject *rtuple = NULL;
+    int width, height;
+
+    FontColor fg_color, bg_color;
+    FontRenderMode render;
+    int vertical = 0;
+    int antialias = 1;
+
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOiiiOiOi", kwlist,
+                &text, &fg_color_obj, &bg_color_obj, &target_surf, &xpos, &ypos, 
+                &style, &vertical_obj, &rotation, &antialias_obj, &ptsize))
+        return NULL;
+
+    if (!RGBAFromColorObj(fg_color_obj, (Uint8 *)&fg_color))
+    {
+        PyErr_SetString(PyExc_TypeError, "fgcolor must be a Color");
+        return NULL;
+    }
+
+    if (bg_color_obj)
+    {
+        if (bg_color_obj == Py_None)
+            bg_color_obj = NULL;
+        
+        else if (!RGBAFromColorObj(bg_color_obj, (Uint8 *)&bg_color))
+        {
+            PyErr_SetString(PyExc_TypeError, "bgcolor must be a Color");
+            return NULL;
+        }
+    }
+
+    PGFT_CHECK_BOOL(vertical_obj, vertical);
+    PGFT_CHECK_BOOL(antialias_obj, antialias);
+
+    if (PGFT_BuildRenderMode(ft, font, 
+                &render, ptsize, style, vertical, antialias, rotation) != 0)
+    {
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+        return NULL;
+    }
+
+    if (!target_surf || target_surf == Py_None)
+    {
+        SDL_Surface *r_surface = NULL;
+
+        r_surface = PGFT_Render_NewSurface(ft, font, &render, text,
+                &fg_color, bg_color_obj ? &bg_color : NULL, 
+                &width, &height);
+
+        if (!r_surface)
+        {
+            PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+            return NULL;
+        }
+
+        rtuple = Py_BuildValue("(iiO)", width, height, 
+                PySurface_New(r_surface));
+    }
+    else if (PySurface_Check(target_surf))
+    {
+        SDL_Surface *surface = NULL;
+        surface = PySurface_AsSurface(target_surf);
+
+        if (PGFT_Render_ExistingSurface(ft, font, &render, 
+                text, surface, xpos, ypos, 
+                &fg_color, bg_color_obj ? &bg_color : NULL,
+                &width, &height) != 0)
+        {
+            PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+            return NULL;
+        }
+
+        Py_INCREF(target_surf); 
+        rtuple = Py_BuildValue("(iiO)", width, height, target_surf);
+    }
+    else
+    {
+        PyErr_SetString(PyExc_TypeError, 
+                "The given target is not a valid SDL surface");
+        return NULL;
+    }
+
+    return rtuple;
+
+#endif // HAVE_PYGAME_SDL_VIDEO
+}
+
+/****************************************************
+ * C API CALLS
+ ****************************************************/
+PyObject*
+PyFreeTypeFont_New(const char *filename, int face_index)
+{
+    PyFreeTypeFont *font;
+
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    if (!filename)
+        return NULL;
+
+    font = (PyFreeTypeFont *)PyFreeTypeFont_Type.tp_new(
+            &PyFreeTypeFont_Type, NULL, NULL);
+
+    if (!font)
+        return NULL;
+
+    font->default_ptsize = -1;
+    font->default_style = FT_STYLE_NORMAL;
+
+    if (PGFT_TryLoadFont_Filename(ft, font, filename, face_index) != 0)
+    {
+        PyErr_SetString(PyExc_RuntimeError, PGFT_GetError(ft));
+        return NULL;
+    }
+
+    return (PyObject*) font;
+}
+
+
+
+
+
+
+
+/****************************************************
+ * FREETYPE MODULE METHODS
+ ****************************************************/
+
+/***************************************************************
+ *
+ * Bindings for initialization/cleanup functions
+ *
+ * Explicit init/quit functions are required to work around
+ * some issues regarding module caching and multi-threaded apps.
+ * It's always good to let the user choose when to initialize
+ * the module.
+ *
+ * TODO: These bindings can be removed once proper threading
+ * support is in place.
+ *
+ ***************************************************************/
+static PyObject *
+_ft_quit(PyObject *self)
+{
+    if (FREETYPE_MOD_STATE (self)->freetype)
+    {
+        PGFT_Quit(FREETYPE_MOD_STATE (self)->freetype);
+        FREETYPE_MOD_STATE (self)->freetype = NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+_ft_init(PyObject *self, PyObject *args)
+{
+    FT_Error error;
+    FT_Int cache_size = PGFT_DEFAULT_CACHE_SIZE;
+
+    if (FREETYPE_MOD_STATE (self)->freetype)
+        Py_RETURN_NONE;
+
+    if (!PyArg_ParseTuple(args, "|i", &cache_size))
+        return NULL;
+
+    error = PGFT_Init(&(FREETYPE_MOD_STATE (self)->freetype), cache_size);
+    if (error != 0)
+    {
+        PyErr_SetString(PyExc_RuntimeError, 
+                "Failed to initialize the FreeType2 library");
+        return NULL;
+    }
+
+    Py_RETURN_NONE;
+}
+
+
+static PyObject *
+_ft_get_error(PyObject *self)
+{
+    FreeTypeInstance *ft;
+    ASSERT_GRAB_FREETYPE(ft, NULL);
+
+    if (ft->_error_msg[0])
+    {
+        return Text_FromUTF8(ft->_error_msg);
+    }
+
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+_ft_get_version(PyObject *self)
+{
+    /* Return the linked FreeType2 version */
+    return Py_BuildValue("(iii)", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
+}
+
+static PyObject *
+_ft_was_init(PyObject *self)
+{
+    return PyBool_FromLong((FREETYPE_MOD_STATE (self)->freetype != NULL));
+}
+
+
+static int
+_ft_traverse (PyObject *mod, visitproc visit, void *arg)
+{
+    return 0;
+}
+
+static int
+_ft_clear (PyObject *mod)
+{
+    if (FREETYPE_MOD_STATE(mod)->freetype)
+    {
+        PGFT_Quit(FREETYPE_MOD_STATE(mod)->freetype);
+        FREETYPE_MOD_STATE(mod)->freetype = NULL;
+    }
+    return 0;
+}
+
+
+
+/****************************************************
+ * FREETYPE MODULE DECLARATION
+ ****************************************************/
+#if PY3
+struct PyModuleDef _freetypemodule = 
+{
+    PyModuleDef_HEAD_INIT,
+    "freetype",
+    "TODO", /* TODO: DOC */
+    sizeof(_FreeTypeState),
+    _ft_methods,
+    NULL, 
+    _ft_traverse, 
+    _ft_clear, 
+    NULL
+};
+#else
+_FreeTypeState _modstate;
+#endif
+
+MODINIT_DEFINE (freetype)
+{
+    PyObject *module, *apiobj;
+    static void* c_api[PYGAMEAPI_FREETYPE_NUMSLOTS];
+
+    PyFREETYPE_C_API[0] = PyFREETYPE_C_API[0]; 
+
+    import_pygame_base();
+    if (PyErr_Occurred())
+    {   
+        MODINIT_ERROR;
+    }
+
+    import_pygame_surface();
+    if (PyErr_Occurred()) 
+    {
+	    MODINIT_ERROR;
+    }
+
+    import_pygame_color();
+    if (PyErr_Occurred()) 
+    {
+	    MODINIT_ERROR;
+    }
+
+    import_pygame_rwobject();
+    if (PyErr_Occurred()) 
+    {
+	    MODINIT_ERROR;
+    }
+
+    /* type preparation */
+    if (PyType_Ready(&PyFreeTypeFont_Type) < 0) 
+    {
+        MODINIT_ERROR;
+    }
+
+    PyFreeTypeFont_Type.tp_new = PyType_GenericNew;
+
+#if PY3
+    module = PyModule_Create(&_freetypemodule);
+#else
+    /* TODO: DOC */
+    module = Py_InitModule3("freetype", _ft_methods, "TODO"); 
+#endif
+
+    if (module == NULL) 
+    {
+        MODINIT_ERROR;
+    }
+
+    Py_INCREF((PyObject *)&PyFreeTypeFont_Type);
+    if (PyModule_AddObject(module, "Font", (PyObject *)&PyFreeTypeFont_Type) == -1) 
+    {
+        Py_DECREF((PyObject *) &PyFreeTypeFont_Type);
+        DECREF_MOD(module);
+        MODINIT_ERROR;
+    }
+
+#   define DEC_CONST(x)  PyModule_AddIntConstant(module, #x, (int)FT_##x)
+
+    DEC_CONST(STYLE_NORMAL);
+    DEC_CONST(STYLE_BOLD);
+    DEC_CONST(STYLE_ITALIC);
+    DEC_CONST(STYLE_UNDERLINE);
+
+    DEC_CONST(BBOX_EXACT);
+    DEC_CONST(BBOX_EXACT_GRIDFIT);
+    DEC_CONST(BBOX_PIXEL);
+    DEC_CONST(BBOX_PIXEL_GRIDFIT);
+
+    /* export the c api */
+    c_api[0] = &PyFreeTypeFont_Type;
+    c_api[1] = &PyFreeTypeFont_New;
+
+    apiobj = PyCObject_FromVoidPtr(c_api, NULL);
+    if (apiobj == NULL) 
+    {
+        DECREF_MOD(module);
+        MODINIT_ERROR;
+    }
+
+    if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj) == -1) 
+    {
+        Py_DECREF(apiobj);
+        DECREF_MOD(module);
+        MODINIT_ERROR;
+    }
+
+    MODINIT_RETURN(module);
+}

File src/freetype/ft_cache.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2009 Vicent Marti
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#define PYGAME_FREETYPE_INTERNAL
+
+#include "ft_wrap.h"
+#include "pgfreetype.h"
+
+#include FT_MODULE_H
+
+FT_UInt32 _PGFT_Cache_Hash(const FontRenderMode *, FT_UInt);
+FT_UInt32 _PGFT_GetLoadFlags(const FontRenderMode *);
+
+FontCacheNode *_PGFT_Cache_AllocateNode(FreeTypeInstance *, 
+        FontCache *, const FontRenderMode *, FT_UInt);
+void _PGFT_Cache_FreeNode(FontCache *, FontCacheNode *);
+
+
+FT_UInt32 _PGFT_GetLoadFlags(const FontRenderMode *render)
+{
+    FT_UInt32 load_flags = FT_LOAD_DEFAULT;
+
+    load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
+
+    if (render->render_flags & FT_RFLAG_AUTOHINT)
+        load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+    if (render->render_flags & FT_RFLAG_HINTED)
+    {
+        load_flags |=   (render->render_flags & FT_RFLAG_ANTIALIAS) ?
+                        FT_LOAD_TARGET_NORMAL :
+                        FT_LOAD_TARGET_MONO;
+    }
+    else
+    {
+        load_flags |= FT_LOAD_NO_HINTING;
+    }
+
+    return load_flags;
+}
+
+FT_UInt32 _PGFT_Cache_Hash(const FontRenderMode *render, FT_UInt glyph_index)
+{
+	const FT_UInt32 m = 0x5bd1e995;
+	const int r = 24;
+
+	FT_UInt32 h, k; 
+
+    /* 
+     * Quick hashing algorithm, based off MurmurHash2.
+     * Assumes sizeof(FontRenderMode) == 8
+     */
+
+    h = (glyph_index << 12) ^ glyph_index;
+
+    k = *(const FT_UInt32 *)render;
+    k *= m; k ^= k >> r; 
+    k *= m; h *= m; h ^= k;
+
+    k = *(((const FT_UInt32 *)render) + 1);
+    k *= m; k ^= k >> r; 
+    k *= m; h *= m; h ^= k;
+
+	h ^= h >> 13;
+	h *= m;
+	h ^= h >> 15;
+
+	return h;
+} 
+
+void PGFT_Cache_Init(FreeTypeInstance *ft, 
+        FontCache *cache, PyFreeTypeFont *parent)
+{
+    int cache_size = MAX(ft->cache_size - 1, PGFT_MIN_CACHE_SIZE - 1);
+
+    /*
+     * Make sure this is a power of 2.
+     */
+    cache_size = cache_size | (cache_size >> 1);
+    cache_size = cache_size | (cache_size >> 2);
+    cache_size = cache_size | (cache_size >> 4);
+    cache_size = cache_size | (cache_size >> 8);
+    cache_size = cache_size | (cache_size >>16);
+
+    cache_size = cache_size + 1;
+
+    cache->nodes = calloc((size_t)cache_size, sizeof(FontGlyph *));
+    cache->depths = calloc((size_t)cache_size, sizeof(FT_Byte));
+    cache->font = parent;
+    cache->free_nodes = NULL;
+    cache->size_mask = (FT_UInt32)(cache_size - 1);
+
+#ifdef PGFT_DEBUG_CACHE
+    cache->count = 0;
+    cache->_debug_delete_count = 0;
+    cache->_debug_access = 0;
+    cache->_debug_hit = 0;
+    cache->_debug_miss = 0;
+#endif
+}
+
+void PGFT_Cache_Destroy(FontCache *cache)
+{
+    FT_UInt i;
+    FontCacheNode *node, *next;
+
+    if (cache == NULL)
+        return;
+
+#ifdef PGFT_DEBUG_CACHE
+    fprintf(stderr, "Cache stats:\n");
+    fprintf(stderr, "\t%d accesses in total\n", cache->_debug_access);
+    fprintf(stderr, "\t%d hits / %d misses\n", cache->_debug_hit, cache->_debug_miss);
+    fprintf(stderr, "\t%f hit ratio\n", (float)cache->_debug_hit/(float)cache->_debug_access);
+    fprintf(stderr, "\t%d nodes kicked\n", cache->_debug_delete_count);
+#endif
+
+    for (i = 0; i <= cache->size_mask; ++i)
+    {
+        node = cache->nodes[i];
+
+        while (node)
+        {
+            next = node->next;
+            _PGFT_Cache_FreeNode(cache, node);
+            node = next;
+        }
+    }
+
+    free(cache->nodes);
+    free(cache->depths);
+}
+
+void PGFT_Cache_Cleanup(FontCache *cache)
+{
+    const FT_Byte MAX_BUCKET_DEPTH = 2;
+    FontCacheNode *node, *prev;
+    FT_UInt32 i;
+
+    for (i = 0; i <= cache->size_mask; ++i)
+    {
+        while (cache->depths[i] > MAX_BUCKET_DEPTH)
+        {
+            node = cache->nodes[i];
+            prev = NULL;
+
+            for (;;)
+            {
+                if (!node->next)
+                {
+#ifdef PGFT_DEBUG_CACHE
+                    cache->_debug_delete_count++;
+#endif
+
+                    prev->next = NULL; 
+                    _PGFT_Cache_FreeNode(cache, node);
+                    break;
+                }
+
+                prev = node;
+                node = node->next;
+            }
+        }
+    }
+
+}
+
+FontGlyph *PGFT_Cache_FindGlyph(FreeTypeInstance *ft, FontCache *cache, 
+        FT_UInt character, const FontRenderMode *render)
+{
+    FontCacheNode **nodes = cache->nodes;
+    FontCacheNode *node, *prev;
+
+    FT_UInt32 hash = _PGFT_Cache_Hash(render, character);
+    FT_UInt32 bucket = hash & cache->size_mask;
+    
+    node = nodes[bucket];
+    prev = NULL;
+
+#ifdef PGFT_DEBUG_CACHE
+    cache->_debug_access++;
+#endif
+        
+    while (node)
+    {
+        if (node->hash == hash)
+        {
+            if (prev)
+            {
+                prev->next = node->next;
+                node->next = nodes[bucket];
+                nodes[bucket] = node;
+            }
+
+#ifdef PGFT_DEBUG_CACHE
+            cache->_debug_hit++;
+#endif
+
+            return &node->glyph;
+        }
+
+        prev = node;
+        node = node->next;
+    }
+
+    node = _PGFT_Cache_AllocateNode(ft, cache, render, character);
+
+#ifdef PGFT_DEBUG_CACHE
+    cache->_debug_miss++;
+#endif
+
+    return &node->glyph;
+}
+
+void _PGFT_Cache_FreeNode(FontCache *cache, FontCacheNode *node)
+{
+    if (node == NULL)
+        return;
+
+#ifdef PGFT_DEBUG_CACHE
+    cache->count--;
+#endif
+
+    cache->depths[node->hash & cache->size_mask]--;
+
+    FT_Done_Glyph(node->glyph.image);
+    free(node);
+}
+
+FontCacheNode *_PGFT_Cache_AllocateNode(FreeTypeInstance *ft, 
+        FontCache *cache, const FontRenderMode *render, FT_UInt character)
+{
+    FontCacheNode *node = NULL;
+    FontGlyph *glyph = NULL;
+
+    FT_Glyph_Metrics *metrics;
+    FT_Face face;
+
+    FT_UInt32 load_flags;
+    FT_Fixed bold_str = 0;
+    int gindex;
+    FT_UInt32 bucket;
+
+    /*
+     * Grab face reference
+     */
+    face = _PGFT_GetFaceSized(ft, cache->font, render->pt_size);
+
+    if (!face)
+    {
+        _PGFT_SetError(ft, "Failed to resize face", 0);
+        goto cleanup;
+    }
+
+    /* 
+     * Allocate cache node 
+     */
+    node = malloc(sizeof(FontCacheNode));
+    glyph = &node->glyph;
+
+    /*
+     * Calculate the corresponding glyph index for the char
+     */
+    gindex = FTC_CMapCache_Lookup(ft->cache_charmap, 
+            (FTC_FaceID)&(cache->font->id), -1, character);
+
+    if (gindex < 0)
+    {
+        _PGFT_SetError(ft, "Glyph character not found in font", 0);
+        goto cleanup;
+    }
+
+    glyph->glyph_index = (FT_UInt)gindex;
+
+    /*
+     * Get loading information
+     */
+    load_flags = _PGFT_GetLoadFlags(render);
+
+    if (render->style & FT_STYLE_BOLD)
+        bold_str = PGFT_GetBoldStrength(face);
+
+    /*
+     * Load the glyph into the glyph slot
+     */
+    if (FT_Load_Glyph(face, glyph->glyph_index, (FT_Int)load_flags) != 0 ||
+        FT_Get_Glyph(face->glyph, &(glyph->image)) != 0)
+        goto cleanup;
+
+    /*
+     * Precalculate useful metric values
+     */
+    metrics = &face->glyph->metrics;
+
+    glyph->vvector.x  = (metrics->vertBearingX - bold_str / 2) - metrics->horiBearingX;
+    glyph->vvector.y  = -(metrics->vertBearingY + bold_str) - (metrics->horiBearingY + bold_str);
+
+    glyph->vadvance.x = 0;
+    glyph->vadvance.y = -(metrics->vertAdvance + bold_str);
+
+    glyph->baseline = metrics->height - metrics->horiBearingY;
+
+    glyph->size.x = metrics->width + bold_str;
+    glyph->size.y = metrics->height + bold_str;
+
+
+    /*
+     * Update cache internals
+     */
+    node->hash = _PGFT_Cache_Hash(render, character);
+    bucket = node->hash & cache->size_mask;
+    node->next = cache->nodes[bucket];
+    cache->nodes[bucket] = node;
+
+    cache->depths[bucket]++;
+
+#ifdef PGFT_DEBUG_CACHE
+    cache->count++;
+#endif
+
+    return node;
+
+    /*
+     * Cleanup on error
+     */
+cleanup:
+    if (glyph && glyph->image)
+        FT_Done_Glyph(glyph->image);
+
+    free(node);
+    return NULL;
+}

File src/freetype/ft_constants.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2009 Vicent Marti
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "ft_wrap.h"
+#include "pgfreetype.h"
+#include "pgtypes.h"
+#include "freetypebase_doc.h"
+
+#define DEC_CONST(x)  PyModule_AddIntConstant(module, #x, (int)FT_##x)
+
+#ifdef IS_PYTHON_3
+PyMODINIT_FUNC PyInit_constants (void)
+#else
+PyMODINIT_FUNC initconstants (void)
+#endif
+{
+    PyObject *module;
+
+#ifdef IS_PYTHON_3
+    static struct PyModuleDef _module = {
+        PyModuleDef_HEAD_INIT,
+        "constants",
+        "Pygame FreeType constants"
+            -1,
+        NULL, NULL, NULL, NULL, NULL
+    };
+
+    module = PyModule_Create (&_module);
+#else
+    module = Py_InitModule3 ("constants", NULL, "Pygame FreeType constants");
+#endif
+
+    if (!module)
+        goto fail;
+
+    DEC_CONST(STYLE_NORMAL);
+    DEC_CONST(STYLE_BOLD);
+    DEC_CONST(STYLE_ITALIC);
+    DEC_CONST(STYLE_UNDERLINE);
+
+    DEC_CONST(BBOX_EXACT);
+    DEC_CONST(BBOX_EXACT_GRIDFIT);
+    DEC_CONST(BBOX_PIXEL);
+    DEC_CONST(BBOX_PIXEL_GRIDFIT);
+
+    DEC_CONST(RENDER_NEWBYTEARRAY);
+    DEC_CONST(RENDER_NEWSURFACE);
+    
+    MODINIT_RETURN(module);
+
+fail:
+    Py_XDECREF (module);
+    MODINIT_RETURN (NULL);
+}

File src/freetype/ft_metrics.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2009 Vicent Marti
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#define PYGAME_FREETYPE_INTERNAL
+
+#include "ft_wrap.h"
+#include FT_MODULE_H
+
+extern FT_Matrix PGFT_SlantMatrix;
+
+/* Declarations */
+void _PGFT_GetMetrics_INTERNAL(FT_Glyph, FT_UInt, int *, int *, int *, int *, int *);
+int  _PGFT_GetTextSize_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
+        const FontRenderMode *render, FontText *text);
+
+
+/* Real text metrics */
+void _PGFT_GetMetrics_INTERNAL(FT_Glyph glyph, FT_UInt bbmode,
+    int *minx, int *maxx, int *miny, int *maxy, int *advance)
+{
+    FT_BBox box;
+    FT_Glyph_Get_CBox(glyph, bbmode, &box);
+
+    *minx = box.xMin;
+    *maxx = box.xMax;
+    *miny = box.yMin;
+    *maxy = box.yMax;
+    *advance = glyph->advance.x;
+
+    if (bbmode == FT_GLYPH_BBOX_TRUNCATE ||
+        bbmode == FT_GLYPH_BBOX_PIXELS)
+        *advance >>= 16;
+}
+
+
+int PGFT_GetMetrics(FreeTypeInstance *ft, PyFreeTypeFont *font,
+    int character, const FontRenderMode *render, int bbmode,
+    void *minx, void *maxx, void *miny, void *maxy, void *advance)
+{
+    FontGlyph *     glyph = NULL;
+
+    glyph = PGFT_Cache_FindGlyph(ft, &PGFT_INTERNALS(font)->cache, 
+            (FT_UInt)character, render);
+
+    if (!glyph)
+        return -1;
+
+    _PGFT_GetMetrics_INTERNAL(glyph->image, (FT_UInt)bbmode, 
+            minx, maxx, miny, maxy, advance);
+
+    if (bbmode == FT_BBOX_EXACT || bbmode == FT_BBOX_EXACT_GRIDFIT)
+    {
+#       define FP16_16(i)   ((float)((int)(i) / 65536.0f))
+#       define FP26_6(i)    ((float)((int)(i) / 64.0f))
+
+        *(float *)minx =    FP26_6(*(int *)minx);
+        *(float *)miny =    FP26_6(*(int *)miny);
+        *(float *)maxx =    FP26_6(*(int *)maxx);
+        *(float *)maxy =    FP26_6(*(int *)maxy);
+        *(float *)advance = FP16_16(*(int *)advance);
+
+#       undef FP16_16
+#       undef FP26_6
+    }
+
+    return 0;
+
+}
+
+
+int
+_PGFT_GetTextSize_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
+    const FontRenderMode *render, FontText *text)
+{
+    FT_Vector   extent, advances[PGFT_MAX_GLYPHS];
+    FT_Error    error;
+    FT_Vector   size;
+
+    error = PGFT_GetTextAdvances(ft, font, render, text, advances);
+
+    if (error)
+        return error;
+
+    extent = advances[text->length - 1];
+
+    if (render->render_flags & FT_RFLAG_VERTICAL)
+    {
+        size.x = text->glyph_size.x;
+        size.y = ABS(extent.y);
+    }
+    else
+    {
+        size.x = extent.x;
+        size.y = text->glyph_size.y;
+    }
+
+    if (render->rotation_angle)
+    {   
+        size.x = MAX(size.x, size.y);
+        size.y = MAX(size.x, size.y);
+    }
+
+    text->text_size.x = ABS(size.x);
+    text->text_size.y = ABS(size.y);
+
+    return 0;
+}
+
+int
+PGFT_GetSurfaceSize(FreeTypeInstance *ft, PyFreeTypeFont *font,
+        const FontRenderMode *render, FontText *text, 
+        int *width, int *height)
+{
+    int w, h;
+
+    if (text == NULL || 
+        _PGFT_GetTextSize_INTERNAL(ft, font, render, text) != 0)
+        return -1;
+
+    w = text->text_size.x;
+    h = text->text_size.y;
+
+    if (text->underline_size > 0)
+    {
+        h = MAX(h, text->underline_pos + text->underline_size);
+    }
+
+    if (render->style & FT_STYLE_ITALIC)
+    {
+        FT_Vector s = {w, h};
+
+        FT_Vector_Transform(&s, &PGFT_SlantMatrix);
+        w = s.x; h = s.y;
+    }
+
+    *width = PGFT_TRUNC(PGFT_CEIL(w));
+    *height = PGFT_TRUNC(PGFT_CEIL(h));
+    return 0;
+}
+
+int
+PGFT_GetTextSize(FreeTypeInstance *ft, PyFreeTypeFont *font,
+    const FontRenderMode *render, PyObject *text, int *w, int *h)
+{
+    FontText *font_text;
+
+    font_text = PGFT_LoadFontText(ft, font, render, text);
+
+    if (!font_text)
+        return -1;
+
+    return PGFT_GetSurfaceSize(ft, font, render, font_text, w, h);
+}

File src/freetype/ft_pixel.h

+/*
+  pygame - Python Game Library
+  Copyright (C) 2009 Vicent Marti
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+#ifndef _PYGAME_FREETYPE_PIXEL_H_
+#define _PYGAME_FREETYPE_PIXEL_H_
+
+#include "../surface.h"
+
+#define GET_RGB_VALS(pixel, fmt, r, g, b, a)                            \
+    (r) = ((pixel) & (fmt)->Rmask) >> (fmt)->Rshift;                    \
+    (r) = ((r) << (fmt)->Rloss) + ((r) >> (8 - ((fmt)->Rloss << 1)));   \
+    (g) = ((pixel) & (fmt)->Gmask) >> (fmt)->Gshift;                    \
+    (g) = ((g) << (fmt)->Gloss) + ((g) >> (8 - ((fmt)->Gloss << 1)));   \
+    (b) = ((pixel) & (fmt)->Bmask) >> (fmt)->Bshift;                    \
+    (b) = ((b) << (fmt)->Bloss) + ((b) >> (8 - ((fmt)->Bloss << 1)));   \
+    if ((fmt)->Amask)                                                   \
+    {                                                                   \
+        (a) = ((pixel) & (fmt)->Amask) >> (fmt)->Ashift;                \
+        (a) = ((a) << (fmt)->Aloss) + ((a) >> (8 - ((fmt)->Aloss << 1))); \
+    }                                                                   \
+    else                                                                \
+        (a) = 255;
+
+#define GET_PALETTE_VALS(pixel, fmt, sr, sg, sb, sa)                    \
+    (sr) = (fmt)->palette->colors[*((Uint8 *) (pixel))].r;              \
+    (sg) = (fmt)->palette->colors[*((Uint8 *) (pixel))].g;              \
+    (sb) = (fmt)->palette->colors[*((Uint8 *) (pixel))].b;              \
+    (sa) = 255;
+
+#define GET_PIXEL_VALS(pixel, fmt, r, g, b, a)          \
+    if ((fmt)->palette == NULL)                         \
+    {                                                   \
+        GET_RGB_VALS(pixel, fmt, r, g, b, a);           \
+    }                                                   \
+    else                                                \
+    {                                                   \
+        GET_PALETTE_VALS (pixel, fmt, r, g, b, a);      \
+    }
+
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define GET_PIXEL24(b) ((b)[0] + ((b)[1] << 8) + ((b)[2] << 16))
+#define SET_PIXEL24_RGB(buf,format,r,g,b)                               \
+    *((buf) + ((format)->Rshift >> 3)) = (r);                           \
+    *((buf) + ((format)->Gshift >> 3)) = (g);                           \
+    *((buf) + ((format)->Bshift >> 3)) = (b);
+#define SET_PIXEL24(buf,format,rgb)                                     \
+    *((buf) + ((format)->Rshift >> 3)) = (rgb)[0];                      \
+    *((buf) + ((format)->Gshift >> 3)) = (rgb)[1];                      \
+    *((buf) + ((format)->Bshift >> 3)) = (rgb)[2];
+#else
+#define GET_PIXEL24(b) ((b)[2] + ((b)[1] << 8) + ((b)[0] << 16))
+#define SET_PIXEL24_RGB(buf,format,r,g,b)                               \
+    *((buf) + 2 - ((format)->Rshift >> 3)) = (r);                       \
+    *((buf) + 2 - ((format)->Gshift >> 3)) = (g);                       \
+    *((buf) + 2 - ((format)->Bshift >> 3)) = (b);
+#define SET_PIXEL24(buf,format,rgb)                                     \
+    *((buf) + 2 - ((format)->Rshift >> 3)) = (rgb)[0];                  \
+    *((buf) + 2 - ((format)->Gshift >> 3)) = (rgb)[1];                  \
+    *((buf) + 2 - ((format)->Bshift >> 3)) = (rgb)[2];
+#endif
+
+#endif

File src/freetype/ft_render.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2009 Vicent Marti
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#define PYGAME_FREETYPE_INTERNAL
+
+#include "ft_wrap.h"
+#include FT_MODULE_H
+
+typedef void (* FontRenderPtr)(int, int, FontSurface *, FT_Bitmap *, FontColor *);
+typedef void (* FontFillPtr)(int, int, int, int, FontSurface *, FontColor *);
+
+#define SLANT_FACTOR    0.22
+FT_Matrix PGFT_SlantMatrix = 
+{
+    (1 << 16),  (FT_Fixed)(SLANT_FACTOR * (1 << 16)),
+    0,          (1 << 16) 
+};
+
+FT_Fixed PGFT_GetBoldStrength(FT_Face face)
+{
+    const float bold_factor = 0.06f;
+    FT_Fixed bold_str;
+
+    bold_str = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale);
+    bold_str = (FT_Fixed)((float)bold_str * bold_factor);
+
+    return bold_str;
+}
+
+int PGFT_CheckStyle(FT_UInt32 style)
+{
+    const FT_UInt32 max_style =
+        FT_STYLE_NORMAL |
+        FT_STYLE_BOLD   |
+        FT_STYLE_ITALIC |
+        FT_STYLE_UNDERLINE;
+
+    return (style > max_style);
+}
+
+int 
+PGFT_BuildRenderMode(FreeTypeInstance *ft, 
+        PyFreeTypeFont *font, FontRenderMode *mode, 
+        int pt_size, int style, int vertical, int antialias, int rotation)
+{
+    int angle;
+
+    if (pt_size == -1)
+    {
+        if (font->default_ptsize == -1)
+        {
+            _PGFT_SetError(ft, "No font point size specified"
+                    " and no default font size in typeface", 0);
+            return -1;
+        }
+
+        pt_size = font->default_ptsize;
+    }
+
+    if (pt_size <= 0)
+    {
+        _PGFT_SetError(ft, "Invalid point size for font.", 0);
+        return -1;
+    }
+
+    mode->pt_size = (FT_UInt16)pt_size;
+
+    if (style == FT_STYLE_DEFAULT)
+    {
+        mode->style = (FT_Byte)font->default_style;
+    }
+    else
+    {
+        if (PGFT_CheckStyle((FT_UInt32)style) != 0)
+        {
+            _PGFT_SetError(ft, "Invalid style value", 0);
+            return -1;
+        }
+
+        mode->style = (FT_Byte)style;
+    }
+
+    mode->render_flags = FT_RFLAG_DEFAULTS;
+
+    if (vertical)
+        mode->render_flags |= FT_RFLAG_VERTICAL;
+
+    if (antialias)
+        mode->render_flags |= FT_RFLAG_ANTIALIAS;
+
+    angle = rotation % 360;
+    while (angle < 0) angle += 360;
+    mode->rotation_angle = (FT_UInt16)angle;
+
+    return 0;
+}
+
+
+/*********************************************************
+ *
+ * Rendering on SDL-specific surfaces
+ *
+ *********************************************************/
+#ifdef HAVE_PYGAME_SDL_VIDEO
+int PGFT_Render_ExistingSurface(FreeTypeInstance *ft, PyFreeTypeFont *font,
+    const FontRenderMode *render, PyObject *text, SDL_Surface *surface, 
+    int x, int y, FontColor *fgcolor, FontColor *bgcolor, int *_width, int *_height)
+{
+    static const FontRenderPtr __SDLrenderFuncs[] =
+    {
+        NULL,
+        __render_glyph_RGB1,
+        __render_glyph_RGB2,
+        __render_glyph_RGB3,
+        __render_glyph_RGB4
+    };
+
+    static const FontRenderPtr __MONOrenderFuncs[] =
+    {
+        NULL,
+        __render_glyph_MONO1,
+        __render_glyph_MONO2,
+        __render_glyph_MONO3,
+        __render_glyph_MONO4
+    };
+
+    static const FontFillPtr __RGBfillFuncs[] =
+    {
+        NULL,
+        __fill_glyph_RGB1,
+        __fill_glyph_RGB2,
+        __fill_glyph_RGB3,
+        __fill_glyph_RGB4
+    };
+
+    int         locked = 0;
+    int         width, height;
+
+    FontSurface font_surf;
+    FontText    *font_text;
+
+    if (SDL_MUSTLOCK(surface))
+    {
+        if (SDL_LockSurface(surface) == -1)
+        {
+            _PGFT_SetError(ft, SDL_GetError (), 0);
+            SDL_FreeSurface(surface);
+            return -1;
+        }
+        locked = 1;
+    }
+
+    /* build font text */
+    font_text = PGFT_LoadFontText(ft, font, render, text);
+
+    if (!font_text)
+        return -1;
+
+    if (PGFT_GetSurfaceSize(ft, font, render, font_text, &width, &height) != 0)
+        return -1;
+
+    /*
+     * Setup target surface struct
+     */
+    font_surf.buffer = surface->pixels;
+    font_surf.x_offset = x;
+    font_surf.y_offset = y;
+
+    font_surf.width = surface->w;
+    font_surf.height = surface->h;
+    font_surf.pitch = surface->pitch / surface->format->BytesPerPixel;
+
+    font_surf.format = surface->format;
+
+    if (render->render_flags & FT_RFLAG_ANTIALIAS)
+        font_surf.render = __SDLrenderFuncs[surface->format->BytesPerPixel];
+    else
+        font_surf.render = __MONOrenderFuncs[surface->format->BytesPerPixel];
+
+    font_surf.fill = __RGBfillFuncs[surface->format->BytesPerPixel];
+
+    /* 
+     * if bg color exists, paint background 
+     */
+    if (bgcolor)
+    {
+        if (bgcolor->a == 0xFF)
+        {
+            SDL_Rect    bg_fill; 
+            FT_UInt32   fillcolor;
+
+            fillcolor = SDL_MapRGBA(surface->format, 
+                    bgcolor->r, bgcolor->g, bgcolor->b, bgcolor->a);
+
+            bg_fill.x = (FT_Int16)x;
+            bg_fill.y = (FT_Int16)y;
+            bg_fill.w = (FT_UInt16)width;
+            bg_fill.h = (FT_UInt16)height;
+
+            SDL_FillRect(surface, &bg_fill, fillcolor);
+        }
+        else
+        {
+            font_surf.fill(x, y, width, height, &font_surf, bgcolor);
+        }
+    }
+
+    /*
+     * Render!
+     */
+    if (_PGFT_Render_INTERNAL(ft, font, font_text, render, fgcolor, &font_surf) != 0)
+        return -1;
+
+    *_width = width;
+    *_height = height;
+
+    if (locked)
+        SDL_UnlockSurface(surface);
+
+    return 0;
+}
+
+SDL_Surface *PGFT_Render_NewSurface(FreeTypeInstance *ft, PyFreeTypeFont *font, 
+    const FontRenderMode *render, PyObject *text,
+    FontColor *fgcolor, FontColor *bgcolor, int *_width, int *_height)
+{
+    int locked = 0;
+    FT_UInt32 fillcolor, rmask, gmask, bmask, amask;
+    SDL_Surface *surface = NULL;
+
+    FontSurface font_surf;
+    FontText *font_text;
+    int width, height;
+
+    /* build font text */
+    font_text = PGFT_LoadFontText(ft, font, render, text);
+
+    if (!font_text)
+        return NULL;
+
+    if (PGFT_GetSurfaceSize(ft, font, render, font_text, &width, &height) != 0)
+        return NULL;
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    rmask = 0xff000000;
+    gmask = 0x00ff0000;
+    bmask = 0x0000ff00;
+    amask = 0x000000ff;
+#else
+    rmask = 0x000000ff;
+    gmask = 0x0000ff00;
+    bmask = 0x00ff0000;
+    amask = 0xff000000;
+#endif
+
+    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 
+            width, height,
+            32, rmask, gmask, bmask, amask);
+
+    if (!surface)
+    {
+        _PGFT_SetError(ft, SDL_GetError (), 0);
+        return NULL;
+    }
+
+    if (SDL_MUSTLOCK(surface))
+    {
+        if (SDL_LockSurface(surface) == -1)
+        {
+            _PGFT_SetError(ft, SDL_GetError (), 0);
+            SDL_FreeSurface(surface);
+            return NULL;
+        }
+        locked = 1;
+    }
+
+    font_surf.buffer = surface->pixels;
+    font_surf.x_offset = font_surf.y_offset = 0;
+
+    font_surf.width = surface->w;
+    font_surf.height = surface->h;
+    font_surf.pitch = surface->pitch / sizeof(FT_UInt32);
+
+    font_surf.format = surface->format;
+    font_surf.render = __render_glyph_RGB4;
+    font_surf.fill = __fill_glyph_RGB4;
+
+    /*
+     * Fill our texture with the required bg color
+     */
+    if (bgcolor)
+    {
+        fillcolor = SDL_MapRGBA(surface->format, 
+                bgcolor->r, bgcolor->g, bgcolor->b, bgcolor->a);
+    }
+    else
+    {
+        fillcolor = SDL_MapRGBA(surface->format, 0, 0, 0, 0);
+    }
+
+    SDL_FillRect(surface, NULL, fillcolor);
+
+    /*
+     * Render the text!
+     */
+    if (_PGFT_Render_INTERNAL(ft, font, font_text, render, fgcolor, &font_surf) != 0)
+    {
+        SDL_FreeSurface(surface);