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.)