gdi32: Add clipping for horizontal and vertical solid lines.
This commit is contained in:
parent
f33bbbfdd7
commit
1372692fe7
|
@ -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;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.@)
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue