[vlc-commits] freetype: blending: refactor and improve speed

Francois Cartegnie git at videolan.org
Thu Sep 3 21:30:22 CEST 2020


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Aug 27 14:39:11 2020 +0200| [b508504e6dd92064397b6c7ff0375e760a7bfbd5] | committer: Francois Cartegnie

freetype: blending: refactor and improve speed

webvtt_css_family_fallback_mono.mkv
with forced non zero background
32% less instr for RGBA/YUVA

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=b508504e6dd92064397b6c7ff0375e760a7bfbd5
---

 modules/text_renderer/Makefile.am            |   5 +-
 modules/text_renderer/freetype/blend/blend.h |  83 ++++++++
 modules/text_renderer/freetype/blend/rgb.h   | 109 ++++++++++
 modules/text_renderer/freetype/blend/yuv.h   | 103 ++++++++++
 modules/text_renderer/freetype/freetype.c    | 294 +++++----------------------
 5 files changed, 345 insertions(+), 249 deletions(-)

diff --git a/modules/text_renderer/Makefile.am b/modules/text_renderer/Makefile.am
index 1d87479c59..5e29e3c116 100644
--- a/modules/text_renderer/Makefile.am
+++ b/modules/text_renderer/Makefile.am
@@ -9,7 +9,10 @@ libfreetype_plugin_la_SOURCES = \
 	text_renderer/freetype/ftcache.c text_renderer/freetype/ftcache.h \
 	text_renderer/freetype/text_layout.c text_renderer/freetype/text_layout.h \
 	text_renderer/freetype/lru.c text_renderer/freetype/lru.h \
-        text_renderer/freetype/fonts/backends.h
+        text_renderer/freetype/fonts/backends.h \
+        text_renderer/freetype/blend/blend.h \
+        text_renderer/freetype/blend/rgb.h \
+        text_renderer/freetype/blend/yuv.h
 
 libfreetype_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
 libfreetype_plugin_la_LIBADD = $(AM_LIBADD) $(LIBM)
