[GDIPLUS]
authorAmine Khaldi <amine.khaldi@reactos.org>
Tue, 22 Apr 2014 15:42:03 +0000 (15:42 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Tue, 22 Apr 2014 15:42:03 +0000 (15:42 +0000)
* Sync with Wine 1.7.17.
CORE-8080

svn path=/trunk/; revision=62888

reactos/dll/win32/gdiplus/brush.c
reactos/dll/win32/gdiplus/font.c
reactos/dll/win32/gdiplus/gdiplus.c
reactos/dll/win32/gdiplus/gdiplus_private.h
reactos/dll/win32/gdiplus/graphics.c
reactos/dll/win32/gdiplus/graphicspath.c
reactos/dll/win32/gdiplus/image.c
reactos/dll/win32/gdiplus/metafile.c
reactos/dll/win32/gdiplus/pathiterator.c
reactos/dll/win32/gdiplus/region.c
reactos/media/doc/README.WINE

index c4f433f..3382b6b 100644 (file)
@@ -756,8 +756,6 @@ GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
 
 /******************************************************************************
  * GdipCreateTextureIA [GDIPLUS.@]
- *
- * FIXME: imageattr ignored
  */
 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
     GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
@@ -855,6 +853,7 @@ GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
         imageattr->wrap = wrapmode;
 
         stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture);
+        GdipDisposeImageAttributes(imageattr);
     }
 
     return stat;
index 7c055a6..c710f5b 100644 (file)
@@ -1112,15 +1112,39 @@ GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontColle
 /*****************************************************************************
  * GdipPrivateAddFontFile [GDIPLUS.@]
  */
-GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection,
-        GDIPCONST WCHAR* filename)
+GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection *collection, GDIPCONST WCHAR *name)
 {
-    FIXME("stub: %p, %s\n", fontCollection, debugstr_w(filename));
+    HANDLE file, mapping;
+    LARGE_INTEGER size;
+    void *mem;
+    GpStatus status;
+
+    TRACE("%p, %s\n", collection, debugstr_w(name));
+
+    if (!collection || !name) return InvalidParameter;
 
-    if (!(fontCollection && filename))
+    file = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+    if (file == INVALID_HANDLE_VALUE) return InvalidParameter;
+
+    if (!GetFileSizeEx(file, &size) || size.u.HighPart)
+    {
+        CloseHandle(file);
         return InvalidParameter;
+    }
+
+    mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
+    CloseHandle(file);
+    if (!mapping) return InvalidParameter;
+
+    mem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+    CloseHandle(mapping);
+    if (!mem) return InvalidParameter;
+
+    /* GdipPrivateAddMemoryFont creates a copy of the memory block */
+    status = GdipPrivateAddMemoryFont(collection, mem, size.u.LowPart);
+    UnmapViewOfFile(mem);
 
-    return NotImplemented;
+    return status;
 }
 
 #define TT_PLATFORM_APPLE_UNICODE   0
index 7be681a..2204e6a 100644 (file)
@@ -357,7 +357,7 @@ REAL units_scale(GpUnit from, GpUnit to, REAL dpi)
 }
 
 /* Calculates Bezier points from cardinal spline points. */
-void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
+void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
     REAL *y1, REAL *x2, REAL *y2)
 {
     REAL xdiff, ydiff;
@@ -442,7 +442,7 @@ void delete_element(region_element* element)
         case RegionDataRect:
             break;
         case RegionDataPath:
-            GdipDeletePath(element->elementdata.pathdata.path);
+            GdipDeletePath(element->elementdata.path);
             break;
         case RegionDataEmptyRect:
         case RegionDataInfiniteRect:
@@ -456,13 +456,13 @@ void delete_element(region_element* element)
     }
 }
 
-const char *debugstr_rectf(CONST RectF* rc)
+const char *debugstr_rectf(const RectF* rc)
 {
     if (!rc) return "(null)";
     return wine_dbg_sprintf("(%0.2f,%0.2f,%0.2f,%0.2f)", rc->X, rc->Y, rc->Width, rc->Height);
 }
 
-const char *debugstr_pointf(CONST PointF* pt)
+const char *debugstr_pointf(const PointF* pt)
 {
     if (!pt) return "(null)";
     return wine_dbg_sprintf("(%0.2f,%0.2f)", pt->X, pt->Y);
index 94ec592..b983492 100644 (file)
@@ -65,10 +65,12 @@ extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLS
 extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
 extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
 extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN;
+extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
+    GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
+extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
 extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
-extern MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) DECLSPEC_HIDDEN;
 
-extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
+extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
     REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
 extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
     REAL tension, REAL *x, REAL *y) DECLSPEC_HIDDEN;
@@ -122,9 +124,9 @@ static inline ARGB color_over(ARGB bg, ARGB fg)
     return (a<<24)|(r<<16)|(g<<8)|b;
 }
 
-extern const char *debugstr_rectf(CONST RectF* rc) DECLSPEC_HIDDEN;
+extern const char *debugstr_rectf(const RectF* rc) DECLSPEC_HIDDEN;
 
-extern const char *debugstr_pointf(CONST PointF* pt) DECLSPEC_HIDDEN;
+extern const char *debugstr_pointf(const PointF* pt) DECLSPEC_HIDDEN;
 
 extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
     BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride) DECLSPEC_HIDDEN;
@@ -304,8 +306,12 @@ struct GpMetafile{
     GpGraphics *playback_graphics;
     HDC playback_dc;
     GpPointF playback_points[3];
+    GpRectF src_rect;
     HANDLETABLE *handle_table;
     int handle_count;
+    GpMatrix *world_transform;
+    GpUnit page_unit;
+    REAL page_scale;
 };
 
 struct GpBitmap{
@@ -412,17 +418,7 @@ struct region_element
     union
     {
         GpRectF rect;
-        struct
-        {
-            GpPath* path;
-            struct
-            {
-                DWORD size;
-                DWORD magic;
-                DWORD count;
-                DWORD flags;
-            } pathheader;
-        } pathdata;
+        GpPath *path;
         struct
         {
             struct region_element *left;  /* the original region */
@@ -432,13 +428,7 @@ struct region_element
 };
 
 struct GpRegion{
-    struct
-    {
-        DWORD size;
-        DWORD checksum;
-        DWORD magic;
-        DWORD num_children;
-    } header;
+    DWORD num_children;
     region_element node;
 };
 
index 0a6cdcc..8be792a 100644 (file)
@@ -617,7 +617,7 @@ static ARGB transform_color(ARGB color, const ColorMatrix *matrix)
     return (a << 24) | (r << 16) | (g << 8) | b;
 }
 
-static int color_is_gray(ARGB color)
+static BOOL color_is_gray(ARGB color)
 {
     unsigned char r, g, b;
 
@@ -940,12 +940,12 @@ static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL
     return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X;
 }
 
-static INT brush_can_fill_path(GpBrush *brush)
+static BOOL brush_can_fill_path(GpBrush *brush)
 {
     switch (brush->bt)
     {
     case BrushTypeSolidColor:
-        return 1;
+        return TRUE;
     case BrushTypeHatchFill:
     {
         GpHatch *hatch = (GpHatch*)brush;
@@ -956,7 +956,7 @@ static INT brush_can_fill_path(GpBrush *brush)
     case BrushTypeTextureFill:
     /* Gdi32 isn't much help with these, so we should use brush_fill_pixels instead. */
     default:
-        return 0;
+        return FALSE;
     }
 }
 
@@ -1008,7 +1008,7 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
     }
 }
 
-static INT brush_can_fill_pixels(GpBrush *brush)
+static BOOL brush_can_fill_pixels(GpBrush *brush)
 {
     switch (brush->bt)
     {
@@ -1017,9 +1017,9 @@ static INT brush_can_fill_pixels(GpBrush *brush)
     case BrushTypeLinearGradient:
     case BrushTypeTextureFill:
     case BrushTypePathGradient:
-        return 1;
+        return TRUE;
     default:
-        return 0;
+        return FALSE;
     }
 }
 
@@ -1239,7 +1239,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
         INT min_y, max_y, min_x, max_x;
         INT x, y;
         ARGB outer_color;
-        static int transform_fixme_once;
+        static BOOL transform_fixme_once;
 
         if (fill->focus.X != 0.0 || fill->focus.Y != 0.0)
         {
@@ -1276,7 +1276,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
             if (!is_identity)
             {
                 FIXME("path gradient transform not implemented\n");
-                transform_fixme_once = 1;
+                transform_fixme_once = TRUE;
             }
         }
 
@@ -1310,7 +1310,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
         for (i=0; i<flat_path->pathdata.Count; i++)
         {
             int start_center_line=0, end_center_line=0;
-            int seen_start=0, seen_end=0, seen_center=0;
+            BOOL seen_start = FALSE, seen_end = FALSE, seen_center = FALSE;
             REAL center_distance;
             ARGB start_color, end_color;
             REAL dy, dx;
@@ -1370,17 +1370,17 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
 
                 if (!seen_start && yf >= start_point.Y)
                 {
-                    seen_start = 1;
+                    seen_start = TRUE;
                     start_center_line ^= 1;
                 }
                 if (!seen_end && yf >= end_point.Y)
                 {
-                    seen_end = 1;
+                    seen_end = TRUE;
                     end_center_line ^= 1;
                 }
                 if (!seen_center && yf >= center_point.Y)
                 {
-                    seen_center = 1;
+                    seen_center = TRUE;
                     start_center_line ^= 1;
                     end_center_line ^= 1;
                 }
@@ -2243,120 +2243,6 @@ GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
     return GdipCreateFromHWND(hwnd, graphics);
 }
 
-GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
-    GpMetafile **metafile)
-{
-    ENHMETAHEADER header;
-    MetafileType metafile_type;
-
-    TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
-
-    if(!hemf || !metafile)
-        return InvalidParameter;
-
-    if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
-        return GenericError;
-
-    metafile_type = METAFILE_GetEmfType(hemf);
-
-    if (metafile_type == MetafileTypeInvalid)
-        return GenericError;
-
-    *metafile = GdipAlloc(sizeof(GpMetafile));
-    if (!*metafile)
-        return OutOfMemory;
-
-    (*metafile)->image.type = ImageTypeMetafile;
-    (*metafile)->image.format = ImageFormatEMF;
-    (*metafile)->image.frame_count = 1;
-    (*metafile)->image.xres = (REAL)header.szlDevice.cx;
-    (*metafile)->image.yres = (REAL)header.szlDevice.cy;
-    (*metafile)->bounds.X = (REAL)header.rclBounds.left;
-    (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
-    (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
-    (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
-    (*metafile)->unit = UnitPixel;
-    (*metafile)->metafile_type = metafile_type;
-    (*metafile)->hemf = hemf;
-    (*metafile)->preserve_hemf = !delete;
-
-    TRACE("<-- %p\n", *metafile);
-
-    return Ok;
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
-    GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
-{
-    UINT read;
-    BYTE *copy;
-    HENHMETAFILE hemf;
-    GpStatus retval = Ok;
-
-    TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
-
-    if(!hwmf || !metafile || !placeable)
-        return InvalidParameter;
-
-    *metafile = NULL;
-    read = GetMetaFileBitsEx(hwmf, 0, NULL);
-    if(!read)
-        return GenericError;
-    copy = GdipAlloc(read);
-    GetMetaFileBitsEx(hwmf, read, copy);
-
-    hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
-    GdipFree(copy);
-
-    /* FIXME: We should store and use hwmf instead of converting to hemf */
-    retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
-
-    if (retval == Ok)
-    {
-        (*metafile)->image.xres = (REAL)placeable->Inch;
-        (*metafile)->image.yres = (REAL)placeable->Inch;
-        (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
-        (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
-        (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
-                                           placeable->BoundingBox.Left);
-        (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
-                                            placeable->BoundingBox.Top);
-        (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
-        (*metafile)->image.format = ImageFormatWMF;
-
-        if (delete) DeleteMetaFile(hwmf);
-    }
-    else
-        DeleteEnhMetaFile(hemf);
-    return retval;
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
-    GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
-{
-    HMETAFILE hmf = GetMetaFileW(file);
-
-    TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
-
-    if(!hmf) return InvalidParameter;
-
-    return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
-    GpMetafile **metafile)
-{
-    FIXME("(%p, %p): stub\n", file, metafile);
-    return NotImplemented;
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
-    GpMetafile **metafile)
-{
-    FIXME("(%p, %p): stub\n", stream, metafile);
-    return NotImplemented;
-}
-
 GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
     UINT access, IStream **stream)
 {
@@ -2405,6 +2291,12 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
     }
 
     GdipDeleteRegion(graphics->clip);
+
+    /* Native returns ObjectBusy on the second free, instead of crashing as we'd
+     * do otherwise, but we can't have that in the test suite because it means
+     * accessing freed memory. */
+    graphics->busy = TRUE;
+
     GdipFree(graphics);
 
     return Ok;
@@ -2885,9 +2777,33 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
         debugstr_pointf(&points[2]));
 
     memcpy(ptf, points, 3 * sizeof(GpPointF));
+
+    /* Ensure source width/height is positive */
+    if (srcwidth < 0)
+    {
+        GpPointF tmp = ptf[1];
+        srcx = srcx + srcwidth;
+        srcwidth = -srcwidth;
+        ptf[2].X = ptf[2].X + ptf[1].X - ptf[0].X;
+        ptf[2].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
+        ptf[1] = ptf[0];
+        ptf[0] = tmp;
+    }
+
+    if (srcheight < 0)
+    {
+        GpPointF tmp = ptf[2];
+        srcy = srcy + srcheight;
+        srcheight = -srcheight;
+        ptf[1].X = ptf[1].X + ptf[2].X - ptf[0].X;
+        ptf[1].Y = ptf[1].Y + ptf[2].Y - ptf[0].Y;
+        ptf[2] = ptf[0];
+        ptf[0] = tmp;
+    }
+
     ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X;
     ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
-    if (!srcwidth || !srcheight || ptf[3].X == ptf[0].X || ptf[3].Y == ptf[0].Y)
+    if (!srcwidth || !srcheight || (ptf[3].X == ptf[0].X && ptf[3].Y == ptf[0].Y))
         return Ok;
     transform_and_round_points(graphics, pti, ptf, 4);
 
@@ -2919,7 +2835,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
     else if (image->type == ImageTypeBitmap)
     {
         GpBitmap* bitmap = (GpBitmap*)image;
-        int use_software=0;
+        BOOL use_software = FALSE;
 
         TRACE("graphics: %.2fx%.2f dpi, fmt %#x, scale %f, image: %.2fx%.2f dpi, fmt %#x, color %08x\n",
             graphics->xres, graphics->yres,
@@ -2933,11 +2849,12 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             ptf[1].X - ptf[0].X != srcwidth || ptf[2].Y - ptf[0].Y != srcheight ||
             srcx < 0 || srcy < 0 ||
             srcx + srcwidth > bitmap->width || srcy + srcheight > bitmap->height)
-            use_software = 1;
+            use_software = TRUE;
 
         if (use_software)
         {
             RECT dst_area;
+            GpRectF graphics_bounds;
             GpRect src_area;
             int i, x, y, src_stride, dst_stride;
             GpMatrix dst_to_src;
@@ -2963,8 +2880,18 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
                 if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
             }
 
+            stat = get_graphics_bounds(graphics, &graphics_bounds);
+            if (stat != Ok) return stat;
+
+            if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
+            if (graphics_bounds.Y > dst_area.top) dst_area.top = floorf(graphics_bounds.Y);
+            if (graphics_bounds.X + graphics_bounds.Width < dst_area.right) dst_area.right = ceilf(graphics_bounds.X + graphics_bounds.Width);
+            if (graphics_bounds.Y + graphics_bounds.Height < dst_area.bottom) dst_area.bottom = ceilf(graphics_bounds.Y + graphics_bounds.Height);
+
             TRACE("dst_area: %s\n", wine_dbgstr_rect(&dst_area));
 
+            if (IsRectEmpty(&dst_area)) return Ok;
+
             m11 = (ptf[1].X - ptf[0].X) / srcwidth;
             m21 = (ptf[2].X - ptf[0].X) / srcheight;
             mdx = ptf[0].X - m11 * srcx - m21 * srcy;
@@ -3010,8 +2937,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
 
             if (stat != Ok)
             {
-                if (src_data != dst_data)
-                    GdipFree(src_data);
+                GdipFree(src_data);
                 GdipFree(dst_data);
                 return stat;
             }
@@ -3060,7 +2986,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
         else
         {
             HDC hdc;
-            int temp_hdc=0, temp_bitmap=0;
+            BOOL temp_hdc = FALSE, temp_bitmap = FALSE;
             HBITMAP hbitmap, old_hbm=NULL;
 
             if (!(bitmap->format == PixelFormat16bppRGB555 ||
@@ -3074,8 +3000,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
 
                 /* we can't draw a bitmap of this format directly */
                 hdc = CreateCompatibleDC(0);
-                temp_hdc = 1;
-                temp_bitmap = 1;
+                temp_hdc = TRUE;
+                temp_bitmap = TRUE;
 
                 bih.biSize = sizeof(BITMAPINFOHEADER);
                 bih.biWidth = bitmap->width;
@@ -3109,7 +3035,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
                 else
                 {
                     GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
-                    temp_bitmap = 1;
+                    temp_bitmap = TRUE;
                 }
 
                 hdc = bitmap->hdc;
@@ -3338,6 +3264,7 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
 {
     INT save_state;
     GpStatus retval;
+    HRGN hrgn=NULL;
 
     TRACE("(%p, %p, %p)\n", graphics, pen, path);
 
@@ -3355,10 +3282,20 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
 
     save_state = prepare_dc(graphics, pen);
 
+    retval = get_clip_hrgn(graphics, &hrgn);
+
+    if (retval != Ok)
+        goto end;
+
+    if (hrgn)
+        ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+
     retval = draw_poly(graphics, pen, path->pathdata.Points,
                        path->pathdata.Types, path->pathdata.Count, TRUE);
 
+end:
     restore_dc(graphics, save_state);
+    DeleteObject(hrgn);
 
     return retval;
 }
@@ -3603,6 +3540,7 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
 {
     INT save_state;
     GpStatus retval;
+    HRGN hrgn=NULL;
 
     if(!graphics->hdc || !brush_can_fill_path(brush))
         return NotImplemented;
@@ -3612,6 +3550,14 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
     SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
                                                                     : WINDING));
 
+    retval = get_clip_hrgn(graphics, &hrgn);
+
+    if (retval != Ok)
+        goto end;
+
+    if (hrgn)
+        ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+
     BeginPath(graphics->hdc);
     retval = draw_poly(graphics, NULL, path->pathdata.Points,
                        path->pathdata.Types, path->pathdata.Count, FALSE);
@@ -3626,6 +3572,7 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
 
 end:
     RestoreDC(graphics->hdc, save_state);
+    DeleteObject(hrgn);
 
     return retval;
 }
@@ -3795,38 +3742,31 @@ GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush,
 GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
     REAL x, REAL y, REAL width, REAL height)
 {
-    GpStatus stat;
-    GpPath *path;
+    GpRectF rect;
 
     TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
 
-    if(!graphics || !brush)
-        return InvalidParameter;
-
-    if(graphics->busy)
-        return ObjectBusy;
-
-    stat = GdipCreatePath(FillModeAlternate, &path);
-
-    if (stat == Ok)
-    {
-        stat = GdipAddPathRectangle(path, x, y, width, height);
-
-        if (stat == Ok)
-            stat = GdipFillPath(graphics, brush, path);
-
-        GdipDeletePath(path);
-    }
+    rect.X = x;
+    rect.Y = y;
+    rect.Width = width;
+    rect.Height = height;
 
-    return stat;
+    return GdipFillRectangles(graphics, brush, &rect, 1);
 }
 
 GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
     INT x, INT y, INT width, INT height)
 {
+    GpRectF rect;
+
     TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
 
-    return GdipFillRectangle(graphics, brush, x, y, width, height);
+    rect.X = (REAL)x;
+    rect.Y = (REAL)y;
+    rect.Width = (REAL)width;
+    rect.Height = (REAL)height;
+
+    return GdipFillRectangles(graphics, brush, &rect, 1);
 }
 
 GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects,
@@ -3837,9 +3777,16 @@ GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDI
 
     TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
 
-    if(!rects)
+    if(!graphics || !brush || !rects || count <= 0)
         return InvalidParameter;
 
+    if (graphics->image && graphics->image->type == ImageTypeMetafile)
+    {
+        status = METAFILE_FillRectangles((GpMetafile*)graphics->image, brush, rects, count);
+        /* FIXME: Add gdi32 drawing. */
+        return status;
+    }
+
     status = GdipCreatePath(FillModeAlternate, &path);
     if (status != Ok) return status;
 
@@ -4440,13 +4387,25 @@ GpStatus gdip_format_string(HDC hdc,
     INT *hotkeyprefix_offsets=NULL;
     INT hotkeyprefix_count=0;
     INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=0;
-    int seen_prefix=0;
+    BOOL seen_prefix = FALSE;
+    GpStringFormat *dyn_format=NULL;
 
     if(length == -1) length = lstrlenW(string);
 
     stringdup = GdipAlloc((length + 1) * sizeof(WCHAR));
     if(!stringdup) return OutOfMemory;
 
+    if (!format)
+    {
+        stat = GdipStringFormatGetGenericDefault(&dyn_format);
+        if (stat != Ok)
+        {
+            GdipFree(stringdup);
+            return stat;
+        }
+        format = dyn_format;
+    }
+
     nwidth = rect->Width;
     nheight = rect->Height;
     if (ignore_empty_clip)
@@ -4455,10 +4414,7 @@ GpStatus gdip_format_string(HDC hdc,
         if (!nheight) nheight = INT_MAX;
     }
 
-    if (format)
-        hkprefix = format->hkprefix;
-    else
-        hkprefix = HotkeyPrefixNone;
+    hkprefix = format->hkprefix;
 
     if (hkprefix == HotkeyPrefixShow)
     {
@@ -4487,11 +4443,11 @@ GpStatus gdip_format_string(HDC hdc,
             hotkeyprefix_offsets[hotkeyprefix_count++] = j;
         else if (!seen_prefix && hkprefix != HotkeyPrefixNone && string[i] == '&')
         {
-            seen_prefix = 1;
+            seen_prefix = TRUE;
             continue;
         }
 
-        seen_prefix = 0;
+        seen_prefix = FALSE;
 
         stringdup[j] = string[i];
         j++;
@@ -4499,8 +4455,7 @@ GpStatus gdip_format_string(HDC hdc,
 
     length = j;
 
-    if (format) halign = format->align;
-    else halign = StringAlignmentNear;
+    halign = format->align;
 
     while(sum < length){
         GetTextExtentExPointW(hdc, stringdup + sum, length - sum,
@@ -4547,7 +4502,11 @@ GpStatus gdip_format_string(HDC hdc,
         bounds.Width = size.cx;
 
         if(height + size.cy > nheight)
+        {
+            if (format->attr & StringFormatFlagsLineLimit)
+                break;
             bounds.Height = nheight - (height + size.cy);
+        }
         else
             bounds.Height = size.cy;
 
@@ -4589,13 +4548,13 @@ GpStatus gdip_format_string(HDC hdc,
             break;
 
         /* Stop if this was a linewrap (but not if it was a linebreak). */
-        if ((lret == fitcpy) && format &&
-            (format->attr & (StringFormatFlagsNoWrap | StringFormatFlagsLineLimit)))
+        if ((lret == fitcpy) && (format->attr & StringFormatFlagsNoWrap))
             break;
     }
 
     GdipFree(stringdup);
     GdipFree(hotkeyprefix_offsets);
+    GdipDeleteStringFormat(dyn_format);
 
     return stat;
 }
@@ -5239,6 +5198,8 @@ GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
 
 GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
 {
+    GpStatus stat;
+
     TRACE("(%p, %.2f)\n", graphics, scale);
 
     if(!graphics || (scale <= 0.0))
@@ -5247,6 +5208,13 @@ GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
     if(graphics->busy)
         return ObjectBusy;
 
+    if (graphics->image && graphics->image->type == ImageTypeMetafile)
+    {
+        stat = METAFILE_SetPageTransform((GpMetafile*)graphics->image, graphics->unit, scale);
+        if (stat != Ok)
+            return stat;
+    }
+
     graphics->scale = scale;
 
     return Ok;
@@ -5254,6 +5222,8 @@ GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
 
 GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
 {
+    GpStatus stat;
+
     TRACE("(%p, %d)\n", graphics, unit);
 
     if(!graphics)
@@ -5265,6 +5235,13 @@ GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
     if(unit == UnitWorld)
         return InvalidParameter;
 
+    if (graphics->image && graphics->image->type == ImageTypeMetafile)
+    {
+        stat = METAFILE_SetPageTransform((GpMetafile*)graphics->image, unit, graphics->scale);
+        if (stat != Ok)
+            return stat;
+    }
+
     graphics->unit = unit;
 
     return Ok;
@@ -5528,19 +5505,6 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
     return status;
 }
 
-GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
-    UINT limitDpi)
-{
-    static int calls;
-
-    TRACE("(%p,%u)\n", metafile, limitDpi);
-
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    return NotImplemented;
-}
-
 GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points,
     INT count)
 {
@@ -6204,15 +6168,18 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
         if (glyphsize > max_glyphsize)
             max_glyphsize = glyphsize;
 
-        left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
-        top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
-        right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
-        bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
-
-        if (left < min_x) min_x = left;
-        if (top < min_y) min_y = top;
-        if (right > max_x) max_x = right;
-        if (bottom > max_y) max_y = bottom;
+        if (glyphsize != 0)
+        {
+            left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
+            top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
+            right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
+            bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
+
+            if (left < min_x) min_x = left;
+            if (top < min_y) min_y = top;
+            if (right > max_x) max_x = right;
+            if (bottom > max_y) max_y = bottom;
+        }
 
         if (i+1 < length && (flags & DriverStringOptionsRealizedAdvance) == DriverStringOptionsRealizedAdvance)
         {
@@ -6221,6 +6188,10 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
         }
     }
 
+    if (max_glyphsize == 0)
+        /* Nothing to draw. */
+        return Ok;
+
     glyph_mask = GdipAlloc(max_glyphsize);
     text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y));
     text_mask_stride = max_x - min_x;
@@ -6238,11 +6209,15 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
     /* Generate a mask for the text */
     for (i=0; i<length; i++)
     {
+        DWORD ret;
         int left, top, stride;
 
-        GetGlyphOutlineW(hdc, text[i], ggo_flags,
+        ret = GetGlyphOutlineW(hdc, text[i], ggo_flags,
             &glyphmetrics, max_glyphsize, glyph_mask, &identity);
 
+        if (ret == GDI_ERROR || ret == 0)
+            continue; /* empty glyph */
+
         left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
         top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
         stride = (glyphmetrics.gmBlackBoxX + 3) & (~3);
index 4d145c3..e56f380 100644 (file)
@@ -854,7 +854,7 @@ static GpStatus format_string_callback(HDC dc,
     for (i = index; i < length; ++i)
     {
         GLYPHMETRICS gm;
-        TTPOLYGONHEADER *ph = NULL;
+        TTPOLYGONHEADER *ph = NULL, *origph;
         char *start;
         DWORD len, ofs = 0;
         len = GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, 0, NULL, &identity);
@@ -863,7 +863,7 @@ static GpStatus format_string_callback(HDC dc,
             status = GenericError;
             break;
         }
-        ph = GdipAlloc(len);
+        origph = ph = GdipAlloc(len);
         start = (char *)ph;
         if (!ph || !lengthen_path(path, len / sizeof(POINTFX)))
         {
@@ -917,7 +917,7 @@ static GpStatus format_string_callback(HDC dc,
         x += gm.gmCellIncX * args->scale;
         y += gm.gmCellIncY * args->scale;
 
-        GdipFree(ph);
+        GdipFree(origph);
         if (status != Ok)
             break;
     }
@@ -1837,8 +1837,9 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint,
     }
 }
 
-static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
-    path_list_node_t **last_point)
+static void widen_open_figure(const GpPointF *points, GpPen *pen, int start, int end,
+    GpLineCap start_cap, GpCustomLineCap *start_custom, GpLineCap end_cap,
+    GpCustomLineCap *end_custom, path_list_node_t **last_point)
 {
     int i;
     path_list_node_t *prev_point;
@@ -1848,22 +1849,22 @@ static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
 
     prev_point = *last_point;
 
-    widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
-        pen, pen->startcap, pen->customstart, FALSE, TRUE, last_point);
+    widen_cap(&points[start], &points[start+1],
+        pen, start_cap, start_custom, FALSE, TRUE, last_point);
 
     for (i=start+1; i<end; i++)
-        widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i],
-            &path->pathdata.Points[i+1], pen, last_point);
+        widen_joint(&points[i-1], &points[i],
+            &points[i+1], pen, last_point);
 
-    widen_cap(&path->pathdata.Points[end], &path->pathdata.Points[end-1],
-        pen, pen->endcap, pen->customend, TRUE, TRUE, last_point);
+    widen_cap(&points[end], &points[end-1],
+        pen, end_cap, end_custom, TRUE, TRUE, last_point);
 
     for (i=end-1; i>start; i--)
-        widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i],
-            &path->pathdata.Points[i-1], pen, last_point);
+        widen_joint(&points[i+1], &points[i],
+            &points[i-1], pen, last_point);
 
-    widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
-        pen, pen->startcap, pen->customstart, TRUE, FALSE, last_point);
+    widen_cap(&points[start], &points[start+1],
+        pen, start_cap, start_custom, TRUE, FALSE, last_point);
 
     prev_point->next->type = PathPointTypeStart;
     (*last_point)->type |= PathPointTypeCloseSubpath;
@@ -1911,6 +1912,134 @@ static void widen_closed_figure(GpPath *path, GpPen *pen, int start, int end,
     (*last_point)->type |= PathPointTypeCloseSubpath;
 }
 
+static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
+    int closed, path_list_node_t **last_point)
+{
+    int i, j;
+    REAL dash_pos=0.0;
+    int dash_index=0;
+    const REAL *dash_pattern;
+    int dash_count;
+    GpPointF *tmp_points;
+    REAL segment_dy;
+    REAL segment_dx;
+    REAL segment_length;
+    REAL segment_pos;
+    int num_tmp_points=0;
+    int draw_start_cap=0;
+    static const REAL dash_dot_dot[6] = { 3.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
+
+    if (end <= start)
+        return;
+
+    switch (pen->dash)
+    {
+    case DashStyleDash:
+    default:
+        dash_pattern = dash_dot_dot;
+        dash_count = 2;
+        break;
+    case DashStyleDot:
+        dash_pattern = &dash_dot_dot[2];
+        dash_count = 2;
+        break;
+    case DashStyleDashDot:
+        dash_pattern = dash_dot_dot;
+        dash_count = 4;
+        break;
+    case DashStyleDashDotDot:
+        dash_pattern = dash_dot_dot;
+        dash_count = 6;
+        break;
+    case DashStyleCustom:
+        dash_pattern = pen->dashes;
+        dash_count = pen->numdashes;
+        break;
+    }
+
+    tmp_points = GdipAlloc((end - start + 2) * sizeof(GpPoint));
+    if (!tmp_points) return; /* FIXME */
+
+    if (!closed)
+        draw_start_cap = 1;
+
+    for (j=start; j <= end; j++)
+    {
+        if (j == start)
+        {
+            if (closed)
+                i = end;
+            else
+                continue;
+        }
+        else
+            i = j-1;
+
+        segment_dy = path->pathdata.Points[j].Y - path->pathdata.Points[i].Y;
+        segment_dx = path->pathdata.Points[j].X - path->pathdata.Points[i].X;
+        segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
+        segment_pos = 0.0;
+
+        while (1)
+        {
+            if (dash_pos == 0.0)
+            {
+                if ((dash_index % 2) == 0)
+                {
+                    /* start dash */
+                    num_tmp_points = 1;
+                    tmp_points[0].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
+                    tmp_points[0].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
+                }
+                else
+                {
+                    /* end dash */
+                    tmp_points[num_tmp_points].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
+                    tmp_points[num_tmp_points].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
+
+                    widen_open_figure(tmp_points, pen, 0, num_tmp_points,
+                        draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
+                        LineCapFlat, NULL, last_point);
+                    draw_start_cap = 0;
+                    num_tmp_points = 0;
+                }
+            }
+
+            if (dash_pattern[dash_index] - dash_pos > segment_length - segment_pos)
+            {
+                /* advance to next segment */
+                if ((dash_index % 2) == 0)
+                {
+                    tmp_points[num_tmp_points] = path->pathdata.Points[j];
+                    num_tmp_points++;
+                }
+                dash_pos += segment_length - segment_pos;
+                break;
+            }
+            else
+            {
+                /* advance to next dash in pattern */
+                segment_pos += dash_pattern[dash_index] - dash_pos;
+                dash_pos = 0.0;
+                if (++dash_index == dash_count)
+                    dash_index = 0;
+                continue;
+            }
+        }
+    }
+
+    if (dash_index % 2 == 0 && num_tmp_points != 0)
+    {
+        /* last dash overflows last segment */
+        tmp_points[num_tmp_points] = path->pathdata.Points[end];
+        widen_open_figure(tmp_points, pen, 0, num_tmp_points,
+            draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
+            closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
+    }
+
+    GdipFree(tmp_points);
+}
+
 GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
     REAL flatness)
 {
@@ -1952,9 +2081,6 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
         if (pen->join == LineJoinRound)
             FIXME("unimplemented line join %d\n", pen->join);
 
-        if (pen->dash != DashStyleSolid)
-            FIXME("unimplemented dash style %d\n", pen->dash);
-
         if (pen->align != PenAlignmentCenter)
             FIXME("unimplemented pen alignment %d\n", pen->align);
 
@@ -1967,12 +2093,18 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
 
             if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
             {
-                widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
+                if (pen->dash != DashStyleSolid)
+                    widen_dashed_figure(flat_path, pen, subpath_start, i, 1, &last_point);
+                else
+                    widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
             }
             else if (i == flat_path->pathdata.Count-1 ||
                 (flat_path->pathdata.Types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart)
             {
-                widen_open_figure(flat_path, pen, subpath_start, i, &last_point);
+                if (pen->dash != DashStyleSolid)
+                    widen_dashed_figure(flat_path, pen, subpath_start, i, 0, &last_point);
+                else
+                    widen_open_figure(flat_path->pathdata.Points, pen, subpath_start, i, pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point);
             }
         }
 
index 84a0545..4801401 100644 (file)
@@ -1105,12 +1105,12 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
 
     if (flags & ImageLockModeRead)
     {
-        static int fixme=0;
+        static BOOL fixme = FALSE;
 
         if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
         {
             FIXME("Cannot copy rows that don't start at a whole byte.\n");
-            fixme = 1;
+            fixme = TRUE;
         }
 
         stat = convert_pixels(act_rect.Width, act_rect.Height,
@@ -1152,7 +1152,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     BitmapData* lockeddata)
 {
     GpStatus stat;
-    static int fixme=0;
+    static BOOL fixme = FALSE;
 
     TRACE("(%p,%p)\n", bitmap, lockeddata);
 
@@ -1182,7 +1182,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
     {
         FIXME("Cannot copy rows that don't start at a whole byte.\n");
-        fixme = 1;
+        fixme = TRUE;
     }
 
     stat = convert_pixels(lockeddata->Width, lockeddata->Height,
@@ -1207,9 +1207,6 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
 {
-    BitmapData lockeddata_src, lockeddata_dst;
-    int i;
-    UINT row_size;
     Rect area;
     GpStatus stat;
 
@@ -1231,39 +1228,41 @@ GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
     area.Width = gdip_round(width);
     area.Height = gdip_round(height);
 
-    stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
-        &lockeddata_src);
-    if (stat != Ok) return stat;
-
-    stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
-        0, lockeddata_src.PixelFormat, NULL, dstBitmap);
+    stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
     if (stat == Ok)
     {
-        stat = GdipBitmapLockBits(*dstBitmap, NULL, ImageLockModeWrite,
-            lockeddata_src.PixelFormat, &lockeddata_dst);
+        stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
+                              srcBitmap->stride,
+                              srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
+                              srcBitmap->format, srcBitmap->image.palette);
 
-        if (stat == Ok)
+        if (stat == Ok && srcBitmap->image.palette)
         {
-            /* copy the image data */
-            row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
-            for (i=0; i<lockeddata_src.Height; i++)
-                memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
-                       (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
-                       row_size);
-
-            GdipBitmapUnlockBits(*dstBitmap, &lockeddata_dst);
+            ColorPalette *src_palette, *dst_palette;
+
+            src_palette = srcBitmap->image.palette;
+
+            dst_palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count);
+
+            if (dst_palette)
+            {
+                dst_palette->Flags = src_palette->Flags;
+                dst_palette->Count = src_palette->Count;
+                memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count);
+
+                GdipFree((*dstBitmap)->image.palette);
+                (*dstBitmap)->image.palette = dst_palette;
+            }
+            else
+                stat = OutOfMemory;
         }
 
         if (stat != Ok)
             GdipDisposeImage((GpImage*)*dstBitmap);
     }
 
-    GdipBitmapUnlockBits(srcBitmap, &lockeddata_src);
-
     if (stat != Ok)
-    {
         *dstBitmap = NULL;
-    }
 
     return stat;
 }
@@ -1318,47 +1317,10 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
     }
     else if (image->type == ImageTypeBitmap)
     {
-        GpBitmap *bitmap = (GpBitmap*)image;
-        BitmapData lockeddata_src, lockeddata_dst;
-        int i;
-        UINT row_size;
-
-        stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
-            &lockeddata_src);
-        if (stat != Ok) return stat;
-
-        stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
-            0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
-        if (stat == Ok)
-        {
-            stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
-                lockeddata_src.PixelFormat, &lockeddata_dst);
-
-            if (stat == Ok)
-            {
-                /* copy the image data */
-                row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
-                for (i=0; i<lockeddata_src.Height; i++)
-                    memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
-                           (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
-                           row_size);
-
-                GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
-            }
+        GpBitmap *bitmap = (GpBitmap *)image;
 
-            if (stat != Ok)
-                GdipDisposeImage(*cloneImage);
-        }
-
-        GdipBitmapUnlockBits(bitmap, &lockeddata_src);
-
-        if (stat != Ok)
-        {
-            *cloneImage = NULL;
-        }
-        else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
-
-        return stat;
+        return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
+                                    bitmap->format, bitmap, (GpBitmap **)cloneImage);
     }
     else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
     {
@@ -1557,27 +1519,6 @@ GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
     return stat;
 }
 
-GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
-    GpMetafile* metafile, BOOL* succ, EmfType emfType,
-    const WCHAR* description, GpMetafile** out_metafile)
-{
-    static int calls;
-
-    TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
-        debugstr_w(description), out_metafile);
-
-    if(!ref || !metafile || !out_metafile)
-        return InvalidParameter;
-
-    *succ = FALSE;
-    *out_metafile = NULL;
-
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    return NotImplemented;
-}
-
 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
     GpGraphics* target, GpBitmap** bitmap)
 {
@@ -1799,7 +1740,6 @@ static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
 {
-    BITMAPINFO* pbmi;
     HBITMAP hbitmap=NULL;
     INT row_size, dib_stride;
     BYTE *bits=NULL, *own_bits=NULL;
@@ -1829,9 +1769,8 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
 
     if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
     {
-        pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-        if (!pbmi)
-            return OutOfMemory;
+        char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
+        BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
 
         pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
         pbmi->bmiHeader.biWidth = width;
@@ -1848,8 +1787,6 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
 
         hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
 
-        GdipFree(pbmi);
-
         if (!hbitmap) return GenericError;
 
         stride = dib_stride;
@@ -2072,13 +2009,6 @@ GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
     return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
 }
 
-GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
-    LPBYTE pData16, INT iMapMode, INT eFlags)
-{
-    FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
-    return NotImplemented;
-}
-
 /* Internal utility function: Replace the image data of dst with that of src,
  * and free src. */
 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
@@ -2423,76 +2353,6 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
     return Ok;
 }
 
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
-    MetafileHeader * header)
-{
-    static int calls;
-
-    TRACE("(%p, %p)\n", metafile, header);
-
-    if(!metafile || !header)
-        return InvalidParameter;
-
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    memset(header, 0, sizeof(MetafileHeader));
-
-    return Ok;
-}
-
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
-    MetafileHeader *header)
-{
-    static int calls;
-
-    if(!hEmf || !header)
-        return InvalidParameter;
-
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    memset(header, 0, sizeof(MetafileHeader));
-
-    return Ok;
-}
-
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
-    MetafileHeader *header)
-{
-    static int calls;
-
-    TRACE("(%s,%p)\n", debugstr_w(filename), header);
-
-    if(!filename || !header)
-        return InvalidParameter;
-
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    memset(header, 0, sizeof(MetafileHeader));
-
-    return Ok;
-}
-
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
-    MetafileHeader *header)
-{
-    static int calls;
-
-    TRACE("(%p,%p)\n", stream, header);
-
-    if(!stream || !header)
-        return InvalidParameter;
-
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    memset(header, 0, sizeof(MetafileHeader));
-
-    return Ok;
-}
-
 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
 {
     TRACE("(%p, %p)\n", image, num);
@@ -3989,6 +3849,7 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
     HRESULT hr;
     UINT width, height;
     PixelFormat gdipformat=0;
+    const WICPixelFormatGUID *desired_wicformat;
     WICPixelFormatGUID wicformat;
     GpRect rc;
     BitmapData lockeddata;
@@ -4041,20 +3902,40 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
             {
                 if (pixel_formats[i].gdip_format == bitmap->format)
                 {
-                    memcpy(&wicformat, pixel_formats[i].wic_format, sizeof(GUID));
+                    desired_wicformat = pixel_formats[i].wic_format;
                     gdipformat = bitmap->format;
                     break;
                 }
             }
             if (!gdipformat)
             {
-                memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+                desired_wicformat = &GUID_WICPixelFormat32bppBGRA;
                 gdipformat = PixelFormat32bppARGB;
             }
 
+            memcpy(&wicformat, desired_wicformat, sizeof(GUID));
             hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
         }
 
