[PATCH v2 1/2] gdi32: Support the subpixel rendering gamma. correction.

Byeongsik Jeon bsjeon at hanmail.net
Mon Oct 15 08:12:30 CDT 2018


Signed-off-by: Byeongsik Jeon <bsjeon at hanmail.net>
---
v2: Fix the void *, thread safety.

 dlls/gdi32/dc.c                |  2 ++
 dlls/gdi32/dibdrv/dibdrv.h     |  8 +++++-
 dlls/gdi32/dibdrv/graphics.c   | 19 +++++++++----
 dlls/gdi32/dibdrv/primitives.c | 49 +++++++++++++++++++++++++---------
 dlls/gdi32/font.c              | 37 +++++++++++++++++++++++++
 dlls/gdi32/gdi_private.h       |  9 +++++++
 6 files changed, 106 insertions(+), 18 deletions(-)

diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 892d3e9744..de01bf4d3d 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -86,6 +86,7 @@ static void set_initial_dc_state( DC *dc )
     dc->vport_ext.cy        = 1;
     dc->miterLimit          = 10.0f; /* 10.0 is the default, from MSDN */
     dc->layout              = 0;
+    dc->font_gamma          = NULL;
     dc->font_code_page      = CP_ACP;
     dc->ROPmode             = R2_COPYPEN;
     dc->polyFillMode        = ALTERNATE;
@@ -168,6 +169,7 @@ static void free_dc_state( DC *dc )
     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
     if (dc->region) DeleteObject( dc->region );
     if (dc->path) free_gdi_path( dc->path );
+    HeapFree( GetProcessHeap(), 0, dc->font_gamma );
     HeapFree( GetProcessHeap(), 0, dc );
 }
 
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index f79f5b0867..5776490bd4 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -85,6 +85,12 @@ struct intensity_range
     BYTE b_min, b_max;
 };
 
+union font_intensities
+{
+    struct intensity_range  *ranges;
+    struct font_gamma_table *gamma;
+};
+
 typedef struct dibdrv_physdev
 {
     struct gdi_physdev dev;
@@ -192,7 +198,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_table *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..a6d108576f 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 union font_intensities lut, const struct clipped_rects *clipped_rects,
                         RECT *bounds )
 {
     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.gamma );
             else
                 dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
-                                        text_color, ranges );
+                                        text_color, lut.ranges );
         }
     }
 }
@@ -817,6 +817,7 @@ 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];
+    union font_intensities lut = { NULL };
 
     glyph_dib.bit_count    = get_glyph_depth( font->aa_flags );
     glyph_dib.rect.left    = 0;
