gdi32: Add clipping for horizontal and vertical solid lines.

This commit is contained in:
Huw Davies 2011-04-15 13:14:34 +01:00 committed by Alexandre Julliard
parent f33bbbfdd7
commit 1372692fe7
4 changed files with 155 additions and 32 deletions

View File

@ -100,10 +100,10 @@ static inline void order_end_points(int *s, int *e)
}
}
static inline BOOL pt_in_rect( const RECT *rect, POINT pt )
static inline BOOL pt_in_rect( const RECT *rect, const POINT *pt )
{
return ((pt.x >= rect->left) && (pt.x < rect->right) &&
(pt.y >= rect->top) && (pt.y < rect->bottom));
return ((pt->x >= rect->left) && (pt->x < rect->right) &&
(pt->y >= rect->top) && (pt->y < rect->bottom));
}
static void WINAPI solid_pen_line_callback(INT x, INT y, LPARAM lparam)
@ -121,36 +121,79 @@ static void WINAPI solid_pen_line_callback(INT x, INT y, LPARAM lparam)
static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end)
{
RECT rc;
DC *dc = get_dibdrv_dc( &pdev->dev );
const WINEREGION *clip = get_wine_region(pdev->clip);
BOOL ret = TRUE;
if(get_clip_region(dc) || !pt_in_rect(&dc->vis_rect, *start) || !pt_in_rect(&dc->vis_rect, *end))
return FALSE;
rc.left = start->x;
rc.top = start->y;
rc.right = end->x;
rc.bottom = end->y;
if(rc.top == rc.bottom)
if(start->y == end->y)
{
order_end_points(&rc.left, &rc.right);
rc.bottom++;
pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rc, pdev->pen_and, pdev->pen_xor);
RECT rect;
int i;
rect.left = start->x;
rect.top = start->y;
rect.right = end->x;
rect.bottom = end->y + 1;
order_end_points(&rect.left, &rect.right);
for(i = 0; i < clip->numRects; i++)
{
if(clip->rects[i].top >= rect.bottom) break;
if(clip->rects[i].bottom <= rect.top) continue;
/* Optimize the unclipped case */
if(clip->rects[i].left <= rect.left && clip->rects[i].right >= rect.right)
{
pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, pdev->pen_and, pdev->pen_xor);
break;
}
if(clip->rects[i].right > rect.left && clip->rects[i].left < rect.right)
{
RECT tmp = rect;
tmp.left = max(rect.left, clip->rects[i].left);
tmp.right = min(rect.right, clip->rects[i].right);
pdev->dib.funcs->solid_rects(&pdev->dib, 1, &tmp, pdev->pen_and, pdev->pen_xor);
}
}
}
else if(rc.left == rc.right)
else if(start->x == end->x)
{
order_end_points(&rc.top, &rc.bottom);
rc.right++;
pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rc, pdev->pen_and, pdev->pen_xor);
RECT rect;
int i;
rect.left = start->x;
rect.top = start->y;
rect.right = end->x + 1;
rect.bottom = end->y;
order_end_points(&rect.top, &rect.bottom);
for(i = 0; i < clip->numRects; i++)
{
/* Optimize unclipped case */
if(clip->rects[i].top <= rect.top && clip->rects[i].bottom >= rect.bottom &&
clip->rects[i].left <= rect.left && clip->rects[i].right >= rect.right)
{
pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, pdev->pen_and, pdev->pen_xor);
break;
}
if(clip->rects[i].top >= rect.bottom) break;
if(clip->rects[i].bottom <= rect.top) continue;
if(clip->rects[i].right > rect.left && clip->rects[i].left < rect.right)
{
RECT tmp = rect;
tmp.top = max(rect.top, clip->rects[i].top);
tmp.bottom = min(rect.bottom, clip->rects[i].bottom);
pdev->dib.funcs->solid_rects(&pdev->dib, 1, &tmp, pdev->pen_and, pdev->pen_xor);
}
}
}
else
{
/* FIXME: Optimize by moving Bresenham algorithm to the primitive functions,
or at least cache adjacent points in the callback */
LineDDA(start->x, start->y, end->x, end->y, solid_pen_line_callback, (LPARAM)pdev);
if(clip->numRects == 1 && pt_in_rect(&clip->extents, start) && pt_in_rect(&clip->extents, end))
/* FIXME: Optimize by moving Bresenham algorithm to the primitive functions,
or at least cache adjacent points in the callback */
LineDDA(start->x, start->y, end->x, end->y, solid_pen_line_callback, (LPARAM)pdev);
else if(clip->numRects >= 1)
ret = FALSE;
}
return TRUE;
release_wine_region(pdev->clip);
return ret;
}
/***********************************************************************

View File

@ -553,6 +553,19 @@ extern HPALETTE PALETTE_Init(void) DECLSPEC_HIDDEN;
extern INT mirror_region( HRGN dst, HRGN src, INT width ) DECLSPEC_HIDDEN;
extern BOOL REGION_FrameRgn( HRGN dest, HRGN src, INT x, INT y ) DECLSPEC_HIDDEN;
typedef struct
{
INT size;
INT numRects;
RECT *rects;
RECT extents;
} WINEREGION;
extern const WINEREGION *get_wine_region(HRGN rgn) DECLSPEC_HIDDEN;
static inline void release_wine_region(HRGN rgn)
{
GDI_ReleaseObj(rgn);
}
/* null driver entry points */
extern BOOL CDECL nulldrv_AbortPath( PHYSDEV dev ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) DECLSPEC_HIDDEN;

