diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c index ad329be668d..b862ebb6da0 100644 --- a/dlls/gdi32/dibdrv/bitblt.c +++ b/dlls/gdi32/dibdrv/bitblt.c @@ -576,28 +576,17 @@ static DWORD blend_rect( dib_info *dst, const RECT *dst_rect, const dib_info *sr HRGN clip, BLENDFUNCTION blend ) { POINT origin; - RECT clipped_rect; - const WINEREGION *clip_data; + struct clipped_rects clipped_rects; int i; - origin.x = src_rect->left; - origin.y = src_rect->top; - - if (clip == NULL) dst->funcs->blend_rect( dst, dst_rect, src, &origin, blend ); - else + if (!get_clipped_rects( dst, dst_rect, clip, &clipped_rects )) return ERROR_SUCCESS; + for (i = 0; i < clipped_rects.count; i++) { - clip_data = get_wine_region( clip ); - for (i = 0; i < clip_data->numRects; i++) - { - if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i )) - { - origin.x = src_rect->left + clipped_rect.left - dst_rect->left; - origin.y = src_rect->top + clipped_rect.top - dst_rect->top; - dst->funcs->blend_rect( dst, &clipped_rect, src, &origin, blend ); - } - } - release_wine_region( clip ); + origin.x = src_rect->left + clipped_rects.rects[i].left - dst_rect->left; + origin.y = src_rect->top + clipped_rects.rects[i].top - dst_rect->top; + dst->funcs->blend_rect( dst, &clipped_rects.rects[i], src, &origin, blend ); } + free_clipped_rects( &clipped_rects ); return ERROR_SUCCESS; } @@ -679,7 +668,8 @@ static void get_gradient_triangle_vertices( const GRADIENT_TRIANGLE *tri, const static BOOL gradient_rect( dib_info *dib, TRIVERTEX *v, int mode, HRGN clip ) { int i; - RECT rect, clipped_rect; + struct clipped_rects clipped_rects; + RECT rect; BOOL ret = TRUE; if (mode == GRADIENT_FILL_TRIANGLE) @@ -696,26 +686,13 @@ static BOOL gradient_rect( dib_info *dib, TRIVERTEX *v, int mode, HRGN clip ) rect.right = v[1].x; rect.bottom = v[1].y; } - rect.left = max( rect.left, 0 ); - rect.top = max( rect.top, 0 ); - rect.right = min( rect.right, dib->width ); - rect.bottom = min( rect.bottom, dib->height ); - if (clip) + if (!get_clipped_rects( dib, &rect, clip, &clipped_rects )) return TRUE; + for (i = 0; i < clipped_rects.count; i++) { - 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 )) - { - if (!(ret = dib->funcs->gradient_rect( dib, &clipped_rect, v, mode ))) break; - } - } - release_wine_region( clip ); + if (!(ret = dib->funcs->gradient_rect( dib, &clipped_rects.rects[i], v, mode ))) break; } - else if (!is_rect_empty( &rect )) ret = dib->funcs->gradient_rect( dib, &rect, v, mode ); - + free_clipped_rects( &clipped_rects ); return ret; } diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index cdcbd19409e..404ead226d5 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -257,7 +257,48 @@ DWORD convert_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bit return ERROR_SUCCESS; } - /*********************************************************************** +int get_clipped_rects( const dib_info *dib, const RECT *rc, HRGN clip, struct clipped_rects *clip_rects ) +{ + const WINEREGION *region; + RECT rect, *out = clip_rects->buffer; + int i; + + init_clipped_rects( clip_rects ); + + rect.left = 0; + rect.top = 0; + rect.right = dib->width; + rect.bottom = dib->height; + if (rc && !intersect_rect( &rect, &rect, rc )) return 0; + + if (!clip) + { + *out = rect; + clip_rects->count = 1; + return 1; + } + + if (!(region = get_wine_region( clip ))) return 0; + + for (i = 0; i < region->numRects; i++) + { + if (region->rects[i].top >= rect.bottom) break; + if (!intersect_rect( out, &rect, ®ion->rects[i] )) continue; + out++; + if (out == &clip_rects->buffer[sizeof(clip_rects->buffer) / sizeof(RECT)]) + { + clip_rects->rects = HeapAlloc( GetProcessHeap(), 0, region->numRects * sizeof(RECT) ); + if (!clip_rects->rects) return 0; + memcpy( clip_rects->rects, clip_rects->buffer, (out - clip_rects->buffer) * sizeof(RECT) ); + out = clip_rects->rects + (out - clip_rects->buffer); + } + } + release_wine_region( clip ); + clip_rects->count = out - clip_rects->rects; + return clip_rects->count; +} + +/*********************************************************************** * add_extra_clipping_region * * Temporarily add a region to the current clipping region. diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index e8acfa0110c..c0cbc5b7bfe 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -212,6 +212,13 @@ typedef struct DWORD octant; } bres_params; +struct clipped_rects +{ + RECT *rects; + int count; + RECT buffer[32]; +}; + extern void get_rop_codes(INT rop, struct rop_codes *codes) DECLSPEC_HIDDEN; extern void update_brush_rop( dibdrv_physdev *pdev, INT rop ) DECLSPEC_HIDDEN; extern void reset_dash_origin(dibdrv_physdev *pdev) DECLSPEC_HIDDEN; @@ -225,11 +232,23 @@ extern COLORREF make_rgb_colorref( HDC hdc, dib_info *dib, COLORREF color, BOOL extern DWORD get_pixel_color(dibdrv_physdev *pdev, COLORREF color, BOOL mono_fixup) DECLSPEC_HIDDEN; extern BOOL brush_rects( dibdrv_physdev *pdev, int num, const RECT *rects ) DECLSPEC_HIDDEN; extern void solid_rects( dib_info *dib, int num, const RECT *rects, const rop_mask *color, HRGN region ) DECLSPEC_HIDDEN; +extern int get_clipped_rects( const dib_info *dib, const RECT *rc, HRGN clip, struct clipped_rects *clip_rects ) DECLSPEC_HIDDEN; extern HRGN add_extra_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) DECLSPEC_HIDDEN; extern void restore_clipping_region( dibdrv_physdev *pdev, HRGN rgn ) DECLSPEC_HIDDEN; extern int clip_line(const POINT *start, const POINT *end, const RECT *clip, const bres_params *params, POINT *pt1, POINT *pt2) DECLSPEC_HIDDEN; +static inline void init_clipped_rects( struct clipped_rects *clip_rects ) +{ + clip_rects->count = 0; + clip_rects->rects = clip_rects->buffer; +} + +static inline void free_clipped_rects( struct clipped_rects *clip_rects ) +{ + if (clip_rects->rects != clip_rects->buffer) HeapFree( GetProcessHeap(), 0, clip_rects->rects ); +} + /* compute the x coordinate corresponding to y on the specified edge */ static inline int edge_coord( int y, int x1, int y1, int x2, int y2 ) { diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c index ad6c4adfd8e..d9b305d3b88 100644 --- a/dlls/gdi32/dibdrv/graphics.c +++ b/dlls/gdi32/dibdrv/graphics.c @@ -606,36 +606,27 @@ BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) { dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); - int i; + struct clipped_rects clipped_rects; + RECT rect; POINT pt; DWORD pixel; - const WINEREGION *clip = get_wine_region( pdev->clip ); TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color ); pt.x = x; pt.y = y; LPtoDP( dev->hdc, &pt, 1 ); + rect.left = pt.x; + rect.top = pt.y; + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; /* SetPixel doesn't do the 1bpp massaging like other fg colors */ pixel = get_pixel_color( pdev, color, FALSE ); color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel ); - for (i = 0; i < clip->numRects; i++) - { - if (pt_in_rect( clip->rects + i, pt )) - { - RECT rect; - rect.left = pt.x; - rect.top = pt.y; - rect.right = rect.left + 1; - rect.bottom = rect.top + 1; - - pdev->dib.funcs->solid_rects( &pdev->dib, 1, &rect, 0, pixel ); - break; - } - } - - release_wine_region( pdev->clip ); + if (!get_clipped_rects( &pdev->dib, &rect, pdev->clip, &clipped_rects )) return color; + pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects, 0, pixel ); + free_clipped_rects( &clipped_rects ); return color; } diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index d87dfdc4a57..eab87d00375 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -430,12 +430,6 @@ static inline void offset_rect( RECT *rect, int offset_x, int offset_y ) rect->bottom += offset_y; } -static inline BOOL pt_in_rect( const RECT *rect, POINT pt ) -{ - return ((pt.x >= rect->left) && (pt.x < rect->right) && - (pt.y >= rect->top) && (pt.y < rect->bottom)); -} - static inline void get_bounding_rect( RECT *rect, int x, int y, int width, int height ) { rect->left = x;