From 6ae21b934595dd286aa3a0a088650ad88e7a671e Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 6 Sep 2011 14:36:27 +0200 Subject: [PATCH] gdi32: Add RLE support in SetDIBitsToDevice. --- dlls/gdi32/dib.c | 70 ++++++++---- dlls/gdi32/tests/bitmap.c | 222 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+), 22 deletions(-) diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c index c1de074e8f6..57d830d183e 100644 --- a/dlls/gdi32/dib.c +++ b/dlls/gdi32/dib.c @@ -619,6 +619,7 @@ INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWOR BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer; struct bitblt_coords src, dst; struct gdi_image_bits src_bits; + HRGN clip = 0; DWORD err; UINT height; BOOL top_down; @@ -632,28 +633,45 @@ INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWOR src_bits.is_copy = FALSE; src_bits.free = NULL; + if (!lines) return 0; if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_palette( src_info, dev->hdc )) return 0; - if (!lines || (startscan >= height)) return 0; - if (!top_down && lines > height - startscan) lines = height - startscan; - - /* map src to top-down coordinates with startscan as origin */ - src.x = x_src; - src.y = startscan + lines - (y_src + cy); - src.width = cx; - src.height = cy; - if (src.y > 0) + if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8) { - if (!top_down) - { - /* get rid of unnecessary lines */ - if (src.y >= lines) return 0; - lines -= src.y; - src.y = 0; - } - else if (src.y >= lines) return lines; + startscan = 0; + lines = height; + src_info->bmiHeader.biWidth = x_src + cx; + src_info->bmiHeader.biHeight = y_src + cy; + if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0; + src.x = x_src; + src.y = 0; + src.width = cx; + src.height = cy; + if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0; + } + else + { + if (startscan >= height) return 0; + if (!top_down && lines > height - startscan) lines = height - startscan; + + /* map src to top-down coordinates with startscan as origin */ + src.x = x_src; + src.y = startscan + lines - (y_src + cy); + src.width = cx; + src.height = cy; + if (src.y > 0) + { + if (!top_down) + { + /* get rid of unnecessary lines */ + if (src.y >= lines) return 0; + lines -= src.y; + src.y = 0; + } + else if (src.y >= lines) return lines; + } + src_info->bmiHeader.biHeight = top_down ? -lines : lines; } - src_info->bmiHeader.biHeight = top_down ? -lines : lines; src.visrect.left = src.x; src.visrect.top = src.y; @@ -663,7 +681,11 @@ INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWOR rect.top = 0; rect.right = src_info->bmiHeader.biWidth; rect.bottom = abs( src_info->bmiHeader.biHeight ); - if (!intersect_rect( &src.visrect, &src.visrect, &rect )) return 0; + if (!intersect_rect( &src.visrect, &src.visrect, &rect )) + { + lines = 0; + goto done; + } pt.x = x_dst; pt.y = y_dst; @@ -684,11 +706,12 @@ INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWOR intersect_rect( &rect, &src.visrect, &dst.visrect ); src.visrect = dst.visrect = rect; offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y ); - if (is_rect_empty( &dst.visrect )) return lines; + if (is_rect_empty( &dst.visrect )) goto done; + 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, 0, dst_info, &src_bits, &src, &dst, SRCCOPY ); + err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY ); if (err == ERROR_BAD_FORMAT) { void *ptr; @@ -702,12 +725,15 @@ INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWOR src_bits.ptr = ptr; src_bits.is_copy = TRUE; src_bits.free = free_heap_bits; - if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &src_bits, &src, &dst, SRCCOPY ); + if (!err) err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY ); } else err = ERROR_OUTOFMEMORY; } if (err) lines = 0; + +done: if (src_bits.free) src_bits.free( &src_bits ); + if (clip) DeleteObject( clip ); return lines; } diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c index a66113c91ca..14d7f7fa5c5 100644 --- a/dlls/gdi32/tests/bitmap.c +++ b/dlls/gdi32/tests/bitmap.c @@ -4537,6 +4537,227 @@ static void test_SetDIBitsToDevice(void) DeleteObject( dib ); } +static void test_SetDIBitsToDevice_RLE8(void) +{ + char bmi_buf[ FIELD_OFFSET( BITMAPINFO, bmiColors[256] ) ]; + BITMAPINFO *info = (BITMAPINFO *)bmi_buf; + DWORD *dib_bits; + HDC hdc = CreateCompatibleDC( 0 ); + BYTE rle8_data[20] = { 0x04, 0x02, 0x03, 0xf0, 0x00, 0x00, /* 2, 2, 2, 2, f0, f0, f0, */ + 0x00, 0x03, 0x04, 0x05, 0x06, 0x00, /* 4, 5, 6, */ + 0x00, 0x02, 0x01, 0x02, 0x05, 0x80, /* dx=1, dy=2, 80, 80, 80, 80, (80) */ + 0x00, 0x01 }; /* */ + HBITMAP dib; + int i, ret; + DWORD bottom_up[64] = { 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x00f0f0f0, 0x00f0f0f0, 0x00f0f0f0, 0xaaaaaaaa, + 0x00040404, 0x00050505, 0x00060606, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0x00808080, 0x00808080, 0x00808080, 0x00808080, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa }; + DWORD top_down[64] = { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0x00808080, 0x00808080, 0x00808080, 0x00808080, + 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0x00040404, 0x00050505, 0x00060606, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, + 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x00f0f0f0, 0x00f0f0f0, 0x00f0f0f0, 0xaaaaaaaa }; + + memset( info, 0, sizeof(bmi_buf) ); + + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = 8; + info->bmiHeader.biHeight = 8; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biCompression = BI_RGB; + + dib = CreateDIBSection( NULL, info, DIB_RGB_COLORS, (void**)&dib_bits, NULL, 0 ); + memset( dib_bits, 0xaa, 64 * 4 ); + SelectObject( hdc, dib ); + + info->bmiHeader.biBitCount = 8; + info->bmiHeader.biCompression = BI_RLE8; + info->bmiHeader.biSizeImage = sizeof(rle8_data); + + for (i = 0; i < 256; i++) + { + info->bmiColors[i].rgbRed = i; + info->bmiColors[i].rgbGreen = i; + info->bmiColors[i].rgbBlue = i; + info->bmiColors[i].rgbReserved = 0; + } + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + /* startscan and lines are ignored, unless lines == 0 */ + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 1, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 1, 1, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 1, 0, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 0, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biWidth = 2; + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biWidth = 8; + info->bmiHeader.biHeight = 2; + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 2, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biHeight = 9; + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 9, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 9, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 9, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biHeight = 8; + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 1, 9, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == bottom_up[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 3, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 40; i++) ok( dib_bits[i] == bottom_up[i + 24], "%d: got %08x\n", i, dib_bits[i] ); + for (i = 40; i < 64; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 3, 4, 4, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 8; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + for (i = 8; i < 40; i++) + if (i & 4) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + else ok( dib_bits[i] == bottom_up[i - 8], "%d: got %08x\n", i, dib_bits[i] ); + for (i = 40; i < 64; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 3, 3, 8, 4, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 8; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + for (i = 8; i < 40; i++) + if ((i & 7) < 3) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + else ok( dib_bits[i] == bottom_up[i - 11], "%d: got %08x\n", i, dib_bits[i] ); + for (i = 40; i < 64; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 2, 3, 8, 4, 2, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 8; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + for (i = 8; i < 40; i++) + if ((i & 7) < 2) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + else ok( dib_bits[i] == bottom_up[i - 8], "%d: got %08x\n", i, dib_bits[i] ); + for (i = 40; i < 64; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biWidth = 37; + info->bmiHeader.biHeight = 37; + ret = SetDIBitsToDevice( hdc, -2, 1, 10, 5, 2, -1, 12, 24, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 37, "got %d\n", ret ); + for (i = 0; i < 24; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + for (i = 24; i < 64; i++) + if (i == 52) ok( dib_bits[i] == 0x00808080, "%d: got %08x\n", i, dib_bits[i] ); + else if (i & 4) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + else ok( dib_bits[i] == bottom_up[i - 20], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + /* top-down compressed dibs are invalid */ + info->bmiHeader.biWidth = 8; + info->bmiHeader.biHeight = -8; + SetLastError( 0xdeadbeef ); + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 0, "got %d\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %x\n", GetLastError() ); + + /* top-down dst */ + + info->bmiHeader.biHeight = -8; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biSizeImage = 0; + + dib = CreateDIBSection( NULL, info, DIB_RGB_COLORS, (void**)&dib_bits, NULL, 0 ); + memset( dib_bits, 0xaa, 16 * 16 * 4 ); + DeleteObject( SelectObject( hdc, dib )); + + info->bmiHeader.biHeight = 8; + info->bmiHeader.biBitCount = 8; + info->bmiHeader.biCompression = BI_RLE8; + info->bmiHeader.biSizeImage = sizeof(rle8_data); + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == top_down[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 9, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 8, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == top_down[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biHeight = 4; + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 4, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == top_down[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biHeight = 9; + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 9, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == top_down[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 0, 0, 8, 8, 0, 0, 0, 9, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 9, "got %d\n", ret ); + for (i = 0; i < 64; i++) ok( dib_bits[i] == top_down[i], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + ret = SetDIBitsToDevice( hdc, 2, 3, 8, 6, 2, 2, 0, 8, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 9, "got %d\n", ret ); + for (i = 0; i < 24; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + for (i = 24; i < 64; i++) ok( dib_bits[i] == top_down[i - 24], "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + info->bmiHeader.biWidth = 37; + info->bmiHeader.biHeight = 37; + ret = SetDIBitsToDevice( hdc, -2, 1, 10, 5, 2, -1, 12, 24, rle8_data, info, DIB_RGB_COLORS ); + ok( ret == 37, "got %d\n", ret ); + for (i = 0; i < 40; i++) + if (i == 12) ok( dib_bits[i] == 0x00808080, "%d: got %08x\n", i, dib_bits[i] ); + else if (i & 4) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + else ok( dib_bits[i] == top_down[i + 28], "%d: got %08x\n", i, dib_bits[i] ); + for (i = 40; i < 64; i++) ok( dib_bits[i] == 0xaaaaaaaa, "%d: got %08x\n", i, dib_bits[i] ); + memset( dib_bits, 0xaa, 64 * 4 ); + + DeleteDC( hdc ); + DeleteObject( dib ); +} + START_TEST(bitmap) { HMODULE hdll; @@ -4577,4 +4798,5 @@ START_TEST(bitmap) test_SetDIBits_RLE4(); test_SetDIBits_RLE8(); test_SetDIBitsToDevice(); + test_SetDIBitsToDevice_RLE8(); }