Commits

Anonymous committed b0470ba

Many changes to size calculation on FT fonts.

Comments (0)

Files changed (6)

examples/freetype/sdlfont.py

     screen.fill (pygame2.Color (200, 200, 200))
     w, h, _ = font.render("Hello", pygame2.Color(100, 100, 100), None, screen, 100, 100, ptsize=48)
 
-    w, h, _ = font.render("Hello qjky", pygame2.Color(100, 100, 100), None, screen, 100, 200, ptsize=48, vertical = True)
+    w, h, _ = font.render("World", pygame2.Color(200, 100, 100), pygame2.Color(255, 0xCC, 0), screen, 100, 200, ptsize=48, vertical = True, rotation = 45)
 
 #    w, g, buf = font.render("Hello World, Jay",
 #            pygame2.Color(100, 200, 32),

src/freetype/ft_font.c

     if (vertical_obj && PyObject_IsTrue(vertical_obj))
         vertical = 1;
 
-    PGFT_BuildRenderMode(&render, 0.0f, vertical, FONT_RENDER_ANTIALIAS, rotation);
+    PGFT_BuildRenderMode(&render, vertical, FONT_RENDER_ANTIALIAS, rotation);
 
     error = PGFT_GetTextSize(ft, (PyFreeTypeFont *)self, ptsize, &render,
             text, &width, &height);
         vertical = 1;
 
     /* TODO: handle antialiasing */
-    PGFT_BuildRenderMode(&render, 0.0f, vertical, FONT_RENDER_ANTIALIAS, rotation);
+    PGFT_BuildRenderMode(&render, vertical, FONT_RENDER_ANTIALIAS, rotation);
 
 
     if (!target_surf || target_surf == Py_None)
     {
         if (PGFT_Render_ExistingSurface(ft, font, ptsize, &render, 
                 text, (PySDLSurface *)target_surf,
-                xpos, ypos, (PyColor *)fg_color, &width, &height) != 0)
+                xpos, ypos, (PyColor *)fg_color, (PyColor *)bg_color,
+                &width, &height) != 0)
         {
             PyErr_SetString(PyExc_PyGameError, PGFT_GetError(ft));
             return NULL;

src/freetype/ft_metrics.c

 
 int
 _PGFT_GetTextSize_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
-    int pt_size, FontRenderMode *render, FontText *text, int *w, int *h)
+    int pt_size, FontRenderMode *render, FontText *text)
 {
     FT_Vector   extent, advances[MAX_GLYPHS];
     FT_Error    error;
+    FT_Vector   size;
 
     error = PGFT_GetTextAdvances(ft, font, pt_size, render, text, advances);
 
     if (error)
-    {
-        _PGFT_SetError(ft, "Failed to load glyph advances", error);
         return error;
-    }
 
     extent = advances[text->length - 1];
 
     if (render->vertical)
     {
-        *w = PGFT_TRUNC(text->size.x);
-        *h = PGFT_TRUNC(extent.y);
+        size.x = text->glyph_size.x;
+        size.y = ABS(extent.y);
     }
     else
     {
-        *w = PGFT_TRUNC(extent.x);
-        *h = PGFT_TRUNC(text->size.y);
+        size.x = extent.x;
+        size.y = text->glyph_size.y;
     }
 
+    if (render->matrix)
+    {   
+        FT_Vector_Rotate(&size, render->_rotation_angle);
+    }
+
+    text->text_size.x = PGFT_TRUNC(PGFT_ROUND(ABS(size.x)));
+    text->text_size.y = PGFT_TRUNC(PGFT_ROUND(ABS(size.y)));
+
     return 0;
 }
 
     if (!font_text)
         return -1;
 
-    return _PGFT_GetTextSize_INTERNAL(ft, font, pt_size, render, font_text, w, h);
+    if (_PGFT_GetTextSize_INTERNAL(ft, font, pt_size, render, font_text) != 0)
+        return -1;
+
+    *w = font_text->text_size.x;
+    *h = font_text->text_size.y;
+    return 0;
 }

