gdi32: Support the gamma correction for the subpixel rendering.
Signed-off-by: Byeongsik Jeon <bsjeon@hanmail.net> Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7e96514029
commit
649dd1292d
|
@ -168,6 +168,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_ramp );
|
||||
HeapFree( GetProcessHeap(), 0, dc );
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,12 @@ struct intensity_range
|
|||
BYTE b_min, b_max;
|
||||
};
|
||||
|
||||
struct font_intensities
|
||||
{
|
||||
struct intensity_range ranges[17];
|
||||
struct font_gamma_ramp *gamma_ramp;
|
||||
};
|
||||
|
||||
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_ramp *gamma_ramp);
|
||||
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);
|
||||
|
|
|
@ -683,8 +683,8 @@ 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,
|
||||
RECT *bounds )
|
||||
const struct font_intensities *intensity,
|
||||
const struct clipped_rects *clipped_rects, RECT *bounds )
|
||||
{
|
||||
int i;
|
||||
RECT rect, clipped_rect;
|
||||
|
@ -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, intensity->gamma_ramp );
|
||||
else
|
||||
dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
|
||||
text_color, ranges );
|
||||
text_color, intensity->ranges );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -816,7 +816,7 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
|
|||
struct cached_glyph *glyph;
|
||||
dib_info glyph_dib;
|
||||
DWORD text_color;
|
||||
struct intensity_range ranges[17];
|
||||
struct font_intensities intensity;
|
||||
|
||||
glyph_dib.bit_count = get_glyph_depth( font->aa_flags );
|
||||
glyph_dib.rect.left = 0;
|
||||
|
@ -826,8 +826,10 @@ 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)
|
||||
get_aa_ranges( dib->funcs->pixel_to_colorref( dib, text_color ), ranges );
|
||||
if (glyph_dib.bit_count == 32)
|
||||
intensity.gamma_ramp = dc->font_gamma_ramp;
|
||||
else
|
||||
get_aa_ranges( dib->funcs->pixel_to_colorref( dib, text_color ), intensity.ranges );
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -841,7 +843,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, &intensity, clipped_rects, bounds );
|
||||
|
||||
if (dx)
|
||||
{
|
||||
|
|
|
@ -6272,16 +6272,35 @@ static void draw_glyph_null( const dib_info *dib, const RECT *rect, const dib_in
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha )
|
||||
static inline BYTE blend_color_gamma( BYTE dst, BYTE text, BYTE alpha,
|
||||
const struct font_gamma_ramp *gamma_ramp )
|
||||
{
|
||||
if (alpha == 0) return dst;
|
||||
if (alpha == 255) return text;
|
||||
if (dst == text) return dst;
|
||||
|
||||
return gamma_ramp->encode[ blend_color( gamma_ramp->decode[dst],
|
||||
gamma_ramp->decode[text],
|
||||
alpha ) ];
|
||||
}
|
||||
|
||||
static inline DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha,
|
||||
const struct font_gamma_ramp *gamma_ramp )
|
||||
{
|
||||
if (gamma_ramp != NULL && gamma_ramp->gamma != 1000)
|
||||
{
|
||||
return blend_color_gamma( r, text >> 16, (BYTE)(alpha >> 16), gamma_ramp ) << 16 |
|
||||
blend_color_gamma( g, text >> 8, (BYTE)(alpha >> 8), gamma_ramp ) << 8 |
|
||||
blend_color_gamma( b, text, (BYTE) alpha, gamma_ramp );
|
||||
}
|
||||
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_ramp *gamma_ramp )
|
||||
{
|
||||
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_ramp );
|
||||
}
|
||||
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_ramp *gamma_ramp )
|
||||
{
|
||||
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_ramp );
|
||||
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_ramp *gamma_ramp )
|
||||
{
|
||||
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_ramp );
|
||||
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_ramp *gamma_ramp )
|
||||
{
|
||||
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_ramp *gamma_ramp )
|
||||
{
|
||||
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_ramp *gamma_ramp )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -729,6 +729,47 @@ 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_ramp *get_font_gamma_ramp( void )
|
||||
{
|
||||
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 };
|
||||
const DWORD gamma_default = 1400;
|
||||
struct font_gamma_ramp *ramp;
|
||||
DWORD i, gamma;
|
||||
HKEY key;
|
||||
|
||||
ramp = HeapAlloc( GetProcessHeap(), 0, sizeof(*ramp) );
|
||||
if ( ramp == 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 );
|
||||
}
|
||||
|
||||
/* Calibration the difference between the registry value and the Wine gamma value.
|
||||
This shows a roughly similar looks to the Windows Native with the same registry value.
|
||||
MS GDI seems to be rasterizing the outline at the different rate than FreeType. */
|
||||
gamma = 1000 * gamma / 1400;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
ramp->encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
|
||||
ramp->decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
|
||||
}
|
||||
|
||||
ramp->gamma = gamma;
|
||||
TRACE("gamma %d\n", ramp->gamma);
|
||||
|
||||
return ramp;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FONT_SelectObject
|
||||
*/
|
||||
|
@ -754,6 +795,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_ramp == NULL)
|
||||
dc->font_gamma_ramp = get_font_gamma_ramp();
|
||||
GDI_dec_ref_count( ret );
|
||||
}
|
||||
else GDI_dec_ref_count( handle );
|
||||
|
|
|
@ -99,6 +99,8 @@ typedef struct tagDC
|
|||
|
||||
struct gdi_path *path;
|
||||
|
||||
struct font_gamma_ramp *font_gamma_ramp;
|
||||
|
||||
UINT font_code_page;
|
||||
WORD ROPmode;
|
||||
WORD polyFillMode;
|
||||
|
@ -270,6 +272,14 @@ extern BOOL DRIVER_GetDriverName( LPCWSTR device, LPWSTR driver, DWORD size ) DE
|
|||
/* enhmetafile.c */
|
||||
extern HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk ) DECLSPEC_HIDDEN;
|
||||
|
||||
/* font.c */
|
||||
struct font_gamma_ramp
|
||||
{
|
||||
DWORD gamma;
|
||||
BYTE encode[256];
|
||||
BYTE decode[256];
|
||||
};
|
||||
|
||||
/* freetype.c */
|
||||
|
||||
/* Undocumented structure filled in by GetFontRealizationInfo */
|
||||
|
|
Loading…
Reference in New Issue