Huw Davies : gdi32: Implement nulldrv_StretchDIBits using the PutImage gdi driver function.
Alexandre Julliard
julliard at winehq.org
Mon Oct 17 13:08:55 CDT 2011
Module: wine
Branch: master
Commit: c9a7bb715d2db1512db30deb11e4676e76791a07
URL: http://source.winehq.org/git/wine.git/?a=commit;h=c9a7bb715d2db1512db30deb11e4676e76791a07
Author: Huw Davies <huw at codeweavers.com>
Date: Mon Oct 17 15:46:07 2011 +0100
gdi32: Implement nulldrv_StretchDIBits using the PutImage gdi driver function.
---
dlls/gdi32/dib.c | 160 ++++++++++++++++++++++++++++++++-------------
dlls/gdi32/tests/bitmap.c | 4 +-
2 files changed, 116 insertions(+), 48 deletions(-)
diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c
index eea257c..550f099 100644
--- a/dlls/gdi32/dib.c
+++ b/dlls/gdi32/dib.c
@@ -388,68 +388,136 @@ fail:
-/* nulldrv fallback implementation using SetDIBits/StretchBlt */
INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
- BITMAPINFO *info, UINT coloruse, DWORD rop )
+ BITMAPINFO *src_info, UINT coloruse, DWORD rop )
{
DC *dc = get_nulldrv_dc( dev );
- INT ret;
- LONG height;
- HBITMAP hBitmap;
- HDC hdcMem;
+ char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+ BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
+ struct bitblt_coords src, dst;
+ struct gdi_image_bits src_bits;
+ DWORD err;
+ HRGN clip = NULL;
+ INT ret = 0;
+ INT height = abs( src_info->bmiHeader.biHeight );
+ BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
+ RECT rect, clip_rect;
- /* make sure we have a real implementation for StretchBlt and PutImage */
- if (GET_DC_PHYSDEV( dc, pStretchBlt ) == dev || GET_DC_PHYSDEV( dc, pPutImage ) == dev)
- return 0;
+ TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
+ xSrc, ySrc, widthSrc, heightSrc, rop);
+
+ src_bits.ptr = (void*)bits;
+ src_bits.is_copy = FALSE;
+ src_bits.free = NULL;
+
+ if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_palette( src_info, dev->hdc )) return 0;
- height = info->bmiHeader.biHeight;
+ rect.left = xDst;
+ rect.top = yDst;
+ rect.right = xDst + widthDst;
+ rect.bottom = yDst + heightDst;
+ LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
+ dst.x = rect.left;
+ dst.y = rect.top;
+ dst.width = rect.right - rect.left;
+ dst.height = rect.bottom - rect.top;
+
+ if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
+ {
+ dst.x += dst.width;
+ dst.width = -dst.width;
+ }
+ rop &= ~NOMIRRORBITMAP;
+
+ src.x = xSrc;
+ src.width = widthSrc;
+ src.y = ySrc;
+ src.height = heightSrc;
+
+ if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
+ non_stretch_from_origin = TRUE;
- if (xSrc == 0 && ySrc == 0 && widthDst == widthSrc && heightDst == heightSrc &&
- info->bmiHeader.biCompression == BI_RGB)
+ if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
{
- /* Windows appears to have a fast case optimization
- * that uses the wrong origin for top-down DIBs */
- if (height < 0 && heightSrc < abs(height)) ySrc = abs(height) - heightSrc;
+ BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
+ if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
+ }
- if (xDst == 0 && yDst == 0 && info->bmiHeader.biCompression == BI_RGB && rop == SRCCOPY)
+ if (rop != SRCCOPY || non_stretch_from_origin)
+ {
+ if (dst.width == 1 && src.width > 1) src.width--;
+ if (dst.height == 1 && src.height > 1) src.height--;
+ }
+
+ if (rop != SRCCOPY)
+ {
+ if (dst.width < 0 && dst.width == src.width)
{
- BITMAP bm;
- hBitmap = GetCurrentObject( dev->hdc, OBJ_BITMAP );
- if (GetObjectW( hBitmap, sizeof(bm), &bm ) &&
- bm.bmWidth == widthSrc && bm.bmHeight == heightSrc &&
- bm.bmBitsPixel == info->bmiHeader.biBitCount && bm.bmPlanes == 1)
- {
- /* fast path */
- return SetDIBits( dev->hdc, hBitmap, 0, abs( height ), bits, info, coloruse );
- }
+ /* This is off-by-one, but that's what Windows does */
+ dst.x += dst.width;
+ src.x += src.width;
+ dst.width = -dst.width;
+ src.width = -src.width;
+ }
+ if (dst.height < 0 && dst.height == src.height)
+ {
+ dst.y += dst.height;
+ src.y += src.height;
+ dst.height = -dst.height;
+ src.height = -src.height;
}
}
- hdcMem = CreateCompatibleDC( dev->hdc );
- hBitmap = CreateCompatibleBitmap( dev->hdc, info->bmiHeader.biWidth, height );
- SelectObject( hdcMem, hBitmap );
- if (coloruse == DIB_PAL_COLORS)
- SelectPalette( hdcMem, GetCurrentObject( dev->hdc, OBJ_PAL ), FALSE );
+ if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
+
+ if (src.y >= height && src.y + src.height + 1 < height)
+ src.y = height - 1;
+ else if (src.y > 0 && src.y + src.height + 1 < 0)
+ src.y = -src.height - 1;
+
+ get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
+
+ src.visrect.left = 0;
+ src.visrect.right = src_info->bmiHeader.biWidth;
+ src.visrect.top = 0;
+ src.visrect.bottom = height;
+ if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
+
+ get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
+
+ if (get_clip_box( dc, &clip_rect ))
+ intersect_rect( &dst.visrect, &rect, &clip_rect );
+ else
+ dst.visrect = rect;
+ if (is_rect_empty( &dst.visrect )) goto done;
+
+ if (!intersect_vis_rectangles( &dst, &src )) goto done;
- if (info->bmiHeader.biCompression == BI_RLE4 || info->bmiHeader.biCompression == BI_RLE8)
+ if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
+
+ dev = GET_DC_PHYSDEV( dc, pPutImage );
+ memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
+ err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
+ if (err == ERROR_BAD_FORMAT)
+ {
+ err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
+ if (!err) err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
+ }
+
+ if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
{
- /* when RLE compression is used, there may be some gaps (ie the DIB doesn't
- * contain all the rectangle described in bmiHeader, but only part of it.
- * This mean that those undescribed pixels must be left untouched.
- * So, we first copy on a memory bitmap the current content of the
- * destination rectangle, blit the DIB bits on top of it - hence leaving
- * the gaps untouched -, and blitting the rectangle back.
- * This insure that gaps are untouched on the destination rectangle
- */
- StretchBlt( hdcMem, xSrc, abs(height) - heightSrc - ySrc, widthSrc, heightSrc,
- dev->hdc, xDst, yDst, widthDst, heightDst, rop );
+ memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
+ err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
+ if (!err) err = dev->funcs->pPutImage( dev, 0, NULL, dst_info, &src_bits, &src, &dst, rop );
}
- ret = SetDIBits( hdcMem, hBitmap, 0, abs( height ), bits, info, coloruse );
- if (ret) StretchBlt( dev->hdc, xDst, yDst, widthDst, heightDst,
- hdcMem, xSrc, abs(height) - heightSrc - ySrc, widthSrc, heightSrc, rop );
- DeleteDC( hdcMem );
- DeleteObject( hBitmap );
+ if (err) ret = 0;
+ else if (rop == SRCCOPY) ret = height;
+ else ret = src_info->bmiHeader.biHeight;
+
+done:
+ if (src_bits.free) src_bits.free( &src_bits );
+ if (clip) DeleteObject( clip );
return ret;
}
diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c
index 32fabb8..ed304aa 100644
--- a/dlls/gdi32/tests/bitmap.c
+++ b/dlls/gdi32/tests/bitmap.c
@@ -984,7 +984,7 @@ static void test_dib_formats(void)
ret = SetDIBitsToDevice( memdc, 0, 0, 1, 1, 0, 0, 0, 1, data, bi, DIB_RGB_COLORS );
ok( ret, "SetDIBitsToDevice failed with null bitfields\n" );
ret = StretchDIBits( memdc, 0, 0, 1, 1, 0, 0, 1, 1, data, bi, DIB_RGB_COLORS, SRCCOPY );
- todo_wine ok( ret, "StretchDIBits failed with null bitfields\n" );
+ ok( ret, "StretchDIBits failed with null bitfields\n" );
ret = GetDIBits(hdc, hbmp, 0, 2, data, bi, DIB_RGB_COLORS);
ok( ret, "GetDIBits failed with null bitfields\n" );
bi->bmiHeader.biPlanes = 1;
@@ -3152,7 +3152,7 @@ static void test_StretchDIBits(void)
expected[2] = 0x00000000, expected[3] = 0x00000000;
legacy_expected[0] = 0x00543210, legacy_expected[1] = 0x00000000;
legacy_expected[2] = 0x00000000, legacy_expected[3] = 0x00000000;
- todo_wine check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer,
+ check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer,
0, 0, 1, 1, 0, 0, 2, 2, expected, legacy_expected, __LINE__);
expected[0] = 0x00000000, expected[1] = 0x00000000;
More information about the wine-cvs
mailing list