@@ -826,8 +827,16 @@ 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 = ranges;
+        break;
+    case 32:
+        lut.gamma = dc->font_gamma;
+        break;
+    }
 
     for (i = 0; i < count; i++)
     {
@@ -841,7 +850,7 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
         glyph_dib.stride      = get_dib_stride( glyph->metrics.gmBlackBoxX, glyph_dib.bit_count );
         glyph_dib.bits.ptr    = glyph->bits;
 
-        draw_glyph( dib, x, y, &glyph->metrics, &glyph_dib, text_color, ranges, clipped_rects, bounds );
+        draw_glyph( dib, x, y, &glyph->metrics, &glyph_dib, text_color, lut, clipped_rects, bounds );
 
         if (dx)
         {
diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c
index 0d097b2da6..ca80e4d8f6 100644
--- a/dlls/gdi32/dibdrv/primitives.c
+++ b/dlls/gdi32/dibdrv/primitives.c
@@ -6272,16 +6272,35 @@ static void draw_glyph_null( const dib_info *dib, const RECT *rect, const dib_in
 {
     return;
 }
+static inline BYTE blend_color_gamma( BYTE dst, BYTE text, BYTE alpha,
+                                      const struct font_gamma_table *gamma )
+{
+    if ( alpha == 0 ) return dst;
+    if ( alpha == 255 ) return text;
+    if ( dst == text ) return dst;
+
+    return gamma->encode[ blend_color( gamma->decode[dst],
+                                       gamma->decode[text],
+                                       alpha) ];
+}
 
-static inline DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha )
+static inline DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha,
+                                    const struct font_gamma_table *gamma )
 {
+    if ( gamma != NULL && gamma->value != 1000 )
+    {
+        return blend_color_gamma( r, text >> 16, (BYTE)(alpha >> 16), gamma ) << 16 |
+               blend_color_gamma( g, text >> 8,  (BYTE)(alpha >> 8),  gamma ) << 8  |
+               blend_color_gamma( b, text,       (BYTE) alpha,        gamma );
+    }
     return blend_color( r, text >> 16, (BYTE)(alpha >> 16) ) << 16 |
            blend_color( g, text >> 8,  (BYTE)(alpha >> 8) )  << 8  |
            blend_color( b, text,       (BYTE) alpha );
 }
 
 static void draw_subpixel_glyph_8888( const dib_info *dib, const RECT *rect, const dib_info *glyph,
-                                      const POINT *origin, DWORD text_pixel )
+                                      const POINT *origin, DWORD text_pixel,
+                                      const struct font_gamma_table *gamma )
 {
     DWORD *dst_ptr = get_pixel_ptr_32( dib, rect->left, rect->top );
     const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6292,7 +6311,8 @@ static void draw_subpixel_glyph_8888( const dib_info *dib, const RECT *rect, con
         for (x = 0; x < rect->right - rect->left; x++)
         {
             if (glyph_ptr[x] == 0) continue;
-            dst_ptr[x] = blend_subpixel( dst_ptr[x] >> 16, dst_ptr[x] >> 8, dst_ptr[x], text_pixel, glyph_ptr[x] );
+            dst_ptr[x] = blend_subpixel( dst_ptr[x] >> 16, dst_ptr[x] >> 8, dst_ptr[x],
+                                         text_pixel, glyph_ptr[x], gamma );
         }
         dst_ptr += dib->stride / 4;
         glyph_ptr += glyph->stride / 4;
@@ -6300,7 +6320,8 @@ static void draw_subpixel_glyph_8888( const dib_info *dib, const RECT *rect, con
 }
 
 static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const dib_info *glyph,
-                                    const POINT *origin, DWORD text_pixel )
+                                    const POINT *origin, DWORD text_pixel,
+                                    const struct font_gamma_table *gamma )
 {
     DWORD *dst_ptr = get_pixel_ptr_32( dib, rect->left, rect->top );
     const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6319,7 +6340,7 @@ static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const
             val = blend_subpixel( get_field(dst_ptr[x], dib->red_shift,   dib->red_len),
                                   get_field(dst_ptr[x], dib->green_shift, dib->green_len),
                                   get_field(dst_ptr[x], dib->blue_shift,  dib->blue_len),
-                                  text, glyph_ptr[x] );
+                                  text, glyph_ptr[x], gamma );
             dst_ptr[x] = rgb_to_pixel_masks( dib, val >> 16, val >> 8, val );
         }
         dst_ptr += dib->stride / 4;
@@ -6328,7 +6349,8 @@ static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const
 }
 
 static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const dib_info *glyph,
-                                    const POINT *origin, DWORD text_pixel )
+                                    const POINT *origin, DWORD text_pixel,
+                                    const struct font_gamma_table *gamma )
 {
     BYTE *dst_ptr = get_pixel_ptr_24( dib, rect->left, rect->top );
     const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6341,7 +6363,7 @@ static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const
         {
             if (glyph_ptr[x] == 0) continue;
             val = blend_subpixel( dst_ptr[x * 3 + 2], dst_ptr[x * 3 + 1], dst_ptr[x * 3],
-                                  text_pixel, glyph_ptr[x] );
+                                  text_pixel, glyph_ptr[x], gamma );
             dst_ptr[x * 3]     = val;
             dst_ptr[x * 3 + 1] = val >> 8;
             dst_ptr[x * 3 + 2] = val >> 16;
@@ -6352,7 +6374,8 @@ static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const
 }
 
 static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, const dib_info *glyph,
-                                     const POINT *origin, DWORD text_pixel )
+                                     const POINT *origin, DWORD text_pixel,
+                                     const struct font_gamma_table *gamma )
 {
     WORD *dst_ptr = get_pixel_ptr_16( dib, rect->left, rect->top );
     const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6371,7 +6394,7 @@ static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, cons
             val = blend_subpixel( ((dst_ptr[x] >> 7) & 0xf8) | ((dst_ptr[x] >> 12) & 0x07),
                                   ((dst_ptr[x] >> 2) & 0xf8) | ((dst_ptr[x] >>  7) & 0x07),
                                   ((dst_ptr[x] << 3) & 0xf8) | ((dst_ptr[x] >>  2) & 0x07),
-                                  text, glyph_ptr[x] );
+                                  text, glyph_ptr[x], NULL );
             dst_ptr[x] = ((val >> 9) & 0x7c00) | ((val >> 6) & 0x03e0) | ((val >> 3) & 0x001f);
         }
         dst_ptr += dib->stride / 2;
