Update some gdi32 winetest
[reactos.git] / reactos / regtests / winetests / gdi32 / metafile.c
index 17f0138..3610bf8 100755 (executable)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <assert.h>
@@ -35,7 +35,28 @@ static BOOL emr_processed = FALSE;
 #define LINE_X 55.0f
 #define LINE_Y 15.0f
 
-static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
+static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
+static INT (WINAPI * pSetRelAbs)(HDC, INT);
+
+#define GDI_GET_PROC(func)                                     \
+    p ## func = (void *)GetProcAddress(hGDI, #func);           \
+    if(!p ## func)                                             \
+        trace("GetProcAddress(hGDI, \"%s\") failed\n", #func); \
+
+static void init_function_pointers(void)
+{
+    HMODULE hGDI;
+
+    pGetRelAbs = NULL;
+    pSetRelAbs = NULL;
+
+    hGDI = GetModuleHandleA("gdi32.dll");
+    assert(hGDI);
+    GDI_GET_PROC(GetRelAbs);
+    GDI_GET_PROC(SetRelAbs);
+}
+
+static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
     const ENHMETARECORD *emr, int n_objs, LPARAM param)
 {
     static int n_record;
@@ -55,6 +76,19 @@ static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
     switch (emr->iType)
     {
     case EMR_HEADER:
+        ok(GetTextAlign(hdc) == 0, "text align %08x\n", GetTextAlign(hdc));
+        ok(GetBkColor(hdc) == RGB(0xff, 0xff, 0xff), "bk color %08lx\n", GetBkColor(hdc));
+        ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08lx\n", GetTextColor(hdc));
+        ok(GetROP2(hdc) == R2_COPYPEN, "rop %d\n", GetROP2(hdc));
+        ok(GetArcDirection(hdc) == AD_COUNTERCLOCKWISE, "arc dir %d\n", GetArcDirection(hdc));
+        ok(GetPolyFillMode(hdc) == ALTERNATE, "poly fill %d\n", GetPolyFillMode(hdc));
+        ok(GetStretchBltMode(hdc) == BLACKONWHITE, "stretchblt mode %d\n", GetStretchBltMode(hdc));
+
+        /* GetBkMode, GetRelAbs do not get reset to the default value */
+        ok(GetBkMode(hdc) == OPAQUE, "bk mode %d\n", GetBkMode(hdc));
+        if(pSetRelAbs && pGetRelAbs)
+            ok(pGetRelAbs(hdc, 0) == RELATIVE, "relabs %d\n", pGetRelAbs(hdc, 0));
+
         n_record = 0;
         break;
 
@@ -189,21 +223,147 @@ static void test_ExtTextOut(void)
     ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
     ok( ret, "PlayEnhMetaFile error %ld\n", GetLastError());
 
-    ret = EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, &rc);
+    SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
+    SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
+    SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
+    SetROP2(hdcDisplay, R2_NOT);
+    SetArcDirection(hdcDisplay, AD_CLOCKWISE);
+    SetPolyFillMode(hdcDisplay, WINDING);
+    SetStretchBltMode(hdcDisplay, HALFTONE);
+
+    if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
+    SetBkMode(hdcDisplay, OPAQUE);
+
+    ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
     ok( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
 
+    ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
+        "text align %08x\n", GetTextAlign(hdcDisplay));
+    ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08lx\n", GetBkColor(hdcDisplay));
+    ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08lx\n", GetTextColor(hdcDisplay));
+    ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
+    ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir  %d\n", GetArcDirection(hdcDisplay));
+    ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
+    ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
+
     ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
 
-    ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, NULL),
+    ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
        "A valid hdc has to require a valid rc\n");
 
-    ok(EnumEnhMetaFile(NULL, hMetafile, emf_enum_proc, dx, NULL),
+    ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
        "A null hdc does not require a valid rc\n");
 
     ret = DeleteEnhMetaFile(hMetafile);
     ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
     ret = ReleaseDC(hwnd, hdcDisplay);
     ok( ret, "ReleaseDC error %ld\n", GetLastError());
