From e19a362407a4f57f6389e8f5a40dd3b7f5a03c86 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 28 Nov 2011 13:21:52 +0100 Subject: [PATCH] gdi32: Implement rectangular gradients in the DIB engine. --- dlls/gdi32/dibdrv/bitblt.c | 77 ++++++++ dlls/gdi32/dibdrv/dc.c | 2 +- dlls/gdi32/dibdrv/dibdrv.h | 3 + dlls/gdi32/dibdrv/primitives.c | 326 +++++++++++++++++++++++++++++++++ 4 files changed, 407 insertions(+), 1 deletion(-) diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c index de60f474b1a..3a517aae9e7 100644 --- a/dlls/gdi32/dibdrv/bitblt.c +++ b/dlls/gdi32/dibdrv/bitblt.c @@ -601,6 +601,30 @@ static DWORD blend_rect( dib_info *dst, const RECT *dst_rect, const dib_info *sr return ERROR_SUCCESS; } +static void gradient_rect( dib_info *dib, TRIVERTEX *v, int mode, HRGN clip ) +{ + int i; + RECT rect, clipped_rect; + + rect.left = max( v[0].x, 0 ); + rect.top = max( v[0].y, 0 ); + rect.right = min( v[1].x, dib->width ); + rect.bottom = min( v[1].y, dib->height ); + + if (clip) + { + const WINEREGION *clip_data = get_wine_region( clip ); + + for (i = 0; i < clip_data->numRects; i++) + { + if (intersect_rect( &clipped_rect, &rect, clip_data->rects + i )) + dib->funcs->gradient_rect( dib, &clipped_rect, v, mode ); + } + release_wine_region( clip ); + } + else dib->funcs->gradient_rect( dib, &rect, v, mode ); +} + static DWORD copy_src_bits( dib_info *src, RECT *src_rect ) { int y, stride = get_dib_stride( src->width, src->bit_count ); @@ -1251,3 +1275,56 @@ BOOL dibdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst, release_dc_ptr( dc_dst ); return ret; } + +/*********************************************************************** + * dibdrv_GradientFill + */ +BOOL dibdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, + void *grad_array, ULONG ngrad, ULONG mode ) +{ + dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + unsigned int i; + + if (mode == GRADIENT_FILL_RECT_H || mode == GRADIENT_FILL_RECT_V) + { + const GRADIENT_RECT *rect = grad_array; + TRIVERTEX v[2]; + POINT pt[2]; + + for (i = 0; i < ngrad; i++, rect++) + { + v[0] = vert_array[rect->UpperLeft]; + v[1] = vert_array[rect->LowerRight]; + pt[0].x = v[0].x; + pt[0].y = v[0].y; + pt[1].x = v[1].x; + pt[1].y = v[1].y; + LPtoDP( dev->hdc, pt, 2 ); + if (mode == GRADIENT_FILL_RECT_H) + { + if (pt[1].x < pt[0].x) /* swap the colors */ + { + v[0] = vert_array[rect->LowerRight]; + v[1] = vert_array[rect->UpperLeft]; + } + } + else + { + if (pt[1].y < pt[0].y) /* swap the colors */ + { + v[0] = vert_array[rect->LowerRight]; + v[1] = vert_array[rect->UpperLeft]; + } + } + v[0].x = min( pt[0].x, pt[1].x ); + v[0].y = min( pt[0].y, pt[1].y ); + v[1].x = max( pt[0].x, pt[1].x ); + v[1].y = max( pt[0].y, pt[1].y ); + gradient_rect( &pdev->dib, v, mode, pdev->clip ); + } + return TRUE; + } + + dev = GET_NEXT_PHYSDEV( dev, pGradientFill ); + return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode ); +} diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index 0a75bd2fc55..1fcf9c18c95 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -597,7 +597,7 @@ const struct gdi_dc_funcs dib_driver = NULL, /* pGetTextExtentExPointI */ NULL, /* pGetTextFace */ NULL, /* pGetTextMetrics */ - NULL, /* pGradientFill */ + dibdrv_GradientFill, /* pGradientFill */ NULL, /* pIntersectClipRect */ NULL, /* pInvertRgn */ dibdrv_LineTo, /* pLineTo */ diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 4068b54e178..73ce32bbd6c 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -118,6 +118,8 @@ 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 BOOL dibdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, + void *grad_array, ULONG ngrad, ULONG mode ) DECLSPEC_HIDDEN; extern BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect, LPCWSTR str, UINT count, const INT *dx ) DECLSPEC_HIDDEN; extern DWORD dibdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, @@ -173,6 +175,7 @@ typedef struct primitive_funcs 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); + void (* 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); DWORD (* get_pixel)(const dib_info *dib, const POINT *pt); diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index fa902b9eca1..e882b8ac1d8 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -3977,6 +3977,323 @@ static void blend_rect_null(const dib_info *dst, const RECT *rc, { } +static inline DWORD gradient_rgb_8888( const TRIVERTEX *v, unsigned int pos, unsigned int len ) +{ + BYTE r, g, b, a; + r = (v[0].Red * (len - pos) + v[1].Red * pos) / len / 256; + g = (v[0].Green * (len - pos) + v[1].Green * pos) / len / 256; + b = (v[0].Blue * (len - pos) + v[1].Blue * pos) / len / 256; + a = (v[0].Alpha * (len - pos) + v[1].Alpha * pos) / len / 256; + return a << 24 | r << 16 | g << 8 | b; +} + +static inline DWORD gradient_rgb_24( const TRIVERTEX *v, unsigned int pos, unsigned int len ) +{ + BYTE r, g, b; + r = (v[0].Red * (len - pos) + v[1].Red * pos) / len / 256; + g = (v[0].Green * (len - pos) + v[1].Green * pos) / len / 256; + b = (v[0].Blue * (len - pos) + v[1].Blue * pos) / len / 256; + return r << 16 | g << 8 | b; +} + +static void gradient_rect_8888( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + DWORD *ptr = get_pixel_ptr_32( dib, rc->left, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = 0; x < rc->right - rc->left; x++) + ptr[x] = gradient_rgb_8888( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride / 4) + memcpy( ptr + dib->stride / 4, ptr, (rc->right - rc->left) * 4 ); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_8888( v, y - v[0].y, v[1].y - v[0].y ); + for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val; + ptr += dib->stride / 4; + } + break; + } +} + +static void gradient_rect_32( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + DWORD *ptr = get_pixel_ptr_32( dib, rc->left, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + if (dib->red_len == 8 && dib->green_len == 8 && dib->blue_len == 8) + { + for (x = 0; x < rc->right - rc->left; x++) + { + DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + ptr[x] = ((( val & 0xff) << dib->blue_shift) | + (((val >> 8) & 0xff) << dib->green_shift) | + (((val >> 16) & 0xff) << dib->red_shift)); + } + } + else + { + for (x = 0; x < rc->right - rc->left; x++) + { + DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + 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 )); + } + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride / 4) + memcpy( ptr + dib->stride / 4, ptr, (rc->right - rc->left) * 4 ); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + if (dib->red_len == 8 && dib->green_len == 8 && dib->blue_len == 8) + val = ((( val & 0xff) << dib->blue_shift) | + (((val >> 8) & 0xff) << dib->green_shift) | + (((val >> 16) & 0xff) << dib->red_shift)); + else + val = (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 )); + + for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val; + ptr += dib->stride / 4; + } + break; + } +} + +static void gradient_rect_24( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + BYTE *ptr = get_pixel_ptr_24( dib, rc->left, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = 0; x < rc->right - rc->left; x++) + { + DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + ptr[x * 3] = val; + ptr[x * 3 + 1] = val >> 8; + ptr[x * 3 + 2] = val >> 16; + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride) + memcpy( ptr + dib->stride, ptr, (rc->right - rc->left) * 3 ); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + for (x = 0; x < rc->right - rc->left; x++) + { + ptr[x * 3] = val; + ptr[x * 3 + 1] = val >> 8; + ptr[x * 3 + 2] = val >> 16; + } + ptr += dib->stride; + } + break; + } +} + +static void gradient_rect_555( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + WORD *ptr = get_pixel_ptr_16( dib, rc->left, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = 0; x < rc->right - rc->left; x++) + { + DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + ptr[x] = ((val >> 9) & 0x7c00) | ((val >> 6) & 0x03e0) | ((val >> 3) & 0x001f); + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride / 2) + memcpy( ptr + dib->stride / 2, ptr, (rc->right - rc->left) * 2 ); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + val = ((val >> 9) & 0x7c00) | ((val >> 6) & 0x03e0) | ((val >> 3) & 0x001f); + for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val; + ptr += dib->stride / 2; + } + break; + } +} + +static void gradient_rect_16( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + WORD *ptr = get_pixel_ptr_16( dib, rc->left, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = 0; x < rc->right - rc->left; x++) + { + DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + 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)); + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride / 2) + memcpy( ptr + dib->stride / 2, ptr, (rc->right - rc->left) * 2 ); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + val = (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)); + for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val; + ptr += dib->stride / 2; + } + break; + } +} + +static void gradient_rect_8( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + BYTE *ptr = get_pixel_ptr_8( dib, rc->left, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = 0; x < rc->right - rc->left; x++) + { + DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x ); + ptr[x] = rgb_lookup_colortable( dib, val >> 16, val >> 8, val ); + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride) + memcpy( ptr + dib->stride, ptr, rc->right - rc->left ); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + val = rgb_lookup_colortable( dib, val >> 16, val >> 8, val ); + for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val; + ptr += dib->stride; + } + break; + } +} + +static void gradient_rect_4( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + BYTE *ptr = get_pixel_ptr_4( dib, 0, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = rc->left; x < rc->right; x++) + { + DWORD val = gradient_rgb_24( v, x - v[0].x, v[1].x - v[0].x ); + val = rgb_lookup_colortable( dib, val >> 16, val >> 8, val ); + if (x & 1) + ptr[x / 2] = val | (ptr[x / 2] & 0xf0); + else + ptr[x / 2] = (val << 4) | (ptr[x / 2] & 0x0f); + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride) + { + x = rc->left; + if (x & 1) + { + ptr[dib->stride + x / 2] = (ptr[x / 2] & 0x0f) | (ptr[dib->stride + x / 2] & 0xf0); + x++; + } + for (; x < rc->right - 1; x += 2) ptr[dib->stride + x / 2] = ptr[x / 2]; + if (x < rc->right) + ptr[dib->stride + x / 2] = (ptr[dib->stride + x / 2] & 0x0f) | (ptr[x / 2] & 0xf0); + } + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + val = rgb_lookup_colortable( dib, val >> 16, val >> 8, val ); + x = rc->left; + if (x & 1) + { + ptr[x / 2] = val | (ptr[x / 2] & 0xf0); + x++; + } + for (; x < rc->right - 1; x += 2) ptr[x / 2] = (val << 4) | val; + if (x < rc->right) ptr[x / 2] = (ptr[x / 2] & 0x0f) | (val << 4); + ptr += dib->stride; + } + break; + } +} + +static void gradient_rect_1( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ + BYTE *ptr = get_pixel_ptr_1( dib, 0, rc->top ); + int x, y; + + switch (mode) + { + case GRADIENT_FILL_RECT_H: + for (x = rc->left; x < rc->right; x++) + { + DWORD val = gradient_rgb_24( v, x - v[0].x, v[1].x - v[0].x ); + val = rgb_to_pixel_colortable( dib, val >> 16, val >> 8, val ) ? 0xff : 0; + ptr[x / 8] = (ptr[x / 8] & ~pixel_masks_1[x % 8]) | (val & pixel_masks_1[x % 8]); + } + + for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride) + for (x = rc->left; x < rc->right; x++) + ptr[dib->stride + x / 8] = (ptr[dib->stride + x / 8] & ~pixel_masks_1[x % 8]) | + (ptr[x / 8] & pixel_masks_1[x % 8]); + break; + + case GRADIENT_FILL_RECT_V: + for (y = rc->top; y < rc->bottom; y++) + { + DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y ); + val = rgb_to_pixel_colortable( dib, val >> 16, val >> 8, val ) ? 0xff : 0; + for (x = rc->left; x < rc->right; x++) + ptr[x / 8] = (ptr[x / 8] & ~pixel_masks_1[x % 8]) | (val & pixel_masks_1[x % 8]); + ptr += dib->stride; + } + break; + } +} + +static void gradient_rect_null( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode ) +{ +} + static inline BYTE aa_color( BYTE dst, BYTE text, BYTE min_comp, BYTE max_comp ) { if (dst == text) return dst; @@ -4854,6 +5171,7 @@ const primitive_funcs funcs_8888 = pattern_rects_32, copy_rect_32, blend_rect_8888, + gradient_rect_8888, draw_glyph_8888, get_pixel_32, colorref_to_pixel_888, @@ -4871,6 +5189,7 @@ const primitive_funcs funcs_32 = pattern_rects_32, copy_rect_32, blend_rect_32, + gradient_rect_32, draw_glyph_32, get_pixel_32, colorref_to_pixel_masks, @@ -4888,6 +5207,7 @@ const primitive_funcs funcs_24 = pattern_rects_24, copy_rect_24, blend_rect_24, + gradient_rect_24, draw_glyph_24, get_pixel_24, colorref_to_pixel_888, @@ -4905,6 +5225,7 @@ const primitive_funcs funcs_555 = pattern_rects_16, copy_rect_16, blend_rect_555, + gradient_rect_555, draw_glyph_555, get_pixel_16, colorref_to_pixel_555, @@ -4922,6 +5243,7 @@ const primitive_funcs funcs_16 = pattern_rects_16, copy_rect_16, blend_rect_16, + gradient_rect_16, draw_glyph_16, get_pixel_16, colorref_to_pixel_masks, @@ -4939,6 +5261,7 @@ const primitive_funcs funcs_8 = pattern_rects_8, copy_rect_8, blend_rect_8, + gradient_rect_8, draw_glyph_8, get_pixel_8, colorref_to_pixel_colortable, @@ -4956,6 +5279,7 @@ const primitive_funcs funcs_4 = pattern_rects_4, copy_rect_4, blend_rect_4, + gradient_rect_4, draw_glyph_4, get_pixel_4, colorref_to_pixel_colortable, @@ -4973,6 +5297,7 @@ const primitive_funcs funcs_1 = pattern_rects_1, copy_rect_1, blend_rect_1, + gradient_rect_1, draw_glyph_1, get_pixel_1, colorref_to_pixel_colortable, @@ -4990,6 +5315,7 @@ const primitive_funcs funcs_null = pattern_rects_null, copy_rect_null, blend_rect_null, + gradient_rect_null, draw_glyph_null, get_pixel_null, colorref_to_pixel_null,