text: /*
   * Unit tests for metafile functions
   *
   * Copyright (c) 2002 Dmitry Timoshkov
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   */
  
  #include <assert.h>
  #include <stdio.h>
  #include <math.h>
  
  #include "wine/test.h"
  #include "winbase.h"
  #include "wingdi.h"
  #include "winuser.h"
  #include "winerror.h"
  
  static LOGFONTA orig_lf;
  static BOOL emr_processed = FALSE;
  
  /* Arbitrarily chosen values for the second co-ordinate of a metafile line */
  #define LINE_X 55.0f
  #define LINE_Y 15.0f
  
  static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
  static INT (WINAPI * pSetRelAbs)(HDC, INT);
  static COLORREF (WINAPI *pSetDCBrushColor)(HDC,COLORREF);
  static COLORREF (WINAPI *pSetDCPenColor)(HDC,COLORREF);
  
  #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);
      GDI_GET_PROC(SetDCBrushColor);
      GDI_GET_PROC(SetDCPenColor);
  }
  
  static DWORD rgn_rect_count(HRGN hrgn)
  {
      DWORD size;
      RGNDATA *data;
  
      if (!hrgn) return 0;
      if (!(size = GetRegionData(hrgn, 0, NULL))) return 0;
      if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return 0;
      GetRegionData(hrgn, size, data);
      size = data->rdh.nCount;
      HeapFree(GetProcessHeap(), 0, data);
      return size;
  }
  
  static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
      const ENHMETARECORD *emr, int n_objs, LPARAM param)
  {
      static int n_record;
      DWORD i;
      const INT *dx;
      INT *orig_dx = (INT *)param;
      LOGFONTA device_lf;
      INT ret;
  
      if(!hdc) return 1;
  
      PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
  
      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 %08x\n", GetBkColor(hdc));
          ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08x\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;
  
      case EMR_EXTTEXTOUTA:
      {
          const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
          dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
  
          ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
          ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
  
          /* compare up to lfOutPrecision, other values are not interesting,
           * and in fact sometimes arbitrary adapted by Win9x.
           */
          ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
          ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
  
          for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
          {
              ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
                                       n_record, i, dx[i], orig_dx[i]);
          }
          n_record++;
          emr_processed = TRUE;
          break;
      }
  
      case EMR_EXTTEXTOUTW:
      {
          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) ||
              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.
           */
          ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
          ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
  
          ok(!emr_ExtTextOutW->rclBounds.left, "emr_ExtTextOutW->rclBounds.left = %d\n",
                  emr_ExtTextOutW->rclBounds.left);
          ok(emr_ExtTextOutW->rclBounds.right != -1, "emr_ExtTextOutW->rclBounds.right = %d\n",
                  emr_ExtTextOutW->rclBounds.right);
          ok(emr_ExtTextOutW->rclBounds.bottom != -1, "emr_ExtTextOutW->rclBounds.bottom = %d\n",
                  emr_ExtTextOutW->rclBounds.bottom);
  
          for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
          {
              ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
                                       n_record, i, dx[i], orig_dx[i]);
          }
          n_record++;
          emr_processed = TRUE;
          break;
      }
  
      default:
          break;
      }
  
      return 1;
  }
  
  static void test_ExtTextOut(void)
  {
      HWND hwnd;
      HDC hdcDisplay, hdcMetafile;
      HENHMETAFILE hMetafile;
      HFONT hFont;
      static const char text[] = "Simple text to test ExtTextOut on metafiles";
      INT i, len, dx[256];
      static const RECT rc = { 0, 0, 100, 100 };
      BOOL ret;
  
      assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
  
      /* 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 %d\n", GetLastError());
  
      hdcDisplay = GetDC(hwnd);
      ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
  
      trace("hdcDisplay %p\n", hdcDisplay);
  
      SetMapMode(hdcDisplay, MM_TEXT);
  
      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());
  
      hFont = SelectObject(hdcDisplay, hFont);
  
      len = lstrlenA(text);
      for (i = 0; i < len; i++)
      {
          ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
          ok( ret, "GetCharWidthA error %d\n", GetLastError());
      }
      hFont = SelectObject(hdcDisplay, hFont);
  
      hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      trace("hdcMetafile %p\n", hdcMetafile);
  
      ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
         "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
  
      hFont = SelectObject(hdcMetafile, hFont);
  
      /* 1. pass NULL lpDx */
      ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
      ok( ret, "ExtTextOutA error %d\n", GetLastError());
  
      /* 2. pass custom lpDx */
      ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
      ok( ret, "ExtTextOutA error %d\n", GetLastError());
  
      /* 3. pass NULL lprc */
      ret = ExtTextOutA(hdcMetafile, 0, 40, 0, NULL, text, lstrlenA(text), NULL);
      ok( ret, "ExtTextOutA error %d\n", GetLastError());
  
      /* 4. test with unmatched BeginPath/EndPath calls */
      ret = BeginPath(hdcMetafile);
      ok( ret, "BeginPath error %d\n", GetLastError());
      ret = BeginPath(hdcMetafile);
      ok( ret, "BeginPath error %d\n", GetLastError());
      ret = EndPath(hdcMetafile);
      ok( ret, "BeginPath error %d\n", GetLastError());
      ret = ExtTextOutA(hdcMetafile, 0, 60, 0, NULL, text, lstrlenA(text), NULL);
      ok( ret, "ExtTextOutA error %d\n", GetLastError());
  
      hFont = SelectObject(hdcMetafile, hFont);
      ret = DeleteObject(hFont);
      ok( ret, "DeleteObject error %d\n", GetLastError());
  
      hMetafile = CloseEnhMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
      ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
  
      ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
      ok( ret, "PlayEnhMetaFile error %d\n", GetLastError());
  
      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 %d\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 %08x\n", GetBkColor(hdcDisplay));
      ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08x\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, eto_emf_enum_proc, dx, NULL),
         "A valid hdc has to require a valid rc\n");
  
      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 %d\n", GetLastError());
      ret = ReleaseDC(hwnd, hdcDisplay);
      ok( ret, "ReleaseDC error %d\n", GetLastError());
      DestroyWindow(hwnd);
  }
  
  struct eto_scale_test_record
  {
      INT graphics_mode;
      INT map_mode;
      double ex_scale;
      double ey_scale;
      BOOL processed;
  };
  
  static int CALLBACK eto_scale_enum_proc(HDC hdc, HANDLETABLE *handle_table,
      const ENHMETARECORD *emr, int n_objs, LPARAM param)
  {
      struct eto_scale_test_record *test = (struct eto_scale_test_record*)param;
  
      if (emr->iType == EMR_EXTTEXTOUTW)
      {
          const EMREXTTEXTOUTW *pExtTextOutW = (const EMREXTTEXTOUTW *)emr;
          ok(fabs(test->ex_scale - pExtTextOutW->exScale) < 0.001,
             "Got exScale %f, expected %f\n", pExtTextOutW->exScale, test->ex_scale);
          ok(fabs(test->ey_scale - pExtTextOutW->eyScale) < 0.001,
             "Got eyScale %f, expected %f\n", pExtTextOutW->eyScale, test->ey_scale);
          test->processed = TRUE;
      }
  
      return 1;
  }
  
  static void test_ExtTextOutScale(void)
  {
      const RECT rc = { 0, 0, 100, 100 };
      const WCHAR str[] = {'a',0 };
      struct eto_scale_test_record test;
      HDC hdcDisplay, hdcMetafile;
      HENHMETAFILE hMetafile;
      HWND hwnd;
      SIZE wndext, vportext;
      int horzSize, vertSize, horzRes, vertRes;
      int ret;
      int i;
  
      hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
                             0, 0, 200, 200, 0, 0, 0, NULL);
      ok(hwnd != 0, "CreateWindowExA failed\n");
  
      hdcDisplay = GetDC(hwnd);
      ok(hdcDisplay != 0, "GetDC failed\n");
  
      horzSize = GetDeviceCaps(hdcDisplay, HORZSIZE);
      horzRes  = GetDeviceCaps(hdcDisplay, HORZRES);
      vertSize = GetDeviceCaps(hdcDisplay, VERTSIZE);
      vertRes  = GetDeviceCaps(hdcDisplay, VERTRES);
      ok(horzSize && horzRes && vertSize && vertRes, "GetDeviceCaps failed\n");
  
      for (i = 0; i < 16; i++)
      {
          test.graphics_mode = i / 8 + 1;
          test.map_mode      = i % 8 + 1;
  
          ret = SetGraphicsMode(hdcDisplay, test.graphics_mode);
          ok(ret, "SetGraphicsMode failed\n");
          ret = SetMapMode(hdcDisplay, test.map_mode);
          ok(ret, "SetMapMode failed\n");
  
          if ((test.map_mode == MM_ISOTROPIC) || (test.map_mode == MM_ANISOTROPIC))
          {
              ret = SetWindowExtEx(hdcDisplay, 1, 1, NULL);
              ok(ret, "SetWindowExtEx failed\n");
              ret = SetViewportExtEx(hdcDisplay, -20, -10, NULL);
              ok(ret, "SetViewportExtEx failed\n");
          }
  
          ret = GetViewportExtEx(hdcDisplay, &vportext);
          ok(ret, "GetViewportExtEx failed\n");
          ret = GetWindowExtEx(hdcDisplay, &wndext);
          ok(ret, "GetWindowExtEx failed\n");
  
          trace("gm %d, mm %d, wnd %d,%d, vp %d,%d horz %d,%d vert %d,%d\n",
                 test.graphics_mode, test.map_mode,
                 wndext.cx, wndext.cy, vportext.cx, vportext.cy,
                 horzSize, horzRes, vertSize, vertRes);
  
          if (test.graphics_mode == GM_COMPATIBLE)
          {
              test.ex_scale = 100.0 * ((FLOAT)horzSize  / (FLOAT)horzRes) /
                                      ((FLOAT)wndext.cx / (FLOAT)vportext.cx);
              test.ey_scale = 100.0 * ((FLOAT)vertSize  / (FLOAT)vertRes) /
                                      ((FLOAT)wndext.cy / (FLOAT)vportext.cy);
          }
          else
          {
              test.ex_scale = 0.0;
              test.ey_scale = 0.0;
          }
  
          hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
          ok(hdcMetafile != 0, "CreateEnhMetaFileA failed\n");
  
          ret = SetGraphicsMode(hdcMetafile, test.graphics_mode);
          ok(ret, "SetGraphicsMode failed\n");
          ret = SetMapMode(hdcMetafile, test.map_mode);
          ok(ret, "SetMapMode failed\n");
  
          if ((test.map_mode == MM_ISOTROPIC) || (test.map_mode == MM_ANISOTROPIC))
          {
              ret = SetWindowExtEx(hdcMetafile, 1, 1, NULL);
              ok(ret, "SetWindowExtEx failed\n");
              ret = SetViewportExtEx(hdcMetafile, -20, -10, NULL);
              ok(ret, "SetViewportExtEx failed\n");
          }
  
          ret = ExtTextOutW(hdcMetafile, 0, 0, 0, 0, str, 1, NULL);
          ok(ret, "ExtTextOutW failed\n");
  
          hMetafile = CloseEnhMetaFile(hdcMetafile);
          ok(hMetafile != 0, "CloseEnhMetaFile failed\n");
  
          test.processed = 0;
          ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_scale_enum_proc, &test, &rc);
          ok(ret, "EnumEnhMetaFile failed\n");
          ok(test.processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTW record\n");
  
          ret = DeleteEnhMetaFile(hMetafile);
          ok(ret, "DeleteEnhMetaFile failed\n");
      }
  
      ret = ReleaseDC(hwnd, hdcDisplay);
      ok(ret, "ReleaseDC failed\n");
      DestroyWindow(hwnd);
  }
  
  
  static void check_dc_state(HDC hdc, int restore_no,
                             int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
                             int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
  {
      BOOL ret;
      XFORM xform;
      POINT vp_org, win_org;
      SIZE vp_size, win_size;
      FLOAT xscale, yscale, edx, edy;
  
      SetLastError(0xdeadbeef);
      ret = GetWorldTransform(hdc, &xform);
      if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
      ok(ret, "GetWorldTransform error %u\n", GetLastError());
  
      trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
  
      ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
      ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
  
      xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
      trace("x scale %f\n", xscale);
      ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
         restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
  
      yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
      trace("y scale %f\n", yscale);
      ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
         restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
  
      edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
      ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
      edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
      ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
  
      return;
  
  win9x_here:
  
      GetWindowOrgEx(hdc, &win_org);
      GetViewportOrgEx(hdc, &vp_org);
      GetWindowExtEx(hdc, &win_size);
      GetViewportExtEx(hdc, &vp_size);
  
      ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
      ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
  
      ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
      ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
  
      ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
      ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
  
      ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
      ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
  }
  
  static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
                                           const ENHMETARECORD *emr, int n_objs, LPARAM param)
  {
      BOOL ret;
      XFORM xform;
      POINT pt;
      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);
  
      SetLastError(0xdeadbeef);
      ret = GetWorldTransform(hdc, &xform);
      if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
      {
          ret = GetWindowOrgEx(hdc, &pt);
          ok(ret, "GetWindowOrgEx error %u\n", GetLastError());
          trace("window org (%d,%d)\n", pt.x, pt.y);
          ret = GetViewportOrgEx(hdc, &pt);
          ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
          trace("vport org (%d,%d)\n", pt.x, pt.y);
          ret = GetWindowExtEx(hdc, &size);
          ok(ret, "GetWindowExtEx error %u\n", GetLastError());
          trace("window ext (%d,%d)\n", size.cx, size.cy);
          ret = GetViewportExtEx(hdc, &size);
          ok(ret, "GetViewportExtEx error %u\n", GetLastError());
          trace("vport ext (%d,%d)\n", size.cx, size.cy);
      }
      else
      {
          ok(ret, "GetWorldTransform error %u\n", GetLastError());
          trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
      }
  
      PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
  
      switch (emr->iType)
      {
      case EMR_HEADER:
      {
          static RECT exp_bounds = { 0, 0, 150, 150 };
          RECT bounds;
          const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
  
          trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
                 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
                 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
          trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
                 emf->szlDevice.cx, emf->szlDevice.cy);
  
          SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
          ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
  
          save_state = 0;
          restore_no = 0;
          select_no = 0;
          check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
          break;
      }
  
      case EMR_LINETO:
          {
              const EMRLINETO *line = (const EMRLINETO *)emr;
              trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
              break;
          }
      case EMR_SETWINDOWORGEX:
          {
              const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
              trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
              break;
          }
      case EMR_SETWINDOWEXTEX:
          {
              const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
              trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
              break;
          }
      case EMR_SETVIEWPORTORGEX:
          {
              const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
              trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
              break;
          }
      case EMR_SETVIEWPORTEXTEX:
          {
              const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
              trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
              break;
          }
      case EMR_SAVEDC:
          save_state++;
          trace("EMR_SAVEDC\n");
          break;
  
      case EMR_RESTOREDC:
          {
              const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
              trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
  
              switch(++restore_no)
              {
              case 1:
                  ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
                  check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
                  break;
              case 2:
                  ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
                  check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
                  break;
              case 3:
                  ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
                  check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
                  break;
              }
              ok(restore_no <= 3, "restore_no %d\n", restore_no);
              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;
      }
  
      SetLastError(0xdeadbeef);
      ret = GetWorldTransform(hdc, &xform);
      if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
      {
          ret = GetWindowOrgEx(hdc, &pt);
          ok(ret, "GetWindowOrgEx error %u\n", GetLastError());
          trace("window org (%d,%d)\n", pt.x, pt.y);
          ret = GetViewportOrgEx(hdc, &pt);
          ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
          trace("vport org (%d,%d)\n", pt.x, pt.y);
          ret = GetWindowExtEx(hdc, &size);
          ok(ret, "GetWindowExtEx error %u\n", GetLastError());
          trace("window ext (%d,%d)\n", size.cx, size.cy);
          ret = GetViewportExtEx(hdc, &size);
          ok(ret, "GetViewportExtEx error %u\n", GetLastError());
          trace("vport ext (%d,%d)\n", size.cx, size.cy);
      }
      else
      {
          ok(ret, "GetWorldTransform error %u\n", GetLastError());
          trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
      }
  
      return 1;
  }
  
  static void test_SaveDC(void)
  {
      HDC hdcMetafile, hdcDisplay;
      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 */
      hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
                             0, 0, 200, 200, 0, 0, 0, NULL);
      ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
  
      hdcDisplay = GetDC(hwnd);
      ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
  
      hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      SetMapMode(hdcMetafile, MM_ANISOTROPIC);
  
      /* 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);
      ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
      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 = GetViewportOrgEx(hdcMetafile, &pt);
      ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 10,"Expecting ViewportOrg x of 10, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      ok(size.cx == 200,"Expecting ViewportExt cx of 200, got %i\n",size.cx);
      ret = SaveDC(hdcMetafile);
      ok(ret == 2, "ret = %d\n", ret);
  
      SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
      ret = SaveDC(hdcMetafile);
      ok(ret == 3, "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 );
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 30,"Expecting ViewportOrg x of 30, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
  
      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 = GetViewportOrgEx(hdcMetafile, &pt);
      ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      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(ret, "GetViewportOrgEx error %u\n", GetLastError());
      ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
      ret = GetViewportExtEx(hdcMetafile, &size);
      ok(ret, "GetViewportExtEx error %u\n", GetLastError());
      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);
      ok( ret, "ReleaseDC error %d\n", GetLastError());
      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);
  
      pt.x = pt.y = 5555;
      SetWindowOrgEx(hdcMetafile, 0, 0, &pt);
      ok( pt.x == 5555 && pt.y == 5555, "wrong origin %d,%d\n", pt.x, pt.y);
      pt.x = pt.y = 5555;
      SetViewportOrgEx(hdcMetafile, 0, 0, &pt);
      ok( pt.x == 5555 && pt.y == 5555, "wrong origin %d,%d\n", pt.x, pt.y);
      size.cx = size.cy = 5555;
      SetWindowExtEx(hdcMetafile, 110, 110, &size );
      ok( size.cx == 5555 && size.cy == 5555, "wrong size %d,%d\n", size.cx, size.cy );
      size.cx = size.cy = 5555;
      SetViewportExtEx(hdcMetafile, 120, 120, &size );
      ok( size.cx == 5555 && size.cy == 5555, "wrong size %d,%d\n", size.cx, size.cy );
  
      /* 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. */
  
  /* Maximum size of sample metafiles in bytes. */
  #define MF_BUFSIZE 1024
  
  /* 8x8 bitmap data for a pattern brush */
  static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
      0x01, 0x00, 0x02, 0x00,
      0x03, 0x00, 0x04, 0x00,
      0x05, 0x00, 0x06, 0x00,
      0x07, 0x00, 0x08, 0x00
  };
  
  /* Sample metafiles to be compared to the outputs of the
   * test functions.
   */
  
  static const unsigned char MF_BLANK_BITS[] = {
      0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
  };
  
  static const unsigned char MF_GRAPHICS_BITS[] = {
      0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
      0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
      0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
      0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
      0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
      0x00, 0x00, 0x00, 0x00
  };
  
  static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
      0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
      0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
      0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
      0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
      0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
      0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
      0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x00, 0x00
  };
  
  static const unsigned char MF_DCBRUSH_BITS[] =
  {
      0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x2a, 0x00,
      0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfc, 0x02,
      0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x04, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0xfa, 0x02, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x04, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x01, 0x00,
      0x07, 0x00, 0x00, 0x00, 0x1b, 0x04, 0x14, 0x00,
      0x14, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x03, 0x00,
      0x00, 0x00, 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
  };
  
  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,
      0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0x64, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x80, 0x07, 0x00, 0x00, 0xb0, 0x04, 0x00, 0x00,
      0xfc, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
      0x30, 0xda, 0x04, 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, 0x4d, 0x00, 0x00, 0x00,
      0xc4, 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,
      0x0a, 0xd7, 0xa3, 0x3b, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0x23, 0x3c,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x6c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
      0x94, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
      0x90, 0x01, 0x00, 0x00, 0x90, 0x01, 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,
      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_DCBRUSH_BITS[] =
  {
      0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
      0x39, 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00,
      0x52, 0x02, 0x00, 0x00, 0x52, 0x02, 0x00, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0x44, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
      0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x25, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x80,
      0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
      0x13, 0x00, 0x00, 0x80, 0x27, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x26, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x33, 0x44, 0x55, 0x00, 0x25, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
      0x2b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x02, 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_BEZIER_BITS[] =
  {
      0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x1a, 0x2a, 0x0d, 0x00, 0x1a, 0x2f, 0x0d, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0x44, 0x01, 0x00, 0x00, 0x06, 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,
      0x51, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x68, 0x24, 0x05, 0x00,
      0xb0, 0x1e, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x14, 0x00,
      0x0f, 0x00, 0x0f, 0x00, 0x55, 0x00, 0x00, 0x00,
      0x2c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
      0x19, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x14, 0x00,
      0x0f, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x19, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
      0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
      0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
      0x04, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
      0x01, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
      0x0f, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
      0x19, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
      0x34, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
      0x0f, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
      0x01, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
      0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x0f, 0x00, 0x00, 0x00, 0x0f, 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_POLYPOLYLINE_BITS[] =
  {
      0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x00, 0x90, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00,
      0x61, 0x01, 0x00, 0x00, 0xc2, 0x02, 0x00, 0x00,
      0x7a, 0xd4, 0x13, 0x00, 0xe8, 0x44, 0x00, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0x84, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xa1, 0x05, 0x00, 0x00, 0x47, 0x03, 0x00, 0x00,
      0xfc, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0xc0, 0xc1, 0x07, 0x00,
      0x2c, 0x84, 0x04, 0x00, 0x5a, 0x00, 0x00, 0x00,
      0x20, 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, 0x5a, 0x00, 0x00, 0x00,
      0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00,
      0x5a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x14, 0x00, 0x64, 0x00, 0xc8, 0x00,
      0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x64, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
      0x00, 0x90, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
      0x07, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x00, 0x90, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x64, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
      0x00, 0x90, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
      0x90, 0x01, 0x00, 0x00, 0xf4, 0x01, 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_GRADIENTFILL_BITS[] =
  {
      0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x2b, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00,
      0x23, 0x00, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00,
      0x31, 0x29, 0x00, 0x00, 0xa3, 0x2a, 0x00, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0x0c, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x40, 0x05, 0x00, 0x00, 0x46, 0x03, 0x00, 0x00,
      0xda, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x15, 0x3c, 0x07, 0x00,
      0xcb, 0x82, 0x04, 0x00, 0x76, 0x00, 0x00, 0x00,
      0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00,
      0x35, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x00, 0xff, 0x00, 0x80, 0x00, 0x00, 0x01, 0x80,
      0xc8, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
      0xb4, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00,
      0x34, 0x12, 0x78, 0x56, 0xbc, 0x9a, 0xf0, 0xde,
      0x2c, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
      0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
      0x90, 0x01, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00,
      0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x01, 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.
   */
  static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
                                   INT nobj, LPARAM param)
  {
      trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, 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)
  {
      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%02x", buf[i]);
          if (i == mfsize-1)
              printf ("\n");
          else if (i % 8 == 7)
              printf (",\n    ");
          else
              printf (", ");
      }
      printf ("};\n");
  }
  
  /* Compare the metafile produced by a test function with the
   * expected raw metafile 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_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
      const char *desc)
  {
      unsigned char buf[MF_BUFSIZE];
      UINT mfsize, i;
      int diff;
  
      mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
      ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
      if (mfsize < MF_BUFSIZE)
          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++;
      }
      ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
          desc, mfsize, bsize, diff);
  
      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 %d\n", GetLastError());
  
      CloseHandle(hfile);
  
      ok(mfsize == bsize, "%s: mfsize=%d, 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=%d, 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 %d\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 %d, emr->nSize %u\n", emr->iType, emr->nSize);
          /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
          offset += emr->nSize;
      }
  }
  
  static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
  {
      const BYTE *buf;
      DWORD i;
  
      if (!winetest_debug) return;
  
      printf ("%s: EMF record %u has bits:\n{\n", desc, emr->iType);
      buf = (const BYTE *)emr;
      for (i = 0; i < emr->nSize; i++)
      {
          printf ("0x%02x", buf[i]);
          if (i == emr->nSize - 1)
              printf ("\n");
          else if (i % 8 == 7)
              printf (",\n");
          else
              printf (", ");
      }
      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 ignore_scaling)
  {
      int diff;
  
      ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
         desc, emr1->iType, emr2->iType);
  
      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;
  
      /* 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"))
      {
          /* 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 if (emr1->iType == EMR_POLYBEZIERTO16 || emr1->iType == EMR_POLYBEZIER16)
      {
          EMRPOLYBEZIER16 *eto1, *eto2;
  
          eto1 = (EMRPOLYBEZIER16*)emr1;
          eto2 = (EMRPOLYBEZIER16*)emr2;
  
          diff = eto1->cpts != eto2->cpts;
          if(!diff)
              diff = memcmp(eto1->apts, eto2->apts, eto1->cpts * sizeof(POINTS));
      }
      else if (emr1->iType == EMR_POLYBEZIERTO || emr1->iType == EMR_POLYBEZIER)
      {
          EMRPOLYBEZIER *eto1, *eto2;
  
          eto1 = (EMRPOLYBEZIER*)emr1;
          eto2 = (EMRPOLYBEZIER*)emr2;
  
          diff = eto1->cptl != eto2->cptl;
          if(!diff)
              diff = memcmp(eto1->aptl, eto2->aptl, eto1->cptl * sizeof(POINTL));
      }
      else
          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(emr1, "expected bits");
          dump_emf_record(emr2, "actual bits");
      }
  
      return diff == 0; /* report all non-fatal record mismatches */
  }
  
  /* 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 ignore_scaling)
  {
      unsigned char buf[MF_BUFSIZE];
      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)
      {
          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",
             desc, mfsize, bsize);
  
      /* basic things must match */
      emh1 = (const ENHMETAHEADER *)bits;
      emh2 = (const ENHMETAHEADER *)buf;
      ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
      ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
      ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
      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 ||
         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->rclBounds.left == emh2->rclBounds.left, "%s: expected rclBounds.left = %d, got %d\n",
              desc, emh1->rclBounds.left, emh2->rclBounds.left);
      ok(emh1->rclBounds.top == emh2->rclBounds.top, "%s: expected rclBounds.top = %d, got %d\n",
              desc, emh1->rclBounds.top, emh2->rclBounds.top);
      ok(emh1->rclBounds.right == emh2->rclBounds.right, "%s: expected rclBounds.right = %d, got %d\n",
              desc, emh1->rclBounds.right, emh2->rclBounds.right);
      ok(emh1->rclBounds.bottom == emh2->rclBounds.bottom, "%s: expected rclBounds.bottom = %d, got %d\n",
              desc, emh1->rclBounds.bottom, emh2->rclBounds.bottom);
      ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
      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)
      {
          const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset1);
          const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset2);
  
          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;
  
          /* We have already bailed out if iType or nSize don't match */
          offset1 += emr1->nSize;
          offset2 += emr2->nSize;
      }
      return 0;
  }
  
  
  /* 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 =
      {
          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;
      XFORM xform;
      BOOL ret;
  
      hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL);
      ok( hdcDisplay != 0, "CreateDCA error %d\n", GetLastError() );
  
      hdcBitmap = CreateCompatibleDC(hdcDisplay);
      ok( hdcBitmap != 0, "CreateCompatibleDC failed\n" );
      ok(SetGraphicsMode(hdcBitmap, GM_ADVANCED), "SetGraphicsMode 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);
  
      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" );
  
      ok(SetMapMode(hdcBitmap, MM_ANISOTROPIC), "SetMapMode failed\n");
      ok(SetWindowOrgEx(hdcBitmap, 0, 0, NULL), "SetWindowOrgEx failed\n");
      ok(SetWindowExtEx(hdcBitmap, 400, 400, NULL), "SetWindowExtEx failed\n");
      ok(SetViewportOrgEx(hdcBitmap, 0, 0, NULL), "SetViewportOrgEx failed\n");
      ok(SetViewportExtEx(hdcBitmap, BMP_DIM, BMP_DIM, NULL), "SetViewportExtEx failed\n");
      memset(&xform, 0, sizeof(xform));
      xform.eM11 = 0.5;
      xform.eM22 = 1.0;
      ok(SetWorldTransform(hdcBitmap, &xform), "SetWorldTransform failed\n");
  
      ret = StretchBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, hdcBitmap, 0, 0, 400, 400, SRCCOPY);
      ok( ret, "StretchBlt(SRCCOPY) 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");
      }
  
      SelectObject(hdcBitmap, hOldBitmap);
      DeleteObject(hBitmap);
      DeleteDC(hdcBitmap);
      DeleteDC(hdcDisplay);
  #undef BMP_DIM
  }
  
  static void test_emf_DCBrush(void)
  {
      HDC hdcMetafile;
      HENHMETAFILE hMetafile;
      HBRUSH hBrush;
      HPEN hPen;
      BOOL ret;
      COLORREF color;
  
      if (!pSetDCBrushColor || !pSetDCPenColor)
      {
          win_skip( "SetDCBrush/PenColor not supported\n" );
          return;
      }
  
      hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
      ok( hdcMetafile != 0, "CreateEnhMetaFileA failed\n" );
  
      hBrush = SelectObject(hdcMetafile, GetStockObject(DC_BRUSH));
      ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
  
      hPen = SelectObject(hdcMetafile, GetStockObject(DC_PEN));
      ok(hPen != 0, "SelectObject error %d.\n", GetLastError());
  
      color = pSetDCBrushColor( hdcMetafile, RGB(0x55,0x55,0x55) );
      ok( color == 0xffffff, "SetDCBrushColor returned %x\n", color );
  
      color = pSetDCPenColor( hdcMetafile, RGB(0x33,0x44,0x55) );
      ok( color == 0, "SetDCPenColor returned %x\n", color );
  
      Rectangle( hdcMetafile, 10, 10, 20, 20 );
  
      color = pSetDCBrushColor( hdcMetafile, RGB(0x12,0x34,0x56) );
      ok( color == 0x555555, "SetDCBrushColor returned %x\n", color );
  
      hMetafile = CloseEnhMetaFile(hdcMetafile);
      ok( hMetafile != 0, "CloseEnhMetaFile failed\n" );
  
      if (compare_emf_bits (hMetafile, EMF_DCBRUSH_BITS, sizeof(EMF_DCBRUSH_BITS),
                            "emf_DC_Brush", FALSE ) != 0)
      {
          dump_emf_bits(hMetafile, "emf_DC_Brush");
          dump_emf_records(hMetafile, "emf_DC_Brush");
      }
      ret = DeleteEnhMetaFile(hMetafile);
      ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
      ret = DeleteObject(hBrush);
      ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
      ret = DeleteObject(hPen);
      ok( ret, "DeleteObject(HPEN) error %d\n", GetLastError());
  }
  
  /* Test a blank metafile.  May be used as a template for new tests. */
  
  static void test_mf_Blank(void)
  {
      HDC hdcMetafile;
      HMETAFILE hMetafile;
      INT caps;
      BOOL ret;
      INT type;
  
      hdcMetafile = CreateMetaFileA(NULL);
      ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
      trace("hdcMetafile %p\n", hdcMetafile);
  
  /* Tests on metafile initialization */
      caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
      ok (caps == DT_METAFILE,
          "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
  
      hMetafile = CloseMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseMetaFile error %d\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");
          EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hMetafile);
      ok( ret, "DeleteMetaFile(%p) error %d\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 %d\n", GetLastError());
      trace("hdcMetafile %p\n", hdcMetafile);
  
      hMetafile = CloseMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseMetaFile error %d\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 %d\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 %d\n", hMetafile, GetLastError());
  
      if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
      {
          dump_mf_bits(hmf_copy, "mf_Blank");
          EnumMetaFile(0, hmf_copy, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hmf_copy);
      ok( ret, "DeleteMetaFile(%p) error %d\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);
      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);
  
      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 %d\n", hmf, GetLastError());
  
      /* NULL data crashes XP SP1 */
      /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
  
      /* 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 ||
         broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
         "wrong error %d\n", GetLastError());
  
      /* 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 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);
      trace("hmf %p\n", hmf);
      ok(!hmf, "SetMetaFileBitsEx should fail\n");
      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));
      mh = (METAHEADER *)buf;
      /* 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)
      {
          dump_mf_bits(hmf, "mf_Graphics");
          EnumMetaFile(0, hmf, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hmf);
      ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
  
  #ifndef _WIN64 /* Generates access violation on XP x64 and Win2003 x64 */
      /* 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);
      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)
      {
          dump_mf_bits(hmf, "mf_Graphics");
          EnumMetaFile(0, hmf, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hmf);
      ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
  #endif
  }
  
  /* Simple APIs from mfdrv/graphics.c
   */
  
  static void test_mf_Graphics(void)
  {
      HDC hdcMetafile;
      HMETAFILE hMetafile;
      POINT oldpoint;
      BOOL ret;
  
      hdcMetafile = CreateMetaFileA(NULL);
      ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
      trace("hdcMetafile %p\n", hdcMetafile);
  
      ret = MoveToEx(hdcMetafile, 1, 1, NULL);
      ok( ret, "MoveToEx error %d.\n", GetLastError());
      ret = LineTo(hdcMetafile, 2, 2);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
      ok( ret, "MoveToEx error %d.\n", GetLastError());
  
  /* oldpoint gets garbage under Win XP, so the following test would
   * work under Wine but fails under Windows:
   *
   *   ok((oldpoint.x == 2) && (oldpoint.y == 2),
   *       "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
   *       oldpoint.x, oldpoint.y);
   */
  
      ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
      ok( ret, "Ellipse error %d.\n", GetLastError());
  
      hMetafile = CloseMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
      ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
  
      if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
          "mf_Graphics") != 0)
      {
          dump_mf_bits(hMetafile, "mf_Graphics");
          EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hMetafile);
      ok( ret, "DeleteMetaFile(%p) error %d\n",
          hMetafile, GetLastError());
  }
  
  static void test_mf_PatternBrush(void)
  {
      HDC hdcMetafile;
      HMETAFILE hMetafile;
      LOGBRUSH *orig_lb;
      HBRUSH hBrush;
      BOOL ret;
  
      orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
  
      orig_lb->lbStyle = BS_PATTERN;
      orig_lb->lbColor = RGB(0, 0, 0);
      orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
      ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
  
      hBrush = CreateBrushIndirect (orig_lb);
      ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
  
      hdcMetafile = CreateMetaFileA(NULL);
      ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
      trace("hdcMetafile %p\n", hdcMetafile);
  
      hBrush = SelectObject(hdcMetafile, hBrush);
      ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
  
      hMetafile = CloseMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
      ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
  
      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");
          EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hMetafile);
      ok( ret, "DeleteMetaFile error %d\n", GetLastError());
      ret = DeleteObject(hBrush);
      ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
      ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
      ok( ret, "DeleteObject(HBITMAP) error %d\n",
          GetLastError());
      HeapFree (GetProcessHeap(), 0, orig_lb);
  }
  
  static void test_mf_DCBrush(void)
  {
      HDC hdcMetafile;
      HMETAFILE hMetafile;
      HBRUSH hBrush;
      HPEN hPen;
      BOOL ret;
      COLORREF color;
  
      if (!pSetDCBrushColor || !pSetDCPenColor)
      {
          win_skip( "SetDCBrush/PenColor not supported\n" );
          return;
      }
  
      hdcMetafile = CreateMetaFileA(NULL);
      ok( hdcMetafile != 0, "CreateMetaFileA failed\n" );
  
      hBrush = SelectObject(hdcMetafile, GetStockObject(DC_BRUSH));
      ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
  
      hPen = SelectObject(hdcMetafile, GetStockObject(DC_PEN));
      ok(hPen != 0, "SelectObject error %d.\n", GetLastError());
  
      color = pSetDCBrushColor( hdcMetafile, RGB(0x55,0x55,0x55) );
      ok( color == CLR_INVALID, "SetDCBrushColor returned %x\n", color );
  
      color = pSetDCPenColor( hdcMetafile, RGB(0x33,0x44,0x55) );
      ok( color == CLR_INVALID, "SetDCPenColor returned %x\n", color );
  
      Rectangle( hdcMetafile, 10, 10, 20, 20 );
  
      color = pSetDCBrushColor( hdcMetafile, RGB(0x12,0x34,0x56) );
      ok( color == CLR_INVALID, "SetDCBrushColor returned %x\n", color );
  
      hMetafile = CloseMetaFile(hdcMetafile);
      ok( hMetafile != 0, "CloseMetaFile failed\n" );
  
      if (compare_mf_bits(hMetafile, MF_DCBRUSH_BITS, sizeof(MF_DCBRUSH_BITS), "mf_DCBrush") != 0)
      {
          dump_mf_bits(hMetafile, "mf_DCBrush");
          EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
      }
      ret = DeleteMetaFile(hMetafile);
      ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
  }
  
  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 %d\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 %d\n", GetLastError());
  
      ret = EndPath(hdcMetafile);
      ok(!ret, "EndPath on metafile DC should fail\n");
  
      hMetafile = CloseMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseMetaFile error %d\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 %d\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 %d\n", GetLastError());
  
      hdcDisplay = GetDC(hwnd);
      ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
  
      hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      ret = BeginPath(hdcMetafile);
      ok(ret, "BeginPath error %d\n", GetLastError());
  
      ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
      todo_wine ok(ret, "ExtTextOut error %d\n", GetLastError());
  
      ret = EndPath(hdcMetafile);
      ok(ret, "EndPath error %d\n", GetLastError());
  
      hMetafile = CloseEnhMetaFile(hdcMetafile);
      ok(hMetafile != 0, "CloseEnhMetaFile error %d\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", FALSE) != 0)
      {
          dump_emf_bits(hMetafile, "emf_TextOut_on_path");
          dump_emf_records(hMetafile, "emf_TextOut_on_path");
      }
  
      ret = DeleteEnhMetaFile(hMetafile);
      ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
      ret = ReleaseDC(hwnd, hdcDisplay);
      ok(ret, "ReleaseDC error %d\n", GetLastError());
      DestroyWindow(hwnd);
  }
  
  static const unsigned char EMF_CLIPPING[] =
  {
      0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x1a, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0x04, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x80, 0x07, 0x00, 0x00, 0xb0, 0x04, 0x00, 0x00,
      0xfc, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
      0x30, 0xda, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
      0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
      0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
      0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
      0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
      0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
      0x00, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
      0x64, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00,
      0xff, 0x03, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
      0x14, 0x00, 0x00, 0x00
  };
  
  static void translate( POINT *pt, UINT count, const XFORM *xform )
  {
      while (count--)
      {
          FLOAT x = (FLOAT)pt->x;
          FLOAT y = (FLOAT)pt->y;
          pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
          pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
          pt++;
      }
  }
  
  /* 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)
  {
      if (emr->iType == EMR_EXTSELECTCLIPRGN)
      {
          const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
          union _rgn
          {
              RGNDATA data;
              char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
          };
          const union _rgn *rgn1;
          union _rgn rgn2;
          RECT rect, rc_transformed;
          const RECT *rc = (const RECT *)param;
          HRGN hrgn;
          XFORM xform;
          INT ret;
          BOOL is_win9x;
  
          trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
                 clip->cbRgnData, clip->iMode);
  
          ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
          ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
             "too small data block: %u bytes\n", clip->cbRgnData);
          if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
              return 0;
  
          rgn1 = (const union _rgn *)clip->RgnData;
  
          trace("size %u, type %u, count %u, rgn size %u, bound %s\n",
                rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
                rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
                wine_dbgstr_rect(&rgn1->data.rdh.rcBound));
  
          ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
  
          rect = *(const RECT *)rgn1->data.Buffer;
          trace("rect %s\n", wine_dbgstr_rect(&rect));
          ok(EqualRect(&rect, rc), "rects don't match\n");
  
          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) ||
             broken(rgn1->data.rdh.nRgnSize == 168), /* NT4 */
             "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
  
          hrgn = CreateRectRgn(0, 0, 0, 0);
  
          memset(&xform, 0, sizeof(xform));
          SetLastError(0xdeadbeef);
          ret = GetWorldTransform(hdc, &xform);
          is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
          if (!is_win9x)
              ok(ret, "GetWorldTransform error %u\n", GetLastError());
  
          trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
  
          ret = GetClipRgn(hdc, hrgn);
          ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
  
          PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
  
          ret = GetClipRgn(hdc, hrgn);
          ok(ret == 1, "GetClipRgn returned %d, expected 1\n", ret);
  
          /* Win9x returns empty clipping region */
          if (is_win9x) return 1;
  
          ret = GetRegionData(hrgn, 0, NULL);
          ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
  
          ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
          ok(ret == sizeof(rgn2), "expected sizeof(rgn2), got %u\n", ret);
  
          trace("size %u, type %u, count %u, rgn size %u, bound %s\n", rgn2.data.rdh.dwSize,
                rgn2.data.rdh.iType, rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
                wine_dbgstr_rect(&rgn2.data.rdh.rcBound));
  
          rect = rgn2.data.rdh.rcBound;
          rc_transformed = *rc;
          translate((POINT *)&rc_transformed, 2, &xform);
          trace("transformed %s\n", wine_dbgstr_rect(&rc_transformed));
          ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
  
          rect = *(const RECT *)rgn2.data.Buffer;
          trace("rect %s\n", wine_dbgstr_rect(&rect));
          rc_transformed = *rc;
          translate((POINT *)&rc_transformed, 2, &xform);
          trace("transformed %s\n", wine_dbgstr_rect(&rc_transformed));
          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) ||
             broken(rgn2.data.rdh.nRgnSize == 168), /* NT4 */
             "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
  
          DeleteObject(hrgn);
      }
      return 1;
  }
  
  static void test_emf_clipping(void)
  {
      static const RECT rc = { 0, 0, 100, 100 };
      RECT rc_clip = { 100, 100, 1024, 1024 };
      HWND hwnd;
      HDC hdc;
      HENHMETAFILE hemf;
      HRGN hrgn;
      INT ret;
      RECT rc_res, rc_sclip;
  
      SetLastError(0xdeadbeef);
      hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
      ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      /* Need to write something to the emf, otherwise Windows won't play it back */
      LineTo(hdc, 1, 1);
  
      hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
      ret = SelectClipRgn(hdc, hrgn);
      ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
  
      BeginPath(hdc);
      Rectangle(hdc, rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
      EndPath(hdc);
      ret = SelectClipPath(hdc, RGN_AND);
      ok(ret, "SelectClipPath error %d\n", GetLastError());
  
      SetLastError(0xdeadbeef);
      hemf = CloseEnhMetaFile(hdc);
      ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
      if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
          "emf_clipping", FALSE) != 0)
      {
          dump_emf_bits(hemf, "emf_clipping");
          dump_emf_records(hemf, "emf_clipping");
      }
  
      DeleteObject(hrgn);
  
      /* 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 %d\n", GetLastError());
  
      hdc = GetDC(hwnd);
  
      ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
      ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
  
      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);
      SetRect(&rc_res, -1, -1, -1, -1);
      ret = GetClipBox(hdc, &rc_res);
      ok(ret == SIMPLEREGION, "got %d\n", ret);
      ok(EqualRect(&rc_res, &rc_sclip), "expected %s, got %s\n", wine_dbgstr_rect(&rc_sclip),
         wine_dbgstr_rect(&rc_res));
  
      OffsetRect(&rc_sclip, -100, -100);
      ret = OffsetClipRgn(hdc, -100, -100);
      ok(ret == SIMPLEREGION, "got %d\n", ret);
      SetRect(&rc_res, -1, -1, -1, -1);
      ret = GetClipBox(hdc, &rc_res);
      ok(ret == SIMPLEREGION, "got %d\n", ret);
      ok(EqualRect(&rc_res, &rc_sclip), "expected %s, got %s\n", wine_dbgstr_rect(&rc_sclip),
         wine_dbgstr_rect(&rc_res));
  
      ret = IntersectClipRect(hdc, 0, 0, 100, 100);
      ok(ret == SIMPLEREGION || broken(ret == COMPLEXREGION) /* XP */, "got %d\n", ret);
      if (ret == COMPLEXREGION)
      {
          /* XP returns COMPLEXREGION although region contains only 1 rect */
          ret = GetClipRgn(hdc, hrgn);
          ok(ret == 1, "expected 1, got %d\n", ret);
          ret = rgn_rect_count(hrgn);
          ok(ret == 1, "expected 1, got %d\n", ret);
      }
      SetRect(&rc_res, -1, -1, -1, -1);
      ret = GetClipBox(hdc, &rc_res);
      ok(ret == SIMPLEREGION, "got %d\n", ret);
      ok(EqualRect(&rc_res, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rc),
         wine_dbgstr_rect(&rc_res));
  
      SetRect(&rc_sclip, 0, 0, 100, 50);
      ret = ExcludeClipRect(hdc, 0, 50, 100, 100);
      ok(ret == SIMPLEREGION || broken(ret == COMPLEXREGION) /* XP */, "got %d\n", ret);
      if (ret == COMPLEXREGION)
      {
          /* XP returns COMPLEXREGION although region contains only 1 rect */
          ret = GetClipRgn(hdc, hrgn);
          ok(ret == 1, "expected 1, got %d\n", ret);
          ret = rgn_rect_count(hrgn);
          ok(ret == 1, "expected 1, got %d\n", ret);
      }
      SetRect(&rc_res, -1, -1, -1, -1);
      ret = GetClipBox(hdc, &rc_res);
      ok(ret == SIMPLEREGION, "got %d\n", ret);
      ok(EqualRect(&rc_res, &rc_sclip), "expected %s, got %s\n", wine_dbgstr_rect(&rc_sclip),
         wine_dbgstr_rect(&rc_res));
  
      hemf = CloseEnhMetaFile(hdc);
      DeleteEnhMetaFile(hemf);
      DeleteObject(hrgn);
  }
  
  static const unsigned char MF_CLIP_BITS[] = {
      /* METAHEADER */
      0x01, 0x00,             /* mtType */
      0x09, 0x00,             /* mtHeaderSize */
      0x00, 0x03,             /* mtVersion */
      0x32, 0x00, 0x00, 0x00, /* mtSize */
      0x01, 0x00,             /* mtNoObjects */
      0x14, 0x00, 0x00, 0x00, /* mtMaxRecord (size in words of longest record) */
      0x00, 0x00,             /* reserved */
  
      /* METARECORD for CreateRectRgn(0x11, 0x22, 0x33, 0x44) */
      0x14, 0x00, 0x00, 0x00, /* rdSize in words */
      0xff, 0x06,             /* META_CREATEREGION */
      0x00, 0x00, 0x06, 0x00, 0xf6, 0x02, 0x00, 0x00,
      0x24, 0x00, 0x01, 0x00, 0x02, 0x00, 0x11, 0x00,
      0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x02, 0x00,
      0x22, 0x00, 0x44, 0x00, 0x11, 0x00, 0x33, 0x00,
      0x02, 0x00,
  
      /* METARECORD for SelectObject */
      0x04, 0x00, 0x00, 0x00,
      0x2d, 0x01,             /* META_SELECTOBJECT (not META_SELECTCLIPREGION?!) */
      0x00, 0x00,
  
      /* METARECORD */
      0x04, 0x00, 0x00, 0x00,
      0xf0, 0x01,             /* META_DELETEOBJECT */
      0x00, 0x00,
  
      /* METARECORD for MoveTo(1,0x30) */
      0x05, 0x00, 0x00, 0x00, /* rdSize in words */
      0x14, 0x02,             /* META_MOVETO */
      0x30, 0x00,             /* y */
      0x01, 0x00,             /* x */
  
      /* METARECORD for LineTo(0x20, 0x30) */
      0x05, 0x00, 0x00, 0x00, /* rdSize in words */
      0x13, 0x02,             /* META_LINETO */
      0x30, 0x00,             /* y */
      0x20, 0x00,             /* x */
  
      /* EOF */
      0x03, 0x00, 0x00, 0x00,
      0x00, 0x00
  };
  
  static int clip_mf_enum_proc_seen_selectclipregion;
  static int clip_mf_enum_proc_seen_selectobject;
  
  static int CALLBACK clip_mf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
                                         METARECORD *mr, int n_objs, LPARAM param)
  {
      switch (mr->rdFunction) {
      case META_SELECTCLIPREGION:
          clip_mf_enum_proc_seen_selectclipregion++;
          break;
      case META_SELECTOBJECT:
          clip_mf_enum_proc_seen_selectobject++;
          break;
      }
      return 1;
  }
  
  static void test_mf_clipping(void)
  {
                            /* left top right bottom */
      static RECT rc_clip = { 0x11, 0x22, 0x33, 0x44 };
      HWND hwnd;
      HDC hdc;
      HMETAFILE hmf;
      HRGN hrgn;
      INT ret;
  
      SetLastError(0xdeadbeef);
      hdc = CreateMetaFileA(NULL);
      ok(hdc != 0, "CreateMetaFileA error %d\n", GetLastError());
  
      hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
      ret = SelectClipRgn(hdc, hrgn);
      /* Seems like it should be SIMPLEREGION, but windows returns NULLREGION? */
      ok(ret == NULLREGION, "expected NULLREGION, got %d\n", ret);
  
      /* Draw a line that starts off left of the clip region and ends inside it */
      MoveToEx(hdc, 0x1, 0x30, NULL);
      LineTo(hdc,  0x20, 0x30);
  
      SetLastError(0xdeadbeef);
      hmf = CloseMetaFile(hdc);
      ok(hmf != 0, "CloseMetaFile error %d\n", GetLastError());
  
      if (compare_mf_bits(hmf, MF_CLIP_BITS, sizeof(MF_CLIP_BITS),
          "mf_clipping") != 0)
      {
          dump_mf_bits(hmf, "mf_clipping");
      }
  
      DeleteObject(hrgn);
  
      hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
                             0, 0, 200, 200, 0, 0, 0, NULL);
      ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
  
      hdc = GetDC(hwnd);
  
      ret = EnumMetaFile(hdc, hmf, clip_mf_enum_proc, (LPARAM)&rc_clip);
      ok(ret, "EnumMetaFile error %d\n", GetLastError());
  
      /* Oddly, windows doesn't seem to use META_SELECTCLIPREGION */
      ok(clip_mf_enum_proc_seen_selectclipregion == 0,
         "expected 0 selectclipregion, saw %d\n", clip_mf_enum_proc_seen_selectclipregion);
      ok(clip_mf_enum_proc_seen_selectobject == 1,
         "expected 1 selectobject, saw %d\n", clip_mf_enum_proc_seen_selectobject);
  
      DeleteMetaFile(hmf);
      ReleaseDC(hwnd, hdc);
      DestroyWindow(hwnd);
  }
  
  static const unsigned char MF_PATH_BITS[] =
  {
      0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x2c, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
      0x32, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,
      0x13, 0x02, 0x96, 0x00, 0x32, 0x00, 0x05, 0x00,
      0x00, 0x00, 0x13, 0x02, 0x96, 0x00, 0x96, 0x00,
      0x05, 0x00, 0x00, 0x00, 0x13, 0x02, 0x32, 0x00,
      0x96, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
      0x32, 0x00, 0x32, 0x00, 0x07, 0x00, 0x00, 0x00,
      0x1b, 0x04, 0x14, 0x00, 0x14, 0x00, 0x0a, 0x00,
      0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
  };
  
  static void test_mf_GetPath(void)
  {
      HDC hdc;
      HMETAFILE hmf;
      BOOL ret;
      int size;
  
      SetLastError(0xdeadbeef);
      hdc = CreateMetaFileA(NULL);
      ok(hdc != 0, "CreateMetaFileA error %d\n", GetLastError());
  
      BeginPath(hdc);
      ret = MoveToEx(hdc, 50, 50, NULL);
      ok( ret, "MoveToEx error %d.\n", GetLastError());
      ret = LineTo(hdc, 50, 150);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = LineTo(hdc, 150, 150);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = LineTo(hdc, 150, 50);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = LineTo(hdc, 50, 50);
      ok( ret, "LineTo error %d.\n", GetLastError());
      Rectangle(hdc, 10, 10, 20, 20);
      EndPath(hdc);
  
      size = GetPath(hdc, NULL, NULL, 0);
      ok( size == -1, "GetPath returned %d.\n", size);
  
      hmf = CloseMetaFile(hdc);
      ok(hmf != 0, "CloseMetaFile error %d\n", GetLastError());
  
      if (compare_mf_bits (hmf, MF_PATH_BITS, sizeof(MF_PATH_BITS), "mf_GetPath") != 0)
      {
          dump_mf_bits(hmf, "mf_GetPath");
          EnumMetaFile(0, hmf, mf_enum_proc, 0);
      }
  
      ret = DeleteMetaFile(hmf);
      ok( ret, "DeleteMetaFile error %d\n", GetLastError());
  }
  
  static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
  {
      LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
      POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
      /* When using MM_TEXT Win9x does not update the mapping mode 
       * until a record is played which actually outputs something */
      PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
      LPtoDP(hdc, mapping, 2);
      trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\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;
          if (!lpMFP || lpMFP->mm == MM_TEXT)
          {
              x0 = 0;
              y0 = 0;
              x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
              y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
          }
          else
          {
              ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
              
              x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
              y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
              x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
              y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
          }
          ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
              "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
              mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
              x0, y0, x1, y1);
      }
      return TRUE;
  }
  
  static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
  {
      HDC hdcMf;
      HMETAFILE hmf;
      HENHMETAFILE hemf;
      BOOL ret;
      UINT size;
      LPBYTE pBits;
  
      hdcMf = CreateMetaFileA(NULL);
      ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
      ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
      ok(ret, "LineTo failed with error %d\n", GetLastError());
      hmf = CloseMetaFile(hdcMf);
      ok(hmf != NULL, "CloseMetaFile failed with error %d\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 %d\n", GetLastError());
      pBits = HeapAlloc(GetProcessHeap(), 0, size);
      GetMetaFileBitsEx(hmf, size, pBits);
      DeleteMetaFile(hmf);
      hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
      HeapFree(GetProcessHeap(), 0, pBits);
      return hemf;
  }
  
  static void test_mf_conversions(void)
  {
      trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
      {
          HDC hdcOffscreen = CreateCompatibleDC(NULL);
          HENHMETAFILE hemf;
          METAFILEPICT mfp;
          RECT rect = { 0, 0, 100, 100 };
          mfp.mm = MM_ANISOTROPIC;
          mfp.xExt = 100;
          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);
      }
  
      trace("Testing MF->EMF conversion (MM_TEXT)\n");
      {
          HDC hdcOffscreen = CreateCompatibleDC(NULL);
          HENHMETAFILE hemf;
          METAFILEPICT mfp;
          RECT rect = { 0, 0, 100, 100 };
          mfp.mm = MM_TEXT;
          mfp.xExt = 0;
          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);
      }
  
      trace("Testing MF->EMF conversion (NULL mfp)\n");
      {
          HDC hdcOffscreen = CreateCompatibleDC(NULL);
          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=%d, yExt=%d", mm_str, xExt, yExt);
        msg = buf;
      }
  
      ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
      ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
      ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
      ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
      ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
      ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
      ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
      ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%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 = CreateMetaFileA(NULL);
    ok(wmfDC != NULL, "CreateMetaFile failed\n");
    if (!wmfDC) return;
  
    SetWindowExtEx(wmfDC, 100, 100, NULL);
    SetRect(&rect, 0, 0, 50, 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 = 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);
  
    /* 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(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, GetDeviceCaps(dc, VERTRES) / 2, 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 (%dx%d)\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 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, emf2;
      HDC display_dc, emf_dc;
      ENHMETAHEADER *enh_header, *enh2_header;
      UINT size, emf_size, i, emf2_size;
      WORD check = 0;
      DWORD rec_num = 0;
      METAHEADER *mh = NULL;
      METARECORD *rec;
      INT horz_res, vert_res, horz_size, vert_size;
      INT curve_caps, line_caps, poly_caps;
      METAFILEPICT mfp;
  
      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");
  
      curve_caps = GetDeviceCaps(emf_dc, CURVECAPS);
      ok(curve_caps == 511, "expect 511 got %d\n", curve_caps);
  
      line_caps = GetDeviceCaps(emf_dc, LINECAPS);
      ok(line_caps == 254, "expect 254 got %d\n", line_caps);
  
      poly_caps = GetDeviceCaps(emf_dc, POLYGONALCAPS);
      ok(poly_caps == 255, "expect 511 got %d\n", poly_caps);
  
      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);
      }
  
      /* Show that we get the original back when we do the reverse conversion.
         mfp is ignored in this case. */
      mfp.mm = MM_ISOTROPIC;
      mfp.xExt = 0xcafe;
      mfp.yExt = 0xbeef;
      emf2 = SetWinMetaFileBits( size, (BYTE*)mh, NULL, &mfp );
      ok( !!emf2, "got NULL\n" );
      emf2_size = GetEnhMetaFileBits( emf2, 0, NULL );
      enh2_header = HeapAlloc( GetProcessHeap(), 0, emf2_size );
      emf2_size = GetEnhMetaFileBits( emf2, emf2_size, (BYTE*)enh2_header );
      ok( emf_size == emf2_size, "%d %d\n", emf_size, emf2_size );
      ok( !memcmp( enh_header, enh2_header, emf_size ), "mismatch\n" );
      HeapFree( GetProcessHeap(), 0, enh2_header );
      DeleteEnhMetaFile( emf2 );
  
  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;
          for(rc = frames; rc->right - rc->left > 0; rc++)
          {
              getwinmetafilebits(mode, 1, rc);
              getwinmetafilebits(mode, 2, rc);
          }
      }
  }
  
  static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
  static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
  static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
  
  static void test_gdiis(void)
  {
      RECT rect = {0,0,100,100};
      HDC hdc, hemfDC, hmfDC;
      HENHMETAFILE hemf;
      HMODULE hgdi32;
  
      /* resolve all the functions */
      hgdi32 = GetModuleHandleA("gdi32.dll");
      pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
      pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
      pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
  
      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");
      ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
      ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
  
      /* try with a metafile */
      hmfDC = CreateMetaFileA(NULL);
      ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
      ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
      ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
      DeleteMetaFile(CloseMetaFile(hmfDC));
  
      /* try with an enhanced metafile */
      hdc = GetDC(NULL);
      hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
      ok(hemfDC != NULL, "failed to create emf\n");
  
      ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
      ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
      ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
  
      hemf = CloseEnhMetaFile(hemfDC);
      ok(hemf != NULL, "failed to close EMF\n");
      DeleteEnhMetaFile(hemf);
      ReleaseDC(NULL,hdc);
  }
  
  static void test_SetEnhMetaFileBits(void)
  {
      BYTE data[256];
      HENHMETAFILE hemf;
      ENHMETAHEADER *emh;
  
      memset(data, 0xAA, sizeof(data));
      SetLastError(0xdeadbeef);
      hemf = SetEnhMetaFileBits(sizeof(data), data);
      ok(!hemf, "SetEnhMetaFileBits should fail\n");
      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->iType = EMR_HEADER;
      emh->nSize = sizeof(*emh);
      emh->dSignature = ENHMETA_SIGNATURE;
      /* emh->nVersion  = 0x10000; XP doesn't care about version */
      emh->nBytes = sizeof(*emh);
      /* emh->nRecords = 1; XP doesn't care about records */
      emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
  
      SetLastError(0xdeadbeef);
      hemf = SetEnhMetaFileBits(emh->nBytes, data);
      ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
      DeleteEnhMetaFile(hemf);
  
      /* XP refuses to load unaligned EMF */
      emh->nBytes++;
      SetLastError(0xdeadbeef);
      hemf = SetEnhMetaFileBits(emh->nBytes, data);
      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 ||
         broken(hemf != NULL), /* Win9x, WinMe */
         "SetEnhMetaFileBits should fail\n");
      ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
      DeleteEnhMetaFile(hemf);
  }
  
  static void test_emf_polybezier(void)
  {
      HDC hdcMetafile;
      HENHMETAFILE hemf;
      POINT pts[4];
      BOOL ret;
  
      SetLastError(0xdeadbeef);
      hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      pts[0].x = pts[0].y = 10;
      pts[1].x = pts[1].y = 20;
      pts[2].x = pts[2].y = 15;
      pts[3].x = pts[3].y = 25;
      ret = PolyBezierTo(hdcMetafile, pts, 3);  /* EMR_POLYBEZIERTO16 */
      ok( ret, "PolyBezierTo failed\n" );
      ret = PolyBezier(hdcMetafile, pts, 4);    /* EMR_POLYBEZIER16   */
      ok( ret, "PolyBezier failed\n" );
  
      pts[0].x = pts[0].y = 32769;
      ret = PolyBezier(hdcMetafile, pts, 4);    /* EMR_POLYBEZIER   */
      ok( ret, "PolyBezier failed\n" );
      ret = PolyBezierTo(hdcMetafile, pts, 3);  /* EMR_POLYBEZIERTO */
      ok( ret, "PolyBezierTo failed\n" );
  
      hemf = CloseEnhMetaFile(hdcMetafile);
      ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
      if(compare_emf_bits(hemf, EMF_BEZIER_BITS, sizeof(EMF_BEZIER_BITS),
          "emf_Bezier", FALSE) != 0)
      {
          dump_emf_bits(hemf, "emf_Bezier");
          dump_emf_records(hemf, "emf_Bezier");
      }
  
      DeleteEnhMetaFile(hemf);
  }
  
  static const unsigned char EMF_PATH_BITS[] =
  {
      0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
      0x90, 0x01, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
      0x70, 0x17, 0x00, 0x00, 0x70, 0x17, 0x00, 0x00,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0xf8, 0x02, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x20, 0x03, 0x00, 0x00, 0x58, 0x02, 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, 0x1b, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
      0x32, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
      0x96, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
      0x96, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
      0x32, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
      0x32, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
      0x13, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
      0x15, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
      0x1c, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
      0x1d, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
      0x15, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
      0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
      0x1a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
      0x1b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
      0x17, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
      0x15, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
      0x1c, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
      0x1d, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
      0x15, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
      0x15, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
      0x1c, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
      0x1d, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
      0x15, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
      0x13, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
      0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
      0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
      0x05, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
      0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x0a, 0x00,
      0x0a, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00,
      0x59, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
      0x14, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00,
      0x14, 0x00, 0x14, 0x00, 0x5a, 0x00, 0x00, 0x00,
      0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00,
      0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
      0x14, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00,
      0x14, 0x00, 0x14, 0x00, 0x5c, 0x00, 0x00, 0x00,
      0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x0a, 0x00,
      0x0a, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00,
      0x1e, 0x00, 0x1e, 0x00, 0x28, 0x00, 0x14, 0x00,
      0x14, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x14, 0x00,
      0x14, 0x00, 0x0a, 0x00, 0x06, 0x02, 0x04, 0x04,
      0x04, 0x02, 0x03, 0x06, 0x02, 0x00, 0x00, 0x00,
      0x29, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
      0x25, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
      0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x42,
      0x00, 0x00, 0x34, 0x43, 0x3c, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
      0x0a, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
      0x96, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
      0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff, 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_EMPTY_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,
      0xd8, 0xff, 0xff, 0xff, 0xd8, 0xff, 0xff, 0xff,
      0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
      0xc8, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x20, 0x03, 0x00, 0x00, 0x58, 0x02, 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, 0x3d, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
      0x08, 0x00, 0x00, 0x00, 0x44, 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 void test_emf_paths(void)
  {
      POINT pts[9] = {{10, 10}, {20, 10}, {10, 20}, {20, 20}, {30, 30}, {40, 20}, {20, 30}, {20, 20}, {20, 10}};
      DWORD counts[2] = {2, 2};
      BYTE types[9] = { PT_MOVETO, PT_LINETO, PT_BEZIERTO, PT_BEZIERTO, PT_BEZIERTO, PT_LINETO,
                        PT_LINETO | PT_CLOSEFIGURE, PT_MOVETO, PT_LINETO };
      HDC hdcMetafile;
      HENHMETAFILE hemf;
      BOOL ret;
      int size;
  
      SetLastError(0xdeadbeef);
      hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      BeginPath(hdcMetafile);
      ret = MoveToEx(hdcMetafile, 50, 50, NULL);
      ok( ret, "MoveToEx error %d.\n", GetLastError());
      ret = LineTo(hdcMetafile, 50, 150);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = LineTo(hdcMetafile, 150, 150);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = LineTo(hdcMetafile, 150, 50);
      ok( ret, "LineTo error %d.\n", GetLastError());
      ret = LineTo(hdcMetafile, 50, 50);
      ok( ret, "LineTo error %d.\n", GetLastError());
      Rectangle(hdcMetafile, 10, 10, 20, 20);
      Arc(hdcMetafile, 21, 21, 39, 29, 39, 29, 21, 21);
      ArcTo(hdcMetafile, 23, 23, 37, 27, 37, 27, 23, 23);
      Chord(hdcMetafile, 21, 21, 39, 29, 39, 29, 21, 21);
      Pie(hdcMetafile, 21, 21, 39, 29, 39, 29, 21, 21);
      Ellipse(hdcMetafile, 10, 10, 20, 20);
      RoundRect(hdcMetafile, 10, 10, 20, 20, 3, 5);
      Polyline(hdcMetafile, pts, 4);
      PolylineTo(hdcMetafile, pts, 4);
      PolyPolyline(hdcMetafile, pts, counts, 2);
      PolyDraw(hdcMetafile, pts, types, 9);
      AngleArc(hdcMetafile, 37, 36, 23, 90, 180);
      EndPath(hdcMetafile);
  
      size = GetPath(hdcMetafile, NULL, NULL, 0);
      ok( size == 112, "GetPath returned %d.\n", size);
  
      ret = StrokeAndFillPath( hdcMetafile );
      ok( ret, "StrokeAndFillPath failed err %d\n", GetLastError() );
      ret = StrokeAndFillPath( hdcMetafile );
      ok( !ret, "StrokeAndFillPath succeeded\n" );
  
      hemf = CloseEnhMetaFile(hdcMetafile);
      ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
      if (compare_emf_bits(hemf, EMF_PATH_BITS, sizeof(EMF_PATH_BITS), "test_emf_paths", FALSE) != 0)
      {
          dump_emf_bits(hemf, "test_emf_paths");
          dump_emf_records(hemf, "test_emf_paths");
      }
  
      DeleteEnhMetaFile(hemf);
  
      SetLastError(0xdeadbeef);
      hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      ret = BeginPath(hdcMetafile);
      ok( ret, "BeginPath failed error %d\n", GetLastError() );
      ret = CloseFigure(hdcMetafile);
      ok( ret, "CloseFigure failed error %d\n", GetLastError() );
      ret = BeginPath(hdcMetafile);
      ok( ret, "BeginPath failed error %d\n", GetLastError() );
      ret = EndPath(hdcMetafile);
      ok( ret, "EndPath failed error %d\n", GetLastError() );
      ret = EndPath(hdcMetafile);
      ok( !ret, "EndPath succeeded\n" );
      ret = CloseFigure(hdcMetafile);
      ok( !ret, "CloseFigure succeeded\n" );
      ret = BeginPath(hdcMetafile);
      ok( ret, "BeginPath failed error %d\n", GetLastError() );
      ret = AbortPath(hdcMetafile);
      ok( ret, "AbortPath failed error %d\n", GetLastError() );
      ret = AbortPath(hdcMetafile);
      ok( ret, "AbortPath failed error %d\n", GetLastError() );
  
      hemf = CloseEnhMetaFile(hdcMetafile);
      ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
      if (compare_emf_bits(hemf, EMF_EMPTY_PATH_BITS, sizeof(EMF_EMPTY_PATH_BITS), "empty path", FALSE) != 0)
      {
          dump_emf_bits(hemf, "empty path");
          dump_emf_records(hemf, "empty path");
      }
  
      DeleteEnhMetaFile(hemf);
  }
  
  static void test_emf_PolyPolyline(void)
  {
      HDC hdcMetafile;
      HENHMETAFILE hemf;
      POINT pts[4] = {{10, 20}, {100, 200}, {0x9000,300}, {400, 500}};
      DWORD counts[2];
      BOOL ret;
  
      SetLastError(0xdeadbeef);
      hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
      ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
      ret = PolyPolyline(hdcMetafile, NULL, NULL, 0);
      ok( !ret, "PolyPolyline\n" );
  
      SetLastError( 0xdeadbeef );
      counts[0] = 0;
      counts[1] = 1;
      ret = PolyPolyline(hdcMetafile, pts, counts, 2);
      ok( !ret, "PolyPolyline\n" );
      ok( GetLastError() == ERROR_INVALID_PARAMETER, "gle %d\n", GetLastError() );
  
      SetLastError( 0xdeadbeef );
      counts[0] = 1;
      counts[1] = 1;
      ret = PolyPolyline(hdcMetafile, pts, counts, 2);
      ok( !ret, "PolyPolyline\n" );
      ok( GetLastError() == ERROR_INVALID_PARAMETER, "gle %d\n", GetLastError() );
  
      SetLastError( 0xdeadbeef );
      counts[0] = 2;
      counts[1] = 1;
      ret = PolyPolyline(hdcMetafile, pts, counts, 2);
      ok( !ret, "PolyPolyline\n" );
      ok( GetLastError() == ERROR_INVALID_PARAMETER, "gle %d\n", GetLastError() );
  
      counts[0] = 2;
      counts[1] = 2;
      ret = PolyPolyline(hdcMetafile, pts, counts, 2);
      ok( ret, "PolyPolyline\n" );
  
      hemf = CloseEnhMetaFile(hdcMetafile);
      ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
      if(compare_emf_bits(hemf, EMF_POLYPOLYLINE_BITS, sizeof(EMF_POLYPOLYLINE_BITS),
          "emf_PolyPolyline", FALSE) != 0)
      {
          dump_emf_bits(hemf, "emf_PolyPolyline");
          dump_emf_records(hemf, "emf_PolyPolyline");
      }
  
      DeleteEnhMetaFile(hemf);
  }
  
  static void test_emf_GradientFill(void)
  {
      HDC mf;
      HENHMETAFILE hemf;
      TRIVERTEX v[] =
      {
          {   1,  10, 0xff00, 0x8000, 0x0000, 0x8001 },
          { 200, 210, 0x0000, 0x0000, 0xff00, 0xff00 },
          { 180, 190, 0x1234, 0x5678, 0x9abc, 0xdef0 },
          { 300, 310, 0xff00, 0xff00, 0xff00, 0x0000 },
          { 400, 410, 0xff00, 0xff00, 0xff00, 0x0000 }
      };
      GRADIENT_TRIANGLE tri[] = { { 0, 1, 2 }, { 3, 1, 0 } };
      BOOL ret;
  
      mf = CreateEnhMetaFileA( GetDC( 0 ), NULL, NULL, NULL );
      ok( mf != 0, "CreateEnhMetaFileA error %d\n", GetLastError() );
  
      /* Don't test the GRADIENT_FILL_RECT_ modes since a Windows bug
       * means it allocates three mesh indices rather than two per
       * rectangle.  This results in uninitialised values being written
       * to the EMF which is rather difficult to test against.
       *
       * Note also that the final vertex here is not required, yet it is
       * written to the EMF, but is not considered in the bounds
       * calculation.
       */
      ret = GdiGradientFill( mf, v, sizeof(v) / sizeof(v[0]), tri, sizeof(tri) / sizeof(tri[0]),
                             GRADIENT_FILL_TRIANGLE );
      ok( ret, "GradientFill\n" );
  
      hemf = CloseEnhMetaFile( mf );
      ok( hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError() );
  
      if (compare_emf_bits( hemf, EMF_GRADIENTFILL_BITS, sizeof(EMF_GRADIENTFILL_BITS),
                            "emf_GradientFill", FALSE ) != 0)
      {
          dump_emf_bits( hemf, "emf_GradientFill" );
          dump_emf_records( hemf, "emf_GradientFill" );
      }
  
      DeleteEnhMetaFile( hemf );
  }
  
  static void set_rotation_xform(XFORM *out, float rad, int dx, int dy)
  {
      out->eM11 = cosf(rad);
      out->eM12 = -1.f * sinf(rad);
      out->eM21 = sinf(rad);
      out->eM22 = cosf(rad);
      out->eDx = dx;
      out->eDy = dy;
  }
  
  struct emf_WorldTransform_test_data
  {
      const char *name;
  
      BOOL do_modify;
      BOOL do_playback;
  
      XFORM expected;
      XFORM scale;
      XFORM stored; /* this is the "hidden" world transform used in PlayEnhMetaFileRecord */
  };
  
  static BOOL xform_eq(const XFORM *a, const XFORM *b)
  {
      return fabs(a->eM11 - b->eM11) < 0.001f &&
          fabs(a->eM12 - b->eM12) < 0.001f &&
          fabs(a->eM21 - b->eM21) < 0.001f &&
          fabs(a->eM22 - b->eM22) < 0.001f &&
          fabs(a->eDx - b->eDx) < 0.001f &&
          fabs(a->eDy - b->eDy) < 0.001f;
  }
  
  static INT CALLBACK enum_emf_WorldTransform(HDC hdc, HANDLETABLE *ht,
          const ENHMETARECORD *emr, INT nobj, LPARAM param)
  {
      XFORM xform = {0};
      struct emf_WorldTransform_test_data *test_data = (struct emf_WorldTransform_test_data *)param;
      BOOL ret;
  
      switch(emr->iType)
      {
      case EMR_SETWORLDTRANSFORM:
          {
              const EMRSETWORLDTRANSFORM *lpXfrm = (const EMRSETWORLDTRANSFORM *)emr;
  
              /* get scale factors with an identity world transform */
              GetWorldTransform(hdc, &test_data->scale);
  
              /* play back record */
              ret = PlayEnhMetaFileRecord(hdc, ht, emr, nobj);
              ok(ret == TRUE, "%s: PlayEnhMetaFileRecord failed\n", test_data->name);
  
              test_data->stored = lpXfrm->xform;
              CombineTransform(&test_data->expected, &test_data->stored, &test_data->scale);
  
              /* verify it is updated immediately */
              ret = GetWorldTransform(hdc, &xform);
              ok(ret == TRUE, "%s: GetWorldTransform failed\n", test_data->name);
              ok(xform_eq(&xform, &test_data->expected),
                      "%s: After SWT playback, got wrong world transform: %f, %f; %f %f; %f %f; expected: %f, %f; %f %f; %f %f\n",
                      test_data->name,
                      xform.eM11, xform.eM12,
                      xform.eM21, xform.eM22,
                      xform.eDx, xform.eDy,
                      test_data->expected.eM11, test_data->expected.eM12,
                      test_data->expected.eM21, test_data->expected.eM22,
                      test_data->expected.eDx, test_data->expected.eDy);
  
              break;
          }
  
      case EMR_MODIFYWORLDTRANSFORM:
          {
              const EMRMODIFYWORLDTRANSFORM *lpXfrm = (const EMRMODIFYWORLDTRANSFORM *)emr;
  
              /* transform persists across calls */
              ret = GetWorldTransform(hdc, &xform);
              ok(ret == TRUE, "%s: GetWorldTransform failed\n", test_data->name);
              ok(xform_eq(&xform, &test_data->expected),
                      "%s: On MWT entry, got wrong world transform: %f, %f; %f %f; %f %f; expected: %f, %f; %f %f; %f %f\n",
                      test_data->name,
                      xform.eM11, xform.eM12,
                      xform.eM21, xform.eM22,
                      xform.eDx, xform.eDy,
                      test_data->expected.eM11, test_data->expected.eM12,
                      test_data->expected.eM21, test_data->expected.eM22,
                      test_data->expected.eDx, test_data->expected.eDy);
  
              if(test_data->do_playback)
              {
                  /* play back record */
                  ret = PlayEnhMetaFileRecord(hdc, ht, emr, nobj);
                  ok(ret == TRUE, "%s: PlayEnhMetaFileRecord failed\n", test_data->name);
  
                  if(lpXfrm->iMode == MWT_LEFTMULTIPLY)
                  {
                      /* left multiply does not discard direct modifications */
                      CombineTransform(&test_data->expected, &lpXfrm->xform, &test_data->expected);
  
                      /* and updates the stored matrix separately */
                      CombineTransform(&test_data->stored, &lpXfrm->xform, &test_data->stored);
  
                  }
                  else if(lpXfrm->iMode == MWT_RIGHTMULTIPLY)
                  {
                      /* but right multiply does discard */
                      CombineTransform(&test_data->stored, &test_data->stored, &lpXfrm->xform);
  
                      CombineTransform(&test_data->expected, &test_data->stored, &test_data->scale);
                  }
  
                  /* verify it is updated immediately */
                  ret = GetWorldTransform(hdc, &xform);
                  ok(ret == TRUE, "%s: GetWorldTransform failed\n", test_data->name);
                  ok(xform_eq(&xform, &test_data->expected),
                          "%s: After MWT playback, got wrong world transform: %f, %f; %f %f; %f %f; expected: %f, %f; %f %f; %f %f\n",
                          test_data->name,
                          xform.eM11, xform.eM12,
                          xform.eM21, xform.eM22,
                          xform.eDx, xform.eDy,
                          test_data->expected.eM11, test_data->expected.eM12,
                          test_data->expected.eM21, test_data->expected.eM22,
                          test_data->expected.eDx, test_data->expected.eDy);
              }
  
              if(test_data->do_modify)
              {
                  /* modify directly */
                  set_rotation_xform(&xform, M_PI / 4.f, 1, -1);
                  ret = ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
                  ok(ret == TRUE, "%s: ModifyWorldTransform failed\n", test_data->name);
  
                  /* the modified transform persists across callback calls */
                  CombineTransform(&test_data->expected, &xform, &test_data->expected);
  
                  ret = GetWorldTransform(hdc, &xform);
                  ok(ret == TRUE, "%s: GetWorldTransform failed\n", test_data->name);
                  ok(xform_eq(&xform, &test_data->expected),
                          "%s: After ModifyWT, got wrong world transform: %f, %f; %f %f; %f %f; expected: %f, %f; %f %f; %f %f\n",
                          test_data->name,
                          xform.eM11, xform.eM12,
                          xform.eM21, xform.eM22,
                          xform.eDx, xform.eDy,
                          test_data->expected.eM11, test_data->expected.eM12,
                          test_data->expected.eM21, test_data->expected.eM22,
                          test_data->expected.eDx, test_data->expected.eDy);
              }
  
              break;
          }
  
      case EMR_LINETO:
          ret = GetWorldTransform(hdc, &xform);
          ok(ret == TRUE, "%s: GetWorldTransform failed\n", test_data->name);
          ok(xform_eq(&xform, &test_data->expected),
                  "%s: Before LINETO playback, got wrong world transform: %f, %f; %f %f; %f %f; expected: %f, %f; %f %f; %f %f\n",
                  test_data->name,
                  xform.eM11, xform.eM12,
                  xform.eM21, xform.eM22,
                  xform.eDx, xform.eDy,
                  test_data->expected.eM11, test_data->expected.eM12,
                  test_data->expected.eM21, test_data->expected.eM22,
                  test_data->expected.eDx, test_data->expected.eDy);
  
          ret = PlayEnhMetaFileRecord(hdc, ht, emr, nobj);
          ok(ret == TRUE, "%s: PlayEnhMetaFileRecord failed\n", test_data->name);
  
          /* transform doesn't change during LINETO playback */
          ret = GetWorldTransform(hdc, &xform);
          ok(ret == TRUE, "%s: GetWorldTransform failed\n", test_data->name);
          ok(xform_eq(&xform, &test_data->expected),
                  "%s: After LINETO playback, got wrong world transform: %f, %f; %f %f; %f %f; expected: %f, %f; %f %f; %f %f\n",
                  test_data->name,
                  xform.eM11, xform.eM12,
                  xform.eM21, xform.eM22,
                  xform.eDx, xform.eDy,
                  test_data->expected.eM11, test_data->expected.eM12,
                  test_data->expected.eM21, test_data->expected.eM22,
                  test_data->expected.eDx, test_data->expected.eDy);
  
          break;
  
      default:
          PlayEnhMetaFileRecord(hdc, ht, emr, nobj);
          break;
      }
  
      return 1;
  }
  
  static void test_emf_WorldTransform(void)
  {
      HDC hdcMetafile, hdc;
      HWND hwnd;
      HENHMETAFILE hemf;
      XFORM xform;
      BOOL ret;
      RECT rect = { 0, 0, 100, 100 };
      int i;
      struct emf_WorldTransform_test_data test_data[] = {
          { "normal", FALSE, TRUE },
          { "playback and modify", TRUE, TRUE },
          { "manual modify", TRUE, FALSE }
      };
  
      for(i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
      {
          hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
          ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
  
          ret = SetGraphicsMode(hdcMetafile, GM_ADVANCED);
          ok(ret == TRUE, "SetGraphicsMode failed\n");
  
          set_rotation_xform(&xform, M_PI / 4.f, 2, 3);
          ret = SetWorldTransform(hdcMetafile, &xform); /* EMR_SETWORLDTRANSFORM */
          ok(ret == TRUE, "SetWorldTransform failed\n");
  
          set_rotation_xform(&xform, M_PI / 2.f, -2, -3);
          ret = ModifyWorldTransform(hdcMetafile, &xform, MWT_LEFTMULTIPLY); /* EMR_MODIFYWORLDTRANSFORM */
          ok(ret == TRUE, "ModifyWorldTransform failed\n");
  
          set_rotation_xform(&xform, M_PI / 3.f, -2, 3);
          ret = ModifyWorldTransform(hdcMetafile, &xform, MWT_LEFTMULTIPLY); /* EMR_MODIFYWORLDTRANSFORM */
          ok(ret == TRUE, "ModifyWorldTransform failed\n");
  
          set_rotation_xform(&xform, M_PI, 2, -3);
          ret = ModifyWorldTransform(hdcMetafile, &xform, MWT_RIGHTMULTIPLY); /* EMR_MODIFYWORLDTRANSFORM */
          ok(ret == TRUE, "ModifyWorldTransform failed\n");
  
          ret = LineTo(hdcMetafile, 1, 1);
          ok(ret == TRUE, "LineTo failed\n");
  
          hemf = CloseEnhMetaFile(hdcMetafile);
          ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
  
          hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
                                 0, 0, 200, 200, 0, 0, 0, NULL);
          ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
  
          hdc = GetDC(hwnd);
          ok(hdc != 0, "GetDC failed\n");
  
          ret = EnumEnhMetaFile(hdc, hemf, enum_emf_WorldTransform, &test_data[i], &rect);
          ok(ret == TRUE, "EnumEnhMetaFile failed: %u\n", GetLastError());
  
          ReleaseDC(hwnd, hdc);
          DestroyWindow(hwnd);
  
          DeleteEnhMetaFile(hemf);
      }
  }
  
  START_TEST(metafile)
  {
      init_function_pointers();
  
      /* For enhanced metafiles (enhmfdrv) */
      test_ExtTextOut();
      test_ExtTextOutScale();
      test_SaveDC();
      test_emf_BitBlt();
      test_emf_DCBrush();
      test_emf_ExtTextOut_on_path();
      test_emf_clipping();
      test_emf_polybezier();
      test_emf_paths();
      test_emf_PolyPolyline();
      test_emf_GradientFill();
      test_emf_WorldTransform();
  
      /* For win-format metafiles (mfdrv) */
      test_mf_SaveDC();
      test_mf_Blank();
      test_mf_Graphics();
      test_mf_PatternBrush();
      test_mf_DCBrush();
      test_CopyMetaFile();
      test_SetMetaFileBits();
      test_mf_ExtTextOut_on_path();
      test_mf_clipping();
      test_mf_GetPath();
  
      /* For metafile conversions */
      test_mf_conversions();
      test_SetWinMetaFileBits();
      test_GetWinMetaFileBits();
  
      test_gdiis();
      test_SetEnhMetaFileBits();
  }
  