[vlc-devel] [PATCH] freetype: RFC knockout blending implementation
sarah-kamall
sarah.kamal.soliman at gmail.com
Fri Dec 26 13:44:43 UTC 2025
This patch implements knockout blending logic for Freetype renderer.
RFC: Should this new knockout blending mode replace the regular mode (as implemented in this patch) or be introduced as a new style flag?
Note: This implementation introduces new warnings.
Fixes: #29195
Signed-off-by: sarah soliman <sarah.kamal.soliman at gmail.com>
---
modules/text_renderer/freetype/blend/blend.h | 20 +++++++++++++++
modules/text_renderer/freetype/blend/rgb.h | 20 +++++++++++++++
modules/text_renderer/freetype/blend/yuv.h | 27 +++++++++++++++++---
modules/text_renderer/freetype/freetype.c | 10 ++++----
4 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/modules/text_renderer/freetype/blend/blend.h b/modules/text_renderer/freetype/blend/blend.h
index dd5a39c7e1..8316392370 100644
--- a/modules/text_renderer/freetype/blend/blend.h
+++ b/modules/text_renderer/freetype/blend/blend.h
@@ -63,6 +63,26 @@ static inline void Blend##name##Pixel( uint8_t **dst, int a, int x, int y, int z
}\
}
+#define DECL_PIXEL_BLENDER_KNOCKOUT( name, APOS, XPOS, YPOS, ZPOS, APLANE, XPLANE, YPLANE, ZPLANE ) \
+static inline void Blend##name##PixelKnockout( uint8_t **dst, int a, int x, int y, int z, int glyph_a )\
+{\
+ if( glyph_a == 0 )\
+ return;\
+\
+ int i_ao = dst[APLANE][APOS];\
+ /* Knockout Mode: Interpolate between Source and Dest based on glyph shape */ \
+ /* Result = (Dest * (255 - Glyph) + Src * Glyph) / 255 */ \
+ int i_an = (i_ao * (255 - glyph_a) + a * glyph_a) / 255; \
+ dst[APLANE][APOS] = i_an; \
+\
+ if (i_an > 0)\
+ {\
+ dst[XPLANE][XPOS] = ( dst[XPLANE][XPOS] * (255 - glyph_a) + x * glyph_a ) / 255;\
+ dst[YPLANE][YPOS] = ( dst[YPLANE][YPOS] * (255 - glyph_a) + y * glyph_a ) / 255;\
+ dst[ZPLANE][ZPOS] = ( dst[ZPLANE][ZPOS] * (255 - glyph_a) + z * glyph_a ) / 255;\
+ }\
+}
+
static void BlendAXYZLine( picture_t *p_picture,
int i_picture_x, int i_picture_y,
int i_a, int i_x, int i_y, int i_z,
diff --git a/modules/text_renderer/freetype/blend/rgb.h b/modules/text_renderer/freetype/blend/rgb.h
index e9490cccab..7e6e1bbfb3 100644
--- a/modules/text_renderer/freetype/blend/rgb.h
+++ b/modules/text_renderer/freetype/blend/rgb.h
@@ -57,9 +57,11 @@ static void Fill##name##Picture( picture_t *p_picture,\
DECL_RGB_FILLER( RGBA, 3, 0, 1, 2 );
DECL_PIXEL_BLENDER(RGBA, 3, 0, 1, 2, 0, 0, 0, 0);
+DECL_PIXEL_BLENDER_KNOCKOUT(RGBA, 3, 0, 1, 2, 0, 0, 0, 0);
DECL_RGB_FILLER( ARGB, 0, 1, 2, 3 );
DECL_PIXEL_BLENDER(ARGB, 0, 1, 2, 3, 0, 0, 0, 0);
+DECL_PIXEL_BLENDER_KNOCKOUT(ARGB, 0, 1, 2, 3, 0, 0, 0, 0);
#undef DECL_RGB_FILLER
@@ -107,3 +109,21 @@ static void BlendGlyphToARGB( picture_t *p_picture,
i_a, i_x, i_y, i_z, p_glyph,
BlendARGBPixel );
}
+static void BlendGlyphToRGBAKnockout( picture_t *p_picture,
+ int i_picture_x, int i_picture_y,
+ int i_a, int i_x, int i_y, int i_z,
+ FT_BitmapGlyph p_glyph )
+{
+ BlendGlyphToRGB( p_picture, i_picture_x, i_picture_y,
+ i_a, i_x, i_y, i_z, p_glyph,
+ BlendRGBAPixelKnockout );
+}
+static void BlendGlyphToARGBKnockout( picture_t *p_picture,
+ int i_picture_x, int i_picture_y,
+ int i_a, int i_x, int i_y, int i_z,
+ FT_BitmapGlyph p_glyph )
+{
+ BlendGlyphToRGB( p_picture, i_picture_x, i_picture_y,
+ i_a, i_x, i_y, i_z, p_glyph,
+ BlendARGBPixelKnockout );
+}
diff --git a/modules/text_renderer/freetype/blend/yuv.h b/modules/text_renderer/freetype/blend/yuv.h
index d6955a1448..4b6457c6eb 100644
--- a/modules/text_renderer/freetype/blend/yuv.h
+++ b/modules/text_renderer/freetype/blend/yuv.h
@@ -60,11 +60,13 @@ static void FillYUVAPicture( picture_t *p_picture,
}
DECL_PIXEL_BLENDER(YUVA, 0, 0, 0, 0, A_PLANE, Y_PLANE, U_PLANE, V_PLANE);
+DECL_PIXEL_BLENDER_KNOCKOUT(YUVA, 0, 0, 0, 0, A_PLANE, Y_PLANE, U_PLANE, V_PLANE);
-static void BlendGlyphToYUVA( picture_t *p_picture,
- int i_picture_x, int i_picture_y,
- int i_a, int i_x, int i_y, int i_z,
- FT_BitmapGlyph p_glyph )
+static void BlendGlyphToYUVACommon( picture_t *p_picture,
+ int i_picture_x, int i_picture_y,
+ int i_a, int i_x, int i_y, int i_z,
+ FT_BitmapGlyph p_glyph,
+ void (*BlendPixel)( uint8_t **, int, int, int, int, int ) )
{
const uint8_t *srcrow = p_glyph->bitmap.buffer;
int i_pitch_src = p_glyph->bitmap.pitch;
@@ -101,3 +103,20 @@ static void BlendGlyphToYUVA( picture_t *p_picture,
dstrows[3] += p_picture->p[3].i_pitch;
}
}
+
+static void BlendGlyphToYUVA( picture_t *p_picture,
+ int i_picture_x, int i_picture_y,
+ int i_a, int i_x, int i_y, int i_z,
+ FT_BitmapGlyph p_glyph )
+{
+ BlendGlyphToYUVACommon( p_picture, i_picture_x, i_picture_y, i_a, i_x, i_y, i_z, p_glyph, BlendYUVAPixel );
+}
+
+static void BlendGlyphToYUVAKnockout( picture_t *p_picture,
+ int i_picture_x, int i_picture_y,
+ int i_a, int i_x, int i_y, int i_z,
+ FT_BitmapGlyph p_glyph )
+{
+ BlendGlyphToYUVACommon( p_picture, i_picture_x, i_picture_y, i_a, i_x, i_y, i_z, p_glyph, BlendYUVAPixelKnockout );
+}
+
diff --git a/modules/text_renderer/freetype/freetype.c b/modules/text_renderer/freetype/freetype.c
index 8b49ec7aee..9b4d1d3657 100644
--- a/modules/text_renderer/freetype/freetype.c
+++ b/modules/text_renderer/freetype/freetype.c
@@ -562,7 +562,7 @@ static void RenderCharAXYZ( filter_t *p_filter,
i_color = ch->p_style->i_shadow_color;
break;
case 1:
- i_a = i_a * ch->p_style->i_outline_alpha / 255;
+ i_a = ch->p_style->i_outline_alpha;
i_color = ch->p_style->i_outline_color;
break;
default:
@@ -583,7 +583,7 @@ static void RenderCharAXYZ( filter_t *p_filter,
}
/* Don't render if invisible or not wanted */
- if( i_a == STYLE_ALPHA_TRANSPARENT ||
+ if(
(g == 0 && 0 == (ch->p_style->i_style_flags & STYLE_SHADOW) ) ||
(g == 1 && 0 == (ch->p_style->i_style_flags & STYLE_OUTLINE) )
)
@@ -1103,7 +1103,7 @@ static subpicture_region_t *Render( filter_t *p_filter,
static const ft_drawing_functions DRAW_YUVA =
{ .extract = YUVFromXRGB,
.fill = FillYUVAPicture,
- .blend = BlendGlyphToYUVA };
+ .blend = BlendGlyphToYUVAKnockout};
func = &DRAW_YUVA;
}
else if( *p_chroma == VLC_CODEC_RGBA
@@ -1112,7 +1112,7 @@ static subpicture_region_t *Render( filter_t *p_filter,
static const ft_drawing_functions DRAW_RGBA =
{ .extract = RGBFromXRGB,
.fill = FillRGBAPicture,
- .blend = BlendGlyphToRGBA };
+ .blend = BlendGlyphToRGBAKnockout };
func = &DRAW_RGBA;
}
else if( *p_chroma == VLC_CODEC_ARGB
@@ -1121,7 +1121,7 @@ static subpicture_region_t *Render( filter_t *p_filter,
static const ft_drawing_functions DRAW_ARGB =
{ .extract = RGBFromXRGB,
.fill = FillARGBPicture,
- .blend = BlendGlyphToARGB };
+ .blend = BlendGlyphToARGBKnockout };
func = &DRAW_ARGB;
}
else
--
2.43.0
More information about the vlc-devel
mailing list