src/freetype/ft_render.c

 void __render_glyph_ByteArray(int x, int y, FontSurface *surface, FT_Bitmap *bitmap, PyColor *color);
 
 void 
-PGFT_BuildRenderMode(FontRenderMode *mode, float center, int vertical, int antialias, int rotation)
+PGFT_BuildRenderMode(FontRenderMode *mode, int vertical, int antialias, int rotation)
 {
     double      radian;
     FT_Fixed    cosinus;
 
     mode->kerning_mode = 1;
     mode->kerning_degree = 0;
-    mode->center = (FT_Fixed)(center * (1 << 16));
+
     mode->vertical = (FT_Byte)vertical;
     mode->hinted = (FT_Byte)1;
     mode->autohint = 0;
     if (angle != 0)
     {
         radian  = angle * 3.14159 / 180.0;
-        cosinus = (FT_Fixed)( cos( radian ) * 65536.0 );
-        sinus   = (FT_Fixed)( sin( radian ) * 65536.0 );
+        cosinus = (FT_Fixed)(cos(radian) * 65536.0);
+        sinus   = (FT_Fixed)(sin(radian) * 65536.0);
 
         mode->_rotation_matrix.xx = cosinus;
         mode->_rotation_matrix.yx = sinus;
         mode->_rotation_matrix.xy = -sinus;
         mode->_rotation_matrix.yy = cosinus;
+        mode->_rotation_angle = (angle << 16);
 
         mode->matrix = &mode->_rotation_matrix;
     }
 
 int PGFT_Render_ExistingSurface(FreeTypeInstance *ft, PyFreeTypeFont *font,
     int font_size, FontRenderMode *render, PyObject *text, PySDLSurface *_surface, 
-    int x, int y, PyColor *fgcolor, int *_width, int *_height)
+    int x, int y, PyColor *fgcolor, PyColor *bgcolor, int *_width, int *_height)
 {
     static const FontRenderPtr __renderFuncs[] =
     {
         __render_glyph_SDL32
     };
 
-    int width, glyph_height, height, locked = 0;
+    int         locked = 0;
 
-    SDL_Surface *surface = PySDLSurface_AsSDLSurface(_surface);
+    SDL_Surface *surface;
     FontSurface font_surf;
-    FontText *font_text;
+    FontText    *font_text;
+
+    surface = PySDLSurface_AsSDLSurface(_surface);
 
     if (SDL_MUSTLOCK(surface))
     {
     if (!font_text)
         return -1;
 
-    _PGFT_GetTextSize_INTERNAL(ft, font, font_size, render, font_text, &width, &height);
+    _PGFT_GetTextSize_INTERNAL(ft, font, font_size, render, font_text);
 
-#if 1
-    fprintf(stderr, "Drawing @ (%d, %d, %d, %d)\n", x, y, width, height);
+    /* if bg color exists, paint background */
+    if (bgcolor)
+    {
+        SDL_Rect    bg_fill; 
+        FT_UInt32   fillcolor;
 
-    SDL_Rect fill = {x, y, width, height};
-    SDL_FillRect(surface, &fill, 0x00FFAA00);
-#endif
+        fillcolor = SDL_MapRGBA(surface->format, 
+                bgcolor->r, bgcolor->g, bgcolor->b, 255);
+
+        bg_fill.x = (FT_Int16)x;
+        bg_fill.y = (FT_Int16)y;
+        bg_fill.w = (FT_UInt16)font_text->text_size.x;
+        bg_fill.h = (FT_UInt16)font_text->text_size.y;
+
+        SDL_FillRect(surface, &bg_fill, fillcolor);
+    }
 
     /*
      * Setup target surface struct
     /*
      * Render!
      */
-    if (_PGFT_Render_NEW(ft, font, font_text, font_size, fgcolor, &font_surf, render) != 0)
+    if (_PGFT_Render_INTERNAL(ft, font, font_text, font_size, fgcolor, &font_surf, render) != 0)
         return -1;
 
-    *_width = width;
-    *_height = height;
+    *_width = font_text->text_size.x;
+    *_height = font_text->text_size.y;
 
     if (locked)
         SDL_UnlockSurface(surface);
     int ptsize, FontRenderMode *render, PyObject *text,
     PyColor *fgcolor, PyColor *bgcolor, int *_width, int *_height)
 {
-    int width, height, locked = 0;
+    int locked = 0;
     FT_UInt32 fillcolor, rmask, gmask, bmask, amask;
     SDL_Surface *surface = NULL;
 
     if (!font_text)
         return NULL;
 
-    if (_PGFT_GetTextSize_INTERNAL(ft, font, ptsize, render, 
-                font_text, &width, &height) != 0)
+    if (_PGFT_GetTextSize_INTERNAL(ft, font, ptsize, render, font_text) != 0)
         return NULL;
 
 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
     amask = 0xff000000;
 #endif
 
-    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 
+    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 
+            font_text->text_size.x,
+            font_text->text_size.y,
             32, rmask, gmask, bmask, amask);
 
     if (!surface)
     font_surf.format = surface->format;
     font_surf.render = __render_glyph_SDL32;
 
-    if (_PGFT_Render_NEW(ft, font, font_text, ptsize, fgcolor, &font_surf, render) != 0)
+    if (_PGFT_Render_INTERNAL(ft, font, font_text, ptsize, fgcolor, &font_surf, render) != 0)
     {
         SDL_FreeSurface(surface);
         return NULL;
     }
 
-    *_width = width;
-    *_height = height;
+    *_width = font_text->text_size.x;
+    *_height = font_text->text_size.y;
 
     if (locked)
         SDL_UnlockSurface(surface);
 PyObject *PGFT_Render_PixelArray(FreeTypeInstance *ft, PyFreeTypeFont *font,
     int ptsize, PyObject *text, int *_width, int *_height)
 {
-    int width, height, glyph_height;
     FT_Byte *buffer = NULL;
     PyObject *array = NULL;
     FontSurface surf;
 
     FontText *font_text;
     FontRenderMode render;
+    int array_size;
 
-    PGFT_BuildRenderMode(&render, 0.0f, 
+    PGFT_BuildRenderMode(&render, 
             FONT_RENDER_HORIZONTAL, FONT_RENDER_ANTIALIAS, 0);
 
     /* build font text */
     if (!font_text)
         goto cleanup;
 
-    if (_PGFT_GetTextSize_INTERNAL(ft, font, ptsize, &render, 
-                font_text, &width, &height) != 0)
+    if (_PGFT_GetTextSize_INTERNAL(ft, font, ptsize, &render, font_text) != 0)
         goto cleanup;
 
-    buffer = malloc((size_t)(width * height));
+    array_size = font_text->text_size.x * font_text->text_size.y;
+    buffer = malloc((size_t)array_size);
     if (!buffer)
     {
         _PGFT_SetError(ft, "Could not allocate memory", 0);
         goto cleanup;
     }
 
-    memset(buffer, 0xFF, (size_t)(width * height));
+    memset(buffer, 0xFF, (size_t)array_size);
 
     surf.buffer = buffer;
-    surf.width = surf.pitch = width;
-    surf.height = height;
+    surf.width = surf.pitch = font_text->text_size.x;
+    surf.height = font_text->text_size.y;
 
     surf.format = NULL;
     surf.render = __render_glyph_ByteArray;
 
-    if (_PGFT_Render_NEW(ft, font, font_text, ptsize, 0x0, &surf, &render) != 0)
+    if (_PGFT_Render_INTERNAL(ft, font, font_text, ptsize, 0x0, &surf, &render) != 0)
         goto cleanup;
 
-    *_width = width;
-    *_height = height;
+    *_width = font_text->text_size.x;
+    *_height = font_text->text_size.y;
 
-    array = Bytes_FromStringAndSize((char *)buffer, width * height);
+    array = Bytes_FromStringAndSize((char *)buffer, array_size);
 
 cleanup:
     if (buffer)
  * New rendering algorithm (rotation + veritical drawing)
  *
  *********************************************************/
-int _PGFT_Render_NEW(FreeTypeInstance *ft, PyFreeTypeFont *font, 
+int _PGFT_Render_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
     FontText *text, int font_size, PyColor *fg_color, FontSurface *surface, 
     FontRenderMode *render)
 {
     FT_Vector pen, advances[MAX_GLYPHS];
     FT_Face face;
     FT_Error error;
+    FT_Fixed center = 0;
 
     int x = surface->x_offset;
     int y = surface->y_offset;
 
-    if (render->vertical)
-        x += PGFT_TRUNC(PGFT_ROUND(text->size.x / 2));
+    assert(text->text_size.x);
+    assert(text->text_size.y);
+
+
+    if (render->_rotation_angle)
+    {
+        x += ((text->text_size.x + 1) & ~1) / 2;
+        y += ((text->text_size.y + 1) & ~1) / 2;
+        center = (1 << 15);
+    }
+    else if (render->vertical)
+    {
+        x += PGFT_TRUNC(PGFT_ROUND(text->glyph_size.x / 2));
+        y += text->text_size.y;
+    }
     else
     {
-        y += PGFT_TRUNC(text->size.y);
+        y += PGFT_TRUNC(text->glyph_size.y);
         y -= PGFT_TRUNC(text->baseline_offset.y);
     }
 
-
     /* TODO: return if drawing outside surface */
 
 
     /* get the extent, which we store in the last slot */
     pen = advances[text->length - 1];
 
-    pen.x = FT_MulFix(pen.x, render->center); 
-    pen.y = FT_MulFix(pen.y, render->center);
+    pen.x = FT_MulFix(pen.x, center); 
+    pen.y = FT_MulFix(pen.y, center);
 
     /* get pen position */
     if (render->matrix && FT_IS_SCALABLE(face))
     return error;
 }
 
-
-
-
-
-
-/*********************************************************
- *
- * Old rendering algorithm (DEPRECATE)
- *
- *********************************************************/
-int _PGFT_Render_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
-    const FT_UInt16 *text, int font_size, PyColor *fg_color, FontSurface *surface)
-{
-    const FT_UInt16 *ch;
-
-    FTC_ScalerRec scale;
-    FT_Face face;
-    FT_Glyph glyph;
-    FT_Bitmap *bitmap;
-
-    FT_UInt32 prev_index, cur_index;
-
-    int swapped, use_kerning;
-    int pen_x, pen_y;
-    int x_advance;
-
-    _PGFT_BuildScaler(font, &scale, font_size);
-    face = _PGFT_GetFace(ft, font);
-
-    if (!face)
-    {
-        _PGFT_SetError(ft, "Failed to cache font face", 0);
-        return -1;
-    }
-
-    use_kerning = FT_HAS_KERNING(face);
-    prev_index = 0;
-
-    /* FIXME: Some way to set the system's default ? */
-    swapped = 0;
-
-    pen_x = 0;
-    pen_y = surface->glyph_height;
-
-    for (ch = text; *ch; ++ch)
-    {
-        FT_UInt16 c = *ch;
-
-        if (c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED)
-        {
-            swapped = (c == UNICODE_BOM_SWAPPED);
-            if (text == ch)
-                ++text;
-
-            continue;
-        }
-
-        if (swapped)
-            c = (FT_UInt16)((c << 8) | (c >> 8));
-
-        if (_PGFT_LoadGlyph(ft, font, 1 /* RENDER! */, &scale, c, &glyph, &cur_index) != 0)
-            continue; /* FIXME: fail if we cannot find a char? */
-
-        assert(glyph->format == FT_GLYPH_FORMAT_BITMAP);
-        bitmap = &((FT_BitmapGlyph)glyph)->bitmap;
-
-        if (use_kerning && prev_index)
-        {
-            FT_Vector delta;
-            FT_Get_Kerning(face, prev_index, cur_index, ft_kerning_default, &delta); 
-            pen_x += delta.x >> 6;
-        }
-
-        x_advance = (glyph->advance.x + 0x8000) >> 16;
-
-        /*
-         * Render bitmap on the surface at coords:
-         *      pen_x + bitmap->left, pen_y - bitmap->top
-         */
-        {
-            const int left = pen_x + ((FT_BitmapGlyph)glyph)->left;
-            const int top = pen_y - ((FT_BitmapGlyph)glyph)->top;
-
-            surface->render(left, top, surface, bitmap, fg_color);
-        }
-
-        /* FIXME: Why the extra pixel? */
-        pen_x += x_advance; /* + 1; */
-        prev_index = cur_index;
-    }
-
-    return 0;
-}

src/freetype/ft_text.c

 
     FT_Face     face;
 
-    FTC_ScalerRec scale;
-    FT_Size fontsize;
-
     /* compute proper load flags */
     load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
 
     ftext = malloc(sizeof(FontText));
     ftext->length = string_length;
     ftext->glyphs = calloc((size_t)string_length, sizeof(FontGlyph));
-    ftext->size.x = ftext->size.y = 0;
+    ftext->glyph_size.x = ftext->glyph_size.y = 0;
+    ftext->text_size.x = ftext->text_size.y = 0;
     ftext->baseline_offset.x = ftext->baseline_offset.y = 0;
 
     /* fill it with the glyphs */
             if (baseline > ftext->baseline_offset.y)
                 ftext->baseline_offset.y = baseline;
 
-            if (metrics->width > ftext->size.x)
-                ftext->size.x = metrics->width;
+            if (metrics->width > ftext->glyph_size.x)
+                ftext->glyph_size.x = metrics->width;
 
-            if (metrics->height > ftext->size.y)
-                ftext->size.y = metrics->height;
+            if (metrics->height > ftext->glyph_size.y)
+                ftext->glyph_size.y = metrics->height;
 
             if (prev_rsb_delta - face->glyph->lsb_delta >= 32)
                 glyph->delta = -1 << 6;

src/freetype/ft_wrap.h

 
     int width;
     int height;
-    int glyph_height;
     int pitch;
 
     SDL_PixelFormat *format;
 typedef struct __rendermode
 {
     int         kerning_degree;
-    FT_Fixed    center;            /* 0..1 */
-    FT_Matrix*  matrix;            /* string transformation */
+    FT_Matrix*  matrix;
 
     FT_Matrix   _rotation_matrix;
+    FT_Fixed    _rotation_angle;
 
     FT_Byte     hinted;
     FT_Byte     vertical;
     int length;
     FT_UInt32 _hash;
 
-    FT_Vector size;
-    FT_Vector baseline_offset;
+    FT_Vector glyph_size;       /* 26.6 */
+    FT_Vector text_size;        /* integer */
+    FT_Vector baseline_offset;  /* 26.6 */
 
 } FontText;
 
                 void *minx, void *maxx, void *miny, void *maxy, void *advance);
 
 int         _PGFT_GetTextSize_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
-                int pt_size, FontRenderMode *render, FontText *text, int *w, int *h);
+                int pt_size, FontRenderMode *render, FontText *text);
 
 void        _PGFT_GetMetrics_INTERNAL(FT_Glyph, FT_UInt, int *, int *, int *, int *, int *);
 
 
 int         PGFT_Render_ExistingSurface(FreeTypeInstance *ft, PyFreeTypeFont *font,
                 int font_size, FontRenderMode *render, PyObject *text, 
-                PySDLSurface *_surface, int x, int y, PyColor *fgcolor, 
+                PySDLSurface *_surface, int x, int y, PyColor *fgcolor, PyColor *bgcolor,
                 int *_width, int *_height);
 
-void        PGFT_BuildRenderMode(FontRenderMode *mode, float center,
-                int vertical, int antialias, int rotation);
+void        PGFT_BuildRenderMode(FontRenderMode *mode, int vertical, 
+                int antialias, int rotation);
 
 int         _PGFT_Render_INTERNAL(FreeTypeInstance *ft, PyFreeTypeFont *font, 
-                const FT_UInt16 *text, int font_size, PyColor *fg_color, 
-                FontSurface *surf);
-
-int         _PGFT_Render_NEW(FreeTypeInstance *ft, PyFreeTypeFont *font, 
                 FontText *text, int font_size, PyColor *fg_color, 
                 FontSurface *surface, FontRenderMode *render);