gdi32: SetWinMetaFileBits
Michael Kaufmann
hallo at michael-kaufmann.ch
Tue Jun 20 09:02:37 CDT 2006
This is an improved version of this patch:
http://www.winehq.org/pipermail/wine-patches/2006-February/024461.html
Changelog:
- SetWinMetaFileBits: Use the whole device surface if the METAFILEPICT
parameter is NULL
- Also use the whole device surface if one of the extents is zero or
negative and the mapping mode is MM_ANISOTROPIC or MM_ISOTROPIC
- New tests
-------------- next part --------------
Index: dlls/gdi/enhmetafile.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/enhmetafile.c,v
retrieving revision 1.21
diff -u -r1.21 enhmetafile.c
--- dlls/gdi/enhmetafile.c 23 May 2006 12:47:58 -0000 1.21
+++ dlls/gdi/enhmetafile.c 20 Jun 2006 13:28:39 -0000
@@ -1339,10 +1339,10 @@
if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom ||
!lpScaleViewportExtEx->yNum || !lpScaleViewportExtEx->yDenom)
break;
- info->vportExtX = (info->vportExtX * lpScaleViewportExtEx->xNum) /
- lpScaleViewportExtEx->xDenom;
- info->vportExtY = (info->vportExtY * lpScaleViewportExtEx->yNum) /
- lpScaleViewportExtEx->yDenom;
+ info->vportExtX = MulDiv(info->vportExtX, lpScaleViewportExtEx->xNum,
+ lpScaleViewportExtEx->xDenom);
+ info->vportExtY = MulDiv(info->vportExtY, lpScaleViewportExtEx->yNum,
+ lpScaleViewportExtEx->yDenom);
if (info->vportExtX == 0) info->vportExtX = 1;
if (info->vportExtY == 0) info->vportExtY = 1;
if (info->mode == MM_ISOTROPIC)
@@ -1364,10 +1364,10 @@
if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom ||
!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->yDenom)
break;
- info->wndExtX = (info->wndExtX * lpScaleWindowExtEx->xNum) /
- lpScaleWindowExtEx->xDenom;
- info->wndExtY = (info->wndExtY * lpScaleWindowExtEx->yNum) /
- lpScaleWindowExtEx->yDenom;
+ info->wndExtX = MulDiv(info->wndExtX, lpScaleWindowExtEx->xNum,
+ lpScaleWindowExtEx->xDenom);
+ info->wndExtY = MulDiv(info->wndExtY, lpScaleWindowExtEx->yNum,
+ lpScaleWindowExtEx->yDenom);
if (info->wndExtX == 0) info->wndExtX = 1;
if (info->wndExtY == 0) info->wndExtY = 1;
if (info->mode == MM_ISOTROPIC)
@@ -2627,6 +2627,7 @@
RECT rc, *prcFrame = NULL;
gdi_mf_comment *mfcomment;
UINT mfcomment_size;
+ LONG mm, xExt, yExt;
TRACE("(%d, %p, %p, %p)\n", cbBuffer, lpbBuffer, hdcRef, lpmfp);
@@ -2641,19 +2642,45 @@
hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL);
if (lpmfp)
+ {
TRACE("mm = %ld %ldx%ld\n", lpmfp->mm, lpmfp->xExt, lpmfp->yExt);
-
- if (lpmfp && (lpmfp->mm == MM_ISOTROPIC || lpmfp->mm == MM_ANISOTROPIC))
+
+ mm = lpmfp->mm;
+ xExt = lpmfp->xExt;
+ yExt = lpmfp->yExt;
+ }
+ else
{
- rc.left = rc.top = 0;
- rc.right = lpmfp->xExt;
- rc.bottom = lpmfp->yExt;
- prcFrame = &rc;
+ TRACE("lpmfp == NULL\n");
+
+ /* Use the whole device surface */
+ mm = MM_ANISOTROPIC;
+ xExt = 0;
+ yExt = 0;
+ }
+
+ if (mm == MM_ISOTROPIC || mm == MM_ANISOTROPIC)
+ {
+ if (xExt < 0 || yExt < 0)
+ {
+ /* Use the whole device surface */
+ xExt = 0;
+ yExt = 0;
+ }
+
+ /* Use the x and y extents as the frame box */
+ if (xExt && yExt)
+ {
+ rc.left = rc.top = 0;
+ rc.right = xExt;
+ rc.bottom = yExt;
+ prcFrame = &rc;
+ }
}
if(!(hdc = CreateEnhMetaFileW(hdcRef, NULL, prcFrame, NULL)))
{
- ERR("CreateEnhMetaFile fails?\n");
+ ERR("CreateEnhMetaFile failed\n");
goto end;
}
@@ -2676,23 +2703,33 @@
HeapFree(GetProcessHeap(), 0, mfcomment);
}
- if(lpmfp && lpmfp->mm != MM_TEXT)
- SetMapMode(hdc, lpmfp->mm);
+ if (mm != MM_TEXT)
+ SetMapMode(hdc, mm);
- if (lpmfp && (lpmfp->mm == MM_ISOTROPIC || lpmfp->mm == MM_ANISOTROPIC))
+ if (mm == MM_ISOTROPIC || mm == MM_ANISOTROPIC)
{
- INT horzres, vertres, horzsize, vertsize, xext, yext;
+ INT horzsize, vertsize, horzres, vertres;
- horzres = GetDeviceCaps(hdcRef, HORZRES);
- vertres = GetDeviceCaps(hdcRef, VERTRES);
horzsize = GetDeviceCaps(hdcRef, HORZSIZE);
vertsize = GetDeviceCaps(hdcRef, VERTSIZE);
+ horzres = GetDeviceCaps(hdcRef, HORZRES);
+ vertres = GetDeviceCaps(hdcRef, VERTRES);
+
+ if (!xExt || !yExt)
+ {
+ /* Use the whole device surface */
+ xExt = horzres;
+ yExt = vertres;
+ }
+ else
+ {
+ xExt = MulDiv(xExt, horzres, 100 * horzsize);
+ yExt = MulDiv(yExt, vertres, 100 * vertsize);
+ }
/* set the initial viewport:window ratio as 1:1 */
- xext = lpmfp->xExt*horzres/(100*horzsize);
- yext = lpmfp->yExt*vertres/(100*vertsize);
- SetViewportExtEx(hdc, xext, yext, NULL);
- SetWindowExtEx(hdc, xext, yext, NULL);
+ SetViewportExtEx(hdc, xExt, yExt, NULL);
+ SetWindowExtEx(hdc, xExt, yExt, NULL);
}
PlayMetaFile(hdc, hmf);
Index: dlls/gdi/tests/metafile.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/tests/metafile.c,v
retrieving revision 1.23
diff -u -r1.23 metafile.c
--- dlls/gdi/tests/metafile.c 23 May 2006 12:48:00 -0000 1.23
+++ dlls/gdi/tests/metafile.c 20 Jun 2006 13:28:41 -0000
@@ -1299,6 +1299,217 @@
}
}
+static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
+ LONG mm, LONG xExt, LONG yExt,
+ RECTL * rclBounds, RECTL * rclFrame)
+{
+ METAFILEPICT mfp;
+ METAFILEPICT * mfpPtr = NULL;
+ HENHMETAFILE emf;
+ ENHMETAHEADER header;
+ UINT res;
+
+ if (!mfpIsNull)
+ {
+ mfp.mm = mm;
+ mfp.xExt = xExt;
+ mfp.yExt = yExt;
+ mfpPtr = &mfp;
+ }
+
+ emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
+ ok(emf != NULL, "SetWinMetaFileBits failed\n");
+ if (!emf) return FALSE;
+ res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
+ ok(res != 0, "GetEnhMetaHeader failed\n");
+ DeleteEnhMetaFile(emf);
+ if (!res) return FALSE;
+
+ *rclBounds = header.rclBounds;
+ *rclFrame = header.rclFrame;
+ return TRUE;
+}
+
+static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
+ LONG mm, LONG xExt, LONG yExt,
+ RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
+{
+ RECTL rclBounds, rclFrame;
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
+ {
+ char * msg;
+ char buf[64];
+
+ if (mfpIsNull)
+ {
+ msg = "mfp == NULL";
+ }
+ else
+ {
+ char * mm_str;
+ switch (mm)
+ {
+ case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
+ case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
+ default: mm_str = "Unexpected";
+ }
+ snprintf(buf, 64, "mm=%s, xExt=%ld, yExt=%ld", mm_str, xExt, yExt);
+ msg = buf;
+ }
+
+ ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %ld, got %ld (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
+ ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %ld, got %ld (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
+ ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %ld, got %ld (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
+ ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %ld, got %ld (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
+ ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %ld, got %ld (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
+ ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %ld, got %ld (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
+ ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %ld, got %ld (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
+ ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %ld, got %ld (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
+ }
+}
+
+static void test_SetWinMetaFileBits(void)
+{
+ HMETAFILE wmf;
+ HDC wmfDC;
+ BYTE * buffer;
+ UINT buffer_size;
+ RECT rect;
+ UINT res;
+ RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
+ RECTL rclBoundsIsotropic, rclFrameIsotropic;
+ RECTL rclBounds, rclFrame;
+ HDC dc;
+ LONG diffx, diffy;
+
+ wmfDC = CreateMetaFile(NULL);
+ ok(wmfDC != NULL, "CreateMetaFile failed\n");
+ if (!wmfDC) return;
+
+ SetWindowExtEx(wmfDC, 100, 100, NULL);
+ rect.left = rect.top = 0;
+ rect.right = rect.bottom = 50;
+ FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
+ wmf = CloseMetaFile(wmfDC);
+ ok(wmf != NULL, "Metafile creation failed\n");
+ if (!wmf) return;
+
+ buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
+ ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
+ if (buffer_size == 0)
+ {
+ DeleteMetaFile(wmf);
+ return;
+ }
+
+ buffer = (BYTE *)HeapAlloc(GetProcessHeap(), 0, buffer_size);
+ ok(buffer != NULL, "HeapAlloc failed\n");
+ if (!buffer)
+ {
+ DeleteMetaFile(wmf);
+ return;
+ }
+
+ res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
+ ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
+ DeleteMetaFile(wmf);
+ if (res != buffer_size)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return;
+ }
+
+ /* Get the reference bounds and frame */
+ getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
+
+ ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
+ rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
+ "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
+
+ ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
+ ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
+ diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
+ if (diffx < 0) diffx = -diffx;
+ ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
+
+ dc = CreateCompatibleDC(NULL);
+ todo_wine
+ {
+ ok(rclBoundsAnisotropic.right == GetDeviceCaps(dc, HORZRES) / 2 - 1 &&
+ rclBoundsAnisotropic.bottom == GetDeviceCaps(dc, VERTRES) / 2 - 1,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%ldx%ld)\n",
+ GetDeviceCaps(dc, HORZRES) / 2 - 1, GetDeviceCaps(dc, VERTRES) / 2 - 1, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
+ }
+
+ /* Allow 1 mm difference (rounding errors) */
+ diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
+ diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
+ if (diffx < 0) diffx = -diffx;
+ if (diffy < 0) diffy = -diffy;
+ todo_wine
+ {
+ ok(diffx <= 1 && diffy <= 1,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%ldx%ld)\n",
+ GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
+ }
+ DeleteDC(dc);
+
+ /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
+ checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+
+ /* If xExt or yExt is zero or negative, the whole device surface is used */
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+
+ /* MSDN says that negative xExt and yExt values specify a ratio.
+ Check that this is wrong and the whole device surface is used */
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
+
+ /* Ordinary conversions */
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
+ {
+ ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
+ ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
+ }
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
+ {
+ ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
+ "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
+ ok(rclBounds.left == 0 && rclBounds.top == 0,
+ "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
+
+ /* Wine has a rounding error */
+ diffx = rclBounds.right - rclBounds.bottom;
+ if (diffx < 0) diffx = -diffx;
+ ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
+ }
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
+ {
+ ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
+ "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
+ }
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+}
+
static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
@@ -1366,6 +1577,7 @@
/* For metafile conversions */
test_mf_conversions();
+ test_SetWinMetaFileBits();
test_gdiis();
}
More information about the wine-patches
mailing list