+    DestroyWindow(hwnd);
+}
+
+static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
+                                         const ENHMETARECORD *emr, int n_objs, LPARAM param)
+{
+    static int save_state;
+    static int restore_no;
+
+    switch (emr->iType)
+    {
+    case EMR_HEADER:
+        save_state = 0;
+        restore_no = 0;
+        break;
+
+    case EMR_SAVEDC:
+        save_state++;
+        break;
+
+    case EMR_RESTOREDC:
+        {
+            EMRRESTOREDC *restoredc = (EMRRESTOREDC *)emr;
+            switch(++restore_no)
+            {
+            case 1:
+                ok(restoredc->iRelative == -1, "first restore %ld\n", restoredc->iRelative);
+                break;
+
+            case 2:
+                ok(restoredc->iRelative == -3, "second restore %ld\n", restoredc->iRelative);
+                break;
+            case 3:
+                ok(restoredc->iRelative == -2, "third restore %ld\n", restoredc->iRelative);
+                break;
+            }
+            ok(restore_no <= 3, "restore_no %d\n", restore_no);
+            save_state += restoredc->iRelative;
+            break;
+        }
+    case EMR_EOF:
+        ok(save_state == 0, "EOF save_state %d\n", save_state);
+        break;
+    }
+
+
+    return 1;        
+}
+
+void test_SaveDC(void)
+{
+    HDC hdcMetafile, hdcDisplay;
+    HENHMETAFILE hMetafile;
+    HWND hwnd;
+    int ret;
+    static const RECT rc = { 0, 0, 100, 100 };
+
+    /* Win9x doesn't play EMFs on invisible windows */
+    hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
+                           0, 0, 200, 200, 0, 0, 0, NULL);
+    ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
+
+    hdcDisplay = GetDC(hwnd);
+    ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
+
+    hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+    ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
+
+    /* Need to write something to the emf, otherwise Windows won't play it back */
+    LineTo(hdcMetafile, 100, 100);
+
+    ret = SaveDC(hdcMetafile);
+    ok(ret == 1, "ret = %d\n", ret);
+
+    ret = SaveDC(hdcMetafile);
+    ok(ret == 2, "ret = %d\n", ret);
+
+    ret = SaveDC(hdcMetafile);
+    ok(ret == 3, "ret = %d\n", ret);
+
+    ret = RestoreDC(hdcMetafile, -1);
+    ok(ret, "ret = %d\n", ret);
+
+    ret = SaveDC(hdcMetafile);
+    ok(ret == 3, "ret = %d\n", ret);
+
+    ret = RestoreDC(hdcMetafile, 1);
+    ok(ret, "ret = %d\n", ret);
+
+    ret = SaveDC(hdcMetafile);
+    ok(ret == 1, "ret = %d\n", ret);
+
+    ret = SaveDC(hdcMetafile);
+    ok(ret == 2, "ret = %d\n", ret);
+
+    hMetafile = CloseEnhMetaFile(hdcMetafile);
+    ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
+
+    ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
+    ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
+
+    ret = DeleteEnhMetaFile(hMetafile);
+    ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
+    ret = ReleaseDC(hwnd, hdcDisplay);
+    ok( ret, "ReleaseDC error %ld\n", GetLastError());
+    DestroyWindow(hwnd);
 }
 
 /* Win-format metafile (mfdrv) tests */
@@ -211,7 +371,7 @@ static void test_ExtTextOut(void)
 /* with the nominal results. */
 
 /* Maximum size of sample metafiles in bytes. */
-#define MF_BUFSIZE 256
+#define MF_BUFSIZE 512
 
 /* 8x8 bitmap data for a pattern brush */
 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
@@ -262,22 +422,205 @@ static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
     0x00, 0x00
 };
 
