Commits

Lenard Lindstrom committed c2d5114

freetype: Some changes to make freetype.Font behave more like font.Font. Also some more experimentation with the text layout code. Passes unit tests again.

Comments (0)

Files changed (4)

         RAISE(PyExc_ValueError, "Invalid point size for font.");
         return NULL;
     }
-    value = (long)PGFT_Face_GetHeightSized(ft, self, (FT_UInt16)pt_size);
+    value = PGFT_Face_GetHeightSized(ft, self, (FT_UInt16)pt_size);
     if (!value && PyErr_Occurred())
     {
         return NULL;
                         text, surface, xpos, ypos,
                         &fg_color,
                         bg_color_obj ? &bg_color : NULL, &r);
-         PGFT_FreeString(text);
+        PGFT_FreeString(text);
         if (rcode)
         {
             Py_DECREF(surface_obj);

src/freetype/ft_render.c

     if (!font_text)
         return NULL;
 
-    width = font_text->width;
-    height = font_text->height;
-    if (height <= 0)
+    if (font_text->length > 0)
     {
+        width = font_text->width;
+        height = font_text->height;
+    }
+    else
+    {
+        width = 1;
         height = PGFT_Face_GetHeightSized(ft, font, render->pt_size);
     }
-    if (width < 0)
-    {
-        width = 0;
-    }
 
     surface = SDL_CreateRGBSurface(surface_flags, width, height,
                    bits_per_pixel, rmask, gmask, bmask,
                    bits_per_pixel == 32 ? amask : 0);
-    if (!surface)
-    {
-        PyErr_NoMemory(); /* Everything else should be Okay */
+    if (!surface) {
+        PyErr_SetString(PyExc_SDLError, SDL_GetError());
         return NULL;
     }
 
-    if (width == 0)
-    {
-        /* Nothing more to do. */
-        r->x = 0;
-        r->y = 0;
-        r->w = 0;
-        r->h = height;
-        return surface;
-    }
-
     if (SDL_MUSTLOCK(surface))
     {
         if (SDL_LockSurface(surface) == -1)

src/freetype/ft_text.c

     0,          (1 << 16) 
 };
 
+static FT_Matrix PGFT_Unit =
+{
+    (1 << 16),  0,
+    0,          (1 << 16) 
+};
+
 typedef struct __fonttextcontext
 {
     FT_Library lib;
     FTC_FaceID id;
     FT_Face face;
     FTC_CMapCache charmap;
+    int do_transform;
+    FT_Matrix transform;
 } FontTextContext;
 
 #define BOLD_STRENGTH_D (0.65)
                          FT_Pos bearing_x, FT_Pos bearing_y,
                          FT_Vector *bearing_rotated,
                          FT_Vector *advance_rotated);
+static void fill_context(FontTextContext *context,
+                         const FreeTypeInstance *ft,
+                         const PyFreeTypeFont *font,
+                         const FontRenderMode *render,
+                         const FT_Face face);
 
 int
 PGFT_FontTextInit(FreeTypeInstance *ft, PyFreeTypeFont *font)
     FT_UInt     prev_glyph_index = 0;
 
     /* All these are 16.16 precision */
-    FT_Angle    angle = render->rotation_angle;
+    FT_Angle    rotation_angle = render->rotation_angle;
 
     /* All these are 26.6 precision */
     FT_Vector   kerning;
         return NULL;
     }
 
-    context.lib = ft->library;
-    context.id = (FTC_FaceID)&(font->id);
-    context.face = face;
-    context.charmap = ft->cache_charmap;
-
     /* cleanup the cache */
     PGFT_Cache_Cleanup(&ftext->glyph_cache);
 
         }
         ftext->buffer_size = string_length;
     }
-
     ftext->length = string_length;
     ftext->underline_pos = ftext->underline_size = 0;
 
     /* fill it with the glyphs */
+    fill_context(&context, ft, font, render, face);
     glyph_array = ftext->glyphs;
-
     next_pos = ftext->posns;
 
     for (ch = buffer, buffer_end = ch + string_length; ch < buffer_end; ++ch)
                 PyErr_SetString(PyExc_SDLError, PGFT_GetError(ft));
                 return NULL;
             }