diff --git a/modules/text_renderer/freetype/blend/blend.h b/modules/text_renderer/freetype/blend/blend.h
new file mode 100644
index 0000000000..93e97ff840
--- /dev/null
+++ b/modules/text_renderer/freetype/blend/blend.h
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * blend.h :
+ *****************************************************************************
+ * Copyright (C) 2002 - 2020 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef VLC_FREETYPE_BLEND_H
+#define VLC_FREETYPE_BLEND_H
+
+typedef void (*ft_glyph_blender)( picture_t *, int, int,
+                                  int, int, int, int, FT_BitmapGlyph );
+typedef void (*ft_surface_filler)( picture_t *, int, int, int, int,
+                                   int, int, int, int);
+typedef void (*ft_components_extractor)( uint32_t, uint8_t *, uint8_t *, uint8_t * );
+
+typedef struct
+{
+    ft_components_extractor extract;
+    ft_surface_filler fill;
+    ft_glyph_blender blend;
+} ft_drawing_functions;
+
+#define DECL_PIXEL_BLENDER( name, APOS, XPOS, YPOS, ZPOS, APLANE, XPLANE, YPLANE, ZPLANE ) \
+static inline void Blend##name##Pixel( uint8_t **dst, int a, int x, int y, int z, int glyph_a )\
+{\
+    if( glyph_a == 0 )\
+        return;\
+\
+    int i_an = a * glyph_a / 255;\
+\
+    int i_ao = dst[APLANE][APOS];\
+    if( i_ao == 0 )\
+    {\
+        dst[XPLANE][XPOS] = x;\
+        dst[YPLANE][YPOS] = y;\
+        dst[ZPLANE][ZPOS] = z;\
+        dst[APLANE][APOS] = i_an;\
+    }\
+    else\
+    {\
+        int i_ani = 255 - i_an;\
+        dst[APLANE][APOS] = 255 - (255 - i_ao) * i_ani / 255;\
+        if( dst[APLANE][APOS] != 0 )\
+        {\
+            int i_aoni = i_ao * i_ani / 255;\
+            dst[XPLANE][XPOS] = ( dst[XPLANE][XPOS] * i_aoni + x * i_an ) / dst[APLANE][APOS];\
+            dst[YPLANE][YPOS] = ( dst[YPLANE][YPOS] * i_aoni + y * i_an ) / dst[APLANE][APOS];\
+            dst[ZPLANE][ZPOS] = ( dst[ZPLANE][ZPOS] * i_aoni + z * i_an ) / dst[APLANE][APOS];\
+        }\
+    }\
+}
+
+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,
+                           const line_character_t *p_current,
+                           const line_character_t *p_next,
+                           ft_drawing_functions draw )
+{
+    int i_line_width = p_current->p_glyph->bitmap.width;
+    if( p_next )
+        i_line_width = p_next->p_glyph->left - p_current->p_glyph->left;
+
+    draw.fill( p_picture,
+               i_a, i_x, i_y, i_z,
+               i_picture_x, i_picture_y + p_current->i_line_offset,
+               i_line_width, p_current->i_line_thickness );
+}
+
+#endif // VLC_FREETYPE_BLEND_H
diff --git a/modules/text_renderer/freetype/blend/rgb.h b/modules/text_renderer/freetype/blend/rgb.h
new file mode 100644
index 0000000000..f3d9c45706
--- /dev/null
+++ b/modules/text_renderer/freetype/blend/rgb.h
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * rgb.h :
+ *****************************************************************************
+ * Copyright (C) 2002 - 2020 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "blend.h"
+
+static void RGBFromRGB( uint32_t i_argb,
+                        uint8_t *pi_r, uint8_t *pi_g, uint8_t *pi_b )
+{
+    *pi_r = ( i_argb & 0x00ff0000 ) >> 16;
+    *pi_g = ( i_argb & 0x0000ff00 ) >>  8;
+    *pi_b = ( i_argb & 0x000000ff );
+}
+
+#define DECL_RGB_FILLER( name, APOS, XPOS, YPOS, ZPOS ) \
+static void Fill##name##Picture( picture_t *p_picture,\
+                                 int a, int r, int g, int b,\
+                                 int x, int y, int w, int h )\
+{\
+    uint8_t *row = &p_picture->p[0].p_pixels[y * p_picture->p->i_pitch + x * 4];\
+\
+    if (unlikely(a == 0 || (a == r && b == g && r == g)))\
+    {   /* fast path */\
+        memset(row, a, h * p_picture->p[0].i_pitch);\
+        return;\
+    }\
+\
+    for( int dy = 0; dy < h; dy++ )\
+    {\
+        uint8_t *p = row;\
+        for( int dx = 0; dx < w; dx++ )\
+        {\
+            p[XPOS] = r;\
+            p[YPOS] = g;\
+            p[ZPOS] = b;\
+            p[APOS] = a;\
+            p += 4;\
+        }\
+        row += p_picture->p->i_pitch;\
+    }\
+}
+
+DECL_RGB_FILLER( RGBA, 3, 0, 1, 2 );
+DECL_PIXEL_BLENDER(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);
+
+#undef DECL_RGB_FILLER
+
+static inline void BlendGlyphToRGB( 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;
+    int i_pitch_dst = p_picture->p[0].i_pitch;
+    uint8_t *dstrow = &p_picture->p[0].p_pixels[i_picture_y * i_pitch_dst + 4 * i_picture_x];
+
+    for( unsigned int dy = 0; dy < p_glyph->bitmap.rows; dy++ )
+    {
+        const uint8_t *src = srcrow;
+        uint8_t *dst = dstrow;
+        for( unsigned int dx = 0; dx < p_glyph->bitmap.width; dx++ )
+        {
+            BlendPixel( &dst, i_a, i_x, i_y, i_z, *src++ );
+            dst += 4;
+        }
+        srcrow += i_pitch_src;
+        dstrow += i_pitch_dst;
+    }
+}
+
+static void BlendGlyphToRGBA( 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,
+                     BlendRGBAPixel );
+}
+
+static void BlendGlyphToARGB( 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,
+                     BlendARGBPixel );
+}
diff --git a/modules/text_renderer/freetype/blend/yuv.h b/modules/text_renderer/freetype/blend/yuv.h
new file mode 100644
index 0000000000..30fc134b18
--- /dev/null
+++ b/modules/text_renderer/freetype/blend/yuv.h
@@ -0,0 +1,103 @@
+/*****************************************************************************
+ * yuv.h :
+ *****************************************************************************
+ * Copyright (C) 2002 - 2020 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "blend.h"
+
+static void YUVFromRGB( uint32_t i_argb,
+                        uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v )
+{
+    int i_red   = ( i_argb & 0x00ff0000 ) >> 16;
+    int i_green = ( i_argb & 0x0000ff00 ) >>  8;
+    int i_blue  = ( i_argb & 0x000000ff );
+
+    /* 18.13 fixed point of
+        Y  =      (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
+        Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
+        Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 */
+    uint8_t y = abs( 2104 * i_red  + 4130 * i_green +
+                     802 * i_blue + 4096 + 131072 ) >> 13;
+    uint8_t u = abs( -1214 * i_red  + -2384 * i_green +
+                     3598 * i_blue + 4096 + 1048576) >> 13;
+    uint8_t v = abs( 3598 * i_red + -3013 * i_green +
+                    -585 * i_blue + 4096 + 1048576) >> 13;
+    *pi_y = __MIN(y, 235);
+    *pi_u = __MIN(u, 240);
+    *pi_v = __MIN(v, 240);
+}
+
+static void FillYUVAPicture( picture_t *p_picture,
+                             int i_a, int i_y, int i_u, int i_v,
+                             int x, int y, int w, int h )
+{
+    int values[4] = { i_y, i_u, i_v, i_a };
+    for( int i = 0; i < 4; i++ )
+    {
+        plane_t *plane = &p_picture->p[i];
+        uint8_t *row = &plane->p_pixels[y * p_picture->p->i_pitch +
+                                        x * plane->i_pixel_pitch];
+        for( int dy = 0; dy < h; dy++ )
+        {
+            memset( row, values[i], plane->i_pixel_pitch * w );
+            row += p_picture->p->i_pitch;
+        }
+    }
+}
+
+DECL_PIXEL_BLENDER(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 )
+{
+    const uint8_t *srcrow = p_glyph->bitmap.buffer;
+    int i_pitch_src = p_glyph->bitmap.pitch;
+
+    uint8_t *dstrows[4];
+    dstrows[0] = &p_picture->p[0].p_pixels[i_picture_y * p_picture->p[0].i_pitch +
+                                           i_picture_x * p_picture->p[0].i_pixel_pitch];
+    dstrows[1] = &p_picture->p[1].p_pixels[i_picture_y * p_picture->p[1].i_pitch +
+                                           i_picture_x * p_picture->p[1].i_pixel_pitch];
+    dstrows[2] = &p_picture->p[2].p_pixels[i_picture_y * p_picture->p[2].i_pitch +
+                                           i_picture_x * p_picture->p[2].i_pixel_pitch];
+    dstrows[3] = &p_picture->p[3].p_pixels[i_picture_y * p_picture->p[3].i_pitch +
+                                           i_picture_x * p_picture->p[3].i_pixel_pitch];
+
+    for( unsigned int dy = 0; dy < p_glyph->bitmap.rows; dy++ )
+    {
+        const uint8_t *src = srcrow;
+
+        uint8_t *dst[4];
+        memcpy(dst, dstrows, 4 * sizeof(dst[0]));
+        for( unsigned int dx = 0; dx < p_glyph->bitmap.width; dx++ )
+        {
+            BlendYUVAPixel( dst, i_a, i_x, i_y, i_z, *src++ );
+            dst[0] += p_picture->p[0].i_pixel_pitch;
+            dst[1] += p_picture->p[1].i_pixel_pitch;
+            dst[2] += p_picture->p[2].i_pixel_pitch;
+            dst[3] += p_picture->p[3].i_pixel_pitch;
+        }
+
+        srcrow += i_pitch_src;
+        dstrows[0] += p_picture->p[0].i_pitch;
+        dstrows[1] += p_picture->p[1].i_pitch;
+        dstrows[2] += p_picture->p[2].i_pitch;
+        dstrows[3] += p_picture->p[3].i_pitch;
+    }
+}
diff --git a/modules/text_renderer/freetype/freetype.c b/modules/text_renderer/freetype/freetype.c
index 2ecddc56b0..5b5fc2d08f 100644
--- a/modules/text_renderer/freetype/freetype.c
+++ b/modules/text_renderer/freetype/freetype.c
@@ -47,6 +47,8 @@
 #include "platform_fonts.h"
 #include "freetype.h"
 #include "text_layout.h"
