[PATCH] msvfw32: Reimplement ICGetDisplayFormat().

Zebediah Figura z.figura12 at gmail.com
Fri Jul 27 22:28:21 CDT 2018


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44490
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=23175
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/msvfw32/msvideo_main.c | 136 ++++++++++++++++--------
 dlls/msvfw32/tests/msvfw.c  | 246 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 339 insertions(+), 43 deletions(-)

diff --git a/dlls/msvfw32/msvideo_main.c b/dlls/msvfw32/msvideo_main.c
index 5dc99a4..e3bedd9 100644
--- a/dlls/msvfw32/msvideo_main.c
+++ b/dlls/msvfw32/msvideo_main.c
@@ -223,6 +223,15 @@ static int compare_fourcc(DWORD fcc1, DWORD fcc2)
   return strncasecmp(fcc_str1, fcc_str2, 4);
 }
 
+static DWORD get_size_image(LONG width, LONG height, WORD depth)
+{
+    DWORD ret = width * depth;
+    ret = (ret + 7) / 8;    /* divide by byte size, rounding up */
+    ret = (ret + 3) & ~3;   /* align to 4 bytes */
+    ret *= abs(height);
+    return ret;
+}
+
 typedef BOOL (*enum_handler_t)(const char *name, const char *driver, unsigned int index, void *param);
 
 static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
@@ -715,57 +724,98 @@ HIC VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
 /***********************************************************************
  *		ICGetDisplayFormat			[MSVFW32.@]
  */
-HIC VFWAPI ICGetDisplayFormat(
-	HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
-	INT depth,INT dx,INT dy)
+HIC VFWAPI ICGetDisplayFormat(HIC hic, BITMAPINFOHEADER *in, BITMAPINFOHEADER *out,
+                              int depth, int width, int height)
 {
-	HIC	tmphic = hic;
+    HIC tmphic = hic;
 
-	TRACE("(%p,%p,%p,%d,%d,%d)!\n",hic,lpbiIn,lpbiOut,depth,dx,dy);
+    TRACE("(%p, %p, %p, %d, %d, %d)\n", hic, in, out, depth, width, height);
 
-	if (!tmphic) {
-		tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
-		if (!tmphic)
-			return tmphic;
-	}
-	if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
-		dy = dx = 0; /* no resize needed */
+    if (!tmphic)
+    {
+        tmphic = ICLocate(ICTYPE_VIDEO, 0, in, NULL, ICMODE_DECOMPRESS);
+        if (!tmphic)
+            return NULL;
+    }
 
-	/* Can we decompress it ? */
-	if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
-		goto errout; /* no, sorry */
+    if (ICDecompressQuery(tmphic, in, NULL))
+        goto err;
 
-	ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)lpbiIn, (DWORD_PTR)lpbiOut);
+    if (width <= 0 || height <= 0)
+    {
+        width = in->biWidth;
+        height = in->biHeight;
+    }
 
-	if (lpbiOut->biCompression != 0) {
-           FIXME("Ooch, how come decompressor outputs compressed data (%d)??\n",
-			 lpbiOut->biCompression);
-	}
-	if (lpbiOut->biSize < sizeof(*lpbiOut)) {
-           FIXME("Ooch, size of output BIH is too small (%d)\n",
-			 lpbiOut->biSize);
-	   lpbiOut->biSize = sizeof(*lpbiOut);
-	}
-	if (!depth) {
-		HDC	hdc;
+    if (!depth)
+        depth = 32;
 
-		hdc = GetDC(0);
-		depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
-		ReleaseDC(0,hdc);
-		if (depth==15)	depth = 16;
-		if (depth<8)	depth =  8;
-	}
-	if (lpbiIn->biBitCount == 8)
-		depth = 8;
+    *out = *in;
+    out->biSize = sizeof(*out);
+    out->biWidth = width;
+    out->biHeight = height;
+    out->biCompression = BI_RGB;
+    out->biSizeImage = get_size_image(width, height, depth);
 
