Commits

Lenard Lindstrom committed 1d5c94d

freetype once again passes its unit tests

  • Participants
  • Parent commits a54fbe8

Comments (0)

Files changed (9)

File docs/reST/ref/freetype.rst

 
       .. ## Font.antialiased ##
 
+   .. attribute:: kerning
+
+      | :sl:`Character kerning mode`
+      | :sg:`kerning -> bool`
+
+      Gets or sets the font's kerning mode. This defaults to False on all
+      fonts, which will be rendered by default without kerning.
+
+      Setting this to true will change all rendering methods to do kerning
+      between character pairs for surface size calculation and all
+      render operations.
+
+      .. ## Font.kerning ##
+
    .. attribute:: vertical
 
       | :sl:`Font vertical mode`

File examples/freetype_misc.py

     font.render((screen, 64, 190), "Let's spin!", colors["red"], None,
             ptsize=48, rotation=55)
 
-    font.render((screen, 150, 270), "All around!", colors["green"], None,
+    font.render((screen, 160, 290), "All around!", colors["green"], None,
             ptsize=48, rotation=-55)
 
     font.render((screen, 250, 220), "and BLEND", pygame.Color(255, 0, 0, 128), None,

File src/doc/freetype_doc.h

 
 #define DOC_FONTANTIALIASED "Font.antialiased: return bool\nFont antialiasing mode"
 
+#define DOC_FONTKERNING "Font.kerning -> bool\nCharacter kerning mode"
+
 #define DOC_FONTVERTICAL "Font.vertical: return bool\nFont vertical mode"
 
 #define DOC_ ""

File src/freetype.c

 static PyObject *_ft_get_error(PyObject *self);
 static PyObject *_ft_was_init(PyObject *self);
 static PyObject *_ft_autoinit(PyObject *self);
-/* ---> To be removed in final release */
-static PyObject *_ft_render_raw(PyObject *self, PyObject *args, PyObject *kwds);
-static PyObject *_ft_render_raw2(PyObject *self, PyObject *args, PyObject *kwds);
-/* <--- */
 
 /*
  * Constructor/init/destructor
 static int _ftfont_setvertical(PyObject *self, PyObject *value, void *closure);
 static PyObject *_ftfont_getantialias(PyObject *self, void *closure);
 static int _ftfont_setantialias(PyObject *self, PyObject *value, void *closure);
+static PyObject *_ftfont_getkerning(PyObject *self, void *closure);
+static int _ftfont_setkerning(PyObject *self, PyObject *value, void *closure);
 
 static PyObject *_ftfont_getstyle_flag(PyObject *self, void *closure);
 static int _ftfont_setstyle_flag(PyObject *self, PyObject *value, void *closure);
         METH_NOARGS,
         DOC_PYGAMEFREETYPEGETVERSION
     },
-    /* ---> To be removed in final release */
-    { 
-        "render_raw",
-        (PyCFunction) _ft_render_raw,
-        METH_VARARGS | METH_KEYWORDS,
-        "Like Font.render_raw\n"
-        "render_raw(filename, text, ptsize, vertical, rotation, kerning, surrogate) ==> Surface, Rect\n"
-	"\n"
-	"This is a proof of concept method. It will not be in the final module.\n"
-    },
-    { 
-        "render_raw2",
-        (PyCFunction) _ft_render_raw2,
-        METH_VARARGS | METH_KEYWORDS,
-        "Like Font.render_raw2\n"
-        "render_raw(filename, text, ptsize, vertical, rotation, kerning, surrogate) ==> Surface, Rect\n"
-	"\n"
-	"This is a proof of concept method. It will not be in the final module.\n"
-    },
-    /* <--- */
+
     { NULL, NULL, 0, NULL },
 };
 
         NULL
     },
     {
+        "kerning",
+        _ftfont_getkerning,
+        _ftfont_setkerning,
+        DOC_FONTKERNING,
+        NULL
+    },
+    {
         "vertical",
         _ftfont_getvertical,
         _ftfont_setvertical,
         DOC_FONTUNDERLINE,
         (void *)FT_STYLE_UNDERLINE
     },
+
     { NULL, NULL, NULL, NULL, NULL }
 };
 
         obj->style = FT_STYLE_NORMAL;
         obj->vertical = 0;
         obj->antialias = 1;
+	obj->kerning = 0;
     }
     return (PyObject *)obj;
 }
 }
 
 
+/** Antialias attribute */
+PyObject *
+_ftfont_getkerning(PyObject *self, void *closure)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    
+    return PyBool_FromLong(font->kerning);
+}
+
+int
+_ftfont_setkerning(PyObject *self, PyObject *value, void *closure)
+{
+    PyFreeTypeFont *font = (PyFreeTypeFont *)self;
+    
+    if (!PyBool_Check(value))
+    {
+        PyErr_SetString(PyExc_TypeError, "Expecting 'bool' type");
+        return -1;
+    }
+    font->kerning = (FT_Byte)PyObject_IsTrue(value);
+    return 0;
+}
+
+
 /** Generic style attributes */
 PyObject *
 _ftfont_getstyle_flag(PyObject *self, void *closure)
     return Py_BuildValue("iii", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
 }
 
