[GDIPLUS] Sync with Wine Staging 3.9. CORE-14656
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 27 May 2018 03:10:39 +0000 (04:10 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 27 May 2018 03:10:39 +0000 (04:10 +0100)
dll/win32/gdiplus/brush.c
dll/win32/gdiplus/customlinecap.c
dll/win32/gdiplus/font.c
dll/win32/gdiplus/gdiplus.spec
dll/win32/gdiplus/gdiplus_private.h
dll/win32/gdiplus/graphics.c
dll/win32/gdiplus/image.c
dll/win32/gdiplus/metafile.c
dll/win32/gdiplus/pen.c
dll/win32/gdiplus/region.c
media/doc/README.WINE

index 5126421..d068320 100644 (file)
@@ -261,7 +261,7 @@ static const char HatchBrushes[][8] = {
 
 GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result)
 {
-    if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0]))
+    if (hatchstyle < ARRAY_SIZE(HatchBrushes))
     {
         *result = HatchBrushes[hatchstyle];
         return Ok;
@@ -1715,6 +1715,18 @@ GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipSetPathGradientPath(GpPathGradient *grad, GDIPCONST GpPath *path)
+{
+    static int calls;
+
+    TRACE("(%p, %p)\n", grad, path);
+
+    if (!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
     REAL focus, REAL scale)
 {
index ca81bee..c74928e 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <stdarg.h>
+#include <assert.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -38,11 +39,20 @@ GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap* from,
     if(!from || !to)
         return InvalidParameter;
 
-    *to = heap_alloc_zero(sizeof(GpCustomLineCap));
-    if(!*to)   return OutOfMemory;
+    if (from->type == CustomLineCapTypeDefault)
+        *to = heap_alloc_zero(sizeof(GpCustomLineCap));
+    else
+        *to = heap_alloc_zero(sizeof(GpAdjustableArrowCap));
 
-    memcpy(*to, from, sizeof(GpCustomLineCap));
+    if (!*to)
+        return OutOfMemory;
+
+    if (from->type == CustomLineCapTypeDefault)
+        **to = *from;
+    else
+        *(GpAdjustableArrowCap *)*to = *(GpAdjustableArrowCap *)from;
 
+    /* Duplicate path data */
     (*to)->pathdata.Points = heap_alloc_zero(from->pathdata.Count * sizeof(PointF));
     (*to)->pathdata.Types = heap_alloc_zero(from->pathdata.Count);
 
@@ -62,12 +72,44 @@ GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap* from,
     return Ok;
 }
 
+static GpStatus init_custom_linecap(GpCustomLineCap *cap, GpPathData *pathdata, BOOL fill, GpLineCap basecap,
+    REAL base_inset)
+{
+    cap->fill = fill;
+
+    cap->pathdata.Points = heap_alloc_zero(pathdata->Count * sizeof(PointF));
+    cap->pathdata.Types = heap_alloc_zero(pathdata->Count);
+
+    if ((!cap->pathdata.Types || !cap->pathdata.Points) && pathdata->Count)
+    {
+        heap_free(cap->pathdata.Points);
+        heap_free(cap->pathdata.Types);
+        cap->pathdata.Points = NULL;
+        cap->pathdata.Types = NULL;
+        return OutOfMemory;
+    }
+
+    if (pathdata->Points)
+        memcpy(cap->pathdata.Points, pathdata->Points, pathdata->Count * sizeof(PointF));
+    if (pathdata->Types)
+        memcpy(cap->pathdata.Types, pathdata->Types, pathdata->Count);
+    cap->pathdata.Count = pathdata->Count;
+
+    cap->inset = base_inset;
+    cap->cap = basecap;
+    cap->join = LineJoinMiter;
+    cap->scale = 1.0;
+
+    return Ok;
+}
+
 /* FIXME: Sometimes when fillPath is non-null and stroke path is null, the native
  * version of this function returns NotImplemented. I cannot figure out why. */
 GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath,
     GpLineCap baseCap, REAL baseInset, GpCustomLineCap **customCap)
 {
     GpPathData *pathdata;
+    GpStatus stat;
 
     TRACE("%p %p %d %f %p\n", fillPath, strokePath, baseCap, baseInset, customCap);
 
@@ -77,37 +119,18 @@ GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath
     *customCap = heap_alloc_zero(sizeof(GpCustomLineCap));
     if(!*customCap)    return OutOfMemory;
 
-    (*customCap)->type = CustomLineCapTypeDefault;
-    if(strokePath){
-        (*customCap)->fill = FALSE;
+    if (strokePath)
         pathdata = &strokePath->pathdata;
-    }
-    else{
-        (*customCap)->fill = TRUE;
+    else
         pathdata = &fillPath->pathdata;
-    }
 
-    (*customCap)->pathdata.Points = heap_alloc_zero(pathdata->Count * sizeof(PointF));
-    (*customCap)->pathdata.Types = heap_alloc_zero(pathdata->Count);
-
-    if((!(*customCap)->pathdata.Types || !(*customCap)->pathdata.Points) &&
-        pathdata->Count){
-        heap_free((*customCap)->pathdata.Points);
-        heap_free((*customCap)->pathdata.Types);
+    stat = init_custom_linecap(*customCap, pathdata, fillPath != NULL, baseCap, baseInset);
+    if (stat != Ok)
+    {
         heap_free(*customCap);
-        return OutOfMemory;
+        return stat;
     }
 
-    memcpy((*customCap)->pathdata.Points, pathdata->Points, pathdata->Count
-           * sizeof(PointF));
-    memcpy((*customCap)->pathdata.Types, pathdata->Types, pathdata->Count);
-    (*customCap)->pathdata.Count = pathdata->Count;
-
-    (*customCap)->inset = baseInset;
-    (*customCap)->cap = baseCap;
-    (*customCap)->join = LineJoinMiter;
-    (*customCap)->scale = 1.0;
-
     TRACE("<-- %p\n", *customCap);
 
     return Ok;
@@ -257,111 +280,175 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapType(GpCustomLineCap *customCap, CustomL
     return Ok;
 }
 
+static void arrowcap_update_path(GpAdjustableArrowCap *cap)
+{
+    static const BYTE types_filled[] =
+    {
+        PathPointTypeStart, PathPointTypeLine, PathPointTypeLine, PathPointTypeLine | PathPointTypeCloseSubpath
+    };
+    static const BYTE types_unfilled[] =
+    {
+        PathPointTypeStart, PathPointTypeLine, PathPointTypeLine
+    };
+    GpPointF *points;
+
+    assert(cap->cap.pathdata.Count == 3 || cap->cap.pathdata.Count == 4);
+
+    points = cap->cap.pathdata.Points;
+    if (cap->cap.fill)
+    {
+        memcpy(cap->cap.pathdata.Types, types_filled, sizeof(types_filled));
+        cap->cap.pathdata.Count = 4;
+        points[0].X = -cap->width / 2.0;
+        points[0].Y = -cap->height;
+        points[1].X = 0.0;
+        points[1].Y = 0.0;
+        points[2].X = cap->width / 2.0;
+        points[2].Y = -cap->height;
+        points[3].X = 0.0;
+        points[3].Y = -cap->height - cap->middle_inset;
+    }
+    else
+    {
+        memcpy(cap->cap.pathdata.Types, types_unfilled, sizeof(types_unfilled));
+        cap->cap.pathdata.Count = 3;
+        points[0].X = -cap->width / 4.0;
+        points[0].Y = -cap->height / 2.0;
+        points[1].X = 0.0;
+        points[1].Y = 0.0;
+        points[2].X = cap->width / 4.0;
+        points[2].Y = -cap->height / 2.0;
+    }
+
+    if (cap->width == 0.0)
+        cap->cap.inset = 0.0;
+    else
+        cap->cap.inset = cap->height / cap->width;
+}
+
 GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL fill,
     GpAdjustableArrowCap **cap)
 {
-    static int calls;
+    GpPathData pathdata;
+    GpStatus stat;
 
     TRACE("(%0.2f,%0.2f,%i,%p)\n", height, width, fill, cap);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap)
+        return InvalidParameter;
 
-    return NotImplemented;
+    *cap = heap_alloc_zero(sizeof(**cap));
+    if (!*cap)
+        return OutOfMemory;
+
+    /* We'll need 4 points at most. */
+    pathdata.Count = 4;
+    pathdata.Points = NULL;
+    pathdata.Types = NULL;
+    stat = init_custom_linecap(&(*cap)->cap, &pathdata, fill, LineCapTriangle, width != 0.0 ? height / width : 0.0);
+    if (stat != Ok)
+    {
+        heap_free(*cap);
+        return stat;
+    }
+
+    (*cap)->cap.type = CustomLineCapTypeAdjustableArrow;
+    (*cap)->height = height;
+    (*cap)->width = width;
+    (*cap)->middle_inset = 0.0;
+    arrowcap_update_path(*cap);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL* fill)
 {
-    static int calls;
-
     TRACE("(%p,%p)\n", cap, fill);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap || !fill)
+        return InvalidParameter;
 
-    return NotImplemented;
+    *fill = cap->cap.fill;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL* height)
 {
-    static int calls;
-
     TRACE("(%p,%p)\n", cap, height);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap || !height)
