SDL_ttf: Convert BGRA to mono when rendering emoji in the solid style

From fb6529cb7b724e2f973b48ce2a0ea4193099fade Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 30 Jan 2025 12:29:56 -0800
Subject: [PATCH] Convert BGRA to mono when rendering emoji in the solid style

Fixes https://github.com/libsdl-org/SDL_ttf/issues/497
---
 src/SDL_ttf.c | 31 ++++++++++++++++++++++++++-----
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index e2c49262..0dab26d9 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -69,13 +69,17 @@
 #endif
 
 // FT_FACE_FLAG_SVG and FT_HAS_SVG require freetype 2.12+
-#ifndef FT_FACE_FLAG_SVG
-#define FT_FACE_FLAG_SVG               ( 1L << 16 )
-#endif
 #ifndef FT_HAS_SVG
+#define FT_FACE_FLAG_SVG               ( 1L << 16 )
 #define FT_HAS_SVG( face ) \
           ( !!( (face)->face_flags & FT_FACE_FLAG_SVG ) )
-#endif
+
+#define FT_GLYPH_FORMAT_SVG \
+          ( ( (unsigned long)'S' << 24 ) | \
+            ( (unsigned long)'V' << 16 ) | \
+            ( (unsigned long)'G' << 8  ) | \
+              (unsigned long)' '         )
+#endif // !FT_HAS_SVG
 
 /**
  * ZERO WIDTH NO-BREAKSPACE (Unicode byte order mark)
@@ -2540,7 +2544,7 @@ static bool Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int translatio
         FT_Bitmap *src;
         FT_Render_Mode ft_render_mode;
 
-        if (mono) {
+        if (mono && slot->format != FT_GLYPH_FORMAT_SVG) {
             ft_render_mode = FT_RENDER_MODE_MONO;
         } else {
             ft_render_mode = FT_RENDER_MODE_NORMAL;
@@ -2793,6 +2797,23 @@ static bool Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int translatio
                             MONO_GRAY4(2);
                         }
                         MONO_GRAY4(remainder);
+                    } else if (src->pixel_mode == FT_PIXEL_MODE_BGRA) {
+                        while (quotient--) {
+                            Uint8 r, g, b, a;
+                            b = *srcp++;
+                            g = *srcp++;
+                            r = *srcp++;
+                            a = *srcp++;
+                            unsigned char c = 0;
+                            if (a != 0) {
+                                // Technically we should do this in linear colorspace
+                                // Y = 0.2126 * R + 0.7152 * G + 0.0722 * B
+                                c = 255 - (unsigned char)(((int)r * 54) / 255 +
+                                                          ((int)g * 182) / 255 +
+                                                          ((int)b * 18) / 255);
+                            }
+                            *dstp++ = (c >= 0x80) ? 1 : 0;
+                        }
                     } else {
                         while (quotient--) {
                             unsigned char c = *srcp++;