-/* ---> To be removed in final release */
-static int
-_draw_bitmap(PyObject *b, FT_Byte *bytes, int width, int height, int pitch,
-             FT_Bitmap *bitmap, FT_Int x, FT_Int y)
-{
-    FT_Int  gwidth = bitmap->width;
-    FT_Int  grows = bitmap->rows;
-    FT_Int  gpitch = bitmap->pitch;
-    FT_Byte *bytes_max = bytes + (height * pitch);
-    FT_Byte *row;
-    FT_Byte *row_end = bytes + (y * pitch) + width;
-    FT_Byte *byte;
-    int r;
-    int c;
-    PyObject *ErrMsg = NULL;
-    PyObject *ErrVal = NULL;
-
-    for ( r = 0, row = bytes + (y * pitch) + x;
-          r < grows;
-          ++r, row += pitch  )
-    {
-        for ( c = 0, byte = row; c < gwidth; ++c, ++byte )
-        {
-            if (byte < bytes || byte >= bytes_max)
-            {
-                PyErr_Format(PyExc_RuntimeError,
-                             "(%i, %i), [%i, %i] outside image sized (%i, %i)",
-                             c, r, x + c, y + r, width, height);
-                return -1;
-            } 
-            if (byte >= row_end)
-            {
-                PyErr_Format(PyExc_RuntimeError,
-                             "(%i, %i),[%i, %i] outside image row (%i, %i)",
-                             c, r, x + c, y + r, width, r);
-                return -1;
-            } 
-
-            *byte |= bitmap->buffer[r * gpitch + c];
-        }
-        row_end += pitch;
-    }
-
-    return 0;
-}
-
-static PyObject *
-_ft_render_raw(PyObject *self, PyObject *args, PyObject *kwds)
-{
-    /* keyword list */
-    static char *kwlist[] = 
-    { 
-        "filename", "text", "ptsize", "vertical", "rotation",
-        "kerning", "surrogates", NULL
-    };
-
-    typedef struct My_GlyphRec_ {
-        FT_UInt  glyph_index;
-        FT_Glyph glyph;
-        FT_BBox  bounds;
-    } My_GlyphRec, *My_Glyph;
-
-    /* input arguments */
-    char *filename;
-    PyObject *textobj;
-    PGFT_String *text = NULL;
-    int ptsize = -1;
-    int vertical = 0;
-    double rotation = 0;
-    int use_kerning = 1;
-    int surrogates = 1;
-
-    /* output arguments */
-    PyObject *rbuffer = NULL;
-    PyObject *rtuple = NULL;
-    int width, height;
-
-    FT_Library    library = NULL;
-    FT_Face       face = NULL;
-
-    FT_GlyphSlot  slot;
-    My_Glyph      glyphs = NULL;
-    My_Glyph      glyph;
-    FT_UInt32     flags;
-    FT_BitmapGlyph bitmap;
-    FT_Matrix     matrix;                 /* transformation matrix */
-    FT_Vector     pen;                    /* untransformed origin  */
-    FT_Vector     pen1;
-    FT_Vector     pen2;
-    FT_Vector     kerning;
-    FT_Error      error = 0;
-    char         *error_location = "";
-
-    int           target_top;
-    int           target_left;
-    int           n, num_chars;
-    
-    FT_Pos        min_x;
-    FT_Pos        max_x;
-    FT_Pos        min_y;
-    FT_Pos        max_y;
-    FT_Angle      angle;
-    FT_Vector     unit;
-    
-    PGFT_char     ch;
-    int           bufsize;
-    FT_Byte      *bytes;
-    int           x;
-    int           y;
-
-    FreeTypeInstance *ft;
-    ASSERT_GRAB_FREETYPE(ft, NULL);
-    library = ft->library;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|iidii", kwlist,
-                                     &filename, &textobj, &ptsize,
-                                     &vertical, &rotation, 
-                                     &use_kerning, &surrogates))
-        return NULL;
-
-    /* Encode text */
-    text = PGFT_EncodePyString(textobj, surrogates);
-    if (text == NULL)
-    {
-        goto finished;
-    }
-    num_chars = PGFT_String_GET_LENGTH(text);
-
-    if (num_chars == 0)
-    {
-        PGFT_FreeString(text);
-        return Py_BuildValue("s(ii)", "", 0, 0);
-    }
-    
-    error = FT_New_Face( library, filename, 0, &face ); /* create face object */
-    if (error)
-    {
-        error_location = "Loading font face";
-        goto finished;
-    }
-    
-    if (ptsize < 0)
-    {
-        ptsize = 24;
-    }
-    error = FT_Set_Char_Size( face, ptsize * 64, 0,
-                             100, 0 );                /* set character size */
-    if (error)
-    {
-        error_location = "Setting character size";
-        goto finished;
-    }
-
-    /* calculate start position and transformations */
-    rotation = fmod(rotation, 360);
-    angle = (FT_Angle)(rotation * 0x10000L);
-    FT_Vector_Unit( &unit, angle );
-    matrix.xx = unit.x;  /*  cos(angle) */
-    matrix.xy = -unit.y; /* -sin(angle) */
-    matrix.yx = unit.y;  /*  sin(angle) */
-    matrix.yy = unit.x;  /*  cos(angle) */
-    
-    pen.x = 0;
-    pen.y = 0;
-    pen1.x = 0;
-    pen1.y = 0;
-    
-    /* fill glyph array */
-    use_kerning = !vertical && FT_HAS_KERNING(face) && use_kerning;
-    slot = face->glyph;
-    glyphs = _PGFT_malloc( num_chars * sizeof (My_GlyphRec) );
-    if (glyphs == NULL)
-    {
-        PyErr_NoMemory();
-        goto finished;
-    }
-    flags = FT_LOAD_DEFAULT;
-    if (vertical)
-        flags |= FT_LOAD_VERTICAL_LAYOUT;  
-    for (n = 0; n < num_chars; ++n)
-    {
-        pen2.x = pen1.x;
-        pen2.y = pen1.y;
-        pen1.x = pen.x;
-        pen1.y = pen.y;
-        ch = PGFT_String_GET_DATA(text)[n];
-        glyph = glyphs + n;
-        glyph->glyph = NULL;
-        glyph->glyph_index = FT_Get_Char_Index( face, ch );
-        error = FT_Load_Glyph( face, /* handle to face object */
-                               glyph->glyph_index, /* glyph index */
-                               flags ); /* load flags, see below */
-        if (use_kerning && n > 0)
-        {
-            error = FT_Get_Kerning(face, glyphs[n - 1].glyph_index,
-                                   glyph->glyph_index,
-                                   FT_KERNING_UNFITTED, &kerning);
-            if (error)
-            {
-                error_location = "Kerning";
-                goto finished;
-            }
-            if (angle != 0)
-            {
-                FT_Vector_Rotate(&kerning, angle);
-            }
-            pen.x += PGFT_ROUND(kerning.x);
-            pen.y += PGFT_ROUND(kerning.y);
-            if (FT_Vector_Length(&pen2) > FT_Vector_Length(&pen))
-            {
-                pen.x = pen2.x;
-                pen.y = pen2.y;
-            }
-        }
-        if (!error)
-            error = FT_Get_Glyph(slot, &(glyph->glyph));
-        if (!error)
-            error = FT_Glyph_Transform( glyph->glyph, &matrix, &pen );
-        if (error)
-        {
-            error_location =  "Filling glyph array";
-            goto finished;
-        }
-        pen.x += PGFT_CEIL16_TO_6(glyph->glyph->advance.x);
-        pen.y += PGFT_CEIL16_TO_6(glyph->glyph->advance.y);
-    }
-
-    /* calculate image size */
-    pen.x = 0;
-    pen.y = 0;
-    pen1.x = 0;
-    pen1.y = 0;
-    
-    glyph = glyphs;
-    FT_Glyph_Get_CBox( glyph->glyph, FT_GLYPH_BBOX_SUBPIXELS, &(glyph->bounds) );
-    min_x = 0;
-    if (glyph->bounds.xMin < min_x)
-        min_x = glyph->bounds.xMin;
-    max_x = glyph->bounds.xMax;
-    min_y = glyph->bounds.yMin;
-    max_y = glyph->bounds.yMax;
-    for (n = 1; n < num_chars; ++n)
-    {
-        glyph = glyphs + n;
-        FT_Glyph_Get_CBox( glyph->glyph, FT_GLYPH_BBOX_SUBPIXELS, &(glyph->bounds) );
-        if (glyph->bounds.yMin < min_y)
-            min_y = glyph->bounds.yMin;
-        if (glyph->bounds.yMax > max_y)
-            max_y = glyph->bounds.yMax;
-        if (glyph->bounds.xMin < min_x)
-            min_x = glyph->bounds.xMin;
-        if (glyph->bounds.xMax > max_x)
-            max_x = glyph->bounds.xMax;
-        pen.x += PGFT_CEIL16_TO_6(glyph->glyph->advance.x);
-        pen.y += PGFT_CEIL16_TO_6(glyph->glyph->advance.y);
-    }
-    if (pen.x > max_x)
-        max_x = pen.x;
-    else if (pen.x < min_x)
-        min_x = pen.x;
-    if (pen.y > max_y)
-        max_y = pen.y;
-    else if (pen.y < min_y)
-        min_y = pen.y;
-    width = PGFT_TRUNC(PGFT_CEIL(max_x) - PGFT_FLOOR(min_x));
-    height = PGFT_TRUNC(PGFT_CEIL(max_y) - PGFT_FLOOR(min_y));
-
-    /* create buffer */
-    bufsize = width * height;
-    rbuffer = Bytes_FromStringAndSize(NULL, bufsize);
-    if (rbuffer == NULL)
-    {
-        goto finished;
-    }
-    bytes = (FT_Byte *)Bytes_AS_STRING(rbuffer);
-    memset(bytes, 0x00, (size_t)bufsize);
-
-    /* render characters */
-    target_top = height + PGFT_TRUNC(PGFT_FLOOR(min_y));
-    target_left = PGFT_TRUNC(PGFT_FLOOR(min_x));
-
-    for ( n = 0; n < num_chars; n++ )
-    {
-        FT_Glyph_To_Bitmap(&(glyphs[n].glyph), FT_RENDER_MODE_NORMAL, 0, 1);
-        if (error)
-        {
-            _PGFT_SetError(ft, "Rendering glyphs", error);
-            RAISE(PyExc_SDLError, PGFT_GetError(ft));
-            goto finished;
-        }
-
-        /* now, draw to our target surface (convert position) */
-        bitmap = (FT_BitmapGlyph) glyphs[n].glyph;
-        x = bitmap->left - target_left;
-	y = target_top - bitmap->top;
-        if (_draw_bitmap(rbuffer, bytes, width, height, width,
-                         &(bitmap->bitmap), x, y))
-        {
-            goto finished;
-        }
-    }
-    rtuple = Py_BuildValue("S(ii)", rbuffer, width, height);
-
-finished:    
-    if (glyphs != NULL)
-    {
-        for (n = 0; n < num_chars; ++n)
-        {
-            glyph = glyphs + n;
-            if (glyph->glyph == NULL)
-                break;
-            FT_Done_Glyph ( glyph->glyph );
-        }
-        _PGFT_free ( glyphs );
-    }
-    if (text != NULL)
-        PGFT_FreeString ( text );
-    if (face != NULL)
-        FT_Done_Face ( face );
-    Py_XDECREF(rbuffer);
-    if (error)
-    {
-        _PGFT_SetError(ft, "Loading face", error);
-        RAISE(PyExc_SDLError, PGFT_GetError(ft));
-    }
-    return rtuple;
-}
-
-static PyObject *
-_ft_render_raw2(PyObject *self, PyObject *args, PyObject *kwds)
-{
-    /* keyword list */
-    static char *kwlist[] = 
-    { 
-        "filename", "text", "ptsize", "vertical", "rotation",
-        "kerning", "surrogates", NULL
-    };
-
-    typedef struct My_GlyphRec_ {
-        FT_UInt  glyph_index;
-        FT_Glyph glyph;
-        FT_BBox  bounds;
-    } My_GlyphRec, *My_Glyph;
-
-    /* input arguments */
-    char *filename;
-    PyObject *textobj;
-    PGFT_String *text = NULL;
-    int ptsize = -1;
-    int vertical = 0;
-    double rotation = 0;
-    int use_kerning = 1;
-    int surrogates = 1;
-
-    /* output arguments */
-    PyObject *rbuffer = NULL;
-    PyObject *rtuple = NULL;
-    int width, height;
-
-    FT_Library    library = NULL;
-    FT_Face       face = NULL;
-
-    FT_GlyphSlot  slot;
-    My_Glyph      glyphs = NULL;
-    My_Glyph      glyph;
-    FT_UInt32     flags;
-    FT_BitmapGlyph bitmap;
-    FT_Matrix     matrix;                 /* transformation matrix */
-    FT_Vector     pen;                    /* untransformed origin  */
-    FT_Vector     pen1;
-    FT_Vector     pen2;
-    FT_Vector     kerning;
-    FT_Error      error = 0;
-    char         *error_location = "";
-
-    int           target_top;
-    int           target_left;
-    int           n, num_chars;
-    
-    FT_Pos        min_x;
-    FT_Pos        max_x;
-    FT_Pos        min_y;
-    FT_Pos        max_y;
-    FT_Angle      angle;
-    FT_Vector     unit;
-    
-    PGFT_char     ch;
-    int           bufsize;
-    FT_Byte      *bytes;
-    int           x;
-    int           y;
-
-    FreeTypeInstance *ft;
-    ASSERT_GRAB_FREETYPE(ft, NULL);
-    library = ft->library;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|iidii", kwlist,
-                                     &filename, &textobj, &ptsize,
-                                     &vertical, &rotation, 
-                                     &use_kerning, &surrogates))
-        return NULL;
-
-    /* Encode text */
-    text = PGFT_EncodePyString(textobj, surrogates);
-    if (text == NULL)
-    {
-        goto finished;
-    }
-    num_chars = PGFT_String_GET_LENGTH(text);
-
-    if (num_chars == 0)
-    {
-        PGFT_FreeString(text);
-        return Py_BuildValue("s(ii)", "", 0, 0);
-    }
-    
-    error = FT_New_Face( library, filename, 0, &face ); /* create face object */
-    if (error)
-    {
-        error_location = "Loading font face";
-        goto finished;
-    }
-    
-    if (ptsize < 0)
-    {
-        ptsize = 24;
-    }
-    error = FT_Set_Char_Size( face, ptsize * 64, 0,
-                             100, 0 );                /* set character size */
-    if (error)
-    {
-        error_location = "Setting character size";
-        goto finished;
-    }
-
-    /* calculate start position and transformations */
-    rotation = fmod(rotation, 360);
-    angle = (FT_Angle)(rotation * 0x10000L);
-    FT_Vector_Unit( &unit, angle );
-    matrix.xx = unit.x;  /*  cos(angle) */
-    matrix.xy = -unit.y; /* -sin(angle) */
-    matrix.yx = unit.y;  /*  sin(angle) */
-    matrix.yy = unit.x;  /*  cos(angle) */
-    
-    pen.x = 0;
-    pen.y = 0;
-    pen1.x = 0;
-    pen1.y = 0;
-    
-    /* fill glyph array */
-    use_kerning = !vertical && FT_HAS_KERNING(face) && use_kerning;
-    slot = face->glyph;
-    glyphs = _PGFT_malloc( num_chars * sizeof (My_GlyphRec) );
-    if (glyphs == NULL)
-    {
-        PyErr_NoMemory();
-        goto finished;
-    }
-    flags = FT_LOAD_DEFAULT;
-    if (vertical)
-        flags |= FT_LOAD_VERTICAL_LAYOUT;  
-    for (n = 0; n < num_chars; ++n)
-    {
-        pen2.x = pen1.x;
-        pen2.y = pen1.y;
-        pen1.x = pen.x;
-        pen1.y = pen.y;
-        ch = PGFT_String_GET_DATA(text)[n];
-        glyph = glyphs + n;
-        glyph->glyph = NULL;
-        glyph->glyph_index = FT_Get_Char_Index(face, ch);
-        error = FT_Load_Glyph(face, /* handle to face object */
-                              glyph->glyph_index, /* glyph index */
-                              flags); /* load flags, see below */
-        if (use_kerning && n > 0)
-        {
-            error = FT_Get_Kerning(face, glyphs[n - 1].glyph_index,
-                                   glyph->glyph_index,
-                                   FT_KERNING_UNFITTED, &kerning);
-            if (error)
-            {
-                error_location = "Kerning";
-                goto finished;
-            }
-            if (angle != 0)
-            {
-                FT_Vector_Rotate(&kerning, angle);
-            }
-            pen.x += PGFT_ROUND(kerning.x);
-            pen.y += PGFT_ROUND(kerning.y);
-            if (FT_Vector_Length(&pen2) > FT_Vector_Length(&pen))
-            {
-                pen.x = pen2.x;
-                pen.y = pen2.y;
-            }
-        }
-        if (!error)
-            error = FT_Get_Glyph(slot, &(glyph->glyph));
-        if (!error)
-            error = FT_Glyph_Transform(glyph->glyph, &matrix, &pen);
-        if (error)
-        {
-            error_location =  "Filling glyph array";
-            goto finished;
-        }
-        pen.x += PGFT_CEIL16_TO_6(glyph->glyph->advance.x);
-        pen.y += PGFT_CEIL16_TO_6(glyph->glyph->advance.y);
-    }
-
-    /* calculate image size */
-    glyph = glyphs;
-    FT_Glyph_Get_CBox(glyph->glyph, FT_GLYPH_BBOX_SUBPIXELS, &(glyph->bounds));
-    min_x = glyph->bounds.xMin;
-    max_x = glyph->bounds.xMax;
-    min_y = glyph->bounds.yMin;
-    max_y = glyph->bounds.yMax;
-    for (n = 1; n < num_chars; ++n)
-    {
-        glyph = glyphs + n;
-        FT_Glyph_Get_CBox(glyph->glyph, FT_GLYPH_BBOX_SUBPIXELS, &(glyph->bounds));
-        if (glyph->bounds.yMin < min_y)
-            min_y = glyph->bounds.yMin;
-        if (glyph->bounds.yMax > max_y)
-            max_y = glyph->bounds.yMax;
-        if (glyph->bounds.xMin < min_x)
-            min_x = glyph->bounds.xMin;
-        if (glyph->bounds.xMax > max_x)
-            max_x = glyph->bounds.xMax;
-    }
-    if (pen.x > max_x)
-        max_x = pen.x;
-    else if (pen.x < min_x)
-        min_x = pen.x;
-    if (pen.y > max_y)
-        max_y = pen.y;
-    else if (pen.y < min_y)
-        min_y = pen.y;
-    if (!vertical)
-    {
-        if (min_x < 0)
-        {
-            min_x = -min_x;
-            max_x += 2 * min_x;
-        }
-        else
-        {
-            max_x += min_x;
-            min_x = 0;
-        }
-    }
-    width = PGFT_TRUNC(PGFT_CEIL(max_x) - PGFT_FLOOR(min_x));
-    height = PGFT_TRUNC(PGFT_CEIL(max_y) - PGFT_FLOOR(min_y));
-
-    /* create buffer */
-    bufsize = width * height;
-    rbuffer = Bytes_FromStringAndSize(NULL, bufsize);
-    if (rbuffer == NULL)
-    {
-        goto finished;
-    }
-    bytes = (FT_Byte *)Bytes_AS_STRING(rbuffer);
-    memset(bytes, 0x00, (size_t)bufsize);
-
-    /* render characters */
-    target_top = height + PGFT_TRUNC(PGFT_FLOOR(min_y));
-    target_left = PGFT_TRUNC(PGFT_FLOOR(min_x));
-
-    for ( n = 0; n < num_chars; n++ )
-    {
-        FT_Glyph_To_Bitmap(&(glyphs[n].glyph), FT_RENDER_MODE_NORMAL, 0, 1);
-        if (error)
-        {
-            _PGFT_SetError(ft, "Rendering glyphs", error);
-            RAISE(PyExc_SDLError, PGFT_GetError(ft));
-            goto finished;
-        }
-
-        /* now, draw to our target surface (convert position) */
-        bitmap = (FT_BitmapGlyph) glyphs[n].glyph;
-        x = bitmap->left + target_left;
-        if (vertical)
-            y = bitmap->top;
-        else
-            y = target_top - bitmap->top;
-        if (_draw_bitmap(rbuffer, bytes, width, height, width,
-                         &(bitmap->bitmap), x, y))
-        {
-            goto finished;
-        }
-    }
-    rtuple = Py_BuildValue("S(ii)", rbuffer, width, height);
-
-finished:    
-    if (glyphs != NULL)
-    {
-        for (n = 0; n < num_chars; ++n)
-        {
-            glyph = glyphs + n;
-            if (glyph->glyph == NULL)
-                break;
-            FT_Done_Glyph ( glyph->glyph );
-        }
-        _PGFT_free ( glyphs );
-    }
-    if (text != NULL)
-        PGFT_FreeString ( text );
-    if (face != NULL)
-        FT_Done_Face ( face );
-    Py_XDECREF(rbuffer);
-    if (error)
-    {
-        _PGFT_SetError(ft, "Loading face", error);
-        RAISE(PyExc_SDLError, PGFT_GetError(ft));
-    }
-    return rtuple;
-}
-/* <--- */
-
 PyObject *
 _ft_was_init(PyObject *self)
 {

File src/freetype.h

 
 /* Render styles */
 #define FT_STYLE_NORMAL     0x00
-#define FT_STYLE_BOLD		0x01
+#define FT_STYLE_BOLD	    0x01
 #define FT_STYLE_ITALIC     0x02
 #define FT_STYLE_UNDERLINE  0x04
 #define FT_STYLE_DEFAULT    0xFF
 #define FT_RFLAG_AUTOHINT       (1 << 1)
 #define FT_RFLAG_VERTICAL       (1 << 2)
 #define FT_RFLAG_HINTED         (1 << 3)
+#define FT_RFLAG_KERNING        (1 << 4)
 #define FT_RFLAG_DEFAULTS       (FT_RFLAG_NONE | FT_RFLAG_HINTED)
 
 
     FT_Byte style;
     FT_Byte vertical;
     FT_Byte antialias;
+    FT_Byte kerning;
 
     void *_internals;
 } PyFreeTypeFont;