-	TRACE("=> %p\n", tmphic);
-	return tmphic;
-errout:
-	if (hic!=tmphic)
-		ICClose(tmphic);
+    /* first try the given depth */
+    out->biBitCount = depth;
+    out->biSizeImage = get_size_image(width, height, out->biBitCount);
+    if (!ICDecompressQuery(tmphic, in, out))
+    {
+        if (depth == 8)
+            ICDecompressGetPalette(tmphic, in, out);
+        return tmphic;
+    }
 
-	TRACE("=> 0\n");
-	return 0;
+    /* then try 16, both with BI_RGB and BI_BITFIELDS */
+    if (depth <= 16)
+    {
+        out->biBitCount = 16;
+        out->biSizeImage = get_size_image(width, height, out->biBitCount);
+        if (!ICDecompressQuery(tmphic, in, out))
+            return tmphic;
+
+        out->biCompression = BI_BITFIELDS;
+        if (!ICDecompressQuery(tmphic, in, out))
+            return tmphic;
+        out->biCompression = BI_RGB;
+    }
+
+    /* then try 24 */
+    if (depth <= 24)
+    {
+        out->biBitCount = 24;
+        out->biSizeImage = get_size_image(width, height, out->biBitCount);
+        if (!ICDecompressQuery(tmphic, in, out))
+            return tmphic;
+    }
+
+    /* then try 32 */
+    if (depth <= 32)
+    {
+        out->biBitCount = 32;
+        out->biSizeImage = get_size_image(width, height, out->biBitCount);
+        if (!ICDecompressQuery(tmphic, in, out))
+            return tmphic;
+    }
+
+    /* as a last resort, try 32 bpp with the original width and height */
+    out->biWidth = in->biWidth;
+    out->biHeight = in->biHeight;
+    out->biBitCount = 32;
+    out->biSizeImage = get_size_image(out->biWidth, out->biHeight, out->biBitCount);
+    if (!ICDecompressQuery(tmphic, in, out))
+        return tmphic;
+
+    /* finally, ask the compressor for its default output format */
+    if (!ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)in, (DWORD_PTR)out))
+        return tmphic;
+
+err:
+    if (hic != tmphic)
+        ICClose(tmphic);
+
+    return NULL;
 }
 
 /***********************************************************************
@@ -1358,7 +1408,7 @@ HANDLE VFWAPI ICImageDecompress(
 
 	biSizeImage = lpbiOut->bmiHeader.biSizeImage;
 	if ( biSizeImage == 0 )
-		biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
+		biSizeImage = get_size_image(lpbiOut->bmiHeader.biWidth, lpbiOut->bmiHeader.biHeight, lpbiOut->bmiHeader.biBitCount);
 
 	TRACE( "call ICDecompressBegin\n" );
 
diff --git a/dlls/msvfw32/tests/msvfw.c b/dlls/msvfw32/tests/msvfw.c
index beeca9f..5bff6d1 100644
--- a/dlls/msvfw32/tests/msvfw.c
+++ b/dlls/msvfw32/tests/msvfw.c
@@ -316,10 +316,256 @@ static void test_ICInfo(void)
     ok(info.fccHandler == mmioFOURCC('f','a','k','e'), "got 0x%08x\n", info.fccHandler);
 }
 
+static int get_display_format_test;
+
+static DWORD get_size_image(LONG width, LONG height, WORD depth)
+{
+    DWORD ret = width * depth;
+    ret = (ret + 7) / 8;    /* divide by byte size, rounding up */
+    ret = (ret + 3) & ~3;   /* align to 4 bytes */
+    ret *= abs(height);
+    return ret;
+}
+
+static const RGBQUAD color_yellow = {0x00, 0xff, 0xff, 0x00};
+
+static BITMAPINFOHEADER gdf_in, *gdf_out;
+
+LRESULT CALLBACK gdf_driver_proc(DWORD_PTR id, HDRVR driver, UINT msg,
+    LPARAM lparam1, LPARAM lparam2)
+{
+    LRESULT ret = 0;
+
+    if (winetest_debug > 1)
+        trace("(%#lx, %p, %#x, %#lx, %#lx)\n", id, driver, msg, lparam1, lparam2);
+
+    switch(msg)
+    {
+    case DRV_LOAD:
+    case DRV_OPEN:
+    case DRV_CLOSE:
+    case DRV_FREE:
+        return 1;
+    case ICM_DECOMPRESS_QUERY:
+    {
+        BITMAPINFOHEADER *out = (BITMAPINFOHEADER *)lparam2;
+        DWORD expected_size;
+
+        ok(lparam1 == (LPARAM)&gdf_in, "got input %#lx\n", lparam1);
+
+        if (!out)
+            return ICERR_OK;
+
+        ok(out == gdf_out, "got output %p\n", out);
+
+        ok(out->biSize == sizeof(*out), "got size %d\n", out->biSize);
+        expected_size = get_size_image(out->biWidth, out->biHeight, out->biBitCount);
+        ok(out->biSizeImage == expected_size, "expected image size %d, got %d\n",
+            expected_size, out->biSizeImage);
+
+        ok(out->biPlanes == 0xcccc, "got planes %d\n", out->biPlanes);
+        ok(out->biXPelsPerMeter == 0xcccccccc && out->biYPelsPerMeter == 0xcccccccc,
+            "got resolution %dx%d\n", out->biXPelsPerMeter, out->biYPelsPerMeter);
+        ok(out->biClrUsed == 0xcccccccc, "got biClrUsed %u\n", out->biClrUsed);
+        ok(out->biClrImportant == 0xcccccccc, "got biClrImportant %u\n", out->biClrImportant);
+
+        switch (get_display_format_test)
+        {
+            case 0:
+                return ICERR_OK;
+            case 1:
+                if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_RGB && out->biBitCount == 16)
+                    return ICERR_OK;
+                break;
+            case 2:
+                if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_BITFIELDS && out->biBitCount == 16)
+                    return ICERR_OK;
+                break;
+            case 3:
+                if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_RGB && out->biBitCount == 24)
+                    return ICERR_OK;
+                break;
+            case 4:
+                if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_RGB && out->biBitCount == 32)
+                    return ICERR_OK;
+                break;
+            case 5:
+                if (out->biWidth == 10 && out->biHeight == 20 && out->biCompression == BI_RGB && out->biBitCount == 32)
+                    return ICERR_OK;
+                break;
+            case 6:
+                break;
+        }
+
+        return ICERR_BADFORMAT;
+    }
+    case ICM_DECOMPRESS_GET_FORMAT:
+    {
+        BITMAPINFOHEADER *out = (BITMAPINFOHEADER *)lparam2;
+
+        ok(lparam1 == (LPARAM)&gdf_in, "got input %#lx\n", lparam1);
+        if (out)
+        {
+            ok(out == gdf_out, "got output %p\n", out);
+
+            memset(out, 0x55, sizeof(*out));
+            out->biWidth = 50;
+            out->biHeight = 60;
+            out->biBitCount = 0xdead;
+            out->biCompression = 0xbeef;
+            out->biSizeImage = 0;
+
+            return ICERR_OK;
+        }
+    }
+    case ICM_DECOMPRESS_GET_PALETTE:
+    {
+        BITMAPINFO *out = (BITMAPINFO *)lparam2;
+
+        ok(lparam1 == (LPARAM)&gdf_in, "got input %#lx\n", lparam1);
+        if (out)
+        {
+            ok(out == (BITMAPINFO *)gdf_out, "got output %p\n", out);
+
+            out->bmiHeader.biClrUsed = 1;
+            out->bmiColors[0] = color_yellow;
+
+            return 0xdeadbeef;
+        }
+    }
+    }
+
+    return ret;
+}
+
+static void check_bitmap_header_(int line, BITMAPINFOHEADER *header, LONG width, LONG height, WORD depth, DWORD compression)
+{
+    ok_(__FILE__, line)(header->biWidth == width, "expected %d, got %d\n", width, header->biWidth);
+    ok_(__FILE__, line)(header->biHeight == height, "expected %d, got %d\n", height, header->biHeight);
+    ok_(__FILE__, line)(header->biBitCount == depth, "expected %d, got %d\n", depth, header->biBitCount);
+    ok_(__FILE__, line)(header->biCompression == compression, "expected %#x, got %#x\n", compression, header->biCompression);
+}
+#define check_bitmap_header(a,b,c,d,e) check_bitmap_header_(__LINE__,a,b,c,d,e)
+
+static void test_ICGetDisplayFormat(void)
+{
+    static const DWORD testcc = mmioFOURCC('t','e','s','t');
+    char outbuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
+    BITMAPINFO *out_bmi;
+    LRESULT lres;
+    BOOL ret;
+    HIC hic;
+
+    memset(&gdf_in, 0xcc, sizeof(gdf_in));
+    gdf_in.biSize = sizeof(gdf_in);
+    gdf_in.biWidth = 10;
+    gdf_in.biHeight = 20;
+    gdf_in.biBitCount = 1;
+    gdf_in.biCompression = testcc;
+
+    ret = ICInstall(ICTYPE_VIDEO, testcc, (LPARAM)gdf_driver_proc, NULL, ICINSTALL_FUNCTION);
+    ok(ret, "ICInstall failed\n");
+
+    hic = ICOpen(ICTYPE_VIDEO, testcc, ICMODE_DECOMPRESS);
+    ok(ret, "ICOpen failed\n");
+
+    memset(outbuf, 0, sizeof(outbuf));
+    gdf_out = (BITMAPINFOHEADER *)outbuf;
+
+    /* ICGetDisplayFormat tries several default formats; make sure those work */
+    get_display_format_test = 0;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 1, BI_RGB);
+
+    get_display_format_test = 1;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 16, BI_RGB);
+
+    get_display_format_test = 2;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 16, BI_BITFIELDS);
+
+    get_display_format_test = 3;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 24, BI_RGB);
+
+    get_display_format_test = 4;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 32, BI_RGB);
+
+    get_display_format_test = 5;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 10, 20, 32, BI_RGB);
+
+    /* if every default format is rejected, the output of
+     * ICM_DECOMPRESS_GET_FORMAT is returned */
+    get_display_format_test = 6;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 50, 60, 0xdead, 0xbeef);
+
+    /* given bpp is treated as a lower bound */
+    get_display_format_test = 1;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 24, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 50, 60, 0xdead, 0xbeef);
+
+    get_display_format_test = 3;
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 24, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 24, BI_RGB);
+
+    get_display_format_test = 0;
+
+    /* width or height <= 0 causes the input width and height to be supplied */
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 0, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB);
+
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 0);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB);
+
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, -10, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB);
+
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, -10);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB);
+
+    /* zero bpp causes 32 bpp to be supplied */
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 0, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 32, BI_RGB);
+
+    /* specifying 8 bpp yields a request for palette colours */
+    hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 8, 30, 40);
+    ok(hic != NULL, "ICGetDisplayFormat failed\n");
+    check_bitmap_header(gdf_out, 30, 40, 8, BI_RGB);
+    ok(gdf_out->biClrUsed == 1, "got biClrUsed %u\n", gdf_out->biClrUsed);
+    out_bmi = (BITMAPINFO *)gdf_out;
+    ok(!memcmp(&out_bmi->bmiColors[0], &color_yellow, sizeof(color_yellow)),
+        "got wrong colour\n");
+
+    lres = ICClose(hic);
+    ok(lres == ICERR_OK, "got %ld\n", lres);
+
+    ret = ICRemove(ICTYPE_VIDEO, testcc, 0);
+    ok(ret, "ICRemove failed\n");
+}
+
 START_TEST(msvfw)
 {
     test_OpenCase();
     test_Locate();
     test_ICSeqCompress();
     test_ICInfo();
+    test_ICGetDisplayFormat();
 }
-- 
2.7.4




More information about the wine-devel mailing list