gdi32: Implement a BlendImage entry point in the DIB driver.
This commit is contained in:
parent
7a4349bb99
commit
a3a574fae0
dlls/gdi32/dibdrv
|
@ -572,6 +572,35 @@ static DWORD copy_rect( dib_info *dst, const RECT *dst_rect, const dib_info *src
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static DWORD blend_rect( dib_info *dst, const RECT *dst_rect, const dib_info *src, const RECT *src_rect,
|
||||
HRGN clip, BLENDFUNCTION blend )
|
||||
{
|
||||
POINT origin;
|
||||
RECT clipped_rect;
|
||||
const WINEREGION *clip_data;
|
||||
int i;
|
||||
|
||||
origin.x = src_rect->left;
|
||||
origin.y = src_rect->top;
|
||||
|
||||
if (clip == NULL) dst->funcs->blend_rect( dst, dst_rect, src, &origin, blend );
|
||||
else
|
||||
{
|
||||
clip_data = get_wine_region( clip );
|
||||
for (i = 0; i < clip_data->numRects; i++)
|
||||
{
|
||||
if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
|
||||
{
|
||||
origin.x = src_rect->left + clipped_rect.left - dst_rect->left;
|
||||
origin.y = src_rect->top + clipped_rect.top - dst_rect->top;
|
||||
dst->funcs->blend_rect( dst, &clipped_rect, src, &origin, blend );
|
||||
}
|
||||
}
|
||||
release_wine_region( clip );
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static DWORD copy_src_bits( dib_info *src, RECT *src_rect )
|
||||
{
|
||||
int y, stride = get_dib_stride( src->width, src->bit_count );
|
||||
|
@ -906,6 +935,49 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* dibdrv_BlendImage
|
||||
*/
|
||||
DWORD dibdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
|
||||
struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
|
||||
{
|
||||
dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
|
||||
dib_info src_dib;
|
||||
DWORD ret;
|
||||
|
||||
TRACE( "%p %p\n", dev, info );
|
||||
|
||||
if (info->bmiHeader.biPlanes != 1) goto update_format;
|
||||
if (info->bmiHeader.biBitCount != 32) goto update_format;
|
||||
if (info->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
DWORD *masks = (DWORD *)info->bmiColors;
|
||||
if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
|
||||
goto update_format;
|
||||
}
|
||||
|
||||
if (!bits) return ERROR_SUCCESS;
|
||||
if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
|
||||
|
||||
init_dib_info_from_bitmapinfo( &src_dib, info, bits->ptr, 0 );
|
||||
src_dib.bits.is_copy = bits->is_copy;
|
||||
|
||||
ret = blend_rect( &pdev->dib, &dst->visrect, &src_dib, &src->visrect, pdev->clip, blend );
|
||||
|
||||
free_dib_info( &src_dib );
|
||||
return ret;
|
||||
|
||||
update_format:
|
||||
if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
info->bmiHeader.biPlanes = 1;
|
||||
info->bmiHeader.biBitCount = 32;
|
||||
info->bmiHeader.biCompression = BI_RGB;
|
||||
info->bmiHeader.biClrUsed = 0;
|
||||
return ERROR_BAD_FORMAT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* calc_1d_stretch_params (helper for stretch_bitmapinfo)
|
||||
*
|
||||
|
|
|
@ -518,7 +518,7 @@ const DC_FUNCTIONS dib_driver =
|
|||
NULL, /* pArc */
|
||||
NULL, /* pArcTo */
|
||||
NULL, /* pBeginPath */
|
||||
NULL, /* pBlendImage */
|
||||
dibdrv_BlendImage, /* pBlendImage */
|
||||
NULL, /* pChoosePixelFormat */
|
||||
NULL, /* pChord */
|
||||
NULL, /* pCloseFigure */
|
||||
|
|
|
@ -102,6 +102,8 @@ typedef struct dibdrv_physdev
|
|||
|
||||
extern BOOL dibdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
|
||||
PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blend ) DECLSPEC_HIDDEN;
|
||||
extern DWORD dibdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
|
||||
struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION func ) DECLSPEC_HIDDEN;
|
||||
extern DWORD dibdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
|
||||
struct gdi_image_bits *bits, struct bitblt_coords *src ) DECLSPEC_HIDDEN;
|
||||
extern BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y ) DECLSPEC_HIDDEN;
|
||||
|
@ -140,6 +142,8 @@ typedef struct primitive_funcs
|
|||
const dib_info *brush, void *and_bits, void *xor_bits);
|
||||
void (* copy_rect)(const dib_info *dst, const RECT *rc, const dib_info *src,
|
||||
const POINT *origin, int rop2, int overlap);
|
||||
void (* blend_rect)(const dib_info *dst, const RECT *rc, const dib_info *src,
|
||||
const POINT *origin, BLENDFUNCTION blend);
|
||||
DWORD (* colorref_to_pixel)(const dib_info *dib, COLORREF color);
|
||||
void (* convert_to)(dib_info *dst, const dib_info *src, const RECT *src_rect);
|
||||
BOOL (* create_rop_masks)(const dib_info *dib, const dib_info *hatch,
|
||||
|
|
|
@ -3451,6 +3451,235 @@ static void convert_to_null(dib_info *dst, const dib_info *src, const RECT *src_
|
|||
{
|
||||
}
|
||||
|
||||
static inline BYTE blend_color(BYTE dst, BYTE src, DWORD alpha)
|
||||
{
|
||||
return (src * alpha + dst * (255 - alpha) + 127) / 255;
|
||||
}
|
||||
|
||||
static inline DWORD blend_argb( DWORD dst, DWORD src, DWORD alpha )
|
||||
{
|
||||
return (blend_color( dst, src, alpha ) |
|
||||
blend_color( dst >> 8, src >> 8, alpha ) << 8 |
|
||||
blend_color( dst >> 16, src >> 16, alpha ) << 16 |
|
||||
blend_color( dst >> 24, src >> 24, alpha ) << 24);
|
||||
}
|
||||
|
||||
static inline DWORD blend_argb_alpha( DWORD dst, DWORD src, DWORD alpha )
|
||||
{
|
||||
BYTE b = ((BYTE)src * alpha + 127) / 255;
|
||||
BYTE g = ((BYTE)(src >> 8) * alpha + 127) / 255;
|
||||
BYTE r = ((BYTE)(src >> 16) * alpha + 127) / 255;
|
||||
alpha = ((BYTE)(src >> 24) * alpha + 127) / 255;
|
||||
return ((b + ((BYTE)dst * (255 - alpha) + 127) / 255) |
|
||||
(g + ((BYTE)(dst >> 8) * (255 - alpha) + 127) / 255) << 8 |
|
||||
(r + ((BYTE)(dst >> 16) * (255 - alpha) + 127) / 255) << 16 |
|
||||
(alpha + ((BYTE)(dst >> 24) * (255 - alpha) + 127) / 255) << 24);
|
||||
}
|
||||
|
||||
static inline DWORD blend_rgb( BYTE dst_r, BYTE dst_g, BYTE dst_b, DWORD src, BLENDFUNCTION blend )
|
||||
{
|
||||
if (blend.AlphaFormat & AC_SRC_ALPHA)
|
||||
{
|
||||
DWORD alpha = blend.SourceConstantAlpha;
|
||||
BYTE src_b = ((BYTE)src * alpha + 127) / 255;
|
||||
BYTE src_g = ((BYTE)(src >> 8) * alpha + 127) / 255;
|
||||
BYTE src_r = ((BYTE)(src >> 16) * alpha + 127) / 255;
|
||||
alpha = ((BYTE)(src >> 24) * alpha + 127) / 255;
|
||||
return ((src_b + (dst_b * (255 - alpha) + 127) / 255) |
|
||||
(src_g + (dst_g * (255 - alpha) + 127) / 255) << 8 |
|
||||
(src_r + (dst_r * (255 - alpha) + 127) / 255) << 16);
|
||||
}
|
||||
return (blend_color( dst_b, src, blend.SourceConstantAlpha ) |
|
||||
blend_color( dst_g, src >> 8, blend.SourceConstantAlpha ) << 8 |
|
||||
blend_color( dst_r, src >> 16, blend.SourceConstantAlpha ) << 16);
|
||||
}
|
||||
|
||||
static void blend_rect_8888(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x, origin->y );
|
||||
DWORD *dst_ptr = get_pixel_ptr_32( dst, rc->left, rc->top );
|
||||
int x, y;
|
||||
|
||||
if (blend.AlphaFormat & AC_SRC_ALPHA)
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride / 4, src_ptr += src->stride / 4)
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
dst_ptr[x] = blend_argb_alpha( dst_ptr[x], src_ptr[x], blend.SourceConstantAlpha );
|
||||
else
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride / 4, src_ptr += src->stride / 4)
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
dst_ptr[x] = blend_argb( dst_ptr[x], src_ptr[x], blend.SourceConstantAlpha );
|
||||
}
|
||||
|
||||
static void blend_rect_32(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x, origin->y );
|
||||
DWORD *dst_ptr = get_pixel_ptr_32( dst, rc->left, rc->top );
|
||||
int x, y;
|
||||
|
||||
if (dst->red_len == 8 && dst->green_len == 8 && dst->blue_len == 8)
|
||||
{
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride / 4, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
{
|
||||
DWORD val = blend_rgb( dst_ptr[x] >> dst->red_shift,
|
||||
dst_ptr[x] >> dst->green_shift,
|
||||
dst_ptr[x] >> dst->blue_shift,
|
||||
src_ptr[x], blend );
|
||||
dst_ptr[x] = ((( val & 0xff) << dst->blue_shift) |
|
||||
(((val >> 8) & 0xff) << dst->green_shift) |
|
||||
(((val >> 16) & 0xff) << dst->red_shift));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride / 4, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
{
|
||||
DWORD val = blend_rgb( get_field( dst_ptr[x], dst->red_shift, dst->red_len ),
|
||||
get_field( dst_ptr[x], dst->green_shift, dst->green_len ),
|
||||
get_field( dst_ptr[x], dst->blue_shift, dst->blue_len ),
|
||||
src_ptr[x], blend );
|
||||
dst_ptr[x] = (put_field( val >> 16, dst->red_shift, dst->red_len ) |
|
||||
put_field( val >> 8, dst->green_shift, dst->green_len ) |
|
||||
put_field( val, dst->blue_shift, dst->blue_len ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_24(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x, origin->y );
|
||||
BYTE *dst_ptr = get_pixel_ptr_24( dst, rc->left, rc->top );
|
||||
int x, y;
|
||||
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
{
|
||||
DWORD val = blend_rgb( dst_ptr[x * 3 + 2], dst_ptr[x * 3 + 1], dst_ptr[x * 3],
|
||||
src_ptr[x], blend );
|
||||
dst_ptr[x * 3] = val;
|
||||
dst_ptr[x * 3 + 1] = val >> 8;
|
||||
dst_ptr[x * 3 + 2] = val >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_555(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x, origin->y );
|
||||
WORD *dst_ptr = get_pixel_ptr_16( dst, rc->left, rc->top );
|
||||
int x, y;
|
||||
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride / 2, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
{
|
||||
DWORD val = blend_rgb( ((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),
|
||||
src_ptr[x], blend );
|
||||
dst_ptr[x] = ((val >> 9) & 0x7c00) | ((val >> 6) & 0x03e0) | ((val >> 3) & 0x001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_16(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x, origin->y );
|
||||
WORD *dst_ptr = get_pixel_ptr_16( dst, rc->left, rc->top );
|
||||
int x, y;
|
||||
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride / 2, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
{
|
||||
DWORD val = blend_rgb( get_field( dst_ptr[x], dst->red_shift, dst->red_len ),
|
||||
get_field( dst_ptr[x], dst->green_shift, dst->green_len ),
|
||||
get_field( dst_ptr[x], dst->blue_shift, dst->blue_len ),
|
||||
src_ptr[x], blend );
|
||||
dst_ptr[x] = (put_field((val >> 16), dst->red_shift, dst->red_len) |
|
||||
put_field((val >> 8), dst->green_shift, dst->green_len) |
|
||||
put_field( val, dst->blue_shift, dst->blue_len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_8(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x, origin->y );
|
||||
BYTE *dst_ptr = get_pixel_ptr_8( dst, rc->left, rc->top );
|
||||
int x, y;
|
||||
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
{
|
||||
RGBQUAD rgb = colortable_entry( dst, dst_ptr[x] );
|
||||
DWORD val = blend_rgb( rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, src_ptr[x], blend );
|
||||
dst_ptr[x] = rgb_lookup_colortable( dst, val >> 16, val >> 8, val );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_4(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x - rc->left, origin->y );
|
||||
BYTE *dst_ptr = get_pixel_ptr_4( dst, 0, rc->top );
|
||||
int x, y;
|
||||
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
{
|
||||
DWORD val = ((x & 1) ? dst_ptr[x / 2] : (dst_ptr[x / 2] >> 4)) & 0x0f;
|
||||
RGBQUAD rgb = colortable_entry( dst, val );
|
||||
val = blend_rgb( rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, src_ptr[x], blend );
|
||||
val = rgb_lookup_colortable( dst, val >> 16, val >> 8, val );
|
||||
if (x & 1)
|
||||
dst_ptr[x / 2] = val | (dst_ptr[x / 2] & 0xf0);
|
||||
else
|
||||
dst_ptr[x / 2] = (val << 4) | (dst_ptr[x / 2] & 0x0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_1(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
DWORD *src_ptr = get_pixel_ptr_32( src, origin->x - rc->left, origin->y );
|
||||
BYTE *dst_ptr = get_pixel_ptr_1( dst, 0, rc->top );
|
||||
int x, y;
|
||||
|
||||
for (y = rc->top; y < rc->bottom; y++, dst_ptr += dst->stride, src_ptr += src->stride / 4)
|
||||
{
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
{
|
||||
DWORD val = (dst_ptr[x / 8] & pixel_masks_1[x % 8]) ? 1 : 0;
|
||||
RGBQUAD rgb = dst->color_table[val];
|
||||
val = blend_rgb( rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, src_ptr[x], blend );
|
||||
val = rgb_to_pixel_colortable(dst, val >> 16, val >> 8, val) ? 0xff : 0;
|
||||
dst_ptr[x / 8] = (dst_ptr[x / 8] & ~pixel_masks_1[x % 8]) | (val & pixel_masks_1[x % 8]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_rect_null(const dib_info *dst, const RECT *rc,
|
||||
const dib_info *src, const POINT *origin, BLENDFUNCTION blend)
|
||||
{
|
||||
}
|
||||
|
||||
static BOOL create_rop_masks_32(const dib_info *dib, const dib_info *hatch, const rop_mask *fg, const rop_mask *bg, rop_mask_bits *bits)
|
||||
{
|
||||
BYTE *hatch_start = get_pixel_ptr_1(hatch, 0, 0), *hatch_ptr;
|
||||
|
@ -4089,6 +4318,7 @@ const primitive_funcs funcs_8888 =
|
|||
solid_rects_32,
|
||||
pattern_rects_32,
|
||||
copy_rect_32,
|
||||
blend_rect_8888,
|
||||
colorref_to_pixel_888,
|
||||
convert_to_8888,
|
||||
create_rop_masks_32,
|
||||
|
@ -4101,6 +4331,7 @@ const primitive_funcs funcs_32 =
|
|||
solid_rects_32,
|
||||
pattern_rects_32,
|
||||
copy_rect_32,
|
||||
blend_rect_32,
|
||||
colorref_to_pixel_masks,
|
||||
convert_to_32,
|
||||
create_rop_masks_32,
|
||||
|
@ -4113,6 +4344,7 @@ const primitive_funcs funcs_24 =
|
|||
solid_rects_24,
|
||||
pattern_rects_24,
|
||||
copy_rect_24,
|
||||
blend_rect_24,
|
||||
colorref_to_pixel_888,
|
||||
convert_to_24,
|
||||
create_rop_masks_24,
|
||||
|
@ -4125,6 +4357,7 @@ const primitive_funcs funcs_555 =
|
|||
solid_rects_16,
|
||||
pattern_rects_16,
|
||||
copy_rect_16,
|
||||
blend_rect_555,
|
||||
colorref_to_pixel_555,
|
||||
convert_to_555,
|
||||
create_rop_masks_16,
|
||||
|
@ -4137,6 +4370,7 @@ const primitive_funcs funcs_16 =
|
|||
solid_rects_16,
|
||||
pattern_rects_16,
|
||||
copy_rect_16,
|
||||
blend_rect_16,
|
||||
colorref_to_pixel_masks,
|
||||
convert_to_16,
|
||||
create_rop_masks_16,
|
||||
|
@ -4149,6 +4383,7 @@ const primitive_funcs funcs_8 =
|
|||
solid_rects_8,
|
||||
pattern_rects_8,
|
||||
copy_rect_8,
|
||||
blend_rect_8,
|
||||
colorref_to_pixel_colortable,
|
||||
convert_to_8,
|
||||
create_rop_masks_8,
|
||||
|
@ -4161,6 +4396,7 @@ const primitive_funcs funcs_4 =
|
|||
solid_rects_4,
|
||||
pattern_rects_4,
|
||||
copy_rect_4,
|
||||
blend_rect_4,
|
||||
colorref_to_pixel_colortable,
|
||||
convert_to_4,
|
||||
create_rop_masks_4,
|
||||
|
@ -4173,6 +4409,7 @@ const primitive_funcs funcs_1 =
|
|||
solid_rects_1,
|
||||
pattern_rects_1,
|
||||
copy_rect_1,
|
||||
blend_rect_1,
|
||||
colorref_to_pixel_colortable,
|
||||
convert_to_1,
|
||||
create_rop_masks_1,
|
||||
|
@ -4185,6 +4422,7 @@ const primitive_funcs funcs_null =
|
|||
solid_rects_null,
|
||||
pattern_rects_null,
|
||||
copy_rect_null,
|
||||
blend_rect_null,
|
||||
colorref_to_pixel_null,
|
||||
convert_to_null,
|
||||
create_rop_masks_null,
|
||||
|
|
Loading…
Reference in New Issue