File src/freetype/ft_cache.c

 #include FT_MODULE_H
 #include FT_OUTLINE_H
 
+#define SLANT_FACTOR    0.22
+static FT_Matrix PGFT_SlantMatrix = 
+{
+    (1 << 16),  (FT_Fixed)(SLANT_FACTOR * (1 << 16)),
+    0,          (1 << 16) 
+};
+
 FT_UInt32 _PGFT_Cache_Hash(const FontRenderMode *, FT_UInt);
 FT_UInt32 _PGFT_GetLoadFlags(const FontRenderMode *);
 
         FontCache *, const FontRenderMode *, FT_UInt);
 void _PGFT_Cache_FreeNode(FontCache *, FontCacheNode *);
 
+const int render_flags_mask = (FT_RFLAG_ANTIALIAS |
+                               FT_RFLAG_HINTED |
+                               FT_RFLAG_AUTOHINT);
+
 static int
 equal_node_keys(CacheNodeKey *a, CacheNodeKey *b)
 {
     return (a->ch == b->ch &&
             a->mode.pt_size == b->mode.pt_size &&
             a->mode.rotation_angle == b->mode.rotation_angle &&
-            a->mode.render_flags == b->mode.render_flags &&
+            (a->mode.render_flags & render_flags_mask) ==
+            (b->mode.render_flags & render_flags_mask) &&
             a->mode.style == b->mode.style);
 }
 
 
     if (render->render_flags & FT_RFLAG_HINTED)
     {
-        load_flags |=   (render->render_flags & FT_RFLAG_ANTIALIAS) ?
-                        FT_LOAD_TARGET_NORMAL :
-                        FT_LOAD_TARGET_MONO;
+        load_flags |= ((render->render_flags & FT_RFLAG_ANTIALIAS) ?
+                       FT_LOAD_TARGET_NORMAL :
+                       FT_LOAD_TARGET_MONO);
     }
     else
     {
     _PGFT_free(node);
 }
 
