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