+#include "blend/rgb.h"
+#include "blend/yuv.h"
 
 /*****************************************************************************
  * Module descriptor
@@ -208,27 +210,6 @@ vlc_module_begin ()
 vlc_module_end ()
 
 /* */
-static void YUVFromRGB( uint32_t i_argb,
-                    uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v )
-{
-    int i_red   = ( i_argb & 0x00ff0000 ) >> 16;
-    int i_green = ( i_argb & 0x0000ff00 ) >>  8;
-    int i_blue  = ( i_argb & 0x000000ff );
-
-    *pi_y = (uint8_t)__MIN(abs( 2104 * i_red  + 4130 * i_green +
-                      802 * i_blue + 4096 + 131072 ) >> 13, 235);
-    *pi_u = (uint8_t)__MIN(abs( -1214 * i_red  + -2384 * i_green +
-                     3598 * i_blue + 4096 + 1048576) >> 13, 240);
-    *pi_v = (uint8_t)__MIN(abs( 3598 * i_red + -3013 * i_green +
-                      -585 * i_blue + 4096 + 1048576) >> 13, 240);
-}
-static void RGBFromRGB( uint32_t i_argb,
-                        uint8_t *pi_r, uint8_t *pi_g, uint8_t *pi_b )
-{
-    *pi_r = ( i_argb & 0x00ff0000 ) >> 16;
-    *pi_g = ( i_argb & 0x0000ff00 ) >>  8;
-    *pi_b = ( i_argb & 0x000000ff );
-}
 
 static FT_Vector GetAlignedOffset( const line_desc_t *p_line,
                                    const FT_BBox *p_textbbox,
@@ -494,204 +475,14 @@ static int RenderYUVP( filter_t *p_filter, subpicture_region_t *p_region,
  *****************************************************************************
  * This function merges the previously rendered freetype glyphs into a picture
  *****************************************************************************/
-static void FillYUVAPicture( picture_t *p_picture,
-                             int i_a, int i_y, int i_u, int i_v )
-{
-    memset( p_picture->p[0].p_pixels, i_y,
-            p_picture->p[0].i_pitch * p_picture->p[0].i_lines );
-    memset( p_picture->p[1].p_pixels, i_u,
-            p_picture->p[1].i_pitch * p_picture->p[1].i_lines );
-    memset( p_picture->p[2].p_pixels, i_v,
-            p_picture->p[2].i_pitch * p_picture->p[2].i_lines );
-    memset( p_picture->p[3].p_pixels, i_a,
-            p_picture->p[3].i_pitch * p_picture->p[3].i_lines );
-}
-
-static inline void BlendYUVAPixel( picture_t *p_picture,
-                                   int i_picture_x, int i_picture_y,
-                                   int i_a, int i_y, int i_u, int i_v,
-                                   int i_alpha )
-{
-    if( i_alpha == 0 )
-        return;
-
-    int i_an = i_a * i_alpha / 255;
-
-    uint8_t *p_y = &p_picture->p[0].p_pixels[i_picture_y * p_picture->p[0].i_pitch + i_picture_x];
-    uint8_t *p_u = &p_picture->p[1].p_pixels[i_picture_y * p_picture->p[1].i_pitch + i_picture_x];
-    uint8_t *p_v = &p_picture->p[2].p_pixels[i_picture_y * p_picture->p[2].i_pitch + i_picture_x];
-    uint8_t *p_a = &p_picture->p[3].p_pixels[i_picture_y * p_picture->p[3].i_pitch + i_picture_x];
-
-    int i_ao = *p_a;
-    if( i_ao == 0 )
-    {
-        *p_y = i_y;
-        *p_u = i_u;
-        *p_v = i_v;
-        *p_a = i_an;
-    }
-    else
-    {
-        int i_ani = 255 - i_an;
-        int i_aoni = i_ao * i_ani / 255;
-        *p_a = 255 - (255 - *p_a) * i_ani / 255;
-        if( *p_a != 0 )
-        {
-            *p_y = ( *p_y * i_aoni + i_y * i_an ) / *p_a;
-            *p_u = ( *p_u * i_aoni + i_u * i_an ) / *p_a;
-            *p_v = ( *p_v * i_aoni + i_v * i_an ) / *p_a;
-        }
-    }
-}
-
-static void FillRGBAPicture( picture_t *p_picture,
-                             int i_a, int i_r, int i_g, int i_b )
-{
-    for( int dy = 0; dy < p_picture->p[0].i_visible_lines; dy++ )
-    {
-        for( int dx = 0; dx < p_picture->p[0].i_visible_pitch; dx += 4 )
-        {
-            uint8_t *p_rgba = &p_picture->p->p_pixels[dy * p_picture->p->i_pitch + dx];
-            p_rgba[0] = i_r;
-            p_rgba[1] = i_g;
-            p_rgba[2] = i_b;
-            p_rgba[3] = i_a;
-        }
-    }
-}
-
-static inline void BlendRGBAPixel( picture_t *p_picture,
-                                   int i_picture_x, int i_picture_y,
-                                   int i_a, int i_r, int i_g, int i_b,
-                                   int i_alpha )
-{
-    if( i_alpha == 0 )
-        return;
-
-    int i_an = i_a * i_alpha / 255;
-
-    uint8_t *p_rgba = &p_picture->p->p_pixels[i_picture_y * p_picture->p->i_pitch + 4 * i_picture_x];
-
-    int i_ao = p_rgba[3];
-    if( i_ao == 0 )
-    {
-        p_rgba[0] = i_r;
-        p_rgba[1] = i_g;
-        p_rgba[2] = i_b;
-        p_rgba[3] = i_an;
-    }
-    else
-    {
-        int i_ani = 255 - i_an;
-        p_rgba[3] = 255 - (255 - p_rgba[3]) * i_ani / 255;
-        if( p_rgba[3] != 0 )
-        {
-            int i_aoni = i_ao * i_ani / 255;
-            p_rgba[0] = ( p_rgba[0] * i_aoni + i_r * i_an ) / p_rgba[3];
-            p_rgba[1] = ( p_rgba[1] * i_aoni + i_g * i_an ) / p_rgba[3];
-            p_rgba[2] = ( p_rgba[2] * i_aoni + i_b * i_an ) / p_rgba[3];
-        }
-    }
-}
-
-static void FillARGBPicture(picture_t *pic, int a, int r, int g, int b)
-{
-    if (a == 0)
-        r = g = b = 0;
-    if (a == r && a == b && a == g)
-    {   /* fast path */
-        memset(pic->p->p_pixels, a, pic->p->i_visible_lines * pic->p->i_pitch);
-        return;
-    }
-
-    uint_fast32_t pixel = VLC_FOURCC(a, r, g, b);
-    uint8_t *line = pic->p->p_pixels;
-
-    for (unsigned lines = pic->p->i_visible_lines; lines > 0; lines--)
-    {
-        uint32_t *pixels = (uint32_t *)line;
-        for (unsigned cols = pic->p->i_visible_pitch; cols > 0; cols -= 4)
-            *(pixels++) = pixel;
-        line += pic->p->i_pitch;
-    }
-}
-
-static inline void BlendARGBPixel(picture_t *pic, int pic_x, int pic_y,
-                                  int a, int r, int g, int b, int alpha)
-{
-    if (alpha == 0)
-        return;
-
-    uint8_t *rgba = &pic->p->p_pixels[pic_y * pic->p->i_pitch + 4 * pic_x];
-    int an = a * alpha / 255;
-    int ao = rgba[3];
-
-    if (ao == 0)
-    {
-        rgba[0] = an;
-        rgba[1] = r;
-        rgba[2] = g;
-        rgba[3] = b;
-    }
-    else
-    {
-        int ani = 255 - an;
-        rgba[0] = 255 - (255 - rgba[0]) * ani / 255;
-        if (rgba[0] != 0)
-        {
-            int aoni = ao * ani / 255;
-            rgba[1] = (rgba[1] * aoni + r * an ) / rgba[0];
-            rgba[2] = (rgba[2] * aoni + g * an ) / rgba[0];
-            rgba[3] = (rgba[3] * aoni + b * an ) / rgba[0];
-        }
-    }
-}
-
-static inline void BlendAXYZGlyph( 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)(picture_t *, int, int, int, int, int, int, int) )
-
-{
-    for( unsigned int dy = 0; dy < p_glyph->bitmap.rows; dy++ )
-    {
-        for( unsigned int dx = 0; dx < p_glyph->bitmap.width; dx++ )
-            BlendPixel( p_picture, i_picture_x + dx, i_picture_y + dy,
-                        i_a, i_x, i_y, i_z,
-                        p_glyph->bitmap.buffer[dy * p_glyph->bitmap.pitch + dx] );
-    }
-}
-
-static inline 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,
-                                  const line_character_t *p_current,
-                                  const line_character_t *p_next,
-                                  void (*BlendPixel)(picture_t *, int, int, int, int, int, int, int) )
-{
-    int i_line_width = p_current->p_glyph->bitmap.width;
-    if( p_next )
-        i_line_width = p_next->p_glyph->left - p_current->p_glyph->left;
 
-    for( int dx = 0; dx < i_line_width; dx++ )
-    {
-        for( int dy = 0; dy < p_current->i_line_thickness; dy++ )
-            BlendPixel( p_picture,
-                        i_picture_x + dx,
-                        i_picture_y + p_current->i_line_offset + dy,
-                        i_a, i_x, i_y, i_z, 0xff );
-    }
-}
-
-static inline void RenderBackground( subpicture_region_t *p_region,
+static void RenderBackground( subpicture_region_t *p_region,
                                      line_desc_t *p_line_head,
                                      FT_BBox *p_regionbbox,
                                      FT_BBox *p_paddedbbox,
                                      FT_BBox *p_textbbox,
                                      picture_t *p_picture,
-                                     void (*ExtractComponents)( uint32_t, uint8_t *, uint8_t *, uint8_t * ),
-                                     void (*BlendPixel)(picture_t *, int, int, int, int, int, int, int) )
+                                     ft_drawing_functions draw )
 {
     for( const line_desc_t *p_line = p_line_head; p_line != NULL; p_line = p_line->p_next )
     {
@@ -749,8 +540,8 @@ static inline void RenderBackground( subpicture_region_t *p_region,
             if( p_char->p_style->i_style_flags & STYLE_BACKGROUND )
             {
                 uint8_t i_x, i_y, i_z;
-                ExtractComponents( p_char->p_style->i_background_color,
-                                   &i_x, &i_y, &i_z );
+                draw.extract( p_char->p_style->i_background_color,
+                                 &i_x, &i_y, &i_z );
                 const uint8_t i_alpha = p_char->p_style->i_background_alpha;
 
                 /* Render the actual background */
@@ -767,11 +558,9 @@ static inline void RenderBackground( subpicture_region_t *p_region,
                         .yMax = __MAX(0, p_regionbbox->yMax - segmentbgbox.yMax),
                     };
 
-                    for( int dy = absbox.yMax; dy < absbox.yMin; dy++ )
-                    {
-                        for( int dx = absbox.xMin; dx < absbox.xMax; dx++ )
-                            BlendPixel( p_picture, dx, dy, i_alpha, i_x, i_y, i_z, 0xff );
-                    }
+                    draw.fill( p_picture, i_alpha, i_x, i_y, i_z,
+                               absbox.xMin, absbox.yMax,
+                               absbox.xMax - absbox.xMin, absbox.yMin - absbox.yMax );
                 }
             }
 
@@ -789,8 +578,7 @@ static void RenderCharAXYZ( filter_t *p_filter,
                            int i_offset_x,
                            int i_offset_y,
                            int g,
-                           void (*ExtractComponents)( uint32_t, uint8_t *, uint8_t *, uint8_t * ),
-                           void (*BlendPixel)(picture_t *, int, int, int, int, int, int, int) )
+                           ft_drawing_functions draw )
 {
     VLC_UNUSED(p_filter);
     /* Render all glyphs and underline/strikethrough */
@@ -827,8 +615,7 @@ static void RenderCharAXYZ( filter_t *p_filter,
                             i_offset_x + p_rubydesc->origin.x,
                             i_offset_y - p_rubydesc->origin.y,
                             2,
-                            ExtractComponents,
-                            BlendPixel );
+                            draw );
         }
 
         /* Don't render if invisible or not wanted */