+static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
+{
+    0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
+    0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
+    0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0x00
+};
+
+static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
+{
+    0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
+    0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+    0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
+    0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+    0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
+    0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
+    0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+    0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+    0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char MF_LINETO_BITS[] = {
+    0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
+    0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0x00
+};
+
+static const unsigned char EMF_LINETO_BITS[] = {
+    0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
+    0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+    0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
+    0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
+    0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+    0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
+    0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
+    0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
+    0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+    0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+    0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+    0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+    0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
+    0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+    0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+    0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
+    0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
+    0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+    0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
+    0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
+    0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
+    0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+    0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+    0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+    0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+    0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
+    0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
+    0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+    0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
+    0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+    0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+    0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
+    0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
+    0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
+    0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x05, 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.
+ */
+static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
+                                 INT nobj, LPARAM param)
+{
+    trace("hdc %p, mr->rdFunction %04x, mr->rdSize %lu, param %p\n",
+           hdc, mr->rdFunction, mr->rdSize, (void *)param);
+    return TRUE;
+}
+
 /* For debugging or dumping the raw metafiles produced by
  * new test functions.
  */
 
 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
 {
-    char buf[MF_BUFSIZE];
+    BYTE buf[MF_BUFSIZE];
     UINT mfsize, i;
 
+    if (!winetest_debug) return;
+
     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
 
     printf ("MetaFile %s has bits:\n{\n    ", desc);
     for (i=0; i<mfsize; i++)
     {
-        printf ("0x%.2hhx", buf[i]);
+        printf ("0x%02x", buf[i]);
         if (i == mfsize-1)
             printf ("\n");
         else if (i % 8 == 7)
@@ -295,10 +638,10 @@ static void dump_mf_bits (const HMETAFILE mf, const char *desc)
  * otherwise returns the number of non-matching bytes.
  */
 
-static int compare_mf_bits (const HMETAFILE mf, const char *bits, UINT bsize,
+static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
     const char *desc)
 {
-    char buf[MF_BUFSIZE];
+    unsigned char buf[MF_BUFSIZE];
     UINT mfsize, i;
     int diff;
 
@@ -325,6 +668,150 @@ static int compare_mf_bits (const HMETAFILE mf, const char *bits, UINT bsize,
     return diff; 
 }
 
+static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
+{
+    unsigned char buf[MF_BUFSIZE];
+    DWORD mfsize, rd_size, i;
+    int diff;
+    HANDLE hfile;
+    BOOL ret;
+
+    hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+    assert(hfile != INVALID_HANDLE_VALUE);
+
+    mfsize = GetFileSize(hfile, NULL);
+    assert(mfsize <= MF_BUFSIZE);
+
+    ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
+    ok( ret && rd_size == mfsize, "ReadFile: error %ld\n", GetLastError());
+
+    CloseHandle(hfile);
+
+    ok(mfsize == bsize, "%s: mfsize=%ld, bsize=%d.\n", desc, mfsize, bsize);
+
+    if (mfsize != bsize)
+        return -1;
+
+    diff = 0;
+    for (i=0; i<bsize; i++)
+    {
+        if (buf[i] != bits[i])
+            diff++;
+    }
+    ok(diff == 0, "%s: mfsize=%ld, bsize=%d, diff=%d\n",
+        desc, mfsize, bsize, diff);
+
+    return diff; 
+}
+
+/* For debugging or dumping the raw EMFs produced by
+ * new test functions.
+ */
+static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
+{
+    BYTE buf[MF_BUFSIZE];
+    UINT mfsize, i;
+
+    if (!winetest_debug) return;
+
+    mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+    ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
+
+    printf("EMF %s has bits:\n{\n    ", desc);
+    for (i = 0; i < mfsize; i++)
+    {
+        printf ("0x%02x", buf[i]);
+        if (i == mfsize-1)
+            printf ("\n");
+        else if (i % 8 == 7)
+            printf (",\n    ");
+        else
+            printf (", ");
+    }
+    printf ("};\n");
+}
+
+static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
+{
+    BYTE *emf;
+    BYTE buf[MF_BUFSIZE];
+    UINT mfsize, offset;
+
+    if (!winetest_debug) return;
+
+    mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+    ok (mfsize > 0, "%s: GetEnhMetaFileBits error %ld\n", desc, GetLastError());
+
+    printf("EMF %s has records:\n", desc);
+
+    emf = buf;
+    offset = 0;
+    while(offset < mfsize)
+    {
+        EMR *emr = (EMR *)(emf + offset);
+        printf("emr->iType %ld, emr->nSize %lu\n", emr->iType, emr->nSize);
+        /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
+        offset += emr->nSize;
+    }
+}
+
+/* Compare the EMF produced by a test function with the
+ * expected raw EMF data in "bits".
+ * Return value is 0 for a perfect match,
+ * -1 if lengths aren't equal,
+ * 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)
+{
+    unsigned char buf[MF_BUFSIZE];
+    UINT mfsize, i;
+    int diff;
+
+    mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+    ok (mfsize > 0, "%s: GetEnhMetaFileBits error %ld\n", desc, GetLastError());
+
+    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);
+    }
+    else
+        ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
+           desc, mfsize, bsize);
+
+    if (mfsize != bsize)
+        return -1;
+
+    diff = 0;
+    for (i = 0; i < bsize; i++)
+    {
+       if (buf[i] != bits[i])
+           diff++;
+    }
+    if (diff != 0 && todo)
+    {
+        todo_wine
+        {
+            ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
+               desc, mfsize, bsize, diff);
+        }
+        return diff;
+    }
+    else
+    {
+        ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
+           desc, mfsize, bsize, diff);
+
+        return diff;
+    }
+}
+
 /* Test a blank metafile.  May be used as a template for new tests. */
 
 static void test_mf_Blank(void)
@@ -333,6 +820,7 @@ static void test_mf_Blank(void)
     HMETAFILE hMetafile;
     INT caps;
     BOOL ret;
+    INT type;
 
     hdcMetafile = CreateMetaFileA(NULL);
     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
@@ -345,14 +833,153 @@ static void test_mf_Blank(void)
 
     hMetafile = CloseMetaFile(hdcMetafile);
     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+    type = GetObjectType(hMetafile);
+    ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
 
     if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
         "mf_blank") != 0)
-            dump_mf_bits (hMetafile, "mf_Blank");
+    {
+        dump_mf_bits(hMetafile, "mf_Blank");
+        EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+    }
+
+    ret = DeleteMetaFile(hMetafile);
+    ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
+}
+
+static void test_CopyMetaFile(void)
+{
+    HDC hdcMetafile;
+    HMETAFILE hMetafile, hmf_copy;
+    BOOL ret;
+    char temp_path[MAX_PATH];
+    char mf_name[MAX_PATH];
+    INT type;
+
+    hdcMetafile = CreateMetaFileA(NULL);
+    ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
+    trace("hdcMetafile %p\n", hdcMetafile);
+
+    hMetafile = CloseMetaFile(hdcMetafile);
+    ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+    type = GetObjectType(hMetafile);
+    ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
+
+    if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
+        "mf_blank") != 0)
+    {
+        dump_mf_bits(hMetafile, "mf_Blank");
+        EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+    }
+
+    GetTempPathA(MAX_PATH, temp_path);
+    GetTempFileNameA(temp_path, "wmf", 0, mf_name);
+
+    hmf_copy = CopyMetaFileA(hMetafile, mf_name);
+    ok(hmf_copy != 0, "CopyMetaFile error %ld\n", GetLastError());
+
+    type = GetObjectType(hmf_copy);
+    ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
 
     ret = DeleteMetaFile(hMetafile);
     ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
