Commits

Lenard Lindstrom committed 0921cc0

Anti-aliased underlines for pygame.freetype

When a Font object is set to "antialiased", underlines are also anti-aliased
in the along the y direction.

  • Participants
  • Parent commits f8608dd

Comments (0)

Files changed (3)

File src/freetype/ft_render.c

             SDL_FillRect(surface, &bg_fill, fillcolor);
         }
         else {
-            font_surf.fill(x, y, width, height, &font_surf, bgcolor);
+            font_surf.fill(INT_TO_FX6(x), INT_TO_FX6(y),
+                           INT_TO_FX6(width), INT_TO_FX6(height),
+                           &font_surf, bgcolor);
         }
     }
 
     FT_Vector *posns = text->posns;
     FontRenderPtr render_gray = surface->render_gray;
     FontRenderPtr render_mono = surface->render_mono;
+    int is_underline_gray = 0;
 
     if (length <= 0) {
         return;
         y = FX6_TRUNC(FX6_CEIL(top + posns[n].y));
         if (image->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
             render_gray(x, y, surface, &(image->bitmap), fg_color);
+            is_underline_gray = 1;
         }
         else {
             render_mono(x, y, surface, &(image->bitmap), fg_color);
     }
 
     if (underline_size > 0) {
-        surface->fill(
-            FX6_TRUNC(FX6_CEIL(left - text->min_x)),
-            FX6_TRUNC(FX6_CEIL(top + underline_top)),
-            width, FX6_TRUNC(FX6_CEIL(underline_size)),
-            surface, fg_color);
+        if (is_underline_gray) {
+            surface->fill(left + text->min_x, top + underline_top,
+                          INT_TO_FX6(width), underline_size,
+                          surface, fg_color);
+        }
+        else {
+            surface->fill(FX6_CEIL(left + text->min_x),
+                          FX6_CEIL(top + underline_top),
+                          INT_TO_FX6(width), FX6_CEIL(underline_size),
+                          surface, fg_color);
+        }
     }
 }

File src/freetype/ft_render_cb.c

     }
 }
 