@@ -839,16 +626,13 @@ static void RenderCharAXYZ( filter_t *p_filter,
             continue;
 
         uint8_t i_x, i_y, i_z;
-        ExtractComponents( i_color, &i_x, &i_y, &i_z );
+        draw.extract( i_color, &i_x, &i_y, &i_z );
 
         int i_glyph_y = i_offset_y - p_glyph->top;
         int i_glyph_x = i_offset_x + p_glyph->left;
 
-        BlendAXYZGlyph( p_picture,
-                        i_glyph_x, i_glyph_y,
-                        i_a, i_x, i_y, i_z,
-                        p_glyph,
-                        BlendPixel );
+        draw.blend( p_picture, i_glyph_x, i_glyph_y,
+                    i_a, i_x, i_y, i_z, p_glyph );
 
         /* underline/strikethrough are only rendered for the normal glyph */
         if( g == 2 && ch->i_line_thickness > 0 )
@@ -857,7 +641,7 @@ static void RenderCharAXYZ( filter_t *p_filter,
                            i_a, i_x, i_y, i_z,
                            &ch[0],
                            i + 1 < p_line->i_character_count ? &ch[1] : NULL,
-                           BlendPixel );
+                           draw );
     }
 }
 
@@ -869,9 +653,7 @@ static inline int RenderAXYZ( filter_t *p_filter,
                               FT_BBox *p_textbbox,
                               vlc_fourcc_t i_chroma,
                               const video_format_t *fmt_out,
-                              void (*ExtractComponents)( uint32_t, uint8_t *, uint8_t *, uint8_t * ),
-                              void (*FillPicture)( picture_t *p_picture, int, int, int, int ),
-                              void (*BlendPixel)(picture_t *, int, int, int, int, int, int, int) )
+                              ft_drawing_functions draw )
 {
     filter_sys_t *p_sys = p_filter->p_sys;
 
@@ -904,17 +686,19 @@ static inline int RenderAXYZ( filter_t *p_filter,
 
     if (p_region->b_noregionbg) {
         /* Render the background just under the text */
-        FillPicture( p_picture, STYLE_ALPHA_TRANSPARENT, 0x00, 0x00, 0x00 );
+        draw.fill( p_picture, STYLE_ALPHA_TRANSPARENT, 0x00, 0x00, 0x00,
+                   0, 0, fmt.i_visible_width, fmt.i_visible_height );
     } else {
         /* Render background under entire subpicture block */
-        ExtractComponents( p_style->i_background_color, &i_x, &i_y, &i_z );
-        FillPicture( p_picture, p_style->i_background_alpha, i_x, i_y, i_z );
+        draw.extract( p_style->i_background_color, &i_x, &i_y, &i_z );
+        draw.fill( p_picture, p_style->i_background_alpha, i_x, i_y, i_z,
+                   0, 0, fmt.i_visible_width, fmt.i_visible_height );
     }
 
     /* Render text's background (from decoder) if any */
     RenderBackground(p_region, p_line_head,
                      p_regionbbox, p_paddedtextbbox, p_textbbox,
-                     p_picture, ExtractComponents, BlendPixel);
+                     p_picture, draw);
 
     /* Render shadow then outline and then normal glyphs */
     for( int g = 0; g < 3; g++ )
@@ -929,7 +713,7 @@ static inline int RenderAXYZ( filter_t *p_filter,
 
             RenderCharAXYZ( p_filter, p_picture, p_line,
                             i_glyph_offset_x, i_glyph_offset_y, g,
-                            ExtractComponents, BlendPixel );
+                            draw );
         }
     }
 