View File

@ -105,13 +105,6 @@ SOFTWARE.
WINE_DEFAULT_DEBUG_CHANNEL(region);
typedef struct {
INT size;
INT numRects;
RECT *rects;
RECT extents;
} WINEREGION;
/* GDI logical region object */
typedef struct
{
@ -924,6 +917,20 @@ HRGN WINAPI CreateEllipticRgnIndirect( const RECT *rect )
rect->bottom - rect->top );
}
/*********************************************************************
* get_wine_region
*
* Return the region data without making a copy. The caller
* must not alter anything and must call GDI_ReleaseObj() when
* they have finished with the data.
*/
const WINEREGION *get_wine_region(HRGN rgn)
{
RGNOBJ *obj = GDI_GetObjPtr( rgn, OBJ_REGION );
if(!obj) return NULL;
return &obj->rgn;
}
/***********************************************************************
* GetRegionData (GDI32.@)
*

View File

@ -78,6 +78,8 @@ static const char *sha1_graphics_a8r8g8b8[] =
"a3cadd34d95d3d5cc23344f69aab1c2e55935fcf",
"2426172d9e8fec27d9228088f382ef3c93717da9",
"9e8f27ca952cdba01dbf25d07c34e86a7820c012",
"76343ceb04e6295e0560019249d3c0318a23c8a6",
"6ecee6ba1c06dcb6b70ff42a8ea2df7803847860",
"17b2c177bdce5e94433574a928bda5c94a8cdfa5",
NULL
};
@ -147,12 +149,43 @@ static void compare_hash(BITMAPINFO *bmi, BYTE *bits, const char ***sha1, const
HeapFree(GetProcessHeap(), 0, hash);
}
static const RECT hline_clips[] =
{
{120, 120, 140, 120}, /* unclipped */
{100, 122, 140, 122}, /* l edgecase */
{ 99, 124, 140, 124}, /* l edgecase clipped */
{120, 126, 200, 126}, /* r edgecase */
{120, 128, 201, 128}, /* r edgecase clipped */
{ 99, 130, 201, 130}, /* l and r clipped */
{120, 100, 140, 100}, /* t edgecase */
{120, 99, 140, 99}, /* t edgecase clipped */
{120, 199, 140, 199}, /* b edgecase */
{120, 200, 140, 200}, /* b edgecase clipped */
{120, 132, 310, 132} /* inside two clip rects */
};
static const RECT vline_clips[] =
{
{120, 120, 120, 140}, /* unclipped */
{100, 120, 100, 140}, /* l edgecase */
{ 99, 120, 99, 140}, /* l edgecase clipped */
{199, 120, 199, 140}, /* r edgecase */
{200, 120, 200, 140}, /* r edgecase clipped */
{122, 99, 122, 201}, /* t and b clipped */
{124, 100, 124, 140}, /* t edgecase */
{126, 99, 126, 140}, /* t edgecase clipped */
{128, 120, 128, 200}, /* b edgecase */
{130, 120, 130, 201}, /* b edgecase clipped */
{132, 12, 132, 140} /* inside two clip rects */
};
static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sha1)
{
DWORD dib_size = get_dib_size(bmi);
HPEN solid_pen, orig_pen;
HBRUSH solid_brush, orig_brush;
INT i, y;
HRGN hrgn, hrgn2;
memset(bits, 0xcc, dib_size);
compare_hash(bmi, bits, sha1, "empty");
@ -188,6 +221,33 @@ static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sh
compare_hash(bmi, bits, sha1, "diagonal solid lines");
memset(bits, 0xcc, dib_size);
hrgn = CreateRectRgn(10, 10, 200, 20);
hrgn2 = CreateRectRgn(100, 100, 200, 200);
CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
SetRectRgn(hrgn2, 290, 100, 300, 200);
CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
DeleteObject(hrgn2);
DeleteObject(hrgn);
for(i = 0; i < sizeof(hline_clips)/sizeof(hline_clips[0]); i++)
{
MoveToEx(hdc, hline_clips[i].left, hline_clips[i].top, NULL);
LineTo(hdc, hline_clips[i].right, hline_clips[i].bottom);
}
compare_hash(bmi, bits, sha1, "clipped solid hlines");
memset(bits, 0xcc, dib_size);
for(i = 0; i < sizeof(vline_clips)/sizeof(vline_clips[0]); i++)
{
MoveToEx(hdc, vline_clips[i].left, vline_clips[i].top, NULL);
LineTo(hdc, vline_clips[i].right, vline_clips[i].bottom);
}
compare_hash(bmi, bits, sha1, "clipped solid vlines");
memset(bits, 0xcc, dib_size);
ExtSelectClipRgn(hdc, NULL, RGN_COPY);
solid_brush = CreateSolidBrush(RGB(0x33, 0xaa, 0xff));
orig_brush = SelectObject(hdc, solid_brush);