@@ -6380,7 +6403,8 @@ static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, cons
 }
 
 static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const dib_info *glyph,
-                                    const POINT *origin, DWORD text_pixel )
+                                    const POINT *origin, DWORD text_pixel,
+                                    const struct font_gamma_table *gamma )
 {
     WORD *dst_ptr = get_pixel_ptr_16( dib, rect->left, rect->top );
     const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6399,7 +6423,7 @@ static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const
             val = blend_subpixel( get_field(dst_ptr[x], dib->red_shift,   dib->red_len),
                                   get_field(dst_ptr[x], dib->green_shift, dib->green_len),
                                   get_field(dst_ptr[x], dib->blue_shift,  dib->blue_len),
-                                  text, glyph_ptr[x] );
+                                  text, glyph_ptr[x], NULL );
             dst_ptr[x] = rgb_to_pixel_masks( dib, val >> 16, val >> 8, val );
         }
         dst_ptr += dib->stride / 2;
@@ -6408,7 +6432,8 @@ static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const
 }
 
 static void draw_subpixel_glyph_null( const dib_info *dib, const RECT *rect, const dib_info *glyph,
-                                      const POINT *origin, DWORD text_pixel )
+                                      const POINT *origin, DWORD text_pixel,
+                                      const struct font_gamma_table *gamma )
 {
     return;
 }
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 5c67d5b518..b943800e1e 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -729,6 +729,41 @@ static void update_font_code_page( DC *dc, HANDLE font )
     TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
 }
 
+static struct font_gamma_table *get_font_gamma_table()
+{
+    static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
+                                      'D','e','s','k','t','o','p',0 };
+    static const WCHAR smoothing_gamma[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
+                                            'G','a','m','m','a',0};
+    struct font_gamma_table *font_gamma;
+    const  DWORD gamma_default = 1000; /* FIXME 1400 */
+    DWORD  i, gamma;
+    HKEY key;
+
+    font_gamma = HeapAlloc( GetProcessHeap(), 0, sizeof(struct font_gamma_table) );
+    if ( font_gamma == NULL ) return NULL;
+
+    gamma = gamma_default;
+    if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key ) == ERROR_SUCCESS )
+    {
+        if ( get_key_value( key, smoothing_gamma, &gamma ) || gamma == 0 )
+            gamma = gamma_default;
+        RegCloseKey( key );
+
+        gamma = min( max( gamma, 1000), 2200 );
+    }
+
+    for ( i = 0; i < 256; i++ )
+    {
+        font_gamma->encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
+        font_gamma->decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
+    }
+
+    font_gamma->value = gamma;
+
+    TRACE("font_gamma value %d\n", font_gamma->value);
+}
+
 /***********************************************************************
  *           FONT_SelectObject
  */
@@ -754,6 +789,8 @@ static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
         dc->hFont = handle;
         dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
         update_font_code_page( dc, handle );
+        if ( dc->font_gamma == NULL )
+            dc->font_gamma = get_font_gamma_table();
         GDI_dec_ref_count( ret );
     }
     else GDI_dec_ref_count( handle );
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 5b09b84846..e5ff467b20 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -48,6 +48,13 @@ typedef struct {
 /* extra stock object: default 1x1 bitmap for memory DCs */
 #define DEFAULT_BITMAP (STOCK_LAST+1)
 
+struct font_gamma_table
+{
+    DWORD value;
+    BYTE  encode[256];
+    BYTE  decode[256];
+};
+
 struct gdi_obj_funcs
 {
     HGDIOBJ (*pSelectObject)( HGDIOBJ handle, HDC hdc );
@@ -99,6 +106,8 @@ typedef struct tagDC
 
     struct gdi_path *path;
 
+    struct font_gamma_table *font_gamma;
+
     UINT          font_code_page;
     WORD          ROPmode;
     WORD          polyFillMode;
-- 
2.19.1




More information about the wine-devel mailing list