+
+    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);
+    }
+
+    ret = DeleteMetaFile(hmf_copy);
+    ok( ret, "DeleteMetaFile(%p) error %ld\n", hmf_copy, GetLastError());
+
+    DeleteFileA(mf_name);
+}
+
+static void test_SetMetaFileBits(void)
+{
+    HMETAFILE hmf;
+    INT type;
+    BOOL ret;
+    BYTE buf[256];
+    METAHEADER *mh;
+
+    hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
+    ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
+    type = GetObjectType(hmf);
+    ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
+
+    if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+    {
+        dump_mf_bits(hmf, "mf_Graphics");
+        EnumMetaFile(0, hmf, mf_enum_proc, 0);
+    }
+
+    ret = DeleteMetaFile(hmf);
+    ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
+
+    /* NULL data crashes XP SP1 */
+    /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
+
+    /* Now with not zero size */
+    SetLastError(0xdeadbeef);
+    hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
+    ok(!hmf, "SetMetaFileBitsEx should fail\n");
+    ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %ld\n", GetLastError());
+
+    /* Now with not even size */
+    SetLastError(0xdeadbeef);
+    hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
+    ok(!hmf, "SetMetaFileBitsEx should fail\n");
+    ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %ld\n", GetLastError());
+
+    /* Now with zeroed out or faked some header fields */
+    assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
+    memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
+    mh = (METAHEADER *)buf;
+    /* corruption of any of the below fields leads to a failure */
+    mh->mtType = 0;
+    mh->mtVersion = 0;
+    mh->mtHeaderSize = 0;
+    SetLastError(0xdeadbeef);
+    hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+    ok(!hmf, "SetMetaFileBitsEx should fail\n");
+    ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %ld\n", GetLastError());
+
+    /* Now with corrupted mtSize field */
+    memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
+    mh = (METAHEADER *)buf;
+    /* corruption of mtSize doesn't lead to a failure */
+    mh->mtSize *= 2;
+    hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+    ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
+
+    if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+    {
+        dump_mf_bits(hmf, "mf_Graphics");
+        EnumMetaFile(0, hmf, mf_enum_proc, 0);
+    }
+
+    ret = DeleteMetaFile(hmf);
+    ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
+
+    /* Now with zeroed out mtSize field */
+    memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
+    mh = (METAHEADER *)buf;
+    /* zeroing mtSize doesn't lead to a failure */
+    mh->mtSize = 0;
+    hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+    ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
+
+    if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+    {
+        dump_mf_bits(hmf, "mf_Graphics");
+        EnumMetaFile(0, hmf, mf_enum_proc, 0);
+    }
+
+    ret = DeleteMetaFile(hmf);
+    ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
 }
 
 /* Simple APIs from mfdrv/graphics.c
@@ -393,7 +1020,10 @@ static void test_mf_Graphics(void)
 
     if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
         "mf_Graphics") != 0)
-            dump_mf_bits (hMetafile, "mf_Graphics");
+    {
+        dump_mf_bits(hMetafile, "mf_Graphics");
+        EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+    }
 
     ret = DeleteMetaFile(hMetafile);
     ok( ret, "DeleteMetaFile(%p) error %ld\n",
@@ -412,8 +1042,8 @@ static void test_mf_PatternBrush(void)
 
     orig_lb->lbStyle = BS_PATTERN;
     orig_lb->lbColor = RGB(0, 0, 0);
-    orig_lb->lbHatch = (INT) CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
-    ok((HBITMAP *)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
+    orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
+    ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
 
     hBrush = CreateBrushIndirect (orig_lb);
     ok(hBrush != 0, "CreateBrushIndirect error %ld\n", GetLastError());
@@ -431,18 +1061,103 @@ static void test_mf_PatternBrush(void)
 
     if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
         "mf_Pattern_Brush") != 0)
-            dump_mf_bits (hMetafile, "mf_Pattern_Brush");
+    {
+        dump_mf_bits(hMetafile, "mf_Pattern_Brush");
+        EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+    }
 
     ret = DeleteMetaFile(hMetafile);
     ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
     ret = DeleteObject(hBrush);
     ok( ret, "DeleteObject(HBRUSH) error %ld\n", GetLastError());
-    ret = DeleteObject((HBITMAP *)orig_lb->lbHatch);
+    ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
     ok( ret, "DeleteObject(HBITMAP) error %ld\n",
         GetLastError());
     HeapFree (GetProcessHeap(), 0, orig_lb);
 }
 
+static void test_mf_ExtTextOut_on_path(void)
+{
+    HDC hdcMetafile;
+    HMETAFILE hMetafile;
+    BOOL ret;
+    static const INT dx[4] = { 3, 5, 8, 12 };
+
+    hdcMetafile = CreateMetaFileA(NULL);
+    ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
+    trace("hdcMetafile %p\n", hdcMetafile);
+
+    ret = BeginPath(hdcMetafile);
+    ok(!ret, "BeginPath on metafile DC should fail\n");
+
+    ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
+    ok(ret, "ExtTextOut error %ld\n", GetLastError());
+
+    ret = EndPath(hdcMetafile);
+    ok(!ret, "EndPath on metafile DC should fail\n");
+
+    hMetafile = CloseMetaFile(hdcMetafile);
+    ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+
+    if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
+        "mf_TextOut_on_path") != 0)
+    {
+        dump_mf_bits(hMetafile, "mf_TextOut_on_path");
+        EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+    }
+
+    ret = DeleteMetaFile(hMetafile);
+    ok(ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
+}
+
+static void test_emf_ExtTextOut_on_path(void)
+{
+    HWND hwnd;
+    HDC hdcDisplay, hdcMetafile;
+    HENHMETAFILE hMetafile;
+    BOOL ret;
+    static const INT dx[4] = { 3, 5, 8, 12 };
+
+    /* Win9x doesn't play EMFs on invisible windows */
+    hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
+                           0, 0, 200, 200, 0, 0, 0, NULL);
+    ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
+
+    hdcDisplay = GetDC(hwnd);
+    ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
+
+    hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+    ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
+
+    ret = BeginPath(hdcMetafile);
+    ok(ret, "BeginPath error %ld\n", GetLastError());
+
+    ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
+    ok(ret, "ExtTextOut error %ld\n", GetLastError());
+
+    ret = EndPath(hdcMetafile);
+    ok(ret, "EndPath error %ld\n", GetLastError());
+
+    hMetafile = CloseEnhMetaFile(hdcMetafile);
+    ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
+
+    /* this doesn't succeed yet: EMF has correct size, all EMF records
+     * 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)
+    {
+        dump_emf_bits(hMetafile, "emf_TextOut_on_path");
+        dump_emf_records(hMetafile, "emf_TextOut_on_path");
+    }
+
+    ret = DeleteEnhMetaFile(hMetafile);
+    ok(ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
+    ret = ReleaseDC(hwnd, hdcDisplay);
+    ok(ret, "ReleaseDC error %ld\n", GetLastError());
+    DestroyWindow(hwnd);
+}
+
 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
 {
     LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
@@ -451,7 +1166,10 @@ static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETAREC
      * until a record is played which actually outputs something */
     PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
     LPtoDP(hdc, mapping, 2);