-            if (angle != 0)
+            if (rotation_angle != 0)
             {
-                FT_Vector_Rotate(&kerning, angle);
+                FT_Vector_Rotate(&kerning, rotation_angle);
             }
             pen.x += PGFT_ROUND(kerning.x);
             pen.y += PGFT_ROUND(kerning.y);
         ++next_pos;
     }
 
-    if (render->style & FT_STYLE_UNDERLINE && !vertical && angle == 0)
+    if (render->style & FT_STYLE_UNDERLINE && !vertical && rotation_angle == 0)
     {
         FT_Fixed scale;
         FT_Fixed underline_pos;
                     long *miny, long *maxy,
                     double *advance_x, double *advance_y)
 { 
+    FontText    *ftext = &(PGFT_INTERNALS(font)->active_text);
     FontGlyph *glyph = NULL;
     FontTextContext context;
     FT_Face     face;
         return -1;
     }
 
-    context.lib = ft->library;
-    context.id = (FTC_FaceID)&(font->id);
-    context.face = face;
-    context.charmap = ft->cache_charmap;
+    /* cleanup the cache */
+    PGFT_Cache_Cleanup(&ftext->glyph_cache);
+
+    fill_context(&context, ft, font, render, face);
     glyph = PGFT_Cache_FindGlyph(character, render,
                                  &PGFT_INTERNALS(font)->active_text.glyph_cache, 
                                  &context);
 {
     static FT_Vector delta = {0, 0};
 
-    int oblique = render->style & FT_STYLE_OBLIQUE;
     int embolden = render->style & FT_STYLE_BOLD;
-    int do_transform = render->render_flags & FT_RFLAG_TRANSFORM;
     FT_Render_Mode rmode = (render->render_flags & FT_RFLAG_ANTIALIAS ?
                             FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
     FT_Fixed bold_str = 0;
     FT_UInt gindex;
 
     FT_Fixed rotation_angle = render->rotation_angle;
-    FT_Vector unit;
     /* FT_Matrix transform; */
     FT_Vector h_bearing_rotated;
     FT_Vector v_bearing_rotated;
     FT_Vector h_advance_rotated;
     FT_Vector v_advance_rotated;
 
-    FT_Matrix transform = {PGFT_INT_TO_16(1), 0, 0, PGFT_INT_TO_16(1)};
-
     FT_Error error = 0;
 
     /*
         bold_delta.y += (after.yMax - after.yMin) - (before.yMax - before.yMin);
     }
 
-    if (oblique)
+    if (context->do_transform)
     {
-        FT_Matrix_Multiply(&PGFT_SlantMatrix, &transform);
-        do_transform = 1;
-        /* FT_Outline_Transform(&(((FT_OutlineGlyph)image)->outline), */
-        /*                      &PGFT_SlantMatrix); */
-    }
-
-    if (rotation_angle != 0)
-    {
-        FT_Matrix rotate;
-
-        FT_Vector_Unit(&unit, rotation_angle);
-        rotate.xx = unit.x;  /*  cos(angle) */
-        rotate.xy = -unit.y; /* -sin(angle) */
-        rotate.yx = unit.y;  /*  sin(angle) */
-        rotate.yy = unit.x;  /*  cos(angle) */
-        FT_Matrix_Multiply(&rotate, &transform);
-        do_transform = 1;
-    }
-
-    if (do_transform)
-    {
-        if (FT_Glyph_Transform(image, &transform, &delta))
+        if (FT_Glyph_Transform(image, &context->transform, &delta))
         {
             goto cleanup;
         }
 }
 
 static void
+fill_context(FontTextContext *context,
+             const FreeTypeInstance *ft,
+             const PyFreeTypeFont *font,
+             const FontRenderMode *render,
+             const FT_Face face)
+{
+    context->lib = ft->library;
+    context->id = (FTC_FaceID)&(font->id);
+    context->face = face;
+    context->charmap = ft->cache_charmap;
+    context->do_transform = 0;
+
+    if (render->style & FT_STYLE_OBLIQUE)
+    {
+        context->transform = PGFT_SlantMatrix;
+        context->do_transform = 1;
+    }
+    else
+    {
+        context->transform = PGFT_Unit;
+    }
+
+    if (render->render_flags & FT_RFLAG_TRANSFORM)
+    {
+        FT_Matrix_Multiply(&render->transform, &context->transform);
+        context->do_transform = 1;
+    }
+
+    if (render->rotation_angle != 0)
+    {
+        FT_Vector unit;
+        FT_Matrix rotate;
+
+        FT_Vector_Unit(&unit, render->rotation_angle);
+        rotate.xx = unit.x;  /*  cos(angle) */
+        rotate.xy = -unit.y; /* -sin(angle) */
+        rotate.yx = unit.y;  /*  sin(angle) */
+        rotate.yy = unit.x;  /*  cos(angle) */
+        FT_Matrix_Multiply(&rotate, &context->transform);
+        context->do_transform = 1;
+    }
+}
+
+static void
 fill_metrics(FontMetrics *metrics, 
              FT_Pos bearing_x, FT_Pos bearing_y,
              FT_Vector *bearing_rotated,

test/freetype_font_test.py

         self.assertTrue(isinstance(metrics, list))
 
         for metrics_tuple in metrics:
-            self.assertTrue(isinstance(metrics_tuple, tuple))
+            self.assertTrue(isinstance(metrics_tuple, tuple), metrics_tuple)
             self.assertEqual(len(metrics_tuple), 6)
             for m in metrics_tuple[:4]:
                 self.assertTrue(isinstance(m, int))
         self.assertTrue(isinstance(rend[1], pygame.Rect))
         self.assertEqual(rend[0].get_rect().size, rend[1].size)
         s, r = font.render(None, '', pygame.Color(0, 0, 0), None, ptsize=24)
-        self.assertFalse(r, str(r))
-        self.assertEqual(r.height, font.height)
-        self.assertEqual(s.get_rect(), r)
+        self.assertEqual(r.width, 1)
+        self.assertEqual(r.height, font.get_sized_height(24))
+        self.assertEqual(s.get_size(), r.size)
         self.assertEqual(s.get_bitsize(), 32)
 
         # render to existing surface
 
         s, r = font.render((surf, rect), '', color, None, ptsize=24)
         self.assertFalse(r)
-        self.assertEqual(r.height, font.height)
+        self.assertEqual(r.height, font.get_sized_height(24))
         self.assertTrue(s is surf)
 
         # invalid dest test
         glen = len(glyphs)
         other_glyphs = "123"
         oglen = len(other_glyphs)
-        many_glyphs = unicode("").join([unichr_(i) for i in range(32,127)])
+        uempty = unicode_("")
+##        many_glyphs = (uempty.join([unichr_(i) for i in range(32,127)] +
+##                                   [unichr_(i) for i in range(161,172)] +
+##                                   [unichr_(i) for i in range(174,239)]))
+        many_glyphs = uempty.join([unichr_(i) for i in range(32,127)])
         mglen = len(many_glyphs)
 
         count = 0
         self.assertEqual((ccount + cdelete_count, caccess, chit, cmiss),
                          (count, access, hit, miss))
         # Trigger a cleanup for sure.
-        count += mglen
-        access += mglen
-        miss += mglen
-        f.render_raw(many_glyphs, ptsize=10)
+        count += 2 * mglen
+        access += 2 * mglen
+        miss += 2 * mglen
+        f.get_metrics(many_glyphs, ptsize=8)
+        f.get_metrics(many_glyphs, ptsize=10)
         ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats
+        print (ccount, cdelete_count, caccess, chit, cmiss)
         self.assertTrue(ccount < count)
         self.assertEqual((ccount + cdelete_count, caccess, chit, cmiss),
                          (count, access, hit, miss))
 
     def test_undefined_character_code(self):
         # To be consistent with pygame.font.Font, undefined codes
-        # are rendered as the undefined character.
+        # are rendered as the undefined character, and has metrics
+        # of None.
         font = self._TEST_FONTS['sans']
 
         img, size1 = font.render(None, unichr_(1), (0, 0, 0), ptsize=24)
 
         metrics = font.get_metrics(unichr_(1) + unichr_(48), ptsize=24)
         self.assertEqual(len(metrics), 2)
-        self.assertTrue(isinstance(metrics[0], tuple))
+        self.assertTrue(metrics[0] is None)
+        self.assertTrue(isinstance(metrics[1], tuple))
 
 class FreeTypeFont(unittest.TestCase):