gdi32: Add support for DIB pattern brush fills.

This commit is contained in:
Huw Davies 2011-05-12 12:46:50 +01:00 committed by Alexandre Julliard
parent 3c70a26e4b
commit 5b28336c26
3 changed files with 170 additions and 11 deletions

View file

@ -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;

View file

@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include <stdlib.h>
#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;

View file

@ -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
};