-    trace("Meta record: iType = %ld, (%ld,%ld)-(%ld,%ld)\n", lpEMFR->iType, mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
+    trace("Meta record: iType %ld, nSize %ld, (%ld,%ld)-(%ld,%ld)\n",
+           lpEMFR->iType, lpEMFR->nSize,
+           mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
+
     if (lpEMFR->iType == EMR_LINETO)
     {
         INT x0, y0, x1, y1;
@@ -493,6 +1211,13 @@ static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
     ok(ret, "LineTo failed with error %ld\n", GetLastError());
     hmf = CloseMetaFile(hdcMf);
     ok(hmf != NULL, "CloseMetaFile failed with error %ld\n", GetLastError());
+
+    if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
+    {
+        dump_mf_bits(hmf, "mf_LineTo");
+        EnumMetaFile(0, hmf, mf_enum_proc, 0);
+    }
+
     size = GetMetaFileBitsEx(hmf, 0, NULL);
     ok(size, "GetMetaFileBitsEx failed with error %ld\n", GetLastError());
     pBits = HeapAlloc(GetProcessHeap(), 0, size);
@@ -514,7 +1239,16 @@ static void test_mf_conversions(void)
         mfp.yExt = 100;
         mfp.hMF = NULL;
         hemf = create_converted_emf(&mfp);
+
+        if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
+                             "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
+        {
+            dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
+            dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
+        }
+
         EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
+
         DeleteEnhMetaFile(hemf);
         DeleteDC(hdcOffscreen);
     }
@@ -530,7 +1264,16 @@ static void test_mf_conversions(void)
         mfp.yExt = 0;
         mfp.hMF = NULL;
         hemf = create_converted_emf(&mfp);
+
+        if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
+                             "emf_LineTo MM_TEXT", TRUE) != 0)
+        {
+            dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
+            dump_emf_records(hemf, "emf_LineTo MM_TEXT");
+        }
+
         EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