+static void
+_PGFT_Metrics_Rotate(FontMetrics *metrics,
+                     FT_BitmapGlyph image,
+                     FT_Angle angle)
+{
+    FT_Pos    min_x = metrics->bearing_x;
+    FT_Pos    max_x = min_x + PGFT_INT_TO_6(image->bitmap.width);
+    FT_Pos    max_y = metrics->bearing_y;
+    FT_Pos    min_y = max_y - PGFT_INT_TO_6(image->bitmap.rows);
+    FT_Vector topleft = {min_x, max_y};
+    FT_Vector topright = {max_x, max_y};
+    FT_Vector bottomleft = {min_x, min_y};
+    FT_Vector bottomright = {max_x, min_y};
+    FT_Vector bearing_x = {metrics->bearing_x, 0};
+    FT_Vector bearing_y = {0, metrics->bearing_y};
+
+    FT_Vector_Rotate(&metrics->advance, angle);
+
+    metrics->bearing_x = PGFT_INT_TO_6(image->left);
+    metrics->bearing_y = PGFT_INT_TO_6(image->top);
+#if 0
+    FT_Vector_Rotate(&bearing, angle);
+    metrics->bearing_x = bearing.x;
+    metrics->bearing_y = bearing.y;
+#endif
+#if 0
+    FT_Vector_Rotate(&topleft, angle);
+    FT_Vector_Rotate(&topright, angle);
+    FT_Vector_Rotate(&bottomleft, angle);
+    FT_Vector_Rotate(&bottomright, angle);
+
+    min_x = bottomleft.x;
+    if (bottomright.x < min_x)
+    {
+        min_x = bottomright.x;
+    }
+    if (topleft.x < min_x)
+    {
+        min_x = topleft.x;
+    }
+    if (topright.x < min_x)
+    {
+        min_x = topright.x;
+    }
+    max_y = topright.y;
+    if (topleft.y > max_y)
+    {
+        max_y = bottomright.y;
+    }
+    if (bottomright.y > max_y)
+    {
+        max_y = topleft.y;
+    }
+    if (bottomleft.y > max_y)
+    {
+        max_y = topright.y;
+    }
+    metrics->bearing_x = min_x;
+    metrics->bearing_y = max_y;
+#endif
+}
+
 FontCacheNode *
 _PGFT_Cache_AllocateNode(FreeTypeInstance *ft, 
         FontCache *cache, const FontRenderMode *render, FT_UInt character)
     int embolden = render->style & FT_STYLE_BOLD;
     FontCacheNode *node = NULL;
     FontGlyph *glyph = NULL;