+        if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat))
+        {
+            /* Encoder doesn't support this bitmap's format. */
+            gdipformat = 0;
+            for (i=0; pixel_formats[i].wic_format; i++)
+            {
+                if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format))
+                {
+                    gdipformat = pixel_formats[i].gdip_format;
+                    break;
+                }
+            }
+            if (!gdipformat)
+            {
+                ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat));
+                hr = E_FAIL;
+            }
+        }
+
         if (SUCCEEDED(hr))
         {
             stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
@@ -4652,28 +4533,21 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi
         if (retval == Ok)
         {
             HDC hdc;
-            BITMAPINFO *pbmi;
+            char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
+            BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
             INT src_height;
 
             hdc = CreateCompatibleDC(NULL);
-            pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-
-            if (pbmi)
-            {
-                pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-                pbmi->bmiHeader.biBitCount = 0;
 
-                GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+            pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+            pbmi->bmiHeader.biBitCount = 0;
 
-                src_height = abs(pbmi->bmiHeader.biHeight);
-                pbmi->bmiHeader.biHeight = -src_height;
+            GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
 
-                GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
+            src_height = abs(pbmi->bmiHeader.biHeight);
+            pbmi->bmiHeader.biHeight = -src_height;
 
-                GdipFree(pbmi);
-            }
-            else
-                retval = OutOfMemory;
+            GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
 
             DeleteDC(hdc);
 
@@ -4781,27 +4655,6 @@ GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
     return Ok;
 }
 
-GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
-                            HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
-                            MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
-                            GpMetafile **metafile)
-{
-    FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
-                                 frameUnit, debugstr_w(desc), metafile);
-
-    return NotImplemented;
-}
-
-GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
-                            GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
-                            GDIPCONST WCHAR *desc, GpMetafile **metafile)
-{
-    FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
-                                 frameUnit, debugstr_w(desc), metafile);
-
-    return NotImplemented;
-}
-
 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
 {
     TRACE("%p\n", image);
@@ -4866,7 +4719,7 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
     GpBitmap *new_bitmap;
     GpBitmap *bitmap;
     int bpp, bytesperpixel;
-    int rotate_90, flip_x, flip_y;
+    BOOL rotate_90, flip_x, flip_y;
     int src_x_offset, src_y_offset;
     LPBYTE src_origin;
     UINT x, y, width, height;
@@ -4975,16 +4828,3 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
 
     return stat;
 }