+
         DeleteEnhMetaFile(hemf);
         DeleteDC(hdcOffscreen);
     }
@@ -541,12 +1284,232 @@ static void test_mf_conversions(void)
         HENHMETAFILE hemf;
         RECT rect = { 0, 0, 100, 100 };
         hemf = create_converted_emf(NULL);
+
+        if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
+                             "emf_LineTo NULL", TRUE) != 0)
+        {
+            dump_emf_bits(hemf, "emf_LineTo NULL");
+            dump_emf_records(hemf, "emf_LineTo NULL");
+        }
+
         EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
+
         DeleteEnhMetaFile(hemf);
         DeleteDC(hdcOffscreen);
     }
 }
 
+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))
+  {
+    const char * msg;
+    char buf[64];
+
+    if (mfpIsNull)
+    {
+       msg = "mfp == NULL";
+    }
+    else
+    {
+      const 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";
+      }
+      sprintf(buf, "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);
@@ -597,16 +1560,24 @@ static void test_gdiis(void)
 
 START_TEST(metafile)
 {
+    init_function_pointers();
+
     /* For enhanced metafiles (enhmfdrv) */
     test_ExtTextOut();
+    test_SaveDC();
 
     /* For win-format metafiles (mfdrv) */
     test_mf_Blank();
     test_mf_Graphics();
     test_mf_PatternBrush();
+    test_CopyMetaFile();
+    test_SetMetaFileBits();
+    test_mf_ExtTextOut_on_path();
+    test_emf_ExtTextOut_on_path();
 
     /* For metafile conversions */
     test_mf_conversions();
+    test_SetWinMetaFileBits();
 
     test_gdiis();
 }