+    FontMetrics *metrics;
     FT_Glyph image;
 
-    FT_Glyph_Metrics *metrics;
+    FT_Glyph_Metrics *ft_metrics;
     FT_Face face;
 
     FT_UInt32 load_flags;
         FT_Get_Glyph(face->glyph, &image))
         goto cleanup;
 
-    /*
-     * Precalculate useful metric values
-     */
-    metrics = &face->glyph->metrics;
-    glyph->bold_strength = 0;
-    glyph->h_bearings.x = metrics->horiBearingX;
-    glyph->h_bearings.y = metrics->horiBearingY;
-    glyph->h_advances.x = metrics->horiAdvance;
-    glyph->h_advances.y = 0;
-    glyph->v_bearings.x = metrics->vertBearingX;
-    glyph->v_bearings.y = metrics->vertBearingY;
-    glyph->v_advances.x = 0;
-    glyph->v_advances.y = metrics->vertAdvance;
-
-    /*
-     * Perform any transformations
-     */
     if (embolden)
     {
         bold_str = PGFT_GetBoldStrength(face);
         if (FT_Outline_Embolden(&((FT_OutlineGlyph)image)->outline, bold_str))
             goto cleanup;
-        glyph->bold_strength += bold_str;
-        glyph->h_advances.x += bold_str;
-        glyph->v_advances.y += bold_str;
     }
 
