SDL_ttf: Add functions to use FreeType ClearType-style LCD rendering (#138)

From f26fa4c6ee60f04adabae96bbf147718a873dd8b Mon Sep 17 00:00:00 2001
From: Sylvain Becker <[EMAIL REDACTED]>
Date: Sun, 8 May 2022 18:14:12 +0200
Subject: [PATCH] Add functions to use FreeType ClearType-style LCD rendering
 (#138)

* Add functions to use FreeType LCD rendering

* Restore un-related merge
---
 SDL_ttf.c | 430 +++++++++++++++++++++++++++++++++++++++++++-----------
 SDL_ttf.h |  36 +++++
 2 files changed, 383 insertions(+), 83 deletions(-)

diff --git a/SDL_ttf.c b/SDL_ttf.c
index f3e0353..4a12db0 100644
--- a/SDL_ttf.c
+++ b/SDL_ttf.c
@@ -191,11 +191,13 @@ static SDL_INLINE int hasNEON()
 #define DIVIDE_BY_255(x)    DIVIDE_BY_255_SIGNED(x, 1)
 
 
-#define CACHED_METRICS  0x10
+#define CACHED_METRICS  0x20
+
 #define CACHED_BITMAP   0x01
 #define CACHED_PIXMAP   0x02
 #define CACHED_COLOR    0x04
-#define CACHED_SUBPIX   0x08
+#define CACHED_LCD      0x08
+#define CACHED_SUBPIX   0x10
 
 
 typedef struct {
@@ -323,7 +325,8 @@ static SDL_bool TTF_byteswapped = SDL_FALSE;
 typedef enum {
     RENDER_SOLID = 0,
     RENDER_SHADED,
-    RENDER_BLENDED
+    RENDER_BLENDED,
+    RENDER_LCD
 } render_mode_t;
 
 typedef enum {
@@ -348,7 +351,7 @@ static SDL_Surface* TTF_Render_Wrapped_Internal(TTF_Font *font, const char *text
         SDL_Color fg, SDL_Color bg, Uint32 wrapLength, render_mode_t render_mode);
 
 static SDL_INLINE int Find_GlyphByIndex(TTF_Font *font, FT_UInt idx,
-        int want_bitmap, int want_pixmap, int want_color, int want_subpixel,
+        int want_bitmap, int want_pixmap, int want_color, int want_lcd, int want_subpixel,
         int translation, c_glyph **out_glyph, TTF_Image **out_image);
 
 static void Flush_Cache(TTF_Font *font);
@@ -422,6 +425,72 @@ static SDL_INLINE void BG_Blended_Color(const TTF_Image *image, Uint32 *destinat
     }
 }
 
+/* Blend with LCD rendering */
+static SDL_INLINE void BG_Blended_LCD(const TTF_Image *image, Uint32 *destination, Sint32 srcskip, Uint32 dstskip, SDL_Color *fg)
+{
+    const Uint32 *src   = (Uint32 *)image->buffer;
+    Uint32      *dst    = destination;
+    Uint32       width  = image->width;
+    Uint32       height = image->rows;
+
+    Uint32 tmp, bg;
+    Uint32 r, g, b;
+    Uint8 fg_r, fg_g, fg_b;
+    Uint8 bg_r, bg_g, bg_b;
+    Uint32 bg_a;
+
+    fg_r = fg->r;
+    fg_g = fg->g;
+    fg_b = fg->b;
+
+    int x, y = 0;
+
+    while (height--) {
+        y++;
+        x = 0;
+        /* *INDENT-OFF* */
+        DUFFS_LOOP4(
+                x++;
+                tmp = *src++;
+
+                if (tmp) {
+
+                    bg = *dst;
+
+                    bg_a = bg & 0xff000000;
+                    bg_r = (bg >> 16) & 0xff;
+                    bg_g = (bg >> 8) & 0xff;
+                    bg_b = (bg >> 0) & 0xff;
+
+                    r = (tmp >> 16) & 0xff;
+                    g = (tmp >> 8) & 0xff;
+                    b = (tmp >> 0) & 0xff;
+
+                    r = fg_r * r + bg_r * (255 - r) + 127;
+                    r = DIVIDE_BY_255(r);
+
+                    g = fg_g * g + bg_g * (255 - g) + 127;
+                    g = DIVIDE_BY_255(g);
+
+                    b = fg_b * b + bg_b * (255 - b) + 127;
+                    b = DIVIDE_BY_255(b);
+
+                    r <<= 16;
+                    g <<= 8;
+                    b <<= 0;
+
+                    *dst = r | g | b | bg_a;
+                }
+                dst++;
+
+                , width);
+        /* *INDENT-ON* */
+        src = (const Uint32 *)((const Uint8 *)src + srcskip);
+        dst = (Uint32 *)((Uint8 *)dst + dstskip);
+    }
+
+}
+
 #if TTF_USE_SDF
 
 /* Blended Opaque SDF */
@@ -950,7 +1019,7 @@ static void Draw_Line(TTF_Font *font, const SDL_Surface *textbuf, int row, int l
     /* Wrapped mode with an unbroken line: 'line_width' is greater that 'textbuf->w' */
     line_width = SDL_min(line_width, textbuf->w);
 
-    if (render_mode == RENDER_BLENDED) {
+    if (render_mode == RENDER_BLENDED || render_mode == RENDER_LCD) {
         while (line_thickness--) {
             SDL_memset4(dst, color, line_width);
             dst += textbuf->pitch;
@@ -963,7 +1032,7 @@ static void Draw_Line(TTF_Font *font, const SDL_Surface *textbuf, int row, int l
     }
 }
 
-static void clip_glyph(int *_x, int *_y, TTF_Image *image, const SDL_Surface *textbuf)
+static void clip_glyph(int *_x, int *_y, TTF_Image *image, const SDL_Surface *textbuf, int is_lcd)
 {
     int above_w;
     int above_h;
@@ -971,8 +1040,7 @@ static void clip_glyph(int *_x, int *_y, TTF_Image *image, const SDL_Surface *te
     int y = *_y;
 
     int srcbpp = 1;
-    if (image->is_color) {
-        /* This isn't tested because colored image never ends up left clipped */
+    if (image->is_color || is_lcd) {
         srcbpp = 4;
     }
 
@@ -1042,14 +1110,15 @@ static int Get_Alignement()
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-value"
 #endif
-#define BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, WB_WP_WC, WS, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM) \
+#define BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, IS_LCD, WB_WP_WC, WS, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM) \
                                                                                                                         \
 static SDL_INLINE                                                                                                       \
-int Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, Uint8 fg_alpha)                    \
+int Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg)                     \
 {                                                                                                                       \
     const int alignment = Get_Alignement() - 1;                                                                         \
-    const int bpp = ((IS_BLENDED) ? 4 : 1);                                                                             \
+    const int bpp = ((IS_BLENDED || IS_LCD) ? 4 : 1);                                                                   \
     unsigned int i;                                                                                                     \
+    Uint8 fg_alpha = (fg ? fg->a : 0);                                                                                  \
     for (i = 0; i < font->pos_len; i++) {                                                                               \
         FT_UInt idx = font->pos_buf[i].index;                                                                           \
         int x       = font->pos_buf[i].x;                                                                               \
@@ -1086,7 +1155,16 @@ int Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart, int yst
                 srcskip = image->pitch - image->width;                                                                  \
                 dstskip = textbuf->pitch - image->width * bpp;                                                          \
                 /* Render glyph at (x, y) with optimized copy functions */                                              \
-                if (!IS_BLENDED || image->is_color == 0) {                                                              \
+                if (IS_LCD) {                                                                                           \
+                    image->buffer = saved_buffer;                                                                       \
+                    image->buffer += alignment;                                                                         \
+                    image->width = saved_width;                                                                         \
+                    dst = (Uint8 *)textbuf->pixels + y * textbuf->pitch + x * bpp;                                      \
+                    /* Compute srcskip, dstskip */                                                                      \
+                    srcskip = image->pitch - 4 * image->width;                                                          \
+                    dstskip = textbuf->pitch - image->width * bpp;                                                      \
+                    BG_Blended_LCD(image, (Uint32 *)dst, srcskip, dstskip, fg);                                         \
+                } else if (!IS_BLENDED || image->is_color == 0) {                                                       \
                     if (IS_BLENDED_OPAQUE) {                                                                            \
                         BLIT_GLYPH_BLENDED_OPAQUE_OPTIM(image, (Uint32 *)dst, srcskip, dstskip);                        \
                     } else if (IS_BLENDED) {                                                                            \
@@ -1110,14 +1188,17 @@ int Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart, int yst
                 /* Modify a copy, and clip it */                                                                        \
                 TTF_Image image_clipped = *image;                                                                       \
                 /* Intersect image glyph at (x,y) with textbuf */                                                       \
-                clip_glyph(&x, &y, &image_clipped, textbuf);                                                            \
+                clip_glyph(&x, &y, &image_clipped, textbuf, IS_LCD);                                                    \
                 /* Compute dst */                                                                                       \
                 dst = (Uint8 *)textbuf->pixels + y * textbuf->pitch + x * bpp;                                          \
                 /* Compute srcskip, dstskip */                                                                          \
                 srcskip = image_clipped.pitch - image_clipped.width;                                                    \
                 dstskip = textbuf->pitch - image_clipped.width * bpp;                                                   \
                 /* Render glyph at (x, y) */                                                                            \
-                if (!IS_BLENDED || image->is_color == 0) {                                                              \
+                if (IS_LCD) {                                                                                           \
+                    srcskip -= 3 * image_clipped.width;                                                                 \
+                    BG_Blended_LCD(&image_clipped, (Uint32 *)dst, srcskip, dstskip, fg);                                \
+                } else if (!IS_BLENDED || image->is_color == 0) {                                                       \
                     if (IS_BLENDED_OPAQUE) {                                                                            \
                         BG_Blended_Opaque(&image_clipped, (Uint32 *)dst, srcskip, dstskip);                             \
                     } else if (IS_BLENDED) {                                                                            \
@@ -1140,107 +1221,125 @@ int Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart, int yst
 }                                                                                                                       \
                                                                                                                         \
 
-#define BITMAP  CACHED_BITMAP, 0, 0
-#define PIXMAP  0, CACHED_PIXMAP, 0
-#define COLOR   0, 0, CACHED_COLOR
+#define BITMAP  CACHED_BITMAP, 0, 0, 0
+#define PIXMAP  0, CACHED_PIXMAP, 0, 0
+#define COLOR   0, 0, CACHED_COLOR, 0
+#define LCD     0, 0, 0, CACHED_LCD
 
 #define SUBPIX  CACHED_SUBPIX
 
-/* BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, WANT_BITMAP_PIXMAP_COLOR, WANT_SUBPIXEL, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM) */
+/* BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, WANT_BITMAP_PIXMAP_COLOR_LCD, WANT_SUBPIXEL, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM) */
 
 #if defined(HAVE_SSE2_INTRINSICS)
-BUILD_RENDER_LINE(SSE_Shaded            , 0, 0, PIXMAP, 0     ,                       ,                , BG_SSE     )
-BUILD_RENDER_LINE(SSE_Blended           , 1, 0,  COLOR, 0     ,                       , BG_Blended_SSE ,            )
-BUILD_RENDER_LINE(SSE_Blended_Opaque    , 1, 1,  COLOR, 0     , BG_Blended_Opaque_SSE ,                ,            )
-BUILD_RENDER_LINE(SSE_Solid             , 0, 0, BITMAP, 0     ,                       ,                , BG_SSE     )
-BUILD_RENDER_LINE(SSE_Shaded_SP         , 0, 0, PIXMAP, SUBPIX,                       ,                , BG_SSE     )
-BUILD_RENDER_LINE(SSE_Blended_SP        , 1, 0,  COLOR, SUBPIX,                       , BG_Blended_SSE ,            )
-BUILD_RENDER_LINE(SSE_Blended_Opaque_SP , 1, 1,  COLOR, SUBPIX, BG_Blended_Opaque_SSE ,                ,            )
+BUILD_RENDER_LINE(SSE_Shaded            , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_SSE     )
+BUILD_RENDER_LINE(SSE_Blended           , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_SSE ,            )
+BUILD_RENDER_LINE(SSE_Blended_Opaque    , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_SSE ,                ,            )
+BUILD_RENDER_LINE(SSE_Solid             , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_SSE     )
+BUILD_RENDER_LINE(SSE_Shaded_SP         , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_SSE     )
+BUILD_RENDER_LINE(SSE_Blended_SP        , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_SSE ,            )
+BUILD_RENDER_LINE(SSE_Blended_Opaque_SP , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_SSE ,                ,            )
+BUILD_RENDER_LINE(SSE_LCD               , 0, 0, 1,    LCD, 0,                            ,                ,            )
+BUILD_RENDER_LINE(SSE_LCD_SP            , 0, 0, 1,    LCD, SUBPIX,                       ,                ,            )
 #endif
 
 #if defined(HAVE_NEON_INTRINSICS)
-BUILD_RENDER_LINE(NEON_Shaded           , 0, 0, PIXMAP, 0     ,                       ,                , BG_NEON    )
-BUILD_RENDER_LINE(NEON_Blended          , 1, 0,  COLOR, 0     ,                       , BG_Blended_NEON,            )
-BUILD_RENDER_LINE(NEON_Blended_Opaque   , 1, 1,  COLOR, 0     , BG_Blended_Opaque_NEON,                ,            )
-BUILD_RENDER_LINE(NEON_Solid            , 0, 0, BITMAP, 0     ,                       ,                , BG_NEON    )
-BUILD_RENDER_LINE(NEON_Shaded_SP        , 0, 0, PIXMAP, SUBPIX,                       ,                , BG_NEON    )
-BUILD_RENDER_LINE(NEON_Blended_SP       , 1, 0,  COLOR, SUBPIX,                       , BG_Blended_NEON,            )
-BUILD_RENDER_LINE(NEON_Blended_Opaque_SP, 1, 1,  COLOR, SUBPIX, BG_Blended_Opaque_NEON,                ,            )
+BUILD_RENDER_LINE(NEON_Shaded           , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_NEON    )
+BUILD_RENDER_LINE(NEON_Blended          , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_NEON,            )
+BUILD_RENDER_LINE(NEON_Blended_Opaque   , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_NEON,                ,            )
+BUILD_RENDER_LINE(NEON_Solid            , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_NEON    )
+BUILD_RENDER_LINE(NEON_Shaded_SP        , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_NEON    )
+BUILD_RENDER_LINE(NEON_Blended_SP       , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_NEON,            )
+BUILD_RENDER_LINE(NEON_Blended_Opaque_SP, 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_NEON,                ,            )
+BUILD_RENDER_LINE(NEON_LCD              , 0, 0, 1,    LCD, 0     ,                       ,                ,            )
+BUILD_RENDER_LINE(NEON_LCD_SP           , 0, 0, 1,    LCD, SUBPIX,                       ,                ,            )
 #endif
 
 #if defined(HAVE_BLIT_GLYPH_64)
-BUILD_RENDER_LINE(64_Shaded             , 0, 0, PIXMAP, 0     ,                       ,                , BG_64      )
-BUILD_RENDER_LINE(64_Blended            , 1, 0,  COLOR, 0     ,                       , BG_Blended_32  ,            )
-BUILD_RENDER_LINE(64_Blended_Opaque     , 1, 1,  COLOR, 0     , BG_Blended_Opaque_32  ,                ,            )
-BUILD_RENDER_LINE(64_Solid              , 0, 0, BITMAP, 0     ,                       ,                , BG_64      )
-BUILD_RENDER_LINE(64_Shaded_SP          , 0, 0, PIXMAP, SUBPIX,                       ,                , BG_64      )
-BUILD_RENDER_LINE(64_Blended_SP         , 1, 0,  COLOR, SUBPIX,                       , BG_Blended_32  ,            )
-BUILD_RENDER_LINE(64_Blended_Opaque_SP  , 1, 1,  COLOR, SUBPIX, BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(64_Shaded             , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_64      )
+BUILD_RENDER_LINE(64_Blended            , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_32  ,            )
+BUILD_RENDER_LINE(64_Blended_Opaque     , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(64_Solid              , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_64      )
+BUILD_RENDER_LINE(64_Shaded_SP          , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_64      )
+BUILD_RENDER_LINE(64_Blended_SP         , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_32  ,            )
+BUILD_RENDER_LINE(64_Blended_Opaque_SP  , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(64_LCD                , 0, 0, 1,    LCD, 0     ,                       ,                ,            )
+BUILD_RENDER_LINE(64_LCD_SP             , 0, 0, 1,    LCD, SUBPIX,                       ,                ,            )
 #elif defined(HAVE_BLIT_GLYPH_32)
-BUILD_RENDER_LINE(32_Shaded             , 0, 0, PIXMAP, 0     ,                       ,                , BG_32      )
-BUILD_RENDER_LINE(32_Blended            , 1, 0,  COLOR, 0     ,                       , BG_Blended_32  ,            )
-BUILD_RENDER_LINE(32_Blended_Opaque     , 1, 1,  COLOR, 0     , BG_Blended_Opaque_32  ,                ,            )
-BUILD_RENDER_LINE(32_Solid              , 0, 0, BITMAP, 0     ,                       ,                , BG_32      )
-BUILD_RENDER_LINE(32_Shaded_SP          , 0, 0, PIXMAP, SUBPIX,                       ,                , BG_32      )
-BUILD_RENDER_LINE(32_Blended_SP         , 1, 0,  COLOR, SUBPIX,                       , BG_Blended_32  ,            )
-BUILD_RENDER_LINE(32_Blended_Opaque_SP  , 1, 1,  COLOR, SUBPIX, BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(32_Shaded             , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_32      )
+BUILD_RENDER_LINE(32_Blended            , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_32  ,            )
+BUILD_RENDER_LINE(32_Blended_Opaque     , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(32_Solid              , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_32      )
+BUILD_RENDER_LINE(32_Shaded_SP          , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_32      )
+BUILD_RENDER_LINE(32_Blended_SP         , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_32  ,            )
+BUILD_RENDER_LINE(32_Blended_Opaque_SP  , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(32_LCD                , 0, 0, 1,    LCD, 0     ,                       ,                ,            )
+BUILD_RENDER_LINE(32_LCD_SP             , 0, 0, 1,    LCD, SUBPIX,                       ,                ,            )
 #else
-BUILD_RENDER_LINE(8_Shaded              , 0, 0, PIXMAP, 0     ,                       ,                , BG         )
-BUILD_RENDER_LINE(8_Blended             , 1, 0,  COLOR, 0     ,                       , BG_Blended     ,            )
-BUILD_RENDER_LINE(8_Blended_Opaque      , 1, 1,  COLOR, 0     , BG_Blended_Opaque     ,                ,            )
-BUILD_RENDER_LINE(8_Solid               , 0, 0, BITMAP, 0     ,                       ,                , BG         )
-BUILD_RENDER_LINE(8_Shaded_SP           , 0, 0, PIXMAP, SUBPIX,                       ,                , BG         )
-BUILD_RENDER_LINE(8_Blended_SP          , 1, 0,  COLOR, SUBPIX,                       , BG_Blended     ,            )
-BUILD_RENDER_LINE(8_Blended_Opaque_SP   , 1, 1,  COLOR, SUBPIX, BG_Blended_Opaque     ,                ,            )
+BUILD_RENDER_LINE(8_Shaded              , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG         )
+BUILD_RENDER_LINE(8_Blended             , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended     ,            )
+BUILD_RENDER_LINE(8_Blended_Opaque      , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque     ,                ,            )
+BUILD_RENDER_LINE(8_Solid               , 0, 0, 0, BITMAP, 0     ,                       ,                , BG         )
+BUILD_RENDER_LINE(8_Shaded_SP           , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG         )
+BUILD_RENDER_LINE(8_Blended_SP          , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended     ,            )
+BUILD_RENDER_LINE(8_Blended_Opaque_SP   , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque     ,                ,            )
+BUILD_RENDER_LINE(8_LCD                 , 0, 0, 1,    LCD, 0     ,                       ,                ,            )
+BUILD_RENDER_LINE(8_LCD_SP              , 0, 0, 1,    LCD, SUBPIX,                       ,                ,            )
 #endif
 
 
 #if TTF_USE_SDF
-static int (*Render_Line_SDF_Shaded)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, Uint8 fg_alpha) = NULL;
-BUILD_RENDER_LINE(SDF_Blended           , 1, 0,  COLOR, 0     ,                       , BG_Blended_SDF ,            )
-BUILD_RENDER_LINE(SDF_Blended_Opaque    , 1, 1,  COLOR, 0     , BG_Blended_Opaque_SDF ,                ,            )
-static int (*Render_Line_SDF_Solid)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, Uint8 fg_alpha) = NULL;
-static int (*Render_Line_SDF_Shaded_SP)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, Uint8 fg_alpha) = NULL;
-BUILD_RENDER_LINE(SDF_Blended_SP        , 1, 0,  COLOR, SUBPIX,                       , BG_Blended_SDF ,            )
-BUILD_RENDER_LINE(SDF_Blended_Opaque_SP , 1, 1,  COLOR, SUBPIX, BG_Blended_Opaque_SDF ,                ,            )
+static int (*Render_Line_SDF_Shaded)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg) = NULL;
+BUILD_RENDER_LINE(SDF_Blended           , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_SDF ,            )
+BUILD_RENDER_LINE(SDF_Blended_Opaque    , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_SDF ,                ,            )
+static int (*Render_Line_SDF_Solid)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg) = NULL;
+static int (*Render_Line_SDF_Shaded_SP)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg) = NULL;
+BUILD_RENDER_LINE(SDF_Blended_SP        , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_SDF ,            )
+BUILD_RENDER_LINE(SDF_Blended_Opaque_SP , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_SDF ,                ,            )
+static int (*Render_Line_SDF_LCD)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg) = NULL;
+static int (*Render_Line_SDF_LCD_SP)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg) = NULL;
 #endif
 
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif
 
-static SDL_INLINE int Render_Line(const render_mode_t render_mode, int subpixel, TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, Uint8 fg_alpha)
+static SDL_INLINE int Render_Line(const render_mode_t render_mode, int subpixel, TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color fg)
 {
     /* Render line (pos_buf) to textbuf at (xstart, ystart) */
 
     /* Subpixel with RENDER_SOLID doesn't make sense. */
     /* (and 'cached->subpixel.translation' would need to distinguish bitmap/pixmap). */
-
-    int is_opaque = (fg_alpha == SDL_ALPHA_OPAQUE);
+    int is_opaque = (fg.a == SDL_ALPHA_OPAQUE);
 
 #define Call_Specific_Render_Line(NAME)                                                                     \
         if (render_mode == RENDER_SHADED) {                                                                 \
             if (subpixel == 0) {                                                                            \
-                return Render_Line_##NAME##_Shaded(font, textbuf, xstart, ystart, 0);                       \
+                return Render_Line_##NAME##_Shaded(font, textbuf, xstart, ystart, NULL);                    \
             } else {                                                                                        \
-                return Render_Line_##NAME##_Shaded_SP(font, textbuf, xstart, ystart, 0);                    \
+                return Render_Line_##NAME##_Shaded_SP(font, textbuf, xstart, ystart, NULL);                 \
             }                                                                                               \
         } else if (render_mode == RENDER_BLENDED) {                                                         \
             if (is_opaque) {                                                                                \
                 if (subpixel == 0) {                                                                        \
-                    return Render_Line_##NAME##_Blended_Opaque(font, textbuf, xstart, ystart, 0);           \
+                    return Render_Line_##NAME##_Blended_Opaque(font, textbuf, xstart, ystart, NULL);        \
                 } else {                                                                                    \
-                    return Render_Line_##NAME##_Blended_Opaque_SP(font, textbuf, xstart, ystart, 0);        \
+                    return Render_Line_##NAME##_Blended_Opaque_SP(font, textbuf, xstart, ystart, NULL);     \
                 }                                                                                           \
             } else {                                                                                        \
                 if (subpixel == 0) {                                                                        \
-                    return Render_Line_##NAME##_Blended(font, textbuf, xstart, ystart, fg_alpha);           \
+                    return Render_Line_##NAME##_Blended(font, textbuf, xstart, ystart, &fg);                \
                 } else {                                                                                    \
-                    return Render_Line_##NAME##_Blended_SP(font, textbuf, xstart, ystart, fg_alpha);        \
+                    return Render_Line_##NAME##_Blended_SP(font, textbuf, xstart, ystart, &fg);             \
                 }                                                                                           \
             }                                                                                               \
+        } else if (render_mode == RENDER_LCD) {                                                             \
+            if (subpixel == 0) {                                                                            \
+                return Render_Line_##NAME##_LCD(font, textbuf, xstart, ystart, &fg);                        \
+            } else {                                                                                        \
+                return Render_Line_##NAME##_LCD_SP(font, textbuf, xstart, ystart, &fg);                     \
+            }                                                                                               \
         } else {                                                                                            \
-            return Render_Line_##NAME##_Solid(font, textbuf, xstart, ystart, 0);                            \
+            return Render_Line_##NAME##_Solid(font, textbuf, xstart, ystart, NULL);                         \
         }
 
 #if TTF_USE_SDF
@@ -1481,6 +1580,68 @@ static SDL_Surface *Create_Surface_Blended(int width, int height, SDL_Color fg,
     return textbuf;
 }
 
+static SDL_Surface* Create_Surface_LCD(int width, int height, SDL_Color fg, SDL_Color bg, Uint32 *color)
+{
+    const int alignment = Get_Alignement() - 1;
+    SDL_Surface *textbuf = NULL;
+    Uint32 bgcolor;
+
+    /* Background color */
+    bgcolor = (bg.a << 24) | (bg.r << 16) | (bg.g << 8) | bg.b;
+
+    /* Underline/Strikethrough color style */
+    *color = (bg.a << 24) | (fg.r << 16) | (fg.g << 8) | fg.b;
+
+    /* Create the target surface if required */
+    if (width != 0) {
+        /* Create a surface with memory:
+         * - pitch is rounded to alignment
+         * - adress is aligned
+         */
+        Sint64 size;
+        void *pixels, *ptr;
+        /* Worse case at the end of line pulling 'alignment' extra blank pixels */
+        int pitch = (width + alignment) * 4;
+        pitch += alignment;
+        pitch &= ~alignment;
+        size = height * pitch + sizeof (void *) + alignment;
+        if (size < 0 || size > SDL_MAX_SINT32) {
+            /* Overflow... */
+            return NULL;
+        }
+
+        ptr = SDL_malloc((size_t)size);
+        if (ptr == NULL) {
+            return NULL;
+        }
+
+        /* address is aligned */
+        pixels = (void *)(((size_t)ptr + sizeof(void *) + alignment) & ~alignment);
+        ((void **)pixels)[-1] = ptr;
+
+        textbuf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, width, height, 0, pitch, SDL_PIXELFORMAT_ARGB8888);
+        if (textbuf == NULL) {
+            SDL_free(ptr);
+            return NULL;
+        }
+
+        /* Let SDL handle the memory allocation */
+        textbuf->flags &= ~SDL_PREALLOC;
+        textbuf->flags |= SDL_SIMD_ALIGNED;
+
+        /* Initialize with fg and 0 alpha */
+        SDL_memset4(pixels, bgcolor, (height * pitch) / 4);
+
+        /* Support alpha blending */
+        if (bg.a != SDL_ALPHA_OPAQUE) {
+            SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
+        }
+    }
+
+    return textbuf;
+}
+
+
 /* rcg06192001 get linked library's version. */
 const SDL_version* TTF_Linked_Version(void)
 {
@@ -1980,6 +2141,13 @@ static FT_Error Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int transl
     /* Get our glyph shortcut */
     slot = font->face->glyph;
 
+    if (want & CACHED_LCD) {
+        if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
+            TTF_SetError("LCD mode not possible with bitmap font");
+            return -1;
+        }
+    }
+
     /* Get the glyph metrics, always needed */
     if (cached->stored == 0) {
         cached->sz_left  = slot->bitmap_left;
@@ -2052,6 +2220,7 @@ static F

(Patch may be truncated, please check the link at the top of this post.)