@@ -1310,6 +1094,26 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
 //            p_region_out->i_y = p_region_in->i_y;
 //        }
 
+        enum
+        {
+            DRAW_YUVA = 0,
+            DRAW_RGBA,
+            DRAW_ARGB,
+        };
+
+        const ft_drawing_functions drawfuncs[] =
+        {
+            [DRAW_YUVA] = { .extract = YUVFromRGB,
+                            .fill =    FillYUVAPicture,
+                            .blend =   BlendGlyphToYUVA },
+            [DRAW_RGBA] = { .extract = RGBFromRGB,
+                            .fill =    FillRGBAPicture,
+                            .blend =   BlendGlyphToRGBA },
+            [DRAW_ARGB] = { .extract = RGBFromRGB,
+                            .fill =    FillARGBPicture,
+                            .blend =   BlendGlyphToARGB },
+        };
+
         for( const vlc_fourcc_t *p_chroma = p_chroma_list; *p_chroma != 0; p_chroma++ )
         {
             rv = VLC_EGENERIC;
@@ -1321,26 +1125,20 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
                                  &regionbbox, &paddedbbox, &bbox,
                                  VLC_CODEC_YUVA,
                                  &p_region_out->fmt,
-                                 YUVFromRGB,
-                                 FillYUVAPicture,
-                                 BlendYUVAPixel );
+                                 drawfuncs[DRAW_YUVA] );
             else if( *p_chroma == VLC_CODEC_RGBA
                   || *p_chroma == VLC_CODEC_BGRA )
                 rv = RenderAXYZ( p_filter, p_region_out, text_block.p_laid,
                                  &regionbbox, &paddedbbox, &bbox,
                                  *p_chroma,
                                  &p_region_out->fmt,
-                                 RGBFromRGB,
-                                 FillRGBAPicture,
-                                 BlendRGBAPixel );
+                                 drawfuncs[DRAW_RGBA] );
             else if( *p_chroma == VLC_CODEC_ARGB )
                 rv = RenderAXYZ( p_filter, p_region_out, text_block.p_laid,
                                  &regionbbox, &paddedbbox, &bbox,
                                  VLC_CODEC_ARGB,
                                  &p_region_out->fmt,
-                                 RGBFromRGB,
-                                 FillARGBPicture,
-                                 BlendARGBPixel );
+                                 drawfuncs[DRAW_ARGB] );
 
             if( !rv )
                 break;



More information about the vlc-commits mailing list