-    if (rotation_angle != 0) {
+    /*
+     * Precalculate useful metric values
+     */
+    ft_metrics = &face->glyph->metrics;
+    glyph->bold_strength = bold_str;
+    metrics = &glyph->h_metrics;
+    metrics->bearing_x = ft_metrics->horiBearingX;
+    metrics->bearing_y = ft_metrics->horiBearingY;
+    metrics->advance.x = ft_metrics->horiAdvance + bold_str;
+    metrics->advance.y = 0;
+    metrics = &glyph->v_metrics;
+    metrics->bearing_x = ft_metrics->vertBearingX;
+    metrics->bearing_y = ft_metrics->vertBearingY;
+    metrics->advance.x = 0;
+    metrics->advance.y = ft_metrics->vertAdvance + bold_str;
+
+    /*
+     * Perform any transformations
+     */
+    if (rotation_angle != 0)
+    {
         FT_Vector_Unit(&unit, rotation_angle);
         transform.xx = unit.x;  /*  cos(angle) */
         transform.xy = -unit.y; /* -sin(angle) */
         transform.yx = unit.y;  /*  sin(angle) */
         transform.yy = unit.x;  /*  cos(angle) */
-        if (FT_Glyph_Transform(image, &transform, &delta)) {
+        if (FT_Glyph_Transform(image, &transform, &delta))
+        {
             goto cleanup;
         }
-	FT_Vector_Rotate(&glyph->h_bearings, rotation_angle);
-	FT_Vector_Rotate(&glyph->h_advances, rotation_angle);
-	FT_Vector_Rotate(&glyph->v_bearings, rotation_angle);
-	FT_Vector_Rotate(&glyph->v_advances, rotation_angle);
+    }
+
+    if (render->style & FT_STYLE_ITALIC)
+    {
+        FT_Outline_Transform(&(((FT_OutlineGlyph)image)->outline),
+                             &PGFT_SlantMatrix);
     }
 
     /*
     glyph->image = (FT_BitmapGlyph)image;
 
     /*
+     * Adjust the metrics.
+     */
+    if (rotation_angle != 0)
+    {
+        _PGFT_Metrics_Rotate(&glyph->h_metrics, glyph->image, rotation_angle);
+        _PGFT_Metrics_Rotate(&glyph->v_metrics, glyph->image, rotation_angle);
+    }
+
+    /*
      * Update cache internals
      */
     node->key.mode = *render;

File src/freetype/ft_metrics.c

     *(float *)maxx = glyph->image->left + glyph->image->bitmap.width;
     *(float *)maxy = glyph->image->top;
     *(float *)miny = *(float *)maxy - glyph->image->bitmap.rows;
-    *(float *)advance = glyph->h_advances.x;
+    *(float *)advance = (float)glyph->h_metrics.advance.x / 65536.0;
 
 #   undef FP26_6
     return 0;

File src/freetype/ft_text.c

     FontText    *ftext = NULL;
     FontGlyph   *glyph = NULL;
     FontGlyph   **glyph_array = NULL;
+    FontMetrics *metrics;
     FT_BitmapGlyph image;
 
     FT_Face     face;
     FT_Vector   pen1 = {0, 0};
     FT_Vector   pen2;
 
-    FT_Vector   *next_posn;
+    FT_Vector   *next_pos;
 
     int         vertical = font->vertical;
-    int         use_kerning = 0;
+    int         use_kerning = font->kerning;
     FT_Angle    angle = render->rotation_angle;
     FT_Vector   kerning;
     FT_UInt     prev_glyph_index = 0;
     FT_Pos      max_x = PGFT_MIN_6;  /* 26.6 */
     FT_Pos      min_y = PGFT_MAX_6;  /* 26.6 */
     FT_Pos      max_y = PGFT_MIN_6;  /* 26.6 */
-    int         glyph_width;
-    int         glyph_height;
+    FT_Pos      glyph_width;         /* 26.6 */
+    FT_Pos      glyph_height;        /* 26.6 */
+    FT_Pos      text_width;          /* 26.6 */
+    FT_Pos      text_height;         /* 26.6 */
+    FT_Pos      top = PGFT_MIN_6;    /* 26.6 */
 
     FT_Error    error = 0;
     int         i;
     /* fill it with the glyphs */
     glyph_array = ftext->glyphs;
 
-    next_posn = ftext->posns;
+    next_pos = ftext->posns;
 
     for (ch = buffer, buffer_end = ch + string_length; ch < buffer_end; ++ch)
     {
         if (!glyph)
             continue;
         image = glyph->image;
+        glyph_width = PGFT_INT_TO_6(image->bitmap.width);
+        glyph_height = PGFT_INT_TO_6(image->bitmap.rows);
 
         /*
          * Do size calculations for all the glyphs in the text
             }
         }
 
-	glyph_width = image->bitmap.width;
-	glyph_height = image->bitmap.rows;
         prev_glyph_index = glyph->glyph_index;
-	if (vertical)
+	metrics = vertical ? &glyph->v_metrics : &glyph->h_metrics;
+        if (metrics->bearing_y > top)
         {
-            if (pen.x + glyph->v_bearings.x < min_x)
-                min_x = pen.x + glyph->v_bearings.x;
-            if (min_x + PGFT_INT_TO_6(glyph_width) > max_x)
-                max_x = min_x + PGFT_INT_TO_6(glyph_width);
-            if (pen.y + glyph->v_bearings.y > max_y)
-                max_y = pen.y + glyph->v_bearings.y;
-            if (max_y - PGFT_INT_TO_6(glyph_height) < min_y)
-                min_y = max_y - PGFT_INT_TO_6(glyph_height);
-            next_posn->x = pen.x + glyph->v_bearings.x;
-            next_posn->y = pen.y + glyph->v_bearings.y;
-            pen.x += glyph->v_advances.x;
-            pen.y += glyph->v_advances.y;
+            top = metrics->bearing_y;
+        }
+	if (pen.x + metrics->bearing_x < min_x)
+        {
+            min_x = pen.x + metrics->bearing_x;
+        }
+        if (pen.x + metrics->bearing_x + glyph_width > max_x)
+        {
+            max_x = pen.x + metrics->bearing_x + glyph_width;
+        }
+        if (pen.y - metrics->bearing_y < min_y)
+        {
+            min_y = pen.y - metrics->bearing_y;
+        }
+        if (pen.y - metrics->bearing_y + glyph_height > max_y)
+        {
+            max_y = pen.y - metrics->bearing_y + glyph_height;
+        }
+        next_pos->x = pen.x + metrics->bearing_x;
+	pen.x += metrics->advance.x;
+        if (vertical)
+        {
+            next_pos->y = pen.y + metrics->bearing_y;
+            pen.y += metrics->advance.y;
         }
         else
         {
-            if (pen.x + glyph->h_bearings.x < min_x)
-                min_x = pen.x + glyph->h_bearings.x;
-            if (min_x + PGFT_INT_TO_6(glyph_width) > max_x)
-                max_x = min_x + PGFT_INT_TO_6(glyph_width);
-            if (pen.y + glyph->h_bearings.y > max_y)
-                max_y = pen.y + glyph->h_bearings.y;
-            if (max_y - PGFT_INT_TO_6(glyph_height) < min_y)
-                min_y = max_y - PGFT_INT_TO_6(glyph_height);
-            next_posn->x = pen.x + glyph->h_bearings.x;
-            next_posn->y = pen.y + glyph->h_bearings.y;
-            pen.x += glyph->h_advances.x;
-            pen.y += glyph->h_advances.y;
+            next_pos->y = pen.y - metrics->bearing_y;
+            pen.y -= metrics->advance.y;
         }
-        ++next_posn;
         *glyph_array++ = glyph;
+        ++next_pos;
     }
     if (pen.x > max_x)
         max_x = pen.x;
 
         underline_pos = FT_MulFix(face->underline_position, scale) / 4; /*(1)*/
         underline_size = FT_MulFix(face->underline_thickness, scale) + bold_str;
-        min_y_underline = (underline_pos -
-                           PGFT_CEIL(ftext->underline_size / 2));
-	if (min_y_underline < min_y)
+        min_y_underline = underline_pos - ftext->underline_size / 2;
+	if (min_y_underline < min_y - max_y + top)
         {
-            min_y = min_y_underline;
+            max_y = min_y - min_y_underline + max_y + top;
         }
 
-	ftext->underline_pos = (max_y - PGFT_FLOOR(underline_pos) -
-                                PGFT_CEIL(ftext->underline_size / 2));
-	ftext->underline_size = PGFT_CEIL(underline_size);
+	ftext->underline_pos = top - min_y_underline;
+	ftext->underline_size = underline_size;
 
         /*
          * (1) HACK HACK HACK
          */
     }
 
-    if (min_x < 0)
-    {
-        ftext->width = PGFT_TRUNC(PGFT_CEIL(max_x) - PGFT_FLOOR(min_x));
-        ftext->left = -PGFT_TRUNC(PGFT_FLOOR(min_x));
-    }
-    else
-    {
-        ftext->width = PGFT_TRUNC(PGFT_CEIL(max_x) + PGFT_FLOOR(min_x));
-        ftext->left = 0;
-    }
-    ftext->height = PGFT_TRUNC(PGFT_CEIL(max_y) - PGFT_FLOOR(min_y));
-    ftext->top = max_y;
-
-    glyph_array = ftext->glyphs;
-    next_posn = ftext->posns;
+    text_width = PGFT_CEIL(max_x) - PGFT_FLOOR(min_x);
+    ftext->width = PGFT_TRUNC(text_width);
+    ftext->left = PGFT_TRUNC(PGFT_FLOOR(min_x));
+    text_height = PGFT_CEIL(max_y) - PGFT_FLOOR(min_y);
+    ftext->height = PGFT_TRUNC(text_height);
+    ftext->top = PGFT_TRUNC(PGFT_CEIL(top));
+    
     if (vertical)
     {
+        next_pos = ftext->posns;
         for (i = 0; i < string_length; ++i)
         {
-            next_posn->x -= min_x;
-            ++next_posn;
+            next_pos->x -= min_x;
+            ++next_pos;
         }
     }
     else
     {
+        next_pos = ftext->posns;
         for (i = 0; i < string_length; ++i)
         {
-            next_posn->y = max_y - next_posn->y;
-            ++next_posn;
-        } 
+            next_pos->x -= min_x;
+            next_pos->y -= min_y;
+            ++next_pos;
+        }
     }
 
     return ftext;

File src/freetype/ft_wrap.h

     FT_UInt16   style;
 } FontRenderMode;
 
-typedef struct  __fontglyph
+typedef struct __fontmetrics
+{
+    FT_Pos    bearing_x;   /* 26.6 */
+    FT_Pos    bearing_y;   /* 26.6 */
+    FT_Vector advance;     /* 26.6 */
+} FontMetrics;
+
+typedef struct __fontglyph
 {
     FT_UInt     glyph_index;
     FT_BitmapGlyph image;
 
-    FT_Pos      bold_strength;  /* 26.6 */
-    FT_Vector   h_bearings;     /* 26.6 */
-    FT_Vector   h_advances;     /* 26.6 */
-    FT_Vector   v_bearings;     /* 26.6 */
-    FT_Vector   v_advances;     /* 26.6 */
+    FT_Pos      bold_strength; /* 26.6 */
+    FontMetrics h_metrics;
+    FontMetrics v_metrics;
 } FontGlyph;
 
 typedef struct __fonttext