-
-/*****************************************************************************
- * GdipConvertToEmfPlusToFile [GDIPLUS.@]
- */
-
-GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
-                                               GpMetafile* metafile, BOOL* conversionSuccess,
-                                               const WCHAR* filename, EmfType emfType,
-                                               const WCHAR* description, GpMetafile** out_metafile)
-{
-    FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
-    return NotImplemented;
-}
index 1f717d0..5d2cf49 100644 (file)
@@ -35,6 +35,27 @@ typedef struct EmfPlusHeader
     DWORD LogicalDpiY;
 } EmfPlusHeader;
 
+typedef struct EmfPlusFillRects
+{
+    EmfPlusRecordHeader Header;
+    DWORD BrushID;
+    DWORD Count;
+} EmfPlusFillRects;
+
+typedef struct EmfPlusSetPageTransform
+{
+    EmfPlusRecordHeader Header;
+    REAL PageScale;
+} EmfPlusSetPageTransform;
+
+typedef struct EmfPlusRect
+{
+    SHORT X;
+    SHORT Y;
+    SHORT Width;
+    SHORT Height;
+} EmfPlusRect;
+
 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
 {
     DWORD size_needed;
@@ -211,6 +232,8 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
     (*metafile)->image.picture = NULL;
     (*metafile)->image.flags   = ImageFlagsNone;
     (*metafile)->image.palette = NULL;
+    (*metafile)->image.xres = 72.0;
+    (*metafile)->image.yres = 72.0;
     (*metafile)->bounds = *frameRect;
     (*metafile)->unit = frameUnit;
     (*metafile)->metafile_type = type;
@@ -267,7 +290,11 @@ GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
     stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
 
     if (stat == Ok)
+    {
         *result = metafile->record_graphics;
+        metafile->record_graphics->xres = 96.0;
+        metafile->record_graphics->yres = 96.0;
+    }
 
     return stat;
 }
