[PATCH] gdi32: Support the subpixel rendering gamma correction.

Huw Davies huw at codeweavers.com
Mon Oct 15 03:36:17 CDT 2018


On Sat, Oct 13, 2018 at 01:08:06AM +0900, Byeongsik Jeon wrote:
> Signed-off-by: Byeongsik Jeon <bsjeon at hanmail.net>
> ---
> By setting the appropriate gamma value, subpixel color fringing reduced.
> https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph
> 
>  dlls/gdi32/dc.c                |  1 +
>  dlls/gdi32/dibdrv/dibdrv.h     |  9 ++++++-
>  dlls/gdi32/dibdrv/graphics.c   | 38 ++++++++++++++++++++++----
>  dlls/gdi32/dibdrv/primitives.c | 49 +++++++++++++++++++++++++---------
>  dlls/gdi32/font.c              | 28 +++++++++++++++++++
>  dlls/gdi32/gdi_private.h       |  1 +
>  6 files changed, 108 insertions(+), 18 deletions(-)
> 
> diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
> index 892d3e9744..dd7a86d571 100644
> --- a/dlls/gdi32/dc.c
> +++ b/dlls/gdi32/dc.c
> @@ -87,6 +87,7 @@ static void set_initial_dc_state( DC *dc )
>      dc->miterLimit          = 10.0f; /* 10.0 is the default, from MSDN */
>      dc->layout              = 0;
>      dc->font_code_page      = CP_ACP;
> +    dc->font_gamma          = 0;
>      dc->ROPmode             = R2_COPYPEN;
>      dc->polyFillMode        = ALTERNATE;
>      dc->stretchBltMode      = BLACKONWHITE;
> diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
> index f79f5b0867..ea33386faf 100644
> --- a/dlls/gdi32/dibdrv/dibdrv.h
> +++ b/dlls/gdi32/dibdrv/dibdrv.h
> @@ -85,6 +85,13 @@ struct intensity_range
>      BYTE b_min, b_max;
>  };
>  
> +struct font_gamma_lut
> +{
> +    DWORD value;
> +    BYTE  encode[256];
> +    BYTE  decode[256];
> +};
> +
>  typedef struct dibdrv_physdev
>  {
>      struct gdi_physdev dev;
> @@ -192,7 +199,7 @@ typedef struct primitive_funcs
>      void             (* draw_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph,
>                                      const POINT *origin, DWORD text_pixel, const struct intensity_range *ranges);
>      void    (* draw_subpixel_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph,
> -                                    const POINT *origin, DWORD text_pixel );
> +                                    const POINT *origin, DWORD text_pixel, const struct font_gamma_lut *gamma);
>      DWORD             (* get_pixel)(const dib_info *dib, int x, int y);
>      DWORD     (* colorref_to_pixel)(const dib_info *dib, COLORREF color);
>      COLORREF  (* pixel_to_colorref)(const dib_info *dib, DWORD pixel);
> diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c
> index 08f8c3d6d2..195866b92f 100644
> --- a/dlls/gdi32/dibdrv/graphics.c
> +++ b/dlls/gdi32/dibdrv/graphics.c
> @@ -683,7 +683,7 @@ static inline void get_text_bkgnd_masks( DC *dc, const dib_info *dib, rop_mask *
>  
>  static void draw_glyph( dib_info *dib, int x, int y, const GLYPHMETRICS *metrics,
>                          const dib_info *glyph_dib, DWORD text_color,
> -                        const struct intensity_range *ranges, const struct clipped_rects *clipped_rects,
> +                        const void *lut, const struct clipped_rects *clipped_rects,
>                          RECT *bounds )

Using a void ptr here is ugly, want you want is a union of the two sets of data.


>  {
>      int i;
> @@ -705,10 +705,10 @@ static void draw_glyph( dib_info *dib, int x, int y, const GLYPHMETRICS *metrics
>  
>              if (glyph_dib->bit_count == 32)
>                  dib->funcs->draw_subpixel_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
> -                                                 text_color );
> +                                                 text_color, lut );
>              else
>                  dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
> -                                        text_color, ranges );
> +                                        text_color, lut );
>          }
>      }
>  }
> @@ -808,6 +808,19 @@ done:
>      return add_cached_glyph( font, index, flags, glyph );
>  }
>  
> +static inline void update_font_gamma_lut( DWORD value, struct font_gamma_lut *gamma )
> +{
> +    int i;
> +
> +    for ( i = 0; i < 256; i++ )
> +    {
> +        gamma->encode[i] = pow( i / 255., 1000. / value ) * 255. + .5;
> +        gamma->decode[i] = pow( i / 255., value / 1000. ) * 255. + .5;
> +    }
> +
> +    gamma->value = value;
> +}
> +
>  static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT x, INT y,
>                             UINT flags, const WCHAR *str, UINT count, const INT *dx,
>                             const struct clipped_rects *clipped_rects, RECT *bounds )
> @@ -817,6 +830,8 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
>      dib_info glyph_dib;
>      DWORD text_color;
>      struct intensity_range ranges[17];
> +    static struct font_gamma_lut gamma;
> +    void *lut = NULL;
>  
>      glyph_dib.bit_count    = get_glyph_depth( font->aa_flags );
>      glyph_dib.rect.left    = 0;
> @@ -826,8 +841,21 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
>  
>      text_color = get_pixel_color( dc, dib, dc->textColor, TRUE );
>  
> -    if (glyph_dib.bit_count == 8)
> +    switch ( glyph_dib.bit_count )
> +    {
> +    case 8:
>          get_aa_ranges( dib->funcs->pixel_to_colorref( dib, text_color ), ranges );
> +        lut = ranges;
> +        break;
> +    case 32:
> +        if ( gamma.value != dc->font_gamma )

This isn't thread safe, you should store the computed values in the dc.

> +        {
> +            update_font_gamma_lut( dc->font_gamma, &gamma );
> +            TRACE( "font_contrast = %d\n", gamma.value );
> +        }
> +        lut = γ
> +        break;
> +    }
>  
>      for (i = 0; i < count; i++)
>      {




More information about the wine-devel mailing list