-void __fill_glyph_GRAY1(int x, int y, int w, int h,
-        FontSurface *surface, const FontColor *color)
+void __fill_glyph_GRAY1(FT_Fixed x, FT_Fixed y, FT_Fixed w, FT_Fixed h,
+                        FontSurface *surface, const FontColor *color)
 {
     int i, j;
     FT_Byte *dst;
     FT_Byte *dst_cpy;
     FT_Byte shade = color->a;
+    FT_Byte edge_shade;
 
     x = MAX(0, x);
     y = MAX(0, y);
 
-    if (x + w > surface->width) {
-        w = surface->width - x;
+    if (x + w > INT_TO_FX6(surface->width)) {
+        w = INT_TO_FX6(surface->width) - x;
     }
-    if (y + h > surface->height) {
-        h = surface->height - y;
+    if (y + h > INT_TO_FX6(surface->height)) {
+        h = INT_TO_FX6(surface->height) - y;
     }
 
-    dst = (FT_Byte *)surface->buffer + x + (y * surface->pitch);
+    dst = ((FT_Byte *)surface->buffer +
+           FX6_TRUNC(FX6_CEIL(x)) +
+           FX6_TRUNC(FX6_CEIL(y)) * surface->pitch);
 
-    for (j = 0; j < h; ++j) {
+    if (y < FX6_CEIL(y)) {
+        dst_cpy = dst - surface->pitch;
+        edge_shade = FX6_TRUNC(FX6_ROUND(shade * (FX6_CEIL(y) - y)));
+
+        for (i = 0; i < FX6_TRUNC(FX6_CEIL(w)); ++i, ++dst_cpy) {
+            *dst_cpy = edge_shade;
+        }
+    }
+        
+    for (j = 0; j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); ++j) {
         dst_cpy = dst;
 
-        for (i = 0; i < w; ++i, ++dst_cpy) {
+        for (i = 0; i < FX6_TRUNC(FX6_CEIL(w)); ++i, ++dst_cpy) {
             *dst_cpy = shade;
         }
 
         dst += surface->pitch;
     }
+
+    if (h > FX6_FLOOR(h + y) - y) {
+        dst_cpy = dst;
+        edge_shade = FX6_TRUNC(FX6_ROUND(shade * (y + y - FX6_FLOOR(h + y))));
+        for (i = 0; i < FX6_TRUNC(FX6_CEIL(w)); ++i, ++dst_cpy) {
+            *dst_cpy = edge_shade;
+        }
+    }
 }
 
 void __render_glyph_INT(int x, int y, FontSurface *surface,
     }
 }
 
-void __fill_glyph_INT(int x, int y, int w, int h,
+void __fill_glyph_INT(FT_Fixed x, FT_Fixed y, FT_Fixed w, FT_Fixed h,
                       FontSurface *surface, const FontColor *color)
 {
     int b, i, j;
     int byteoffset = surface->format->Ashift / 8;
     FT_Byte *dst_cpy;
     FT_Byte shade = color->a;
+    FT_Byte edge_shade;
 
     x = MAX(0, x);
     y = MAX(0, y);
 
-    if (x + w > surface->width) {
-        w = surface->width - x;
+    if (x + w > INT_TO_FX6(surface->width)) {
+        w = INT_TO_FX6(surface->width) - x;
     }
-    if (y + h > surface->height) {
-        h = surface->height - y;
+    if (y + h > INT_TO_FX6(surface->height)) {
+        h = INT_TO_FX6(surface->height) - y;
     }
 
-    dst = (FT_Byte *)surface->buffer + x + (y * surface->pitch);
+    dst = ((FT_Byte *)surface->buffer +
+           FX6_TRUNC(FX6_CEIL(x)) * itemsize +
+           FX6_TRUNC(FX6_CEIL(y)) * surface->pitch);
 
     if (itemsize == 1) {
-        for (j = 0; j < h; ++j) {
+        if (y < FX6_CEIL(y)) {
+            dst_cpy = dst - surface->pitch;
+            edge_shade = FX6_TRUNC(FX6_ROUND(shade * (FX6_CEIL(y) - y)));
+
+            for (i = 0;
+                 i < FX6_TRUNC(FX6_CEIL(w));
+                 ++i, dst_cpy += item_stride) {
+                *dst_cpy = edge_shade;
+            }
+        }
+        
+        for (j = 0; j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); ++j) {
             dst_cpy = dst;
 
-            for (i = 0; i < w; ++i, dst_cpy += item_stride) {
+            for (i = 0;
+                 i < FX6_TRUNC(FX6_CEIL(w));
+                 ++i, dst_cpy += item_stride) {
                 *dst_cpy = shade;
             }
 
             dst += surface->pitch;
         }
+
+        if (h > FX6_FLOOR(h + y) - y) {
+            dst_cpy = dst;
+            edge_shade = FX6_TRUNC(FX6_ROUND(shade *
+                                             (y + y - FX6_FLOOR(h + y))));
+            for (i = 0;
+                 i < FX6_TRUNC(FX6_CEIL(w));
+                 ++i, dst_cpy += item_stride) {
+                *dst_cpy = edge_shade;
+            }
+        }
     }
     else {
-        for (j = 0; j < h; ++j) {
+        if (y < FX6_CEIL(y)) {
+            dst_cpy = dst - surface->pitch;
+            edge_shade = FX6_TRUNC(FX6_ROUND(shade * (FX6_CEIL(y) - y)));
+
+            for (i = 0;
+                 i < FX6_TRUNC(FX6_CEIL(w));
+                 ++i, dst_cpy += item_stride) {
+                for (b = 0; b < itemsize; ++b) {
+                    dst_cpy[b] = 0;
+                }
+                dst_cpy[byteoffset] = edge_shade;
+            }
+        }
+        
+        for (j = 0; j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); ++j) {
             dst_cpy = dst;
 
-            for (i = 0; i < w; ++i, dst_cpy += item_stride) {
+            for (i = 0;
+                 i < FX6_TRUNC(FX6_CEIL(w));
+                 ++i, dst_cpy += item_stride) {
                 for (b = 0; b < itemsize; ++b) {
                     dst_cpy[b] = 0;
                 }
 
             dst += surface->pitch;
         }
+
+        if (h > FX6_FLOOR(h + y) - y) {
+            dst_cpy = dst;
+            edge_shade = FX6_TRUNC(FX6_ROUND(shade *
+                                             (h + y - FX6_FLOOR(h + y))));
+            for (i = 0;
+                 i < FX6_TRUNC(FX6_CEIL(w));
+                 ++i, dst_cpy += item_stride) {
+                for (b = 0; b < itemsize; ++b) {
+                    dst_cpy[b] = 0;
+                }
+                dst_cpy[byteoffset] = edge_shade;
+            }
+        }
     }
 }
 
 #ifdef HAVE_PYGAME_SDL_VIDEO
 
 #define _CREATE_RGB_FILLER(_bpp, _getp, _setp, _blendp)     \
-    void __fill_glyph_RGB##_bpp(int x, int y, int w, int h, \
+    void __fill_glyph_RGB##_bpp(FT_Fixed x, FT_Fixed y,     \
+                                FT_Fixed w, FT_Fixed h,     \
                                 FontSurface *surface,       \
                                 const FontColor *color)     \
     {                                                       \
         int i, j;                                           \
         unsigned char *dst;                                 \
         FT_UInt32 bgR, bgG, bgB, bgA;                       \
+        FT_Byte edge_a;                                     \
                                                             \
         x = MAX(0, x);                                      \
         y = MAX(0, y);                                      \
                                                             \
-        if (x + w > surface->width) {                       \
-            w = surface->width - x;                         \
+        if (x + w > INT_TO_FX6(surface->width)) {           \
+            w = INT_TO_FX6(surface->width) - x;             \
         }                                                   \
-        if (y + h > surface->height) {                      \
-            h = surface->height - y;                        \
+        if (y + h > INT_TO_FX6(surface->height)) {          \
+            h = INT_TO_FX6(surface->height) - y;            \
         }                                                   \
                                                             \
-        dst = ((unsigned char *)surface->buffer +           \
-               (x * _bpp) +                                 \
-               (y * surface->pitch));                       \
+        dst = ((FT_Byte *)surface->buffer +                 \
+               FX6_TRUNC(FX6_CEIL(x)) * _bpp +              \
+               FX6_TRUNC(FX6_CEIL(y)) * surface->pitch);    \
                                                             \
-        for (j = 0; j < h; ++j) {                           \
+        if (y < FX6_CEIL(y)) {                              \
+            unsigned char *_dst = dst - surface->pitch;     \
+                                                            \
+            edge_a = (                                      \
+                FX6_TRUNC(FX6_ROUND(color->a *              \
+                                    (FX6_CEIL(y) - y))));   \
+                                                            \
+            for (i = 0;                                     \
+                 i < FX6_TRUNC(FX6_CEIL(w));                \
+                 ++i, _dst += _bpp) {                       \
+                FT_UInt32 pixel = (FT_UInt32)_getp;         \
+                                                            \
+                if (_bpp == 1) {                            \
+                    GET_PALETTE_VALS(                       \
+                            pixel, surface->format,         \
+                            bgR, bgG, bgB, bgA);            \
+                }                                           \
+                else {                                      \
+                    GET_RGB_VALS(                           \
+                            pixel, surface->format,         \
+                            bgR, bgG, bgB, bgA);            \
+                                                            \
+                }                                           \
+                                                            \
+                ALPHA_BLEND(                                \
+                        color->r, color->g, color->b,       \
+                        edge_a, bgR, bgG, bgB, bgA);        \
+                                                            \
+                _blendp;                                    \
+            }                                               \
+        }                                                   \
+                                                            \
+        for (j = 0;                                         \
+             j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); \
+             ++j) {                                         \
             unsigned char *_dst = dst;                      \
                                                             \
-            for (i = 0; i < w; ++i, _dst += _bpp) {         \
+            for (i = 0;                                     \
+                 i < FX6_TRUNC(FX6_CEIL(w));                \
+                 ++i, _dst += _bpp) {                       \
                 FT_UInt32 pixel = (FT_UInt32)_getp;         \
                                                             \
                 if (_bpp == 1) {                            \
                                                             \
             dst += surface->pitch;                          \
         }                                                   \
+                                                            \
+        if (h > FX6_FLOOR(h + y) - y) {                     \
+            unsigned char *_dst = dst;                      \
+                                                            \
+            edge_a = (                                      \
+                FX6_TRUNC(FX6_ROUND(color->a *              \
+                                    (h + y -                \
+                                     FX6_FLOOR(h + y)))));  \
+                                                            \
+            for (i = 0;                                     \
+                 i < FX6_TRUNC(FX6_CEIL(w));                \
+                 ++i, _dst += _bpp) {                       \
+                FT_UInt32 pixel = (FT_UInt32)_getp;         \
+                                                            \
+                if (_bpp == 1) {                            \
+                    GET_PALETTE_VALS(                       \
+                            pixel, surface->format,         \
+                            bgR, bgG, bgB, bgA);            \
+                }                                           \
+                else {                                      \
+                    GET_RGB_VALS(                           \
+                            pixel, surface->format,         \
+                            bgR, bgG, bgB, bgA);            \
+                                                            \
+                }                                           \
+                                                            \
+                ALPHA_BLEND(                                \
+                        color->r, color->g, color->b,       \
+                        edge_a, bgR, bgG, bgB, bgA);        \
+                                                            \
+                _blendp;                                    \
+            }                                               \
+        }                                                   \
     }
 
 #define __MONO_RENDER_INNER_LOOP(_bpp, _code)               \

File src/freetype/ft_wrap.h

 
 typedef void (* FontRenderPtr)(int, int, struct fontsurface_ *,
                                const FT_Bitmap *, const FontColor *);
-typedef void (* FontFillPtr)(int, int, int, int, struct fontsurface_ *,
-                             const FontColor *);
+typedef void (* FontFillPtr)(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                             struct fontsurface_ *, const FontColor *);
 
 typedef struct fontsurface_ {
     void *buffer;
 
 
 /**************************************** Render callbacks *******************/
-void __fill_glyph_RGB1(int, int, int, int, FontSurface *, const FontColor *);
-void __fill_glyph_RGB2(int, int, int, int, FontSurface *, const FontColor *);
-void __fill_glyph_RGB3(int, int, int, int, FontSurface *, const FontColor *);
-void __fill_glyph_RGB4(int, int, int, int, FontSurface *, const FontColor *);
+void __fill_glyph_RGB1(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                       FontSurface *, const FontColor *);
+void __fill_glyph_RGB2(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                       FontSurface *, const FontColor *);
+void __fill_glyph_RGB3(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                       FontSurface *, const FontColor *);
+void __fill_glyph_RGB4(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                       FontSurface *, const FontColor *);
 
-void __fill_glyph_GRAY1(int, int, int, int, FontSurface *, const FontColor *);
+void __fill_glyph_GRAY1(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                        FontSurface *, const FontColor *);
 
-void __fill_glyph_INT(int, int, int, int, FontSurface *, const FontColor *);
+void __fill_glyph_INT(FT_Fixed, FT_Fixed, FT_Fixed, FT_Fixed,
+                      FontSurface *, const FontColor *);
 
 void __render_glyph_MONO1(int, int, FontSurface *, const FT_Bitmap *,
                           const FontColor *);