Commit 92473283 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

gdi32: Implement sub-pixel glyph smoothing.

parent 7f50df4e
......@@ -183,6 +183,8 @@ typedef struct primitive_funcs
BOOL (* gradient_rect)(const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode);
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 );
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);
......
......@@ -462,12 +462,38 @@ static void draw_glyph( dib_info *dib, int x, int y, const GLYPHMETRICS *metrics
src_origin.x = clipped_rect.left - rect.left;
src_origin.y = clipped_rect.top - rect.top;
dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
text_color, ranges );
if (glyph_dib->bit_count == 32)
dib->funcs->draw_subpixel_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
text_color );
else
dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
text_color, ranges );
}
}
}
static int get_glyph_depth( UINT aa_flags )
{
switch (aa_flags)
{
case GGO_BITMAP: return 1;
case GGO_GRAY2_BITMAP:
case GGO_GRAY4_BITMAP:
case GGO_GRAY8_BITMAP:
case WINE_GGO_GRAY16_BITMAP: return 8;
case WINE_GGO_HRGB_BITMAP:
case WINE_GGO_HBGR_BITMAP:
case WINE_GGO_VRGB_BITMAP:
case WINE_GGO_VBGR_BITMAP: return 32;
default:
ERR("Unexpected flags %08x\n", aa_flags);
return 0;
}
}
static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
static const int padding[4] = {0, 3, 2, 1};
......@@ -488,7 +514,7 @@ static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS
int i, x, y;
DWORD ret, size;
BYTE *buf, *dst, *src;
int pad;
int pad = 0, depth = get_glyph_depth( aa_flags );
glyph_dib->bits.ptr = NULL;
glyph_dib->bits.is_copy = FALSE;
......@@ -508,7 +534,7 @@ static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS
if (!ret) return ERROR_SUCCESS; /* empty glyph */
/* We'll convert non-antialiased 1-bpp bitmaps to 8-bpp, so these sizes relate to 8-bpp */
glyph_dib->bit_count = 8;
glyph_dib->bit_count = depth == 1 ? 8 : depth;
glyph_dib->width = metrics->gmBlackBoxX;
glyph_dib->height = metrics->gmBlackBoxY;
glyph_dib->rect.left = 0;
......@@ -517,7 +543,7 @@ static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS
glyph_dib->rect.bottom = metrics->gmBlackBoxY;
glyph_dib->stride = get_dib_stride( metrics->gmBlackBoxX, glyph_dib->bit_count );
pad = padding[ metrics->gmBlackBoxX % 4 ];
if (glyph_dib->bit_count == 8) pad = padding[ metrics->gmBlackBoxX % 4 ];
size = metrics->gmBlackBoxY * glyph_dib->stride;
buf = HeapAlloc( GetProcessHeap(), 0, size );
......
......@@ -4859,6 +4859,150 @@ static void draw_glyph_null( const dib_info *dib, const RECT *rect, const dib_in
return;
}
static DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha )
{
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 )
{
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 );
int x, y;
for (y = rect->top; y < rect->bottom; y++)
{
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 += dib->stride / 4;
glyph_ptr += glyph->stride / 4;
}
}
static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const dib_info *glyph,
const POINT *origin, DWORD text_pixel )
{
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 );
int x, y;
DWORD text, val;
text = get_field( text_pixel, dib->red_shift, dib->red_len ) << 16 |
get_field( text_pixel, dib->green_shift, dib->green_len ) << 8 |
get_field( text_pixel, dib->blue_shift, dib->blue_len );
for (y = rect->top; y < rect->bottom; y++)
{
for (x = 0; x < rect->right - rect->left; x++)
{
if (glyph_ptr[x] == 0) continue;
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] );
dst_ptr[x] = (put_field( val >> 16, dib->red_shift, dib->red_len ) |
put_field( val >> 8, dib->green_shift, dib->green_len ) |
put_field( val, dib->blue_shift, dib->blue_len ));
}
dst_ptr += dib->stride / 4;
glyph_ptr += glyph->stride / 4;
}
}
static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const dib_info *glyph,
const POINT *origin, DWORD text_pixel )
{
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 );
int x, y;
DWORD val;
for (y = rect->top; y < rect->bottom; y++)
{
for (x = 0; x < rect->right - rect->left; x++)
{
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] );
dst_ptr[x * 3] = val;
dst_ptr[x * 3 + 1] = val >> 8;
dst_ptr[x * 3 + 2] = val >> 16;
}
dst_ptr += dib->stride;
glyph_ptr += glyph->stride / 4;
}
}
static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, const dib_info *glyph,
const POINT *origin, DWORD text_pixel )
{
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 );
int x, y;
DWORD text, val;
text = ((text_pixel << 9) & 0xf80000) | ((text_pixel << 4) & 0x070000) |
((text_pixel << 6) & 0x00f800) | ((text_pixel << 1) & 0x000700) |
((text_pixel << 3) & 0x0000f8) | ((text_pixel >> 2) & 0x000007);
for (y = rect->top; y < rect->bottom; y++)
{
for (x = 0; x < rect->right - rect->left; x++)
{
if (glyph_ptr[x] == 0) continue;
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] );
dst_ptr[x] = ((val >> 9) & 0x7c00) | ((val >> 6) & 0x03e0) | ((val >> 3) & 0x001f);
}
dst_ptr += dib->stride / 2;
glyph_ptr += glyph->stride / 4;
}
}
static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const dib_info *glyph,
const POINT *origin, DWORD text_pixel )
{
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 );
int x, y;
DWORD text, val;
text = get_field( text_pixel, dib->red_shift, dib->red_len ) << 16 |
get_field( text_pixel, dib->green_shift, dib->green_len ) << 8 |
get_field( text_pixel, dib->blue_shift, dib->blue_len );
for (y = rect->top; y < rect->bottom; y++)
{
for (x = 0; x < rect->right - rect->left; x++)
{
if (glyph_ptr[x] == 0) continue;
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] );
dst_ptr[x] = (put_field( val >> 16, dib->red_shift, dib->red_len ) |
put_field( val >> 8, dib->green_shift, dib->green_len ) |
put_field( val, dib->blue_shift, dib->blue_len ));
}
dst_ptr += dib->stride / 2;
glyph_ptr += glyph->stride / 4;
}
}
static void draw_subpixel_glyph_null( const dib_info *dib, const RECT *rect, const dib_info *glyph,
const POINT *origin, DWORD text_pixel )
{
return;
}
static void create_rop_masks_32(const dib_info *dib, const BYTE *hatch_ptr,
const rop_mask *fg, const rop_mask *bg, rop_mask_bits *bits)
{
......@@ -5647,6 +5791,7 @@ const primitive_funcs funcs_8888 =
blend_rect_8888,
gradient_rect_8888,
draw_glyph_8888,
draw_subpixel_glyph_8888,
get_pixel_32,
colorref_to_pixel_888,
pixel_to_colorref_888,
......@@ -5666,6 +5811,7 @@ const primitive_funcs funcs_32 =
blend_rect_32,
gradient_rect_32,
draw_glyph_32,
draw_subpixel_glyph_32,
get_pixel_32,
colorref_to_pixel_masks,
pixel_to_colorref_masks,
......@@ -5685,6 +5831,7 @@ const primitive_funcs funcs_24 =
blend_rect_24,
gradient_rect_24,
draw_glyph_24,
draw_subpixel_glyph_24,
get_pixel_24,
colorref_to_pixel_888,
pixel_to_colorref_888,
......@@ -5704,6 +5851,7 @@ const primitive_funcs funcs_555 =
blend_rect_555,
gradient_rect_555,
draw_glyph_555,
draw_subpixel_glyph_555,
get_pixel_16,
colorref_to_pixel_555,
pixel_to_colorref_555,
......@@ -5723,6 +5871,7 @@ const primitive_funcs funcs_16 =
blend_rect_16,
gradient_rect_16,
draw_glyph_16,
draw_subpixel_glyph_16,
get_pixel_16,
colorref_to_pixel_masks,
pixel_to_colorref_masks,
......@@ -5742,6 +5891,7 @@ const primitive_funcs funcs_8 =
blend_rect_8,
gradient_rect_8,
draw_glyph_8,
draw_subpixel_glyph_null,
get_pixel_8,
colorref_to_pixel_colortable,
pixel_to_colorref_colortable,
......@@ -5761,6 +5911,7 @@ const primitive_funcs funcs_4 =
blend_rect_4,
gradient_rect_4,
draw_glyph_4,
draw_subpixel_glyph_null,
get_pixel_4,
colorref_to_pixel_colortable,
pixel_to_colorref_colortable,
......@@ -5780,6 +5931,7 @@ const primitive_funcs funcs_1 =
blend_rect_1,
gradient_rect_1,
draw_glyph_1,
draw_subpixel_glyph_null,
get_pixel_1,
colorref_to_pixel_colortable,
pixel_to_colorref_colortable,
......@@ -5799,6 +5951,7 @@ const primitive_funcs funcs_null =
blend_rect_null,
gradient_rect_null,
draw_glyph_null,
draw_subpixel_glyph_null,
get_pixel_null,
colorref_to_pixel_null,
pixel_to_colorref_null,
......
......@@ -33,6 +33,7 @@
#include "winbase.h"
#include "winnls.h"
#include "winternl.h"
#include "winreg.h"
#include "gdi_private.h"
#include "wine/exception.h"
#include "wine/unicode.h"
......@@ -328,10 +329,74 @@ done:
return ret;
}
enum smoothing { no_smoothing, aa_smoothing, subpixel_smoothing };
static DWORD get_desktop_value( const WCHAR *name, DWORD *value )
{
static const WCHAR desktop[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\','D','e','s','k','t','o','p',0};
HKEY key;
WCHAR buf[12];
DWORD count = sizeof(buf), type, err;
err = RegOpenKeyW( HKEY_CURRENT_USER, desktop, &key );
if (!err)
{
err = RegQueryValueExW( key, name, NULL, &type, (BYTE*)buf, &count );
if (!err) *value = atoiW( buf );
RegCloseKey( key );
}
return err;
}
static enum smoothing get_default_smoothing( void )
{
static const WCHAR smoothing_type[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
DWORD type, err;
/* FIXME: Ignoring FontSmoothing for now since this is
set to off by default in wine.inf */
err = get_desktop_value( smoothing_type, &type );
if (err) return aa_smoothing;
switch (type)
{
case 1: /* FE_FONTSMOOTHINGSTANDARD */
return aa_smoothing;
case 2: /* FE_FONTSMOOTHINGCLEARTYPE */
return subpixel_smoothing;
}
return aa_smoothing;
}
static UINT get_subpixel_orientation( void )
{
static const WCHAR smoothing_orientation[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
'O','r','i','e','n','t','a','t','i','o','n',0};
DWORD orient, err;
/* FIXME: handle vertical orientations even though Windows doesn't */
err = get_desktop_value( smoothing_orientation, &orient );
if (err) return GGO_GRAY4_BITMAP;
switch (orient)
{
case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
return WINE_GGO_HBGR_BITMAP;
case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
return WINE_GGO_HRGB_BITMAP;
}
return GGO_GRAY4_BITMAP;
}
UINT get_font_aa_flags( HDC hdc )
{
LOGFONTW lf;
WORD gasp_flags;
static int hinter = -1;
static int subpixel_enabled = -1;
enum smoothing smoothing;
if (GetObjectType( hdc ) == OBJ_MEMDC)
{
......@@ -344,11 +409,48 @@ UINT get_font_aa_flags( HDC hdc )
GetObjectW( GetCurrentObject( hdc, OBJ_FONT ), sizeof(lf), &lf );
if (lf.lfQuality == NONANTIALIASED_QUALITY) return GGO_BITMAP;
if (get_gasp_flags( hdc, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
return GGO_BITMAP;
if (hinter == -1 || subpixel_enabled == -1)
{
RASTERIZER_STATUS status;
GetRasterizerCaps(&status, sizeof(status));
hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
subpixel_enabled = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
}
/* FIXME, check user prefs */
return GGO_GRAY4_BITMAP;
switch (lf.lfQuality)
{
case ANTIALIASED_QUALITY:
smoothing = aa_smoothing;
break;
case CLEARTYPE_QUALITY:
case CLEARTYPE_NATURAL_QUALITY:
smoothing = subpixel_smoothing;
break;
case DEFAULT_QUALITY:
case DRAFT_QUALITY:
case PROOF_QUALITY:
default:
smoothing = get_default_smoothing();
}
if (smoothing == subpixel_smoothing)
{
if (subpixel_enabled)
{
UINT ret = get_subpixel_orientation();
if (ret != GGO_GRAY4_BITMAP) return ret;
}
smoothing = aa_smoothing;
}
if (smoothing == aa_smoothing)
{
if (hinter && get_gasp_flags( hdc, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
return GGO_BITMAP;
return GGO_GRAY4_BITMAP;
}
return GGO_BITMAP;
}
/***********************************************************************
......@@ -1877,6 +1979,9 @@ BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect
struct bitblt_coords src, dst;
PHYSDEV dst_dev;
/* FIXME Subpixel modes */
aa_flags = GGO_GRAY4_BITMAP;
dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment