From 5b28336c26e02692e6553bb62ba405553da39a31 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 12 May 2011 12:46:50 +0100 Subject: [PATCH] gdi32: Add support for DIB pattern brush fills. --- dlls/gdi32/dibdrv/dibdrv.h | 1 + dlls/gdi32/dibdrv/objects.c | 101 +++++++++++++++++++++++++++++---- dlls/gdi32/dibdrv/primitives.c | 79 ++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 11 deletions(-) diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 19828663aea..a502c726117 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -38,6 +38,7 @@ static inline DC *get_dibdrv_dc( PHYSDEV dev ) typedef struct primitive_funcs { void (* solid_rects)(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor); + void (* pattern_rects)(const dib_info *dib, int num, const RECT *rc, const POINT *orign, const dib_info *brush, void *and_bits, void *xor_bits); DWORD (* colorref_to_pixel)(const dib_info *dib, COLORREF color); } primitive_funcs; diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c index dde7a96495b..795bd5e732a 100644 --- a/dlls/gdi32/dibdrv/objects.c +++ b/dlls/gdi32/dibdrv/objects.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include "gdi_private.h" @@ -956,17 +957,6 @@ static BOOL solid_brush(dibdrv_physdev *pdev, int num, RECT *rects) return TRUE; } -/********************************************************************** - * pattern_brush - * - * Fill a number of rectangles with the pattern brush - * FIXME: Should we insist l < r && t < b? Currently we assume this. - */ -static BOOL pattern_brush(dibdrv_physdev *pdev, int num, RECT *rects) -{ - return FALSE; -} - static void free_pattern_brush_bits( dibdrv_physdev *pdev ) { HeapFree(GetProcessHeap(), 0, pdev->brush_and_bits); @@ -981,6 +971,95 @@ void free_pattern_brush( dibdrv_physdev *pdev ) free_dib_info( &pdev->brush_dib, TRUE ); } +static BOOL create_pattern_brush_bits(dibdrv_physdev *pdev) +{ + DWORD size = pdev->brush_dib.height * abs(pdev->brush_dib.stride); + DWORD *brush_bits = pdev->brush_dib.bits; + DWORD *and_bits, *xor_bits; + + assert(pdev->brush_and_bits == NULL); + assert(pdev->brush_xor_bits == NULL); + + and_bits = pdev->brush_and_bits = HeapAlloc(GetProcessHeap(), 0, size); + xor_bits = pdev->brush_xor_bits = HeapAlloc(GetProcessHeap(), 0, size); + + if(!and_bits || !xor_bits) + { + ERR("Failed to create pattern brush bits\n"); + free_pattern_brush_bits( pdev ); + return FALSE; + } + + if(pdev->brush_dib.stride < 0) + brush_bits = (DWORD*)((BYTE*)brush_bits + (pdev->brush_dib.height - 1) * pdev->brush_dib.stride); + + while(size) + { + calc_and_xor_masks(pdev->brush_rop, *brush_bits++, and_bits++, xor_bits++); + size -= 4; + } + + if(pdev->brush_dib.stride < 0) + { + /* Update the bits ptrs if the dib is bottom up. The subtraction is because stride is -ve */ + pdev->brush_and_bits = (BYTE*)pdev->brush_and_bits - (pdev->brush_dib.height - 1) * pdev->brush_dib.stride; + pdev->brush_xor_bits = (BYTE*)pdev->brush_xor_bits - (pdev->brush_dib.height - 1) * pdev->brush_dib.stride; + } + + return TRUE; +} + +/********************************************************************** + * pattern_brush + * + * Fill a number of rectangles with the pattern brush + * FIXME: Should we insist l < r && t < b? Currently we assume this. + */ +static BOOL pattern_brush(dibdrv_physdev *pdev, int num, RECT *rects) +{ + int i, j; + const WINEREGION *clip; + POINT origin; + + if(pdev->brush_and_bits == NULL) + if(!create_pattern_brush_bits(pdev)) + return FALSE; + + GetBrushOrgEx(pdev->dev.hdc, &origin); + + clip = get_wine_region(pdev->clip); + for(i = 0; i < num; i++) + { + for(j = 0; j < clip->numRects; j++) + { + RECT rect = rects[i]; + + /* Optimize unclipped case */ + if(clip->rects[j].top <= rect.top && clip->rects[j].bottom >= rect.bottom && + clip->rects[j].left <= rect.left && clip->rects[j].right >= rect.right) + { + pdev->dib.funcs->pattern_rects(&pdev->dib, 1, &rect, &origin, &pdev->brush_dib, pdev->brush_and_bits, pdev->brush_xor_bits); + break; + } + + if(clip->rects[j].top >= rect.bottom) break; + if(clip->rects[j].bottom <= rect.top) continue; + + if(clip->rects[j].right > rect.left && clip->rects[j].left < rect.right) + { + rect.left = max(rect.left, clip->rects[j].left); + rect.top = max(rect.top, clip->rects[j].top); + rect.right = min(rect.right, clip->rects[j].right); + rect.bottom = min(rect.bottom, clip->rects[j].bottom); + + pdev->dib.funcs->pattern_rects(&pdev->dib, 1, &rect, &origin, &pdev->brush_dib, pdev->brush_and_bits, pdev->brush_xor_bits); + } + } + } + release_wine_region(pdev->clip); + return TRUE; +} + void update_brush_rop( dibdrv_physdev *pdev, INT rop ) { pdev->brush_rop = rop; diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index a35877ec295..6dec47883c5 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -50,6 +50,82 @@ static void solid_rects_null(const dib_info *dib, int num, const RECT *rc, DWORD return; } +static inline INT calc_offset(INT edge, INT size, INT origin) +{ + INT offset; + + if(edge - origin >= 0) + offset = (edge - origin) % size; + else + { + offset = (origin - edge) % size; + if(offset) offset = size - offset; + } + return offset; +} + +static inline POINT calc_brush_offset(const RECT *rc, const dib_info *brush, const POINT *origin) +{ + POINT offset; + + offset.x = calc_offset(rc->left, brush->width, origin->x); + offset.y = calc_offset(rc->top, brush->height, origin->y); + + return offset; +} + +static void pattern_rects_32(const dib_info *dib, int num, const RECT *rc, const POINT *origin, + const dib_info *brush, void *and_bits, void *xor_bits) +{ + DWORD *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr; + int x, y, i; + POINT offset; + + for(i = 0; i < num; i++, rc++) + { + offset = calc_brush_offset(rc, brush, origin); + + start = get_pixel_ptr_32(dib, rc->left, rc->top); + start_and = (DWORD*)and_bits + offset.y * brush->stride / 4; + start_xor = (DWORD*)xor_bits + offset.y * brush->stride / 4; + + for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4) + { + and_ptr = start_and + offset.x; + xor_ptr = start_xor + offset.x; + + for(x = rc->left, ptr = start; x < rc->right; x++) + { + do_rop_32(ptr++, *and_ptr++, *xor_ptr++); + if(and_ptr == start_and + brush->width) + { + and_ptr = start_and; + xor_ptr = start_xor; + } + } + + offset.y++; + if(offset.y == brush->height) + { + start_and = and_bits; + start_xor = xor_bits; + offset.y = 0; + } + else + { + start_and += brush->stride / 4; + start_xor += brush->stride / 4; + } + } + } +} + +static void pattern_rects_null(const dib_info *dib, int num, const RECT *rc, const POINT *origin, + const dib_info *brush, void *and_bits, void *xor_bits) +{ + return; +} + static DWORD colorref_to_pixel_888(const dib_info *dib, COLORREF color) { return ( ((color >> 16) & 0xff) | (color & 0xff00) | ((color << 16) & 0xff0000) ); @@ -88,17 +164,20 @@ static DWORD colorref_to_pixel_null(const dib_info *dib, COLORREF color) const primitive_funcs funcs_8888 = { solid_rects_32, + pattern_rects_32, colorref_to_pixel_888 }; const primitive_funcs funcs_32 = { solid_rects_32, + pattern_rects_32, colorref_to_pixel_masks }; const primitive_funcs funcs_null = { solid_rects_null, + pattern_rects_null, colorref_to_pixel_null };