const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
+ SetLastError(0xdeadbeef);
ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
- ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
+ ok( ret == sizeof(device_lf) ||
+ broken(ret == (sizeof(device_lf) - LF_FACESIZE + strlen(device_lf.lfFaceName) + 1)), /* NT4 */
+ "GetObjectA error %d\n", GetLastError());
/* compare up to lfOutPrecision, other values are not interesting,
* and in fact sometimes arbitrary adapted by Win9x.
SIZE size;
static int save_state;
static int restore_no;
+ static int select_no;
trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
hdc, emr->iType, emr->nSize, (void *)param);
save_state = 0;
restore_no = 0;
+ select_no = 0;
check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
break;
}
save_state += restoredc->iRelative;
break;
}
+ case EMR_SELECTOBJECT:
+ {
+ const EMRSELECTOBJECT *selectobj = (const EMRSELECTOBJECT*)emr;
+ trace("EMR_SELECTOBJECT: %x\n",selectobj->ihObject);
+ select_no ++;
+ break;
+ }
case EMR_EOF:
ok(save_state == 0, "EOF save_state %d\n", save_state);
+ ok(select_no == 3, "Too many/few selects %i\n",select_no);
break;
}
HENHMETAFILE hMetafile;
HWND hwnd;
int ret;
+ POINT pt;
+ SIZE size;
+ HFONT hFont,hFont2,hFontOld,hFontCheck;
static const RECT rc = { 0, 0, 150, 150 };
/* Win9x doesn't play EMFs on invisible windows */
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
ret = SaveDC(hdcMetafile);
ok(ret == 1, "ret = %d\n", ret);
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 10,"Expecting ViewportOrg x of 10, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 200,"Expecting ViewportExt cx of 200, got %i\n",size.cx);
ret = SaveDC(hdcMetafile);
ok(ret == 2, "ret = %d\n", ret);
SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
SetWindowExtEx(hdcMetafile, 120, 120, NULL );
SetViewportExtEx(hdcMetafile, 300, 300, NULL );
+ SetPolyFillMode( hdcMetafile, ALTERNATE );
+ SetBkColor( hdcMetafile, 0 );
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
ret = SaveDC(hdcMetafile);
ok(ret == 3, "ret = %d\n", ret);
SetWindowExtEx(hdcMetafile, 200, 200, NULL );
SetViewportExtEx(hdcMetafile, 400, 400, NULL );
+ SetPolyFillMode( hdcMetafile, WINDING );
+ SetBkColor( hdcMetafile, 0x123456 );
+ ok( GetPolyFillMode( hdcMetafile ) == WINDING, "PolyFillMode not restored\n" );
+ ok( GetBkColor( hdcMetafile ) == 0x123456, "Background color not restored\n" );
+
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 30,"Expecting ViewportOrg x of 30, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 400,"Expecting ViewportExt cx of 400, got %i\n",size.cx);
ret = RestoreDC(hdcMetafile, -1);
ok(ret, "ret = %d\n", ret);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
+ ok( GetPolyFillMode( hdcMetafile ) == ALTERNATE, "PolyFillMode not restored\n" );
+ ok( GetBkColor( hdcMetafile ) == 0, "Background color not restored\n" );
ret = SaveDC(hdcMetafile);
ok(ret == 3, "ret = %d\n", ret);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
ret = RestoreDC(hdcMetafile, 1);
ok(ret, "ret = %d\n", ret);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
ret = SaveDC(hdcMetafile);
ok(ret == 1, "ret = %d\n", ret);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
ret = SaveDC(hdcMetafile);
ok(ret == 2, "ret = %d\n", ret);
+ memset(&orig_lf, 0, sizeof(orig_lf));
+ orig_lf.lfCharSet = ANSI_CHARSET;
+ orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ orig_lf.lfWeight = FW_DONTCARE;
+ orig_lf.lfHeight = 7;
+ orig_lf.lfQuality = DEFAULT_QUALITY;
+ lstrcpyA(orig_lf.lfFaceName, "Arial");
+ hFont = CreateFontIndirectA(&orig_lf);
+ ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
+
+ hFontOld = SelectObject(hdcMetafile, hFont);
+
+ hFont2 = CreateFontIndirectA(&orig_lf);
+ ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
+ hFontCheck = SelectObject(hdcMetafile, hFont2);
+ ok(hFontCheck == hFont, "Font not selected\n");
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+
+ ret = RestoreDC(hdcMetafile, 1);
+ ok(ret, "ret = %d\n", ret);
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
+
+ hFontCheck = SelectObject(hdcMetafile, hFontOld);
+ ok(hFontOld == hFontCheck && hFontCheck != hFont && hFontCheck != hFont2,
+ "Font not reverted with DC Restore\n");
+
+ ret = RestoreDC(hdcMetafile, -20);
+ ok(!ret, "ret = %d\n", ret);
+ ret = RestoreDC(hdcMetafile, 20);
+ ok(!ret, "ret = %d\n", ret);
+
hMetafile = CloseEnhMetaFile(hdcMetafile);
ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
+ ret = DeleteObject(hFont);
+ ok( ret, "DeleteObject error %d\n", GetLastError());
+ ret = DeleteObject(hFont2);
+ ok( ret, "DeleteObject error %d\n", GetLastError());
ret = DeleteEnhMetaFile(hMetafile);
ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
ret = ReleaseDC(hwnd, hdcDisplay);
DestroyWindow(hwnd);
}
+static void test_mf_SaveDC(void)
+{
+ HDC hdcMetafile;
+ HMETAFILE hMetafile;
+ int ret;
+ POINT pt;
+ SIZE size;
+ HFONT hFont,hFont2,hFontOld,hFontCheck;
+
+ hdcMetafile = CreateMetaFileA(NULL);
+ ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
+
+ ret = SetMapMode(hdcMetafile, MM_ANISOTROPIC);
+ ok (ret, "SetMapMode should not fail\n");
+
+ /* Need to write something to the emf, otherwise Windows won't play it back */
+ LineTo(hdcMetafile, 150, 150);
+
+ SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
+ SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
+ SetWindowExtEx(hdcMetafile, 110, 110, NULL );
+ SetViewportExtEx(hdcMetafile, 120, 120, NULL );
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+
+ ret = GetViewportOrgEx(hdcMetafile, &pt);
+ todo_wine ok (!ret, "GetViewportOrgEx should fail\n");
+ ret = GetViewportExtEx(hdcMetafile, &size);
+ todo_wine ok (!ret, "GetViewportExtEx should fail\n");
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
+ SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
+ SetWindowExtEx(hdcMetafile, 150, 150, NULL );
+ SetViewportExtEx(hdcMetafile, 200, 200, NULL );
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
+ SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
+ SetWindowExtEx(hdcMetafile, 120, 120, NULL );
+ SetViewportExtEx(hdcMetafile, 300, 300, NULL );
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+ SetPolyFillMode( hdcMetafile, ALTERNATE );
+ SetBkColor( hdcMetafile, 0 );
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
+ SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
+ SetWindowExtEx(hdcMetafile, 200, 200, NULL );
+ SetViewportExtEx(hdcMetafile, 400, 400, NULL );
+
+ SetPolyFillMode( hdcMetafile, WINDING );
+ SetBkColor( hdcMetafile, 0x123456 );
+ todo_wine ok( !GetPolyFillMode( hdcMetafile ), "GetPolyFillMode succeeded\n" );
+ todo_wine ok( GetBkColor( hdcMetafile ) == CLR_INVALID, "GetBkColor succeeded\n" );
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+
+ ret = RestoreDC(hdcMetafile, -1);
+ ok(ret, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ ret = RestoreDC(hdcMetafile, 1);
+ ok(ret, "ret = %d\n", ret);
+
+ SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
+ SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
+ SetWindowExtEx(hdcMetafile, 500, 500, NULL );
+ SetViewportExtEx(hdcMetafile, 50, 50, NULL );
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ memset(&orig_lf, 0, sizeof(orig_lf));
+ orig_lf.lfCharSet = ANSI_CHARSET;
+ orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ orig_lf.lfWeight = FW_DONTCARE;
+ orig_lf.lfHeight = 7;
+ orig_lf.lfQuality = DEFAULT_QUALITY;
+ lstrcpyA(orig_lf.lfFaceName, "Arial");
+ hFont = CreateFontIndirectA(&orig_lf);
+ ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
+
+ hFontOld = SelectObject(hdcMetafile, hFont);
+
+ hFont2 = CreateFontIndirectA(&orig_lf);
+ ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
+ hFontCheck = SelectObject(hdcMetafile, hFont2);
+ ok(hFontCheck == hFont, "Font not selected\n");
+
+ /* Force Win9x to update DC state */
+ SetPixelV(hdcMetafile, 50, 50, 0);
+
+ ret = RestoreDC(hdcMetafile, 1);
+ ok(ret, "ret = %d\n", ret);
+
+ hFontCheck = SelectObject(hdcMetafile, hFontOld);
+ ok(hFontOld != hFontCheck && hFontCheck == hFont2, "Font incorrectly reverted with DC Restore\n");
+
+ /* restore level is ignored */
+ ret = RestoreDC(hdcMetafile, -20);
+ ok(ret, "ret = %d\n", ret);
+ ret = RestoreDC(hdcMetafile, 20);
+ ok(ret, "ret = %d\n", ret);
+ ret = RestoreDC(hdcMetafile, 0);
+ ok(ret, "ret = %d\n", ret);
+
+ hMetafile = CloseMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
+
+ ret = DeleteMetaFile(hMetafile);
+ ok( ret, "DeleteMetaFile error %d\n", GetLastError());
+ ret = DeleteObject(hFont);
+ ok( ret, "DeleteObject error %d\n", GetLastError());
+ ret = DeleteObject(hFont2);
+ ok( ret, "DeleteObject error %d\n", GetLastError());
+}
+
+
/* Win-format metafile (mfdrv) tests */
/* These tests compare the generated metafiles byte-by-byte */
/* with the nominal results. */
0x14, 0x00, 0x00, 0x00
};
+static const unsigned char EMF_BITBLT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xa0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x04, 0x00, 0x00, 0x3b, 0x02, 0x00, 0x00,
+ 0x75, 0x01, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0xb1, 0x05, 0x00,
+ 0x28, 0x11, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0xcc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x8c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+
/* For debugging or dumping the raw metafiles produced by
* new test functions.
*/
printf ("};\n");
}
+static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto)
+{
+ trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top,
+ eto->rclBounds.right, eto->rclBounds.bottom);
+ trace("iGraphicsMode %u\n", eto->iGraphicsMode);
+ trace("exScale: %f\n", eto->exScale);
+ trace("eyScale: %f\n", eto->eyScale);
+ trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y);
+ trace("emrtext.nChars %u\n", eto->emrtext.nChars);
+ trace("emrtext.offString %#x\n", eto->emrtext.offString);
+ trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions);
+ trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top,
+ eto->emrtext.rcl.right, eto->emrtext.rcl.bottom);
+ trace("emrtext.offDx %#x\n", eto->emrtext.offDx);
+}
+
static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
- const char *desc, BOOL todo)
+ const char *desc, BOOL ignore_scaling)
{
int diff;
- if (emr1->iType != emr2->iType && todo)
- {
- todo_wine
- {
- ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
- desc, emr1->iType, emr2->iType);
- }
- }
- else
- ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
- desc, emr1->iType, emr2->iType);
+ ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
+ desc, emr1->iType, emr2->iType);
- if (emr1->nSize != emr2->nSize && todo)
- {
- todo_wine
- {
- ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
- desc, emr1->nSize, emr2->nSize);
- }
- }
- else
- ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
- desc, emr1->nSize, emr2->nSize);
+ ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
+ desc, emr1->nSize, emr2->nSize);
/* iType and nSize mismatches are fatal */
if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
/* contents of EMR_GDICOMMENT are not interesting */
if (emr1->iType == EMR_GDICOMMENT) return TRUE;
- diff = memcmp(emr1->dParm, emr2->dParm, emr1->nSize - sizeof(EMR));
- if (diff && todo)
+ /* different Windows versions setup DC scaling differently when
+ * converting an old style metafile to an EMF.
+ */
+ if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX ||
+ emr1->iType == EMR_SETVIEWPORTEXTEX))
+ return TRUE;
+
+ if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA)
+ {
+ EMREXTTEXTOUTW *eto1, *eto2;
+
+ eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize);
+ memcpy(eto1, emr1, emr1->nSize);
+ eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
+ memcpy(eto2, emr2, emr2->nSize);
+
+ /* different Windows versions setup DC scaling differently */
+ eto1->exScale = eto1->eyScale = 0.0;
+ eto2->exScale = eto2->eyScale = 0.0;
+
+ diff = memcmp(eto1, eto2, emr1->nSize);
+ if (diff)
+ {
+ dump_EMREXTTEXTOUT(eto1);
+ dump_EMREXTTEXTOUT(eto2);
+ }
+ HeapFree(GetProcessHeap(), 0, eto1);
+ HeapFree(GetProcessHeap(), 0, eto2);
+ }
+ else if (emr1->iType == EMR_EXTSELECTCLIPRGN && !lstrcmpA(desc, "emf_clipping"))
{
- todo_wine
- ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
+ /* We have to take care of NT4 differences here */
+ diff = memcmp(emr1, emr2, emr1->nSize);
+ if (diff)
+ {
+ ENHMETARECORD *emr_nt4;
+
+ emr_nt4 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
+ memcpy(emr_nt4, emr2, emr2->nSize);
+ /* Correct the nRgnSize field */
+ emr_nt4->dParm[5] = sizeof(RECT);
+
+ diff = memcmp(emr1, emr_nt4, emr1->nSize);
+ if (!diff)
+ win_skip("Catered for NT4 differences\n");
+
+ HeapFree(GetProcessHeap(), 0, emr_nt4);
+ }
}
else
- ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
+ diff = memcmp(emr1, emr2, emr1->nSize);
+
+ ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
if (diff)
{
dump_emf_record(emr2, "actual bits");
}
- return diff == 0 || todo; /* report all non-fatal record mismatches */
+ return diff == 0; /* report all non-fatal record mismatches */
}
/* Compare the EMF produced by a test function with the
* otherwise returns the number of non-matching bytes.
*/
static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
- UINT bsize, const char *desc, BOOL todo)
+ UINT bsize, const char *desc,
+ BOOL ignore_scaling)
{
unsigned char buf[MF_BUFSIZE];
- UINT mfsize, offset;
+ UINT mfsize, offset1, offset2, diff_nt4, diff_9x;
const ENHMETAHEADER *emh1, *emh2;
mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
+ /* ENHMETAHEADER size could differ, depending on platform */
+ diff_nt4 = sizeof(SIZEL);
+ diff_9x = sizeof(SIZEL) + 3 * sizeof(DWORD);
+
if (mfsize < MF_BUFSIZE)
{
- if (mfsize != bsize && todo)
- {
- todo_wine
- ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
- }
- else
- ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
+ ok(mfsize == bsize ||
+ broken(mfsize == bsize - diff_nt4) || /* NT4 */
+ broken(mfsize == bsize - diff_9x), /* Win9x/WinME */
+ "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
}
else
ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
- ok(emh1->nSize == emh2->nSize, "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
+ ok(emh1->nSize == emh2->nSize ||
+ broken(emh1->nSize - diff_nt4 == emh2->nSize) ||
+ broken(emh1->nSize - diff_9x == emh2->nSize),
+ "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
- if (todo && emh1->nBytes != emh2->nBytes)
- {
- todo_wine
- ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
- }
- else
- ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
- if (todo && emh1->nRecords != emh2->nRecords)
+ ok(emh1->nBytes == emh2->nBytes ||
+ broken(emh1->nBytes - diff_nt4 == emh2->nBytes) ||
+ broken(emh1->nBytes - diff_9x == emh2->nBytes),
+ "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
+ ok(emh1->nRecords == emh2->nRecords, "expected nRecords %u, got %u\n", emh1->nRecords, emh2->nRecords);
+
+ offset1 = emh1->nSize;
+ offset2 = emh2->nSize; /* Needed for Win9x/WinME/NT4 */
+ while (offset1 < emh1->nBytes)
{
- todo_wine
- ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
+ const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset1);
+ const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset2);
+
+#if 1
+ skip("skipping match_emf_record(), bug 5393\n");
+#else
+ trace("%s: EMF record %u, size %u/record %u, size %u\n",
+ desc, emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
+
+ if (!match_emf_record(emr1, emr2, desc, ignore_scaling)) return -1;
+#endif
+
+ /* We have already bailed out if iType or nSize don't match */
+ offset1 += emr1->nSize;
+ offset2 += emr2->nSize;
}
- else
- ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
+ return 0;
+}
- offset = emh1->nSize;
- while (offset < emh1->nBytes)
+
+/* tests blitting to an EMF */
+static void test_emf_BitBlt(void)
+{
+ HDC hdcDisplay, hdcMetafile, hdcBitmap;
+ HBITMAP hBitmap, hOldBitmap;
+ HENHMETAFILE hMetafile;
+#define BMP_DIM 4
+ BITMAPINFOHEADER bmih =
{
- const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset);
- const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset);
+ sizeof(BITMAPINFOHEADER),
+ BMP_DIM,/* biWidth */
+ BMP_DIM,/* biHeight */
+ 1, /* biPlanes */
+ 24, /* biBitCount */
+ BI_RGB, /* biCompression */
+ 0, /* biXPelsPerMeter */
+ 0, /* biYPelsPerMeter */
+ 0, /* biClrUsed */
+ 0, /* biClrImportant */
+ };
+ void *bits;
+ BOOL ret;
- trace("EMF record %u, size %u/record %u, size %u\n",
- emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
+ hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL);
+ ok( hdcDisplay != 0, "CreateDCA error %d\n", GetLastError() );
- if (!match_emf_record(emr1, emr2, desc, todo)) return -1;
+ hdcBitmap = CreateCompatibleDC(hdcDisplay);
+ ok( hdcBitmap != 0, "CreateCompatibleDC failed\n" );
+ bmih.biXPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSX), 100, 3937);
+ bmih.biYPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSY), 100, 3937);
+ hBitmap = CreateDIBSection(hdcDisplay, (const BITMAPINFO *)&bmih,
+ DIB_RGB_COLORS, &bits, NULL, 0);
+ hOldBitmap = SelectObject(hdcBitmap, hBitmap);
- offset += emr1->nSize;
+ hdcMetafile = CreateEnhMetaFileA(hdcBitmap, NULL, NULL, NULL);
+ ok( hdcMetafile != 0, "CreateEnhMetaFileA failed\n" );
+
+ /* First fill the bitmap DC with something recognizable, like BLACKNESS */
+ ret = BitBlt(hdcBitmap, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, BLACKNESS);
+ ok( ret, "BitBlt(BLACKNESS) failed\n" );
+
+ ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, hdcBitmap, 0, 0, SRCCOPY);
+ ok( ret, "BitBlt(SRCCOPY) failed\n" );
+ ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, WHITENESS);
+ ok( ret, "BitBlt(WHITENESS) failed\n" );
+
+ hMetafile = CloseEnhMetaFile(hdcMetafile);
+ ok( hMetafile != 0, "CloseEnhMetaFile failed\n" );
+
+ if(compare_emf_bits(hMetafile, EMF_BITBLT, sizeof(EMF_BITBLT),
+ "emf_BitBlt", FALSE) != 0)
+ {
+ dump_emf_bits(hMetafile, "emf_BitBlt");
+ dump_emf_records(hMetafile, "emf_BitBlt");
}
- return 0;
+
+ SelectObject(hdcBitmap, hOldBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hdcBitmap);
+ DeleteDC(hdcDisplay);
+#undef BMP_DIM
}
/* Test a blank metafile. May be used as a template for new tests. */
if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
{
- dump_mf_bits(hMetafile, "mf_Blank");
- EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ dump_mf_bits(hmf_copy, "mf_Blank");
+ EnumMetaFile(0, hmf_copy, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf_copy);
METAHEADER *mh;
hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
+ trace("hmf %p\n", hmf);
ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
type = GetObjectType(hmf);
ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
/* NULL data crashes XP SP1 */
/*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
- /* Now with not zero size */
+ /* Now with zero size */
SetLastError(0xdeadbeef);
hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
+ trace("hmf %p\n", hmf);
ok(!hmf, "SetMetaFileBitsEx should fail\n");
- ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
+ ok(GetLastError() == ERROR_INVALID_DATA ||
+ broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
+ "wrong error %d\n", GetLastError());
- /* Now with not even size */
+ /* Now with odd size */
SetLastError(0xdeadbeef);
hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
+ trace("hmf %p\n", hmf);
ok(!hmf, "SetMetaFileBitsEx should fail\n");
ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
- /* Now with zeroed out or faked some header fields */
+ /* Now with zeroed out header fields */
assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
mh = (METAHEADER *)buf;
mh->mtHeaderSize = 0;
SetLastError(0xdeadbeef);
hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+ trace("hmf %p\n", hmf);
ok(!hmf, "SetMetaFileBitsEx should fail\n");
- ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
+ ok(GetLastError() == ERROR_INVALID_DATA ||
+ broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
+ "wrong error %d\n", GetLastError());
/* Now with corrupted mtSize field */
memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
/* corruption of mtSize doesn't lead to a failure */
mh->mtSize *= 2;
hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+ trace("hmf %p\n", hmf);
ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
/* zeroing mtSize doesn't lead to a failure */
mh->mtSize = 0;
hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+ trace("hmf %p\n", hmf);
ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
* are there, but their contents don't match for different reasons.
*/
if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
- "emf_TextOut_on_path", TRUE) != 0)
+ "emf_TextOut_on_path", FALSE) != 0)
{
dump_emf_bits(hMetafile, "emf_TextOut_on_path");
dump_emf_records(hMetafile, "emf_TextOut_on_path");
}
}
+/* Compare rectangles allowing rounding errors */
+static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2)
+{
+ return abs(rc1->left - rc2->left) <= 1 &&
+ abs(rc1->top - rc2->top) <= 1 &&
+ abs(rc1->right - rc2->right) <= 1 &&
+ abs(rc1->bottom - rc2->bottom) <= 1;
+}
+
static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
const ENHMETARECORD *emr, int n_objs, LPARAM param)
{
ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
- ok(rgn1->data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
+ ok(rgn1->data.rdh.nRgnSize == sizeof(RECT) ||
+ broken(rgn1->data.rdh.nRgnSize == 168), /* NT4 */
+ "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
hrgn = CreateRectRgn(0, 0, 0, 0);
PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
ret = GetClipRgn(hdc, hrgn);
- ok(ret == 1, "GetClipRgn returned %d, expected 0\n", ret);
+ ok(ret == 1, "GetClipRgn returned %d, expected 1\n", ret);
/* Win9x returns empty clipping region */
if (is_win9x) return 1;
translate((POINT *)&rc_transformed, 2, &xform);
trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
rc_transformed.right, rc_transformed.bottom);
- ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
+ ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
rect = *(const RECT *)rgn2.data.Buffer;
trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
translate((POINT *)&rc_transformed, 2, &xform);
trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
rc_transformed.right, rc_transformed.bottom);
- ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
+ ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
- ok(rgn2.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
+ ok(rgn2.data.rdh.nRgnSize == sizeof(RECT) ||
+ broken(rgn2.data.rdh.nRgnSize == 168), /* NT4 */
+ "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
DeleteObject(hrgn);
}
HENHMETAFILE hemf;
HRGN hrgn;
INT ret;
+ RECT rc_res, rc_sclip;
SetLastError(0xdeadbeef);
hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
- "emf_clipping", TRUE) != 0)
+ "emf_clipping", FALSE) != 0)
{
dump_emf_bits(hemf, "emf_clipping");
dump_emf_records(hemf, "emf_clipping");
DeleteEnhMetaFile(hemf);
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
+
+ hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
+
+ SetRect(&rc_sclip, 100, 100, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
+ hrgn = CreateRectRgn(rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom);
+ SelectClipRgn(hdc, hrgn);
+ ret = GetClipBox(hdc, &rc_res);
+todo_wine
+ ok(ret == SIMPLEREGION, "got %d\n", ret);
+ if(ret == SIMPLEREGION)
+ ok(EqualRect(&rc_res, &rc_sclip),
+ "expected rc_res (%d, %d) - (%d, %d), got (%d, %d) - (%d, %d)\n",
+ rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom,
+ rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
+
+ hemf = CloseEnhMetaFile(hdc);
+ DeleteEnhMetaFile(hemf);
+ DeleteObject(hrgn);
+ DeleteDC(hdc);
}
static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
{
HDC hdcMf;
HMETAFILE hmf;
+ HENHMETAFILE hemf;
BOOL ret;
UINT size;
LPBYTE pBits;
pBits = HeapAlloc(GetProcessHeap(), 0, size);
GetMetaFileBitsEx(hmf, size, pBits);
DeleteMetaFile(hmf);
- return SetWinMetaFileBits(size, pBits, NULL, mfp);
+ hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
+ HeapFree(GetProcessHeap(), 0, pBits);
+ return hemf;
}
static void test_mf_conversions(void)
ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
dc = CreateCompatibleDC(NULL);
+
+ /* Allow 1 mm difference (rounding errors) */
+ diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2;
+ diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2;
+ if (diffx < 0) diffx = -diffx;
+ if (diffy < 0) diffy = -diffy;
todo_wine
{
- ok(rclBoundsAnisotropic.right == GetDeviceCaps(dc, HORZRES) / 2 - 1 &&
- rclBoundsAnisotropic.bottom == GetDeviceCaps(dc, VERTRES) / 2 - 1,
+ ok(diffx <= 1 && diffy <= 1,
"SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
- GetDeviceCaps(dc, HORZRES) / 2 - 1, GetDeviceCaps(dc, VERTRES) / 2 - 1, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
+ GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
}
/* Allow 1 mm difference (rounding errors) */
HeapFree(GetProcessHeap(), 0, buffer);
}
+static BOOL near_match(int x, int y)
+{
+ int epsilon = min(abs(x), abs(y));
+
+ epsilon = max(epsilon/100, 2);
+
+ if(x < y - epsilon || x > y + epsilon) return FALSE;
+ return TRUE;
+}
+
+static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
+{
+ HENHMETAFILE emf;
+ HDC display_dc, emf_dc;
+ ENHMETAHEADER *enh_header;
+ UINT size, emf_size, i;
+ WORD check = 0;
+ DWORD rec_num = 0;
+ METAHEADER *mh = NULL;
+ METARECORD *rec;
+ INT horz_res, vert_res, horz_size, vert_size;
+
+ display_dc = GetDC(NULL);
+ ok(display_dc != NULL, "display_dc is NULL\n");
+
+ horz_res = GetDeviceCaps(display_dc, HORZRES);
+ vert_res = GetDeviceCaps(display_dc, VERTRES);
+ horz_size = GetDeviceCaps(display_dc, HORZSIZE);
+ vert_size = GetDeviceCaps(display_dc, VERTSIZE);
+
+ emf_dc = CreateEnhMetaFileA(display_dc, NULL, rc, NULL);
+ ok(emf_dc != NULL, "emf_dc is NULL\n");
+ for(i = 0; i < 3000; i++) /* This is enough to take emf_size > 0xffff */
+ Rectangle(emf_dc, 0, 0, 1000, 20);
+ emf = CloseEnhMetaFile(emf_dc);
+ ok(emf != NULL, "emf is NULL\n");
+
+ emf_size = GetEnhMetaFileBits(emf, 0, NULL);
+ enh_header = HeapAlloc(GetProcessHeap(), 0, emf_size);
+ emf_size = GetEnhMetaFileBits(emf, emf_size, (BYTE*)enh_header);
+ DeleteEnhMetaFile(emf);
+ /* multiply szlDevice.cx by scale, when scale != 1 the recording and playback dcs
+ have different resolutions */
+ enh_header->szlDevice.cx *= scale;
+ emf = SetEnhMetaFileBits(emf_size, (BYTE*)enh_header);
+ ok(emf != NULL, "emf is NULL\n");
+ ok(EqualRect((RECT*)&enh_header->rclFrame, rc), "Frame rectangles differ\n");
+
+ size = GetWinMetaFileBits(emf, 0, NULL, mode, display_dc);
+ ok(size ||
+ broken(size == 0), /* some versions of winxp fail for some reason */
+ "GetWinMetaFileBits returns 0\n");
+ if(!size) goto end;
+ mh = HeapAlloc(GetProcessHeap(), 0, size);
+ GetWinMetaFileBits(emf, size, (BYTE*)mh, mode, display_dc);
+
+ for(i = 0; i < size / 2; i++) check += ((WORD*)mh)[i];
+ ok(check == 0, "check %04x\n", check);
+
+ rec = (METARECORD*)(mh + 1);
+
+ while(rec->rdSize && rec->rdFunction)
+ {
+ const DWORD chunk_size = 0x2000;
+ DWORD mfcomment_chunks = (emf_size + chunk_size - 1) / chunk_size;
+
+ if(rec_num < mfcomment_chunks)
+ {
+ DWORD this_chunk_size = chunk_size;
+
+ if(rec_num == mfcomment_chunks - 1)
+ this_chunk_size = emf_size - rec_num * chunk_size;
+
+ ok(rec->rdSize == (this_chunk_size + 44) / 2, "%04x: got %04x expected %04x\n", rec_num, rec->rdSize, (this_chunk_size + 44) / 2);
+ ok(rec->rdFunction == META_ESCAPE, "%04x: got %04x\n", rec_num, rec->rdFunction);
+ if(rec->rdSize < (this_chunk_size + 44) / 2) break;
+ ok(rec->rdParm[0] == MFCOMMENT, "got %04x\n", rec->rdParm[0]);
+ ok(rec->rdParm[1] == this_chunk_size + 34, "got %04x %x\n", rec->rdParm[1], emf_size + 34);
+ ok(rec->rdParm[2] == 0x4d57, "got %04x\n", rec->rdParm[2]); /* WMFC */
+ ok(rec->rdParm[3] == 0x4346, "got %04x\n", rec->rdParm[3]); /* " */
+ ok(rec->rdParm[4] == 1, "got %04x\n", rec->rdParm[4]);
+ ok(rec->rdParm[5] == 0, "got %04x\n", rec->rdParm[5]);
+ ok(rec->rdParm[6] == 0, "got %04x\n", rec->rdParm[6]);
+ ok(rec->rdParm[7] == 1, "got %04x\n", rec->rdParm[7]);
+ /* parm[8] is the checksum, tested above */
+ if(rec_num > 0) ok(rec->rdParm[8] == 0, "got %04x\n", rec->rdParm[8]);
+ ok(rec->rdParm[9] == 0, "got %04x\n", rec->rdParm[9]);
+ ok(rec->rdParm[10] == 0, "got %04x\n", rec->rdParm[10]);
+ ok(rec->rdParm[11] == mfcomment_chunks, "got %04x\n", rec->rdParm[11]); /* num chunks */
+ ok(rec->rdParm[12] == 0, "got %04x\n", rec->rdParm[12]);
+ ok(rec->rdParm[13] == this_chunk_size, "got %04x expected %04x\n", rec->rdParm[13], this_chunk_size);
+ ok(rec->rdParm[14] == 0, "got %04x\n", rec->rdParm[14]);
+ ok(*(DWORD*)(rec->rdParm + 15) == emf_size - this_chunk_size - rec_num * chunk_size, "got %08x\n", *(DWORD*)(rec->rdParm + 15)); /* DWORD size remaining after current chunk */
+ ok(*(DWORD*)(rec->rdParm + 17) == emf_size, "got %08x emf_size %08x\n", *(DWORD*)(rec->rdParm + 17), emf_size);
+ ok(!memcmp(rec->rdParm + 19, (char*)enh_header + rec_num * chunk_size, this_chunk_size), "bits mismatch\n");
+ }
+
+ else if(rec_num == mfcomment_chunks)
+ {
+ ok(rec->rdFunction == META_SETMAPMODE, "got %04x\n", rec->rdFunction);
+ ok(rec->rdParm[0] == mode, "got %04x\n", rec->rdParm[0]);
+ }
+ else if(rec_num == mfcomment_chunks + 1)
+ {
+ POINT pt;
+ ok(rec->rdFunction == META_SETWINDOWORG, "got %04x\n", rec->rdFunction);
+ switch(mode)
+ {
+ case MM_TEXT:
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ pt.y = MulDiv(rc->top, vert_res, vert_size * 100) + 1;
+ pt.x = MulDiv(rc->left, horz_res, horz_size * 100);
+ break;
+ case MM_LOMETRIC:
+ pt.y = MulDiv(-rc->top, 1, 10) + 1;
+ pt.x = MulDiv( rc->left, 1, 10);
+ break;
+ case MM_HIMETRIC:
+ pt.y = -rc->top + 1;
+ pt.x = (rc->left >= 0) ? rc->left : rc->left + 1; /* strange but true */
+ break;
+ case MM_LOENGLISH:
+ pt.y = MulDiv(-rc->top, 10, 254) + 1;
+ pt.x = MulDiv( rc->left, 10, 254);
+ break;
+ case MM_HIENGLISH:
+ pt.y = MulDiv(-rc->top, 100, 254) + 1;
+ pt.x = MulDiv( rc->left, 100, 254);
+ break;
+ case MM_TWIPS:
+ pt.y = MulDiv(-rc->top, 72 * 20, 2540) + 1;
+ pt.x = MulDiv( rc->left, 72 * 20, 2540);
+ break;
+ default:
+ pt.x = pt.y = 0;
+ }
+ ok(near_match((short)rec->rdParm[0], pt.y), "got %d expect %d\n", (short)rec->rdParm[0], pt.y);
+ ok(near_match((short)rec->rdParm[1], pt.x), "got %d expect %d\n", (short)rec->rdParm[1], pt.x);
+ }
+ if(rec_num == mfcomment_chunks + 2)
+ {
+ ok(rec->rdFunction == META_SETWINDOWEXT, "got %04x\n", rec->rdFunction);
+ ok(near_match((short)rec->rdParm[0], MulDiv(rc->bottom - rc->top, vert_res, vert_size * 100)),
+ "got %d\n", (short)rec->rdParm[0]);
+ ok(near_match((short)rec->rdParm[1], MulDiv(rc->right - rc->left, horz_res, horz_size * 100)),
+ "got %d\n", (short)rec->rdParm[1]);
+ }
+
+ rec_num++;
+ rec = (METARECORD*)((WORD*)rec + rec->rdSize);
+ }
+
+end:
+ HeapFree(GetProcessHeap(), 0, mh);
+ HeapFree(GetProcessHeap(), 0, enh_header);
+ DeleteEnhMetaFile(emf);
+
+ ReleaseDC(NULL, display_dc);
+}
+
+static void test_GetWinMetaFileBits(void)
+{
+ UINT mode;
+ RECT frames[] =
+ {
+ { 1000, 2000, 3000, 6000},
+ {-1000, 2000, 3000, 6000},
+ { 1000, -2000, 3000, 6000},
+ { 1005, 2005, 3000, 6000},
+ {-1005, -2005, 3000, 6000},
+ {-1005, -2010, 3000, 6000},
+ {-1005, 2010, 3000, 6000},
+ { 0, 0, 1, 1},
+ { -1, -1, 1, 1},
+ { 0, 0, 0, 0}
+ };
+
+ for(mode = MM_MIN; mode <= MM_MAX; mode++)
+ {
+ RECT *rc;
+ trace("mode %d\n", mode);
+
+ for(rc = frames; rc->right - rc->left > 0; rc++)
+ {
+ trace("frame %d,%d - %d,%d\n", rc->left, rc->top, rc->right, rc->bottom);
+ getwinmetafilebits(mode, 1, rc);
+ getwinmetafilebits(mode, 2, rc);
+ }
+ }
+}
+
static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
- /* they should all exist or none should exist */
- if(!pGdiIsMetaPrintDC)
+ if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC)
+ {
+ win_skip("Needed GdiIs* functions are not available\n");
return;
+ }
/* try with nothing */
ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
SetLastError(0xdeadbeef);
hemf = SetEnhMetaFileBits(sizeof(data), data);
ok(!hemf, "SetEnhMetaFileBits should fail\n");
- ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA, got %u\n", GetLastError());
+ ok(GetLastError() == ERROR_INVALID_DATA ||
+ GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
+ "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
emh = (ENHMETAHEADER *)data;
memset(emh, 0, sizeof(*emh));
emh->nBytes++;
SetLastError(0xdeadbeef);
hemf = SetEnhMetaFileBits(emh->nBytes, data);
- ok(!hemf, "SetEnhMetaFileBits should fail\n");
- /* XP doesn't set error in this case */
+ ok(!hemf ||
+ broken(hemf != NULL), /* Win9x, WinMe */
+ "SetEnhMetaFileBits should fail\n");
+ ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
+ DeleteEnhMetaFile(hemf);
emh->dSignature = 0;
emh->nBytes--;
SetLastError(0xdeadbeef);
hemf = SetEnhMetaFileBits(emh->nBytes, data);
- ok(!hemf, "SetEnhMetaFileBits should fail\n");
- /* XP doesn't set error in this case */
+ ok(!hemf ||
+ broken(hemf != NULL), /* Win9x, WinMe */
+ "SetEnhMetaFileBits should fail\n");
+ ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
+ DeleteEnhMetaFile(hemf);
}
START_TEST(metafile)
/* For enhanced metafiles (enhmfdrv) */
test_ExtTextOut();
test_SaveDC();
+ test_emf_BitBlt();
/* For win-format metafiles (mfdrv) */
+ test_mf_SaveDC();
test_mf_Blank();
test_mf_Graphics();
test_mf_PatternBrush();
/* For metafile conversions */
test_mf_conversions();
test_SetWinMetaFileBits();
+ test_GetWinMetaFileBits();
test_gdiis();
test_SetEnhMetaFileBits();