@@ -294,6 +321,108 @@ GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
     return Ok;
 }
 
+static BOOL is_integer_rect(const GpRectF *rect)
+{
+    SHORT x, y, width, height;
+    x = rect->X;
+    y = rect->Y;
+    width = rect->Width;
+    height = rect->Height;
+    if (rect->X != (REAL)x || rect->Y != (REAL)y ||
+        rect->Width != (REAL)width || rect->Height != (REAL)height)
+        return FALSE;
+    return TRUE;
+}
+
+GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
+    GDIPCONST GpRectF* rects, INT count)
+{
+    if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
+    {
+        EmfPlusFillRects *record;
+        GpStatus stat;
+        BOOL integer_rects = TRUE;
+        int i;
+        DWORD brushid;
+        int flags = 0;
+
+        if (brush->bt == BrushTypeSolidColor)
+        {
+            flags |= 0x8000;
+            brushid = ((GpSolidFill*)brush)->color;
+        }
+        else
+        {
+            FIXME("brush serialization not implemented\n");
+            return NotImplemented;
+        }
+
+        for (i=0; i<count; i++)
+        {
+            if (!is_integer_rect(&rects[i]))
+            {
+                integer_rects = FALSE;
+                break;
+            }
+        }
+
+        if (integer_rects)
+            flags |= 0x4000;
+
+        stat = METAFILE_AllocateRecord(metafile,
+            sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
+            (void**)&record);
+        if (stat != Ok)
+            return stat;
+
+        record->Header.Type = EmfPlusRecordTypeFillRects;
+        record->Header.Flags = flags;
+        record->BrushID = brushid;
+        record->Count = count;
+
+        if (integer_rects)
+        {
+            EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
+            for (i=0; i<count; i++)
+            {
+                record_rects[i].X = (SHORT)rects[i].X;
+                record_rects[i].Y = (SHORT)rects[i].Y;
+                record_rects[i].Width = (SHORT)rects[i].Width;
+                record_rects[i].Height = (SHORT)rects[i].Height;
+            }
+        }
+        else
+            memcpy(record+1, rects, sizeof(GpRectF) * count);
+
+        METAFILE_WriteRecords(metafile);
+    }
+
+    return Ok;
+}
+
+GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
+{
+    if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
+    {
+        EmfPlusSetPageTransform *record;
+        GpStatus stat;
+
+        stat = METAFILE_AllocateRecord(metafile,
+            sizeof(EmfPlusSetPageTransform),
+            (void**)&record);
+        if (stat != Ok)
+            return stat;
+
+        record->Header.Type = EmfPlusRecordTypeSetPageTransform;
+        record->Header.Flags = unit;
+        record->PageScale = scale;
+
+        METAFILE_WriteRecords(metafile);
+    }
+
+    return Ok;
+}
+
 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
 {
     if (hdc != metafile->record_dc)
@@ -368,9 +497,40 @@ static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
     }
 }
 
+static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
+{
+    GpMatrix *real_transform;
+    GpStatus stat;
+
+    stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
+
+    if (stat == Ok)
+    {
+        REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
+
+        if (metafile->page_unit != UnitDisplay)
+            scale *= metafile->page_scale;
+
+        stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
+
+        if (stat == Ok)
+            stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
+
+        if (stat == Ok)
+            stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
+
+        GdipDeleteMatrix(real_transform);
+    }
+
+    return stat;
+}
+
 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
     EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
 {
+    GpStatus stat;
+    GpMetafile *real_metafile = (GpMetafile*)metafile;
+
     TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
 
     if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
@@ -402,6 +562,8 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
     }
     else
     {
+        EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
+
         METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
 
         switch(recordType)
@@ -412,6 +574,85 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
         case EmfPlusRecordTypeGetDC:
             METAFILE_PlaybackGetDC((GpMetafile*)metafile);
             break;
+        case EmfPlusRecordTypeFillRects:
+        {
+            EmfPlusFillRects *record = (EmfPlusFillRects*)header;
+            GpBrush *brush, *temp_brush=NULL;
+            GpRectF *rects, *temp_rects=NULL;
+
+            if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
+                return InvalidParameter;
+
+            if (flags & 0x4000)
+            {
+                if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
+                    return InvalidParameter;
+            }
+            else
+            {
+                if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
+                    return InvalidParameter;
+            }
+
+            if (flags & 0x8000)
+            {
+                stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
+                brush = temp_brush;
+            }
+            else
+            {
+                FIXME("brush deserialization not implemented\n");
+                return NotImplemented;
+            }
+
+            if (stat == Ok)
+            {
+                if (flags & 0x4000)
+                {
+                    EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
+                    int i;
+
+                    rects = temp_rects = GdipAlloc(sizeof(GpRectF) * record->Count);
+                    if (rects)
+                    {
+                        for (i=0; i<record->Count; i++)
+                        {
+                            rects[i].X = int_rects[i].X;
+                            rects[i].Y = int_rects[i].Y;
+                            rects[i].Width = int_rects[i].Width;
+                            rects[i].Height = int_rects[i].Height;
+                        }
+                    }
+                    else
+                        stat = OutOfMemory;
+                }
+                else
+                    rects = (GpRectF*)(record+1);
+            }
+
+            if (stat == Ok)
+            {
+                stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
+            }
+
+            GdipDeleteBrush(temp_brush);
+            GdipFree(temp_rects);
+
+            return stat;
+        }
+        case EmfPlusRecordTypeSetPageTransform:
+        {
+            EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
+            GpUnit unit = (GpUnit)flags;
+
+            if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
+                return InvalidParameter;
+
+            real_metafile->page_unit = unit;
+            real_metafile->page_scale = record->PageScale;
+
+            return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
+        }
         default:
             FIXME("Not implemented for record type %x\n", recordType);
             return NotImplemented;
@@ -486,6 +727,7 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
     struct enum_metafile_data data;
     GpStatus stat;
     GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
+    GraphicsContainer state;
 
     TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
         destPoints, count, srcRect, srcUnit, callback, callbackData,
@@ -510,19 +752,46 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
 
     real_metafile->playback_graphics = graphics;
     real_metafile->playback_dc = NULL;
+    real_metafile->src_rect = *srcRect;
 
     memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
     stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
 
-    if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
-        metafile->metafile_type == MetafileTypeWmfPlaceable ||
-        metafile->metafile_type == MetafileTypeWmf))
-        stat = METAFILE_PlaybackGetDC((GpMetafile*)metafile);
+    if (stat == Ok)
+        stat = GdipBeginContainer2(graphics, &state);
 
     if (stat == Ok)
-        EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
+    {
+        stat = GdipSetPageScale(graphics, 1.0);
+
+        if (stat == Ok)
+            stat = GdipSetPageUnit(graphics, UnitPixel);
+
+        if (stat == Ok)
+            stat = GdipCreateMatrix(&real_metafile->world_transform);
+
+        if (stat == Ok)
+        {
+            real_metafile->page_unit = UnitDisplay;
+            real_metafile->page_scale = 1.0;
+            stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
+        }
+
+        if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
+            metafile->metafile_type == MetafileTypeWmfPlaceable ||
+            metafile->metafile_type == MetafileTypeWmf))
+            stat = METAFILE_PlaybackGetDC(real_metafile);
 
-    METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
+        if (stat == Ok)
+            EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
+
+        METAFILE_PlaybackReleaseDC(real_metafile);
+
+        GdipDeleteMatrix(real_metafile->world_transform);
+        real_metafile->world_transform = NULL;
+
+        GdipEndContainer(graphics, state);
+    }
 
     real_metafile->playback_graphics = NULL;
 
@@ -623,9 +892,268 @@ static int CALLBACK get_metafile_type_proc(HDC hDC, HANDLETABLE *lpHTable, const
     return FALSE;
 }
 
-MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
+static MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
 {
     MetafileType result = MetafileTypeInvalid;
     EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
     return result;
 }
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
+    MetafileHeader * header)
+{
+    static int calls;
+
+    TRACE("(%p, %p)\n", metafile, header);
+
+    if(!metafile || !header)
+        return InvalidParameter;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    memset(header, 0, sizeof(MetafileHeader));
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
+    MetafileHeader *header)
+{
+    static int calls;
+
+    if(!hEmf || !header)
+        return InvalidParameter;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    memset(header, 0, sizeof(MetafileHeader));
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
+    MetafileHeader *header)
+{
+    static int calls;
+
+    TRACE("(%s,%p)\n", debugstr_w(filename), header);
+
+    if(!filename || !header)
+        return InvalidParameter;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    memset(header, 0, sizeof(MetafileHeader));
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
+    MetafileHeader *header)
+{
+    static int calls;
+
+    TRACE("(%p,%p)\n", stream, header);
+
+    if(!stream || !header)
+        return InvalidParameter;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    memset(header, 0, sizeof(MetafileHeader));
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
+    GpMetafile **metafile)
+{
+    ENHMETAHEADER header;
+    MetafileType metafile_type;
+
+    TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
+
+    if(!hemf || !metafile)
+        return InvalidParameter;
+
+    if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
+        return GenericError;
+
+    metafile_type = METAFILE_GetEmfType(hemf);
+
+    if (metafile_type == MetafileTypeInvalid)
+        return GenericError;
+
+    *metafile = GdipAlloc(sizeof(GpMetafile));
+    if (!*metafile)
+        return OutOfMemory;
+
+    (*metafile)->image.type = ImageTypeMetafile;
+    (*metafile)->image.format = ImageFormatEMF;
+    (*metafile)->image.frame_count = 1;
+    (*metafile)->image.xres = (REAL)header.szlDevice.cx;
+    (*metafile)->image.yres = (REAL)header.szlDevice.cy;
+    (*metafile)->bounds.X = (REAL)header.rclBounds.left;
+    (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
+    (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
+    (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
+    (*metafile)->unit = UnitPixel;
+    (*metafile)->metafile_type = metafile_type;
+    (*metafile)->hemf = hemf;
+    (*metafile)->preserve_hemf = !delete;
+
+    TRACE("<-- %p\n", *metafile);
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
+    GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
+{
+    UINT read;
+    BYTE *copy;
+    HENHMETAFILE hemf;
+    GpStatus retval = Ok;
+
+    TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
+
+    if(!hwmf || !metafile || !placeable)
+        return InvalidParameter;
+
+    *metafile = NULL;
+    read = GetMetaFileBitsEx(hwmf, 0, NULL);
+    if(!read)
+        return GenericError;
+    copy = GdipAlloc(read);
+    GetMetaFileBitsEx(hwmf, read, copy);
+
+    hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
+    GdipFree(copy);
+
+    /* FIXME: We should store and use hwmf instead of converting to hemf */
+    retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
+
+    if (retval == Ok)
+    {
+        (*metafile)->image.xres = (REAL)placeable->Inch;
+        (*metafile)->image.yres = (REAL)placeable->Inch;
+        (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
+        (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
+        (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
+                                           placeable->BoundingBox.Left);
+        (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
+                                            placeable->BoundingBox.Top);
+        (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
+        (*metafile)->image.format = ImageFormatWMF;
+
+        if (delete) DeleteMetaFile(hwmf);
+    }
+    else
+        DeleteEnhMetaFile(hemf);
+    return retval;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
+    GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
+{
+    HMETAFILE hmf = GetMetaFileW(file);
+
+    TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
+
+    if(!hmf) return InvalidParameter;
+
+    return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
+    GpMetafile **metafile)
+{
+    FIXME("(%p, %p): stub\n", file, metafile);
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
+    GpMetafile **metafile)
+{
+    FIXME("(%p, %p): stub\n", stream, metafile);
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
+    UINT limitDpi)
+{
+    static int calls;
+
+    TRACE("(%p,%u)\n", metafile, limitDpi);
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
+    GpMetafile* metafile, BOOL* succ, EmfType emfType,
+    const WCHAR* description, GpMetafile** out_metafile)
+{
+    static int calls;
+
+    TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
+        debugstr_w(description), out_metafile);
+
+    if(!ref || !metafile || !out_metafile)
+        return InvalidParameter;
+
+    *succ = FALSE;
+    *out_metafile = NULL;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
+    LPBYTE pData16, INT iMapMode, INT eFlags)
+{
+    FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
+                            HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
+                            MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
+                            GpMetafile **metafile)
+{
+    FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
+                                 frameUnit, debugstr_w(desc), metafile);
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
+                            GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
+                            GDIPCONST WCHAR *desc, GpMetafile **metafile)
+{
+    FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
+                                 frameUnit, debugstr_w(desc), metafile);
+
+    return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipConvertToEmfPlusToFile [GDIPLUS.@]
+ */
+
+GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
+                                               GpMetafile* metafile, BOOL* conversionSuccess,
+                                               const WCHAR* filename, EmfType emfType,
+                                               const WCHAR* description, GpMetafile** out_metafile)
+{
+    FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
+    return NotImplemented;
+}
index 3171352..be5e51a 100644 (file)
@@ -205,7 +205,7 @@ GpStatus WINGDIPAPI GdipPathIterNextSubpath(GpPathIterator* iterator,
 
     if(iterator->subpath_pos == count){
         *startIndex = *endIndex = *resultCount = 0;
-        *isClosed = 1;
+        *isClosed = TRUE;
         return Ok;
     }
 
index 421fdce..37cb45f 100644 (file)
@@ -75,6 +75,24 @@ typedef struct packed_point
     short Y;
 } packed_point;
 
+/* Test to see if the path could be stored as an array of shorts */
+static BOOL is_integer_path(const GpPath *path)
+{
+    int i;
+
+    if (!path->pathdata.Count) return FALSE;
+
+    for (i = 0; i < path->pathdata.Count; i++)
+    {
+        short x, y;
+        x = gdip_round(path->pathdata.Points[i].X);
+        y = gdip_round(path->pathdata.Points[i].Y);
+        if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
+            return FALSE;
+    }
+    return TRUE;
+}
+
 /* Everything is measured in DWORDS; round up if there's a remainder */
 static inline INT get_pathtypes_size(const GpPath* path)
 {
@@ -94,9 +112,20 @@ static inline INT get_element_size(const region_element* element)
         case RegionDataRect:
             return needed + sizeof(GpRect);
         case RegionDataPath:
-             needed += element->elementdata.pathdata.pathheader.size;
-             needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
-             return needed;
+        {
+            const GpPath *path = element->elementdata.path;
+            DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
+            /* 3 for headers, once again size doesn't count itself */
+            needed += sizeof(DWORD) * 3;
+            if (flags & FLAGS_INTPATH)
+                needed += 2 * sizeof(SHORT) * path->pathdata.Count;
+            else
+                needed += 2 * sizeof(FLOAT) * path->pathdata.Count;
+
+            needed += get_pathtypes_size(path);
+            needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
+            return needed;
+        }
         case RegionDataEmptyRect:
         case RegionDataInfiniteRect:
             return needed;
@@ -112,11 +141,8 @@ static inline INT get_element_size(const region_element* element)
 /* Does not check parameters, caller must do that */
 static inline GpStatus init_region(GpRegion* region, const RegionType type)
 {
-    region->node.type       = type;
-    region->header.checksum = 0xdeadbeef;
-    region->header.magic    = VERSION_MAGIC;
-    region->header.num_children  = 0;
-    region->header.size     = sizeheader_size + get_element_size(&region->node);
+    region->node.type    = type;
+    region->num_children = 0;
 
     return Ok;
 }
@@ -144,9 +170,7 @@ static inline GpStatus clone_element(const region_element* element,
         case RegionDataInfiniteRect:
             return Ok;
         case RegionDataPath:
-            (*element2)->elementdata.pathdata.pathheader = element->elementdata.pathdata.pathheader;
-            stat = GdipClonePath(element->elementdata.pathdata.path,
-                    &(*element2)->elementdata.pathdata.path);
+            stat = GdipClonePath(element->elementdata.path, &(*element2)->elementdata.path);
             if (stat == Ok) return Ok;
             break;
         default:
@@ -178,9 +202,7 @@ static inline void fuse_region(GpRegion* region, region_element* left,
     region->node.type = mode;
     region->node.elementdata.combine.left = left;
     region->node.elementdata.combine.right = right;
-
-    region->header.size = sizeheader_size + get_element_size(&region->node);
-    region->header.num_children += 2;
+    region->num_children += 2;
 }
 
 /*****************************************************************************
@@ -210,7 +232,7 @@ GpStatus WINGDIPAPI GdipCloneRegion(GpRegion *region, GpRegion **clone)
         return OutOfMemory;
     element = &(*clone)->node;
 
-    (*clone)->header = region->header;
+    (*clone)->num_children = region->num_children;
     return clone_element(&region->node, &element);
 }
 
@@ -367,7 +389,7 @@ GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1,
     }
 
     fuse_region(region1, left, right, mode);
-    region1->header.num_children += region2->header.num_children;
+    region1->num_children += region2->num_children;
 
     return Ok;
 }
@@ -413,12 +435,7 @@ GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
 GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
 {
     region_element* element;
-    GpPoint  *pointsi;
-    GpPointF *pointsf;
-
     GpStatus stat;
-    DWORD flags = FLAGS_INTPATH;
-    INT count, i;
 
     TRACE("%p, %p\n", path, region);
 
@@ -435,77 +452,14 @@ GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
         return stat;
     }
     element = &(*region)->node;
-    count = path->pathdata.Count;
 
-    /* Test to see if the path is an Integer path */
-    if (count)
-    {
-        pointsi = GdipAlloc(sizeof(GpPoint) * count);
-        pointsf = GdipAlloc(sizeof(GpPointF) * count);
-        if (!(pointsi && pointsf))
-        {
-            GdipFree(pointsi);
-            GdipFree(pointsf);
-            GdipDeleteRegion(*region);
-            return OutOfMemory;
-        }
-
-        stat = GdipGetPathPointsI(path, pointsi, count);
-        if (stat != Ok)
-        {
-            GdipDeleteRegion(*region);
-            return stat;
-        }
-        stat = GdipGetPathPoints(path, pointsf, count);
-        if (stat != Ok)
-        {
-            GdipDeleteRegion(*region);
-            return stat;
-        }
-
-        for (i = 0; i < count; i++)
-        {
-            if (!(pointsi[i].X == pointsf[i].X &&
-                  pointsi[i].Y == pointsf[i].Y ))
-            {
-                flags = FLAGS_NOFLAGS;
-                break;
-            }
-        }
-        GdipFree(pointsi);
-        GdipFree(pointsf);
-    }
-
-    stat = GdipClonePath(path, &element->elementdata.pathdata.path);
+    stat = GdipClonePath(path, &element->elementdata.path);
     if (stat != Ok)
     {
         GdipDeleteRegion(*region);
         return stat;
     }
 
-    /* 3 for headers, once again size doesn't count itself */
-    element->elementdata.pathdata.pathheader.size = ((sizeof(DWORD) * 3));
-    switch(flags)
-    {
-        /* Floats, sent out as floats */
-        case FLAGS_NOFLAGS:
-            element->elementdata.pathdata.pathheader.size +=
-                (sizeof(DWORD) * count * 2);
-            break;
-        /* INTs, sent out as packed shorts */
-        case FLAGS_INTPATH:
-            element->elementdata.pathdata.pathheader.size +=
-                (sizeof(DWORD) * count);
-            break;
-        default:
-            FIXME("Unhandled flags (%08x). Expect wrong results.\n", flags);
-    }
-    element->elementdata.pathdata.pathheader.size += get_pathtypes_size(path);
-    element->elementdata.pathdata.pathheader.magic = VERSION_MAGIC;
-    element->elementdata.pathdata.pathheader.count = count;
-    element->elementdata.pathdata.pathheader.flags = flags;
-    (*region)->header.size = sizeheader_size + get_element_size(element);
-
     return Ok;
 }
 
@@ -727,25 +681,24 @@ static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
 static inline void write_packed_point(DWORD* location, INT* offset,
         const GpPointF* write)
 {
-    packed_point point;
-
-    point.X = write->X;
-    point.Y = write->Y;
-    memcpy(location + *offset, &point, sizeof(packed_point));
+    packed_point *point = (packed_point *)(location + *offset);
+    point->X = gdip_round(write->X);
+    point->Y = gdip_round(write->Y);
     (*offset)++;
 }
 
 static inline void write_path_types(DWORD* location, INT* offset,
         const GpPath* path)
 {
+    INT rounded_size = get_pathtypes_size(path);
+
     memcpy(location + *offset, path->pathdata.Types, path->pathdata.Count);
 
     /* The unwritten parts of the DWORD (if any) must be cleared */
-    if (path->pathdata.Count % sizeof(DWORD))
+    if (rounded_size - path->pathdata.Count)
         ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
-                path->pathdata.Count,
-                sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD));
-    *offset += (get_pathtypes_size(path) / sizeof(DWORD));
+                path->pathdata.Count, rounded_size - path->pathdata.Count);
+    *offset += rounded_size / sizeof(DWORD);
 }
 
 static void write_element(const region_element* element, DWORD *buffer,
@@ -772,12 +725,31 @@ static void write_element(const region_element* element, DWORD *buffer,
         case RegionDataPath:
         {
             INT i;
-            const GpPath* path = element->elementdata.pathdata.path;
+            const GpPath* path = element->elementdata.path;
+            struct _pathheader
+            {
+                DWORD size;
+                DWORD magic;
+                DWORD count;
+                DWORD flags;
+            } *pathheader;
+
+            pathheader = (struct _pathheader *)(buffer + *filled);
+
+            pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
+            /* 3 for headers, once again size doesn't count itself */
+            pathheader->size = sizeof(DWORD) * 3;
+            if (pathheader->flags & FLAGS_INTPATH)
+                pathheader->size += 2 * sizeof(SHORT) * path->pathdata.Count;
+            else
+                pathheader->size += 2 * sizeof(FLOAT) * path->pathdata.Count;
+            pathheader->size += get_pathtypes_size(path);
+            pathheader->magic = VERSION_MAGIC;
+            pathheader->count = path->pathdata.Count;
 
-            memcpy(buffer + *filled, &element->elementdata.pathdata.pathheader,
-                    sizeof(element->elementdata.pathdata.pathheader));
-            *filled += sizeof(element->elementdata.pathdata.pathheader) / sizeof(DWORD);
-            switch (element->elementdata.pathdata.pathheader.flags)
+            *filled += 4;
+
+            switch (pathheader->flags & FLAGS_INTPATH)
             {
                 case FLAGS_NOFLAGS:
                     for (i = 0; i < path->pathdata.Count; i++)
@@ -792,6 +764,7 @@ static void write_element(const region_element* element, DWORD *buffer,
                         write_packed_point(buffer, filled,
                                 &path->pathdata.Points[i]);
                     }
+                    break;
             }
             write_path_types(buffer, filled, path);
             break;
@@ -838,15 +811,36 @@ static void write_element(const region_element* element, DWORD *buffer,
 GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
         UINT *needed)
 {
+    struct _region_header
+    {
+        DWORD size;
+        DWORD checksum;
+        DWORD magic;
+        DWORD num_children;
+    } *region_header;
     INT filled = 0;
+    UINT required;
+    GpStatus status;
 
     TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
 
-    if (!(region && buffer && size))
+    if (!region || !buffer || !size)
         return InvalidParameter;
 
-    memcpy(buffer, &region->header, sizeof(region->header));
-    filled += sizeof(region->header) / sizeof(DWORD);
+    status = GdipGetRegionDataSize(region, &required);
+    if (status != Ok) return status;
+    if (size < required)
+    {
+        if (needed) *needed = size;
+        return InsufficientBuffer;
+    }
+
+    region_header = (struct _region_header *)buffer;
+    region_header->size = sizeheader_size + get_element_size(&region->node);
+    region_header->checksum = 0;
+    region_header->magic = VERSION_MAGIC;
+    region_header->num_children = region->num_children;
+    filled += 4;
     /* With few exceptions, everything written is DWORD aligned,
      * so use that as our base */
     write_element(&region->node, (DWORD*)buffer, &filled);
@@ -868,7 +862,7 @@ GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
         return InvalidParameter;
 
     /* header.size doesn't count header.size and header.checksum */
-    *needed = region->header.size + sizeof(DWORD) * 2;
+    *needed = sizeof(DWORD) * 2 + sizeheader_size + get_element_size(&region->node);
 
     return Ok;
 }
@@ -938,7 +932,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
             *hrgn = CreateRectRgn(0, 0, 0, 0);
             return *hrgn ? Ok : OutOfMemory;
         case RegionDataPath:
-            return get_path_hrgn(element->elementdata.pathdata.path, graphics, hrgn);
+            return get_path_hrgn(element->elementdata.path, graphics, hrgn);
         case RegionDataRect:
         {
             GpPath* path;
@@ -982,8 +976,8 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
                     case CombineModeIntersect:
                         return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
                     case CombineModeXor: case CombineModeExclude:
-                        FIXME("cannot exclude from an infinite region\n");
-                        /* fall-through */
+                        left = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+                        break;
                     case CombineModeUnion: case CombineModeComplement:
                         *hrgn = NULL;
                         return Ok;
@@ -1007,8 +1001,8 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
                         *hrgn = left;
                         return Ok;
                     case CombineModeXor: case CombineModeComplement:
-                        FIXME("cannot exclude from an infinite region\n");
-                        /* fall-through */
+                        right = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+                        break;
                     case CombineModeUnion: case CombineModeExclude:
                         DeleteObject(left);
                         *hrgn = NULL;
@@ -1291,16 +1285,19 @@ static GpStatus transform_region_element(region_element* element, GpMatrix *matr
             {
                 /* Steal the element from the created region. */
                 memcpy(element, &new_region->node, sizeof(region_element));
-                HeapFree(GetProcessHeap(), 0, new_region);
+                GdipFree(new_region);
             }
             else
                 return stat;
         }
         /* Fall-through to do the actual conversion. */
         case RegionDataPath:
+            if (!element->elementdata.path->pathdata.Count)
+                return Ok;
+
             stat = GdipTransformMatrixPoints(matrix,
-                element->elementdata.pathdata.path->pathdata.Points,
-                element->elementdata.pathdata.path->pathdata.Count);
+                element->elementdata.path->pathdata.Points,
+                element->elementdata.path->pathdata.Count);
             return stat;
         default:
             stat = transform_region_element(element->elementdata.combine.left, matrix);
@@ -1335,9 +1332,9 @@ static void translate_region_element(region_element* element, REAL dx, REAL dy)
             element->elementdata.rect.Y += dy;
             return;
         case RegionDataPath:
-            for(i = 0; i < element->elementdata.pathdata.path->pathdata.Count; i++){
-                element->elementdata.pathdata.path->pathdata.Points[i].X += dx;
-                element->elementdata.pathdata.path->pathdata.Points[i].Y += dy;
+            for(i = 0; i < element->elementdata.path->pathdata.Count; i++){
+                element->elementdata.path->pathdata.Points[i].X += dx;
+                element->elementdata.path->pathdata.Points[i].Y += dy;
             }
             return;
         default:
index 14840c1..89cfc86 100644 (file)
@@ -74,7 +74,7 @@ reactos/dll/win32/dciman32         # Synced to Wine-1.7.1
 reactos/dll/win32/dwmapi           # Synced to Wine-1.7.17
 reactos/dll/win32/faultrep         # Synced to Wine-1.7.1
 reactos/dll/win32/fusion           # Synced to Wine-1.7.1
-reactos/dll/win32/gdiplus          # Synced to Wine-1.7.1
+reactos/dll/win32/gdiplus          # Synced to Wine-1.7.17
 reactos/dll/win32/hhctrl.ocx       # Synced to Wine-1.7.1
 reactos/dll/win32/hlink            # Synced to Wine-1.7.1
 reactos/dll/win32/hnetcfg          # Synced to Wine-1.7.1