+        return InvalidParameter;
 
-    return NotImplemented;
+    *height = cap->height;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL* middle)
 {
-    static int calls;
-
     TRACE("(%p,%p)\n", cap, middle);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap || !middle)
+        return InvalidParameter;
 
-    return NotImplemented;
+    *middle = cap->middle_inset;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL* width)
 {
-    static int calls;
-
     TRACE("(%p,%p)\n", cap, width);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap || !width)
+        return InvalidParameter;
 
-    return NotImplemented;
+    *width = cap->width;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL fill)
 {
-    static int calls;
-
     TRACE("(%p,%i)\n", cap, fill);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap)
+        return InvalidParameter;
 
-    return NotImplemented;
+    cap->cap.fill = fill;
+    arrowcap_update_path(cap);
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL height)
 {
-    static int calls;
-
     TRACE("(%p,%0.2f)\n", cap, height);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap)
+        return InvalidParameter;
 
-    return NotImplemented;
+    cap->height = height;
+    arrowcap_update_path(cap);
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL middle)
 {
-    static int calls;
-
     TRACE("(%p,%0.2f)\n", cap, middle);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap)
+        return InvalidParameter;
 
-    return NotImplemented;
+    cap->middle_inset = middle;
+    arrowcap_update_path(cap);
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL width)
 {
-    static int calls;
-
     TRACE("(%p,%0.2f)\n", cap, width);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (!cap)
+        return InvalidParameter;
 
-    return NotImplemented;
+    cap->width = width;
+    arrowcap_update_path(cap);
+    return Ok;
 }
index f99b026..64778bb 100644 (file)
@@ -1367,7 +1367,7 @@ static int match_name_table_language( const tt_name_record *name, LANGID lang )
     case TT_PLATFORM_MACINTOSH:
         if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
         name_lang = GET_BE_WORD(name->language_id);
-        if (name_lang >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
+        if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0;
         name_lang = mac_langid_table[name_lang];
         break;
     case TT_PLATFORM_APPLE_UNICODE:
@@ -1377,7 +1377,7 @@ static int match_name_table_language( const tt_name_record *name, LANGID lang )
         case TT_APPLE_ID_ISO_10646:
         case TT_APPLE_ID_UNICODE_2_0:
             name_lang = GET_BE_WORD(name->language_id);
-            if (name_lang >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
+            if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0;
             name_lang = mac_langid_table[name_lang];
             break;
         default:
index b29e41e..ed9d50c 100644 (file)
 534 stdcall GdipSetPathGradientFocusScales(ptr float float)
 535 stdcall GdipSetPathGradientGammaCorrection(ptr long)
 536 stdcall GdipSetPathGradientLinearBlend(ptr float float)
-537 stub GdipSetPathGradientPath
+537 stdcall GdipSetPathGradientPath(ptr ptr)
 538 stdcall GdipSetPathGradientPresetBlend(ptr ptr ptr long)
 539 stdcall GdipSetPathGradientSigmaBlend(ptr float float)
 540 stdcall GdipSetPathGradientSurroundColorsWithCount(ptr ptr ptr)
index ea79f11..25b269b 100644 (file)
@@ -35,6 +35,8 @@
 
 #include "gdiplus.h"
 
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+
 #define GP_DEFAULT_PENSTYLE (PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER)
 #define MAX_ARC_PTS (13)
 #define MAX_DASHLEN (16) /* this is a limitation of gdi */
@@ -341,6 +343,9 @@ struct GpCustomLineCap{
 
 struct GpAdjustableArrowCap{
     GpCustomLineCap cap;
+    REAL middle_inset;
+    REAL height;
+    REAL width;
 };
 
 struct GpImage{
index f42fca6..1e2aff1 100644 (file)
@@ -353,15 +353,20 @@ static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
     GpRegion *rgn;
     GpMatrix transform;
     GpStatus stat;
+    BOOL identity;
 
     stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, &transform);
 
+    if (stat == Ok)
+        stat = GdipIsMatrixIdentity(&transform, &identity);
+
     if (stat == Ok)
         stat = GdipCloneRegion(graphics->clip, &rgn);
 
     if (stat == Ok)
     {
-        stat = GdipTransformRegion(rgn, &transform);
+        if (!identity)
+            stat = GdipTransformRegion(rgn, &transform);
 
         if (stat == Ok)
             stat = GdipGetRegionHRgn(rgn, NULL, hrgn);
@@ -1695,9 +1700,9 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
             ptf[3].X = x2 - dbig;
             ptf[2].X = x2 + dsmall;
 
-            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
 
-            round_points(pt, ptf, 3);
+            round_points(pt, ptf, 4);
 
             Polygon(graphics->hdc, pt, 4);
 
@@ -1735,9 +1740,9 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
             ptf[1].X = x2 + dx;
             ptf[1].Y = y2 + dy;
 
-            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 2);
 
-            round_points(pt, ptf, 3);
+            round_points(pt, ptf, 2);
 
             Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
 
@@ -1781,9 +1786,9 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
             ptf[3].X = x2 + dx;
             ptf[3].Y = y2 + dy;
 
-            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
 
-            round_points(pt, ptf, 3);
+            round_points(pt, ptf, 4);
 
             Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
                 pt[2].y, pt[3].x, pt[3].y);
@@ -1793,6 +1798,13 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
             if(!custom)
                 break;
 
+            if (custom->type == CustomLineCapTypeAdjustableArrow)
+            {
+                GpAdjustableArrowCap *arrow = (GpAdjustableArrowCap *)custom;
+                if (arrow->cap.fill && arrow->height <= 0.0)
+                    break;
+            }
+
             count = custom->pathdata.Count;
             custptf = heap_alloc_zero(count * sizeof(PointF));
             custpt = heap_alloc_zero(count * sizeof(POINT));
@@ -1810,9 +1822,9 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
             GdipTranslateMatrix(&matrix, x2, y2, MatrixOrderAppend);
             GdipTransformMatrixPoints(&matrix, custptf, count);
 
-            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+            gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, custptf, count);
 
-            round_points(pt, ptf, 3);
+            round_points(custpt, custptf, count);
 
             for(i = 0; i < count; i++)
                 tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
@@ -6469,9 +6481,12 @@ GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
     if (status == Ok)
     {
         GpMatrix world_to_device;
+        BOOL identity;
 
         get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
-        status = GdipTransformRegion(region, &world_to_device);
+        status = GdipIsMatrixIdentity(&world_to_device, &identity);
+        if (status == Ok && !identity)
+            status = GdipTransformRegion(region, &world_to_device);
         if (status == Ok)
             status = GdipCombineRegionRegion(graphics->clip, region, mode);
 
@@ -6520,9 +6535,12 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
     if (status == Ok)
     {
         GpMatrix world_to_device;
+        BOOL identity;
 
         get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
-        status = GdipTransformRegion(clip, &world_to_device);
+        status = GdipIsMatrixIdentity(&world_to_device, &identity);
+        if (status == Ok && !identity)
+            status = GdipTransformRegion(clip, &world_to_device);
         if (status == Ok)
             status = GdipCombineRegionRegion(graphics->clip, clip, mode);
 
index ff9bd9b..afa2afe 100644 (file)
@@ -2560,7 +2560,7 @@ static UINT vt_to_itemtype(UINT vt)
         { VT_BLOB, PropertyTagTypeUndefined }
     };
     UINT i;
-    for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(vt2type); i++)
     {
         if (vt2type[i].vt == vt) return vt2type[i].type;
     }
@@ -3460,10 +3460,10 @@ static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI
                         {
                             if (name.vt == VT_LPSTR)
                             {
-                                for (j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++)
+                                for (j = 0; j < ARRAY_SIZE(keywords); j++)
                                     if (!strcmp(keywords[j].name, name.u.pszVal))
                                         break;
-                                if (j < sizeof(keywords)/sizeof(keywords[0]) && !keywords[j].seen)
+                                if (j < ARRAY_SIZE(keywords) && !keywords[j].seen)
                                 {
                                     keywords[j].seen = TRUE;
                                     item = create_prop(keywords[j].propid, &value);
@@ -4586,7 +4586,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
     encode_image_func encode_image;
     int i;
 
-    TRACE("%p %p %s %p\n", image, stream, wine_dbgstr_guid(clsid), params);
+    TRACE("%p, %p, %s, %p\n", image, stream, wine_dbgstr_guid(clsid), params);
 
     if(!image || !stream)
         return InvalidParameter;
index 77673a7..08dde2f 100644 (file)
@@ -606,7 +606,7 @@ void METAFILE_Free(GpMetafile *metafile)
     if (metafile->record_stream)
         IStream_Release(metafile->record_stream);
 
-    for (i = 0; i < sizeof(metafile->objtable)/sizeof(metafile->objtable[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(metafile->objtable); i++)
         metafile_free_object_table_entry(metafile, i);
 }
 
index 2c49371..b86808b 100644 (file)
@@ -460,17 +460,12 @@ GpStatus WINGDIPAPI GdipGetPenTransform(GpPen *pen, GpMatrix *matrix)
 
 GpStatus WINGDIPAPI GdipTranslatePenTransform(GpPen *pen, REAL dx, REAL dy, GpMatrixOrder order)
 {
-    static int calls;
-
     TRACE("(%p,%0.2f,%0.2f,%u)\n", pen, dx, dy, order);
 
     if(!pen)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
-
-    return NotImplemented;
+    return GdipTranslateMatrix(&pen->transform, dx, dy, order);
 }
 
 GpStatus WINGDIPAPI GdipScalePenTransform(GpPen *pen, REAL sx, REAL sy, GpMatrixOrder order)
index 8eb3ff3..470bcd2 100644 (file)
@@ -1398,10 +1398,46 @@ static GpStatus transform_region_element(region_element* element, GpMatrix *matr
             return Ok;
         case RegionDataRect:
         {
-            /* We can't transform a rectangle, so convert it to a path. */
             GpRegion *new_region;
             GpPath *path;
 
+            if (matrix->matrix[1] == 0.0 && matrix->matrix[2] == 0.0)
+            {
+                GpPointF points[2];
+
+                points[0].X = element->elementdata.rect.X;
+                points[0].Y = element->elementdata.rect.Y;
+                points[1].X = element->elementdata.rect.X + element->elementdata.rect.Width;
+                points[1].Y = element->elementdata.rect.Y + element->elementdata.rect.Height;
+
+                stat = GdipTransformMatrixPoints(matrix, points, 2);
+                if (stat != Ok)
+                    return stat;
+
+                if (points[0].X > points[1].X)
+                {
+                    REAL temp;
+                    temp = points[0].X;
+                    points[0].X = points[1].X;
+                    points[1].X = temp;
+                }
+
+                if (points[0].Y > points[1].Y)
+                {
+                    REAL temp;
+                    temp = points[0].Y;
+                    points[0].Y = points[1].Y;
+                    points[1].Y = temp;
+                }
+
+                element->elementdata.rect.X = points[0].X;
+                element->elementdata.rect.Y = points[0].Y;
+                element->elementdata.rect.Width = points[1].X - points[0].X;
+                element->elementdata.rect.Height = points[1].Y - points[0].Y;
+                return Ok;
+            }
+
+            /* We can't rotate/shear a rectangle, so convert it to a path. */
             stat = GdipCreatePath(FillModeAlternate, &path);
             if (stat == Ok)
             {
index 08dcf59..e17dedd 100644 (file)
@@ -68,7 +68,7 @@ reactos/dll/win32/dciman32            # Synced to WineStaging-3.3
 reactos/dll/win32/faultrep            # Synced to WineStaging-2.9
 reactos/dll/win32/fontsub             # Synced to WineStaging-2.9
 reactos/dll/win32/fusion              # Synced to WineStaging-3.3
-reactos/dll/win32/gdiplus             # Synced to WineStaging-3.3
+reactos/dll/win32/gdiplus             # Synced to WineStaging-3.9
 reactos/dll/win32/hhctrl.ocx          # Synced to WineStaging-3.3
 reactos/dll/win32/hlink               # Synced to WineStaging-3.3
 reactos/dll/win32/hnetcfg             # Synced to WineStaging-3.3