gdi32: Add support for anti-aliasing in the null driver text output fallback.

This commit is contained in:
Alexandre Julliard 2011-11-17 16:55:16 +01:00
parent 1b63d5a610
commit 670f25cc8f
5 changed files with 236 additions and 19 deletions

View file

@ -231,6 +231,7 @@ extern void free_dib_info(dib_info *dib) DECLSPEC_HIDDEN;
extern void free_pattern_brush(dibdrv_physdev *pdev) DECLSPEC_HIDDEN;
extern void copy_dib_color_info(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN;
extern BOOL convert_dib(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN;
extern COLORREF make_rgb_colorref( HDC hdc, dib_info *dib, COLORREF color, BOOL *got_pixel, DWORD *pixel ) DECLSPEC_HIDDEN;
extern DWORD get_pixel_color(dibdrv_physdev *pdev, COLORREF color, BOOL mono_fixup) DECLSPEC_HIDDEN;
extern BOOL brush_rects( dibdrv_physdev *pdev, int num, const RECT *rects ) DECLSPEC_HIDDEN;
extern void solid_rects( dib_info *dib, int num, const RECT *rects, const rop_mask *color, HRGN region ) DECLSPEC_HIDDEN;

View file

@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include "gdi_private.h"
#include "dibdrv.h"
@ -90,19 +91,24 @@ static inline void get_range( BYTE aa, DWORD text_comp, BYTE *min_comp, BYTE *ma
*max_comp = ramp[16 - aa] + ((0xff - ramp[16 - aa]) * text_comp) / 0xff;
}
void update_aa_ranges( dibdrv_physdev *pdev )
static inline void get_aa_ranges( COLORREF col, struct intensity_range intensities[17] )
{
int i;
COLORREF text = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pdev->text_color );
for (i = 0; i < 17; i++)
{
get_range( i, GetRValue(text), &pdev->glyph_intensities[i].r_min, &pdev->glyph_intensities[i].r_max );
get_range( i, GetGValue(text), &pdev->glyph_intensities[i].g_min, &pdev->glyph_intensities[i].g_max );
get_range( i, GetBValue(text), &pdev->glyph_intensities[i].b_min, &pdev->glyph_intensities[i].b_max );
get_range( i, GetRValue(col), &intensities[i].r_min, &intensities[i].r_max );
get_range( i, GetGValue(col), &intensities[i].g_min, &intensities[i].g_max );
get_range( i, GetBValue(col), &intensities[i].b_min, &intensities[i].b_max );
}
}
void update_aa_ranges( dibdrv_physdev *pdev )
{
COLORREF text = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pdev->text_color );
get_aa_ranges( text, pdev->glyph_intensities );
}
/**********************************************************************
* get_text_bkgnd_masks
*
@ -168,7 +174,7 @@ static const int padding[4] = {0, 3, 2, 1};
* For non-antialiased bitmaps convert them to the 17-level format
* using only values 0 or 16.
*/
static DWORD get_glyph_bitmap( dibdrv_physdev *pdev, UINT index, UINT aa_flags, GLYPHMETRICS *metrics,
static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS *metrics,
struct gdi_image_bits *image )
{
UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
@ -188,7 +194,7 @@ static DWORD get_glyph_bitmap( dibdrv_physdev *pdev, UINT index, UINT aa_flags,
for (i = 0; i < sizeof(indices) / sizeof(indices[0]); index = indices[++i])
{
ret = GetGlyphOutlineW( pdev->dev.hdc, index, ggo_flags, metrics, 0, NULL, &identity );
ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
if (ret != GDI_ERROR) break;
}
@ -203,7 +209,7 @@ static DWORD get_glyph_bitmap( dibdrv_physdev *pdev, UINT index, UINT aa_flags,
buf = HeapAlloc( GetProcessHeap(), 0, size );
if (!buf) return ERROR_OUTOFMEMORY;
ret = GetGlyphOutlineW( pdev->dev.hdc, index, ggo_flags, metrics, size, buf, &identity );
ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, buf, &identity );
if (ret == GDI_ERROR)
{
HeapFree( GetProcessHeap(), 0, buf );
@ -233,6 +239,95 @@ static DWORD get_glyph_bitmap( dibdrv_physdev *pdev, UINT index, UINT aa_flags,
return ERROR_SUCCESS;
}
BOOL render_aa_text_bitmapinfo( HDC hdc, BITMAPINFO *info, struct gdi_image_bits *bits,
struct bitblt_coords *src, INT x, INT y, UINT flags,
UINT aa_flags, LPCWSTR str, UINT count, const INT *dx )
{
dib_info dib;
UINT i;
DWORD err;
BOOL got_pixel;
COLORREF fg, bg;
DWORD fg_pixel, bg_pixel;
struct intensity_range glyph_intensities[17];
assert( info->bmiHeader.biBitCount > 8 ); /* mono and indexed formats don't support anti-aliasing */
if (!init_dib_info_from_bitmapinfo( &dib, info, bits->ptr, 0 )) return FALSE;
fg = make_rgb_colorref( hdc, &dib, GetTextColor( hdc ), &got_pixel, &fg_pixel);
if (!got_pixel) fg_pixel = dib.funcs->colorref_to_pixel( &dib, fg );
get_aa_ranges( fg, glyph_intensities );
if (flags & ETO_OPAQUE)
{
rop_mask bkgnd_color;
bg = make_rgb_colorref( hdc, &dib, GetBkColor( hdc ), &got_pixel, &bg_pixel);
if (!got_pixel) bg_pixel = dib.funcs->colorref_to_pixel( &dib, bg );
bkgnd_color.and = 0;
bkgnd_color.xor = bg_pixel;
solid_rects( &dib, 1, &src->visrect, &bkgnd_color, 0 );
}
for (i = 0; i < count; i++)
{
GLYPHMETRICS metrics;
struct gdi_image_bits image;
err = get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, &image );
if (err) continue;
if (image.ptr)
{
RECT rect, clipped_rect;
POINT src_origin;
dib_info glyph_dib;
glyph_dib.bit_count = 8;
glyph_dib.width = metrics.gmBlackBoxX;
glyph_dib.height = metrics.gmBlackBoxY;
glyph_dib.stride = get_dib_stride( metrics.gmBlackBoxX, 8 );
glyph_dib.bits = image;
rect.left = x + metrics.gmptGlyphOrigin.x;
rect.top = y - metrics.gmptGlyphOrigin.y;
rect.right = rect.left + metrics.gmBlackBoxX;
rect.bottom = rect.top + metrics.gmBlackBoxY;
if (intersect_rect( &clipped_rect, &rect, &src->visrect ))
{
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,
fg_pixel, glyph_intensities );
}
}
if (image.free) image.free( &image );
if (dx)
{
if (flags & ETO_PDY)
{
x += dx[ i * 2 ];
y += dx[ i * 2 + 1];
}
else
x += dx[ i ];
}
else
{
x += metrics.gmCellIncX;
y += metrics.gmCellIncY;
}
}
free_dib_info( &dib );
return TRUE;
}
/***********************************************************************
* dibdrv_ExtTextOut
*/
@ -269,7 +364,7 @@ BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
GLYPHMETRICS metrics;
struct gdi_image_bits image;
err = get_glyph_bitmap( pdev, (UINT)str[i], aa_flags, &metrics, &image );
err = get_glyph_bitmap( dev->hdc, (UINT)str[i], aa_flags, &metrics, &image );
if (err) continue;
if (image.ptr) draw_glyph( pdev, &origin, &metrics, &image );

View file

@ -123,12 +123,11 @@ static inline BOOL rgbquad_equal(const RGBQUAD *a, const RGBQUAD *b)
return FALSE;
}
static COLORREF make_rgb_colorref( dibdrv_physdev *pdev, COLORREF color,
BOOL *got_pixel, DWORD *pixel )
COLORREF make_rgb_colorref( HDC hdc, dib_info *dib, COLORREF color, BOOL *got_pixel, DWORD *pixel )
{
BYTE type = color >> 24;
WORD index = LOWORD( color );
HPALETTE pal = GetCurrentObject( pdev->dev.hdc, OBJ_PAL );
HPALETTE pal = GetCurrentObject( hdc, OBJ_PAL );
PALETTEENTRY pal_ent;
*pixel = 0;
@ -143,13 +142,13 @@ static COLORREF make_rgb_colorref( dibdrv_physdev *pdev, COLORREF color,
*pixel = 0;
color = RGB(0, 0, 0);
if (pdev->dib.bit_count <= 8 && index < (1 << pdev->dib.bit_count))
if (dib->bit_count <= 8 && index < (1 << dib->bit_count))
{
*pixel = index;
if (index < pdev->dib.color_table_size)
color = RGB( pdev->dib.color_table[index].rgbRed,
pdev->dib.color_table[index].rgbGreen,
pdev->dib.color_table[index].rgbBlue );
if (index < dib->color_table_size)
color = RGB( dib->color_table[index].rgbRed,
dib->color_table[index].rgbGreen,
dib->color_table[index].rgbBlue );
}
break;
@ -187,7 +186,7 @@ DWORD get_pixel_color( dibdrv_physdev *pdev, COLORREF color, BOOL mono_fixup )
DWORD pixel;
COLORREF rgb_ref;
rgb_ref = make_rgb_colorref( pdev, color, &got_pixel, &pixel );
rgb_ref = make_rgb_colorref( pdev->dev.hdc, &pdev->dib, color, &got_pixel, &pixel );
if (got_pixel) return pixel;
if (pdev->dib.bit_count != 1 || !mono_fixup)

View file

@ -23,6 +23,7 @@
#include "config.h"
#include "wine/port.h"
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@ -1668,6 +1669,44 @@ static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags,
return ERROR_SUCCESS;
}
/* helper for nulldrv_ExtTextOut */
static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
LPCWSTR str, UINT count, const INT *dx )
{
int i;
RECT rect;
rect.left = rect.top = INT_MAX;
rect.right = rect.bottom = INT_MIN;
for (i = 0; i < count; i++)
{
GLYPHMETRICS metrics;
if (get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, NULL )) continue;
rect.left = min( rect.left, x + metrics.gmptGlyphOrigin.x );
rect.top = min( rect.top, y - metrics.gmptGlyphOrigin.y );
rect.right = max( rect.right, x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX );
rect.bottom = max( rect.bottom, y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY );
if (dx)
{
if (flags & ETO_PDY)
{
x += dx[ i * 2 ];
y += dx[ i * 2 + 1];
}
else x += dx[ i ];
}
else
{
x += metrics.gmCellIncX;
y += metrics.gmCellIncY;
}
}
return rect;
}
/* helper for nulldrv_ExtTextOut */
static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
const struct gdi_image_bits *image, const RECT *clip )
@ -1718,7 +1757,8 @@ static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS
BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
LPCWSTR str, UINT count, const INT *dx )
{
UINT i;
DC *dc = get_nulldrv_dc( dev );
UINT aa_flags, i;
DWORD err;
HGDIOBJ orig;
HPEN pen;
@ -1740,6 +1780,85 @@ BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect
if (!count) return TRUE;
aa_flags = get_font_aa_flags( dev->hdc );
if (aa_flags != GGO_BITMAP)
{
char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *info = (BITMAPINFO *)buffer;
struct gdi_image_bits bits;
struct bitblt_coords src, dst;
PHYSDEV dst_dev;
RECT clip;
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 );
if (get_clip_box( dc, &clip )) intersect_rect( &src.visrect, &src.visrect, &clip );
if (is_rect_empty( &src.visrect )) return TRUE;
/* FIXME: check for ETO_OPAQUE and avoid GetImage */
src.x = src.visrect.left;
src.y = src.visrect.top;
src.width = src.visrect.right - src.visrect.left;
src.height = src.visrect.bottom - src.visrect.top;
dst = src;
if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
(src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
{
/* we can avoid the GetImage, just query the needed format */
memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
info->bmiHeader.biSize = sizeof(info->bmiHeader);
info->bmiHeader.biWidth = src.width;
info->bmiHeader.biHeight = -src.height;
err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, NULL, NULL, NULL, 0 );
if (!err || err == ERROR_BAD_FORMAT)
{
/* make the source rectangle relative to the source bits */
src.x = src.y = 0;
src.visrect.left = src.visrect.top = 0;
src.visrect.right = src.width;
src.visrect.bottom = src.height;
bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
if (!bits.ptr) return ERROR_OUTOFMEMORY;
bits.is_copy = TRUE;
bits.free = free_heap_bits;
err = ERROR_SUCCESS;
}
}
else
{
PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
err = src_dev->funcs->pGetImage( src_dev, 0, info, &bits, &src );
if (!err && !bits.is_copy)
{
void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
if (!ptr)
{
if (bits.free) bits.free( &bits );
return ERROR_OUTOFMEMORY;
}
memcpy( ptr, bits.ptr, get_dib_image_size( info ));
if (bits.free) bits.free( &bits );
bits.ptr = ptr;
bits.is_copy = TRUE;
bits.free = free_heap_bits;
}
}
if (!err)
{
/* make x,y relative to the image bits */
x += src.visrect.left - dst.visrect.left;
y += src.visrect.top - dst.visrect.top;
render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
aa_flags, str, count, dx );
err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, &bits, &src, &dst, SRCCOPY );
if (bits.free) bits.free( &bits );
return !err;
}
}
pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
orig = SelectObject( dev->hdc, pen );

View file

@ -266,6 +266,9 @@ extern DWORD stretch_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, str
extern DWORD blend_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bitblt_coords *src,
const BITMAPINFO *dst_info, void *dst_bits, struct bitblt_coords *dst,
BLENDFUNCTION blend ) DECLSPEC_HIDDEN;
extern BOOL render_aa_text_bitmapinfo( HDC hdc, BITMAPINFO *info, struct gdi_image_bits *bits,
struct bitblt_coords *src, INT x, INT y, UINT flags,
UINT aa_flags, LPCWSTR str, UINT count, const INT *dx ) DECLSPEC_HIDDEN;
/* driver.c */
extern const struct gdi_dc_funcs null_driver DECLSPEC_HIDDEN;