- Sync gdiplus with wine head
authorDmitry Chapyshev <dmitry@reactos.org>
Sun, 7 Sep 2008 10:32:49 +0000 (10:32 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Sun, 7 Sep 2008 10:32:49 +0000 (10:32 +0000)
svn path=/trunk/; revision=36023

15 files changed:
reactos/dll/win32/gdiplus/brush.c
reactos/dll/win32/gdiplus/customlinecap.c
reactos/dll/win32/gdiplus/font.c
reactos/dll/win32/gdiplus/gdiplus.c
reactos/dll/win32/gdiplus/gdiplus.spec
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/imageattributes.c
reactos/dll/win32/gdiplus/matrix.c
reactos/dll/win32/gdiplus/pathiterator.c
reactos/dll/win32/gdiplus/region.c
reactos/include/psdk/gdiplusflat.h
reactos/include/psdk/gdiplusgpstubs.h

index 13cd3ab..067fdde 100644 (file)
@@ -36,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
 {
+    TRACE("(%p, %p)\n", brush, clone);
+
     if(!brush || !clone)
         return InvalidParameter;
 
@@ -125,6 +127,9 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
 {
     COLORREF col = ARGB2COLORREF(startcolor);
 
+    TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint,
+          startcolor, endcolor, wrap, line);
+
     if(!line || !startpoint || !endpoint || wrap == WrapModeClamp)
         return InvalidParameter;
 
@@ -156,6 +161,9 @@ GpStatus WINGDIPAPI GdipCreateLineBrushI(GDIPCONST GpPoint* startpoint,
     GpPointF stF;
     GpPointF endF;
 
+    TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint,
+          startcolor, endcolor, wrap, line);
+
     if(!startpoint || !endpoint)
         return InvalidParameter;
 
@@ -173,6 +181,9 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
 {
     GpPointF start, end;
 
+    TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
+          wrap, line);
+
     if(!line || !rect)
         return InvalidParameter;
 
@@ -190,6 +201,9 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
 {
     GpRectF rectF;
 
+    TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
+          wrap, line);
+
     rectF.X      = (REAL) rect->X;
     rectF.Y      = (REAL) rect->Y;
     rectF.Width  = (REAL) rect->Width;
@@ -205,6 +219,9 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect
     ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
     GpLineGradient **line)
 {
+    TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
+          wrap, line);
+
     return GdipCreateLineBrushFromRect(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
                                        wrap, line);
 }
@@ -213,6 +230,9 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect* rect
     ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
     GpLineGradient **line)
 {
+    TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
+          wrap, line);
+
     return GdipCreateLineBrushFromRectI(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
                                         wrap, line);
 }
@@ -222,6 +242,8 @@ GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
 {
     COLORREF col = ARGB2COLORREF(0xffffffff);
 
+    TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
+
     if(!points || !grad)
         return InvalidParameter;
 
@@ -278,6 +300,8 @@ GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
+
     if(!points || !grad)
         return InvalidParameter;
 
@@ -305,6 +329,8 @@ GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
 {
     COLORREF col = ARGB2COLORREF(0xffffffff);
 
+    TRACE("(%p, %p)\n", path, grad);
+
     if(!path || !grad)
         return InvalidParameter;
 
@@ -357,6 +383,8 @@ GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
 {
     COLORREF col = ARGB2COLORREF(color);
 
+    TRACE("(%x, %p)\n", color, sf);
+
     if(!sf)  return InvalidParameter;
 
     *sf = GdipAlloc(sizeof(GpSolidFill));
@@ -373,6 +401,53 @@ GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
     return Ok;
 }
 
+/*******************************************************************************
+ * GdipCreateTexture [GDIPLUS.@]
+ *
+ * PARAMS
+ *  image       [I] image to use
+ *  wrapmode    [I] optional
+ *  texture     [O] pointer to the resulting texturebrush
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: element of GpStatus
+ */
+GpStatus WINGDIPAPI GdipCreateTexture(GpImage *image, GpWrapMode wrapmode,
+        GpTexture **texture)
+{
+    UINT width, height;
+    GpImageAttributes attributes;
+    GpStatus stat;
+
+    TRACE("%p, %d %p\n", image, wrapmode, texture);
+
+    if (!(image && texture))
+        return InvalidParameter;
+
+    stat = GdipGetImageWidth(image, &width);
+    if (stat != Ok) return stat;
+    stat = GdipGetImageHeight(image, &height);
+    if (stat != Ok) return stat;
+    attributes.wrap = wrapmode;
+
+    return GdipCreateTextureIA(image, &attributes, 0, 0, width, height,
+            texture);
+}
+
+GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
+        REAL x, REAL y, REAL width, REAL height, GpTexture **texture)
+{
+    GpImageAttributes attributes;
+
+    TRACE("%p %d %f %f %f %f %p\n", image, wrapmode,
+            x, y, width, height, texture);
+
+    attributes.wrap = wrapmode;
+    return GdipCreateTextureIA(image, &attributes, x, y, width, height,
+            texture);
+}
+
 /* FIXME: imageattr ignored */
 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
     GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
@@ -387,6 +462,9 @@ GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
     BOOL bm_is_selected;
     BYTE *dibits, *buff, *textbits;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image, imageattr, x, y, width, height,
+           texture);
+
     if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0)
         return InvalidParameter;
 
@@ -491,11 +569,29 @@ GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr,
     INT x, INT y, INT width, INT height, GpTexture **texture)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image, imageattr, x, y, width, height,
+           texture);
+
     return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture);
 }
 
+GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
+        INT x, INT y, INT width, INT height, GpTexture **texture)
+{
+    GpImageAttributes imageattr;
+
+    TRACE("%p %d %d %d %d %d %p\n", image, wrapmode, x, y, width, height,
+            texture);
+
+    imageattr.wrap = wrapmode;
+
+    return GdipCreateTextureIA(image, &imageattr, x, y, width, height, texture);
+}
+
 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
 {
+    TRACE("(%p, %p)\n", brush, type);
+
     if(!brush || !type)  return InvalidParameter;
 
     *type = brush->bt;
@@ -505,6 +601,8 @@ GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
 
 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
 {
+    TRACE("(%p)\n", brush);
+
     if(!brush)  return InvalidParameter;
 
     switch(brush->bt)
@@ -531,7 +629,9 @@ GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
     BOOL *usinggamma)
 {
-    if(!line)
+    TRACE("(%p, %p)\n", line, usinggamma);
+
+    if(!line || !usinggamma)
         return InvalidParameter;
 
     *usinggamma = line->gamma;
@@ -541,6 +641,8 @@ GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
 
 GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapmode)
 {
+    TRACE("(%p, %p)\n", brush, wrapmode);
+
     if(!brush || !wrapmode)
         return InvalidParameter;
 
@@ -552,6 +654,8 @@ GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapm
 GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend,
     REAL *positions, INT count)
 {
+    TRACE("(%p, %p, %p, %d)\n", brush, blend, positions, count);
+
     if(!brush || !blend || !positions || count <= 0)
         return InvalidParameter;
 
@@ -568,6 +672,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend,
 
 GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *count)
 {
+    TRACE("(%p, %p)\n", brush, count);
+
     if(!brush || !count)
         return InvalidParameter;
 
@@ -579,6 +685,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *co
 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
     GpPointF *point)
 {
+    TRACE("(%p, %p)\n", grad, point);
+
     if(!grad || !point)
         return InvalidParameter;
 
@@ -594,6 +702,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
     GpStatus ret;
     GpPointF ptf;
 
+    TRACE("(%p, %p)\n", grad, point);
+
     if(!point)
         return InvalidParameter;
 
@@ -610,6 +720,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
     REAL *x, REAL *y)
 {
+    TRACE("(%p, %p, %p)\n", grad, x, y);
+
     if(!grad || !x || !y)
         return InvalidParameter;
 
@@ -622,6 +734,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
     BOOL *gamma)
 {
+    TRACE("(%p, %p)\n", grad, gamma);
+
     if(!grad || !gamma)
         return InvalidParameter;
 
@@ -633,6 +747,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
     INT *count)
 {
+    TRACE("(%p, %p)\n", grad, count);
+
     if(!grad || !count)
         return InvalidParameter;
 
@@ -647,6 +763,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient *brush, GpRectF *rect
     GpPath* path;
     GpStatus stat;
 
+    TRACE("(%p, %p)\n", brush, rect);
+
     if(!brush || !rect)
         return InvalidParameter;
 
@@ -672,6 +790,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient *brush, GpRect *rect
     GpRectF rectf;
     GpStatus stat;
 
+    TRACE("(%p, %p)\n", brush, rect);
+
     if(!brush || !rect)
         return InvalidParameter;
 
@@ -703,6 +823,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
     GpWrapMode *wrapmode)
 {
+    TRACE("(%p, %p)\n", brush, wrapmode);
+
     if(!brush || !wrapmode)
         return InvalidParameter;
 
@@ -713,6 +835,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
 
 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
 {
+    TRACE("(%p, %p)\n", sf, argb);
+
     if(!sf || !argb)
         return InvalidParameter;
 
@@ -738,6 +862,8 @@ GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
     BOOL usegamma)
 {
+    TRACE("(%p, %d)\n", line, usegamma);
+
     if(!line)
         return InvalidParameter;
 
@@ -763,6 +889,8 @@ GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
     GpWrapMode wrap)
 {
+    TRACE("(%p, %d)\n", line, wrap);
+
     if(!line || wrap == WrapModeClamp)
         return InvalidParameter;
 
@@ -774,6 +902,8 @@ GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
     ARGB argb)
 {
+    TRACE("(%p, %x)\n", grad, argb);
+
     if(!grad)
         return InvalidParameter;
 
@@ -789,6 +919,8 @@ GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
     GpPointF *point)
 {
+    TRACE("(%p, %p)\n", grad, point);
+
     if(!grad || !point)
         return InvalidParameter;
 
@@ -803,6 +935,8 @@ GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
 {
     GpPointF ptf;
 
+    TRACE("(%p, %p)\n", grad, point);
+
     if(!point)
         return InvalidParameter;
 
@@ -815,6 +949,8 @@ GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
     REAL x, REAL y)
 {
+    TRACE("(%p, %.2f, %.2f)\n", grad, x, y);
+
     if(!grad)
         return InvalidParameter;
 
@@ -827,6 +963,8 @@ GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
     BOOL gamma)
 {
+    TRACE("(%p, %d)\n", grad, gamma);
+
     if(!grad)
         return InvalidParameter;
 
@@ -867,6 +1005,8 @@ GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
     GpWrapMode wrap)
 {
+    TRACE("(%p, %d)\n", grad, wrap);
+
     if(!grad)
         return InvalidParameter;
 
@@ -877,6 +1017,8 @@ GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
 
 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
 {
+    TRACE("(%p, %x)\n", sf, argb);
+
     if(!sf)
         return InvalidParameter;
 
@@ -906,6 +1048,8 @@ GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture,
 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
     ARGB color2)
 {
+    TRACE("(%p, %x, %x)\n", brush, color1, color2);
+
     if(!brush)
         return InvalidParameter;
 
@@ -917,6 +1061,8 @@ GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
 
 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors)
 {
+    TRACE("(%p, %p)\n", brush, colors);
+
     if(!brush || !colors)
         return InvalidParameter;
 
@@ -959,8 +1105,18 @@ GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
+        REAL dx, REAL dy, GpMatrixOrder order)
+{
+    FIXME("stub: %p %f %f %d\n", brush, dx, dy, order);
+
+    return NotImplemented;
+}
+
 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
 {
+    TRACE("(%p, %p)\n", brush, rect);
+
     if(!brush || !rect)
         return InvalidParameter;
 
@@ -978,6 +1134,8 @@ GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect)
     GpRectF  rectF;
     GpStatus ret;
 
+    TRACE("(%p, %p)\n", brush, rect);
+
     if(!rect)
         return InvalidParameter;
 
index 48a20df..5658e69 100644 (file)
@@ -33,6 +33,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap* from,
     GpCustomLineCap** to)
 {
+    TRACE("(%p, %p)\n", from, to);
+
     if(!from || !to)
         return InvalidParameter;
 
@@ -108,6 +110,8 @@ GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath
 
 GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap *customCap)
 {
+    TRACE("(%p)\n", customCap);
+
     if(!customCap)
         return InvalidParameter;
 
@@ -121,6 +125,8 @@ GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap *customCap)
 GpStatus WINGDIPAPI GdipGetCustomLineCapStrokeJoin(GpCustomLineCap* customCap,
     GpLineJoin* lineJoin)
 {
+    TRACE("(%p, %p)\n", customCap, lineJoin);
+
     if(!customCap || !lineJoin)
         return InvalidParameter;
 
@@ -132,6 +138,8 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapStrokeJoin(GpCustomLineCap* customCap,
 GpStatus WINGDIPAPI GdipGetCustomLineCapWidthScale(GpCustomLineCap* custom,
     REAL* widthScale)
 {
+    TRACE("(%p, %p)\n", custom, widthScale);
+
     if(!custom || !widthScale)
         return InvalidParameter;
 
@@ -168,6 +176,8 @@ GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap* custom,
 GpStatus WINGDIPAPI GdipGetCustomLineCapBaseInset(GpCustomLineCap* custom,
     REAL* inset)
 {
+    TRACE("(%p, %p)\n", custom, inset);
+
     if(!custom || !inset)
         return InvalidParameter;
 
@@ -191,6 +201,8 @@ GpStatus WINGDIPAPI GdipSetCustomLineCapBaseInset(GpCustomLineCap* custom,
 GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeJoin(GpCustomLineCap* custom,
     GpLineJoin join)
 {
+    TRACE("(%p, %d)\n", custom, join);
+
     if(!custom)
         return InvalidParameter;
 
@@ -212,6 +224,8 @@ GpStatus WINGDIPAPI GdipSetCustomLineCapWidthScale(GpCustomLineCap* custom,
 
 GpStatus WINGDIPAPI GdipGetCustomLineCapBaseCap(GpCustomLineCap *customCap, GpLineCap *baseCap)
 {
+    TRACE("(%p, %p)\n", customCap, baseCap);
+
     if(!customCap || !baseCap)
         return InvalidParameter;
 
@@ -219,3 +233,94 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapBaseCap(GpCustomLineCap *customCap, GpLi
 
     return Ok;
 }
+
+GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL fill,
+    GpAdjustableArrowCap **cap)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL* fill)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL* height)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL* middle)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL* width)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL fill)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL height)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL middle)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL width)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
index 70f7bb0..210ebff 100644 (file)
@@ -166,9 +166,14 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc,
     HFONT hfont, oldfont;
     TEXTMETRICW textmet;
 
+    TRACE("(%p, %p, %p)\n", hdc, logfont, font);
+
     if(!logfont || !font)
         return InvalidParameter;
 
+    if (logfont->lfFaceName[0] == 0)
+        return NotTrueTypeFont;
+
     *font = GdipAlloc(sizeof(GpFont));
     if(!*font)  return OutOfMemory;
 
@@ -203,6 +208,8 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc,
 {
     LOGFONTW lfw;
 
+    TRACE("(%p, %p, %p)\n", hdc, lfa, font);
+
     if(!lfa || !font)
         return InvalidParameter;
 
@@ -221,6 +228,8 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc,
  */
 GpStatus WINGDIPAPI GdipDeleteFont(GpFont* font)
 {
+    TRACE("(%p)\n", font);
+
     if(!font)
         return InvalidParameter;
 
@@ -237,6 +246,8 @@ GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font)
     HFONT hfont;
     LOGFONTW lfw;
 
+    TRACE("(%p, %p)\n", hdc, font);
+
     if(!font)
         return InvalidParameter;
 
@@ -250,6 +261,29 @@ GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font)
     return GdipCreateFontFromLogfontW(hdc, &lfw, font);
 }
 
+/*******************************************************************************
+ * GdipGetFamily [GDIPLUS.@]
+ *
+ * Returns the FontFamily for the specified Font
+ *
+ * PARAMS
+ *  font    [I] Font to request from
+ *  family  [O] Resulting FontFamily object
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: An element of GpStatus
+ */
+GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family)
+{
+    TRACE("%p %p\n", font, family);
+
+    if (!(font && family))
+        return InvalidParameter;
+
+    return GdipCreateFontFamilyFromName(font->lfw.lfFaceName, NULL, family);
+}
+
 /******************************************************************************
  * GdipGetFontSize [GDIPLUS.@]
  *
@@ -268,6 +302,8 @@ GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font)
  */
 GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size)
 {
+    TRACE("(%p, %p)\n", font, size);
+
     if (!(font && size)) return InvalidParameter;
 
     *size = font->emSize;
@@ -275,6 +311,40 @@ GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size)
     return Ok;
 }
 
+/*******************************************************************************
+ * GdipGetFontStyle [GDIPLUS.@]
+ *
+ * Gets the font's style, returned in bitwise OR of FontStyle enumeration
+ *
+ * PARAMS
+ *  font    [I] font to request from
+ *  style   [O] resulting pointer to a FontStyle enumeration
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParameter
+ */
+GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *style)
+{
+    TRACE("%p %p\n", font, style);
+
+    if (!(font && style))
+        return InvalidParameter;
+
+    if (font->lfw.lfWeight > 400)
+        *style = FontStyleBold;
+    else
+        *style = 0;
+    if (font->lfw.lfItalic)
+        *style |= FontStyleItalic;
+    if (font->lfw.lfUnderline)
+        *style |= FontStyleUnderline;
+    if (font->lfw.lfStrikeOut)
+        *style |= FontStyleStrikeout;
+
+    return Ok;
+}
+
 /*******************************************************************************
  * GdipGetFontUnit  [GDIPLUS.@]
  *
@@ -288,6 +358,8 @@ GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size)
  */
 GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit)
 {
+    TRACE("(%p, %p)\n", font, unit);
+
     if (!(font && unit)) return InvalidParameter;
 
     *unit = font->unit;
@@ -301,6 +373,8 @@ GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit)
 GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics,
     LOGFONTW *lfw)
 {
+    TRACE("(%p, %p, %p)\n", font, graphics, lfw);
+
     /* FIXME: use graphics */
     if(!font || !graphics || !lfw)
         return InvalidParameter;
@@ -315,6 +389,8 @@ GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics,
  */
 GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont)
 {
+    TRACE("(%p, %p)\n", font, cloneFont);
+
     if(!font || !cloneFont)
         return InvalidParameter;
 
@@ -326,6 +402,31 @@ GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont)
     return Ok;
 }
 
+/*******************************************************************************
+ * GdipGetFontHeight [GDIPLUS.@]
+ * PARAMS
+ *  font        [I] Font to retrieve height from
+ *  graphics    [I] The current graphics context
+ *  height      [O] Resulting height
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: Another element of GpStatus
+ *
+ * NOTES
+ *  Forwards to GdipGetFontHeightGivenDPI
+ */
+GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font,
+        GDIPCONST GpGraphics *graphics, REAL *height)
+{
+    REAL dpi;
+
+    TRACE("%p %p %p\n", font, graphics, height);
+
+    dpi = GetDeviceCaps(graphics->hdc, LOGPIXELSY);
+
+    return GdipGetFontHeightGivenDPI(font, dpi, height);
+}
+
 /*******************************************************************************
  * GdipGetFontHeightGivenDPI [GDIPLUS.@]
  * PARAMS
@@ -343,12 +444,22 @@ GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont)
  */
 GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, REAL *height)
 {
+    TRACE("%p (%s), %f, %p\n", font,
+            debugstr_w(font->lfw.lfFaceName), dpi, height);
+
     if (!(font && height)) return InvalidParameter;
 
-    FIXME("%p (%s), %f, %p\n", font,
-            debugstr_w(font->lfw.lfFaceName), dpi, height);
+    switch (font->unit)
+    {
+        case UnitPixel:
+            *height = font->emSize;
+            break;
+        default:
+            FIXME("Unhandled unit type: %d\n", font->unit);
+            return NotImplemented;
+    }
 
-    return NotImplemented;
+    return Ok;
 }
 
 /***********************************************************************
@@ -529,6 +640,8 @@ GpStatus WINGDIPAPI GdipGetCellAscent(GDIPCONST GpFontFamily *family,
 GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family,
         INT style, UINT16* CellDescent)
 {
+    TRACE("(%p, %d, %p)\n", family, style, CellDescent);
+
     if (!(family && CellDescent)) return InvalidParameter;
 
     *CellDescent = family->tmw.tmDescent;
@@ -635,6 +748,8 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily)
 {
     static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
 
+    TRACE("(%p)\n", nativeFamily);
+
     if (nativeFamily == NULL) return InvalidParameter;
 
     return GdipCreateFontFamilyFromName(TimesNewRoman, NULL, nativeFamily);
@@ -658,6 +773,8 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamil
      * affect anything */
     static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
 
+    TRACE("(%p)\n", nativeFamily);
+
     if (nativeFamily == NULL) return InvalidParameter;
 
     return GdipCreateFontFamilyFromName(MSSansSerif, NULL, nativeFamily);
index 2b50f2c..046ee14 100644 (file)
@@ -311,3 +311,58 @@ void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
     *x = roundr(tension * (xadj - xend) + xend);
     *y = roundr(tension * (yadj - yend) + yend);
 }
+
+/* make sure path has enough space for len more points */
+BOOL lengthen_path(GpPath *path, INT len)
+{
+    /* initial allocation */
+    if(path->datalen == 0){
+        path->datalen = len * 2;
+
+        path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
+        if(!path->pathdata.Points)   return FALSE;
+
+        path->pathdata.Types = GdipAlloc(path->datalen);
+        if(!path->pathdata.Types){
+            GdipFree(path->pathdata.Points);
+            return FALSE;
+        }
+    }
+    /* reallocation, double size of arrays */
+    else if(path->datalen - path->pathdata.Count < len){
+        while(path->datalen - path->pathdata.Count < len)
+            path->datalen *= 2;
+
+        path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0,
+            path->pathdata.Points, path->datalen * sizeof(PointF));
+        if(!path->pathdata.Points)  return FALSE;
+
+        path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0,
+            path->pathdata.Types, path->datalen);
+        if(!path->pathdata.Types)   return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* recursive deletion of GpRegion nodes */
+inline void delete_element(region_element* element)
+{
+    switch(element->type)
+    {
+        case RegionDataRect:
+            break;
+        case RegionDataPath:
+            GdipDeletePath(element->elementdata.pathdata.path);
+            break;
+        case RegionDataEmptyRect:
+        case RegionDataInfiniteRect:
+            break;
+        default:
+            delete_element(element->elementdata.combine.left);
+            delete_element(element->elementdata.combine.right);
+            GdipFree(element->elementdata.combine.left);
+            GdipFree(element->elementdata.combine.right);
+            break;
+    }
+}
index 18e7eeb..f7b1d5d 100644 (file)
@@ -21,8 +21,8 @@
 @ stdcall GdipAddPathLine(ptr long long long long)
 @ stdcall GdipAddPathLineI(ptr long long long long)
 @ stdcall GdipAddPathPath(ptr ptr long)
-@ stub GdipAddPathPie
-@ stub GdipAddPathPieI
+@ stdcall GdipAddPathPie(ptr long long long long long long)
+@ stdcall GdipAddPathPieI(ptr long long long long long long)
 @ stdcall GdipAddPathPolygon(ptr ptr long)
 @ stdcall GdipAddPathPolygonI(ptr ptr long)
 @ stdcall GdipAddPathRectangle(ptr long long long long)
@@ -69,7 +69,7 @@
 @ stdcall GdipConvertToEmfPlus(ptr ptr ptr long ptr ptr)
 @ stub GdipConvertToEmfPlusToFile
 @ stub GdipConvertToEmfPlusToStream
-@ stub GdipCreateAdjustableArrowCap
+@ stdcall GdipCreateAdjustableArrowCap(long long long ptr)
 @ stub GdipCreateBitmapFromDirectDrawSurface
 @ stdcall GdipCreateBitmapFromFile(wstr ptr)
 @ stdcall GdipCreateBitmapFromFileICM(wstr ptr)
 @ stdcall GdipCreateSolidFill(long ptr)
 @ stdcall GdipCreateStreamOnFile(ptr long ptr)
 @ stdcall GdipCreateStringFormat(long long ptr)
-@ stub GdipCreateTexture2
-@ stub GdipCreateTexture2I
-@ stub GdipCreateTexture
+@ stdcall GdipCreateTexture2(ptr long long long long long ptr)
+@ stdcall GdipCreateTexture2I(ptr long long long long long ptr)
+@ stdcall GdipCreateTexture(ptr long ptr)
 @ stdcall GdipCreateTextureIA(ptr ptr long long long long ptr)
 @ stdcall GdipCreateTextureIAI(ptr ptr long long long long ptr)
 @ stdcall GdipDeleteBrush(ptr)
 @ stub GdipEnumerateMetafileSrcRectDestPointsI
 @ stub GdipEnumerateMetafileSrcRectDestRect
 @ stub GdipEnumerateMetafileSrcRectDestRectI
-@ stub GdipFillClosedCurve2
-@ stub GdipFillClosedCurve2I
+@ stdcall GdipFillClosedCurve2(ptr ptr ptr long long long)
+@ stdcall GdipFillClosedCurve2I(ptr ptr ptr long long long)
 @ stub GdipFillClosedCurve
 @ stub GdipFillClosedCurveI
 @ stdcall GdipFillEllipse(ptr ptr long long long long)
 @ stdcall GdipFillRegion(ptr ptr ptr)
 @ stdcall GdipFindFirstImageItem(ptr ptr)
 @ stub GdipFindNextImageItem
-@ stub GdipFlattenPath
+@ stdcall GdipFlattenPath(ptr ptr long)
 @ stdcall GdipFlush(ptr long)
 @ stdcall GdipFree(ptr)
-@ stub GdipGetAdjustableArrowCapFillState
-@ stub GdipGetAdjustableArrowCapHeight
-@ stub GdipGetAdjustableArrowCapMiddleInset
-@ stub GdipGetAdjustableArrowCapWidth
+@ stdcall GdipGetAdjustableArrowCapFillState(ptr ptr)
+@ stdcall GdipGetAdjustableArrowCapHeight(ptr ptr)
+@ stdcall GdipGetAdjustableArrowCapMiddleInset(ptr ptr)
+@ stdcall GdipGetAdjustableArrowCapWidth(ptr ptr)
 @ stub GdipGetAllPropertyItems
 @ stdcall GdipGetBrushType(ptr ptr)
 @ stdcall GdipGetCellAscent(ptr long ptr)
 @ stdcall GdipGetEmHeight(ptr long ptr)
 @ stub GdipGetEncoderParameterList
 @ stub GdipGetEncoderParameterListSize
-@ stub GdipGetFamily
+@ stdcall GdipGetFamily(ptr ptr)
 @ stdcall GdipGetFamilyName(ptr ptr long)
 @ stdcall GdipGetFontCollectionFamilyCount(ptr ptr)
 @ stdcall GdipGetFontCollectionFamilyList(ptr long ptr ptr)
-@ stub GdipGetFontHeight
+@ stdcall GdipGetFontHeight(ptr ptr ptr)
 @ stdcall GdipGetFontHeightGivenDPI(ptr long ptr)
 @ stdcall GdipGetFontSize(ptr ptr)
-@ stub GdipGetFontStyle
+@ stdcall GdipGetFontStyle(ptr ptr)
 @ stdcall GdipGetFontUnit(ptr ptr)
 @ stdcall GdipGetGenericFontFamilyMonospace(ptr)
 @ stdcall GdipGetGenericFontFamilySansSerif(ptr)
 @ stub GdipGetVisibleClipBounds
 @ stub GdipGetVisibleClipBoundsI
 @ stdcall GdipGetWorldTransform(ptr ptr)
-@ stub GdipGraphicsClear
+@ stdcall GdipGraphicsClear(ptr long)
 @ stub GdipGraphicsSetAbort
 @ stub GdipImageForceValidation
 @ stdcall GdipImageGetFrameCount(ptr ptr ptr)
 @ stub GdipImageSetAbort
 @ stub GdipInitializePalette
 @ stdcall GdipInvertMatrix(ptr)
-@ stub GdipIsClipEmpty
+@ stdcall GdipIsClipEmpty(ptr ptr)
 @ stdcall GdipIsEmptyRegion(ptr ptr ptr)
 @ stdcall GdipIsEqualRegion(ptr ptr ptr ptr)
 @ stdcall GdipIsInfiniteRegion(ptr ptr ptr)
 @ stdcall GdipPathIterGetCount(ptr ptr)
 @ stdcall GdipPathIterGetSubpathCount(ptr ptr)
 @ stdcall GdipPathIterHasCurve(ptr ptr)
-@ stub GdipPathIterIsValid
+@ stdcall GdipPathIterIsValid(ptr ptr)
 @ stdcall GdipPathIterNextMarker(ptr ptr ptr ptr)
-@ stub GdipPathIterNextMarkerPath
-@ stub GdipPathIterNextPathType
+@ stdcall GdipPathIterNextMarkerPath(ptr ptr ptr)
+@ stdcall GdipPathIterNextPathType(ptr ptr ptr ptr ptr)
 @ stdcall GdipPathIterNextSubpath(ptr ptr ptr ptr ptr)
-@ stub GdipPathIterNextSubpathPath
+@ stdcall GdipPathIterNextSubpathPath(ptr ptr ptr ptr)
 @ stdcall GdipPathIterRewind(ptr)
 @ stub GdipPlayMetafileRecord
 @ stub GdipPlayTSClientRecord
 @ stub GdipRecordMetafileStreamI
 @ stdcall GdipReleaseDC(ptr ptr)
 @ stdcall GdipRemovePropertyItem(ptr long)
-@ stub GdipResetClip
+@ stdcall GdipResetClip(ptr)
 @ stub GdipResetImageAttributes
 @ stub GdipResetLineTransform
 @ stub GdipResetPageTransform
 @ stub GdipResetPathGradientTransform
 @ stub GdipResetPenTransform
 @ stub GdipResetTextureTransform
-@ stub GdipResetWorldTransform
+@ stdcall GdipResetWorldTransform(ptr)
 @ stdcall GdipRestoreGraphics(ptr long)
-@ stub GdipReversePath
+@ stdcall GdipReversePath(ptr)
 @ stub GdipRotateLineTransform
 @ stdcall GdipRotateMatrix(ptr long long)
 @ stub GdipRotatePathGradientTransform
 @ stub GdipScalePenTransform
 @ stub GdipScaleTextureTransform
 @ stdcall GdipScaleWorldTransform(ptr long long long)
-@ stub GdipSetAdjustableArrowCapFillState
-@ stub GdipSetAdjustableArrowCapHeight
-@ stub GdipSetAdjustableArrowCapMiddleInset
-@ stub GdipSetAdjustableArrowCapWidth
+@ stdcall GdipSetAdjustableArrowCapFillState(ptr long)
+@ stdcall GdipSetAdjustableArrowCapHeight(ptr long)
+@ stdcall GdipSetAdjustableArrowCapMiddleInset(ptr long)
+@ stdcall GdipSetAdjustableArrowCapWidth(ptr long)
 @ stub GdipSetClipGraphics
 @ stub GdipSetClipHrgn
 @ stub GdipSetClipPath
 @ stdcall GdipTransformRegion(ptr ptr)
 @ stub GdipTranslateClip
 @ stub GdipTranslateClipI
-@ stub GdipTranslateLineTransform
+@ stdcall GdipTranslateLineTransform(ptr long long long)
 @ stdcall GdipTranslateMatrix(ptr long long long)
 @ stub GdipTranslatePathGradientTransform
 @ stub GdipTranslatePenTransform
index 80fc5a6..230eb8f 100644 (file)
@@ -52,6 +52,11 @@ extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
 extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
     REAL tension, REAL *x, REAL *y);
 
+extern BOOL lengthen_path(GpPath *path, INT len);
+
+typedef struct region_element region_element;
+extern inline void delete_element(region_element *element);
+
 static inline INT roundr(REAL x)
 {
     return (INT) floor(x + 0.5);
@@ -93,6 +98,8 @@ struct GpGraphics{
     GpUnit unit;    /* page unit */
     REAL scale;     /* page scale */
     GpMatrix * worldtrans; /* world transform */
+    BOOL busy;      /* hdc handle obtained by GdipGetDC */
+    GpRegion *clip;
 };
 
 struct GpBrush{
@@ -160,6 +167,10 @@ struct GpCustomLineCap{
     REAL scale;
 };
 
+struct GpAdustableArrowCap{
+    GpCustomLineCap cap;
+};
+
 struct GpImage{
     IPicture* picture;
     ImageType type;
@@ -215,7 +226,16 @@ struct GpFontFamily{
     WCHAR FamilyName[LF_FACESIZE];
 };
 
-typedef struct region_element
+/* internal use */
+typedef enum RegionType
+{
+    RegionDataRect          = 0x10000000,
+    RegionDataPath          = 0x10000001,
+    RegionDataEmptyRect     = 0x10000002,
+    RegionDataInfiniteRect  = 0x10000003,
+} RegionType;
+
+struct region_element
 {
     DWORD type; /* Rectangle, Path, SpecialRectangle, or CombineMode */
     union
@@ -238,7 +258,7 @@ typedef struct region_element
             struct region_element *right; /* what *left was combined with */
         } combine;
     } elementdata;
-} region_element;
+};
 
 struct GpRegion{
     struct
index af8331c..8e88ad8 100644 (file)
@@ -717,6 +717,8 @@ end:
 
 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
 {
+    TRACE("(%p, %p)\n", hdc, graphics);
+
     return GdipCreateFromHDC2(hdc, NULL, graphics);
 }
 
@@ -724,6 +726,8 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
 {
     GpStatus retval;
 
+    TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics);
+
     if(hDevice != NULL) {
         FIXME("Don't know how to hadle parameter hDevice\n");
         return NotImplemented;
@@ -743,8 +747,14 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
         return retval;
     }
 
+    if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
+        GdipFree((*graphics)->worldtrans);
+        GdipFree(*graphics);
+        return retval;
+    }
+
     (*graphics)->hdc = hdc;
-    (*graphics)->hwnd = NULL;
+    (*graphics)->hwnd = WindowFromDC(hdc);
     (*graphics)->smoothing = SmoothingModeDefault;
     (*graphics)->compqual = CompositingQualityDefault;
     (*graphics)->interpolation = InterpolationModeDefault;
@@ -752,6 +762,7 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
     (*graphics)->compmode = CompositingModeSourceOver;
     (*graphics)->unit = UnitDisplay;
     (*graphics)->scale = 1.0;
+    (*graphics)->busy = FALSE;
 
     return Ok;
 }
@@ -760,6 +771,8 @@ GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
 {
     GpStatus ret;
 
+    TRACE("(%p, %p)\n", hwnd, graphics);
+
     if((ret = GdipCreateFromHDC(GetDC(hwnd), graphics)) != Ok)
         return ret;
 
@@ -771,6 +784,8 @@ GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
 /* FIXME: no icm handling */
 GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
 {
+    TRACE("(%p, %p)\n", hwnd, graphics);
+
     return GdipCreateFromHWND(hwnd, graphics);
 }
 
@@ -797,6 +812,8 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
     HENHMETAFILE hemf;
     GpStatus retval = GenericError;
 
+    TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
+
     if(!hwmf || !metafile || !placeable)
         return InvalidParameter;
 
@@ -870,6 +887,8 @@ GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
     DWORD dwMode;
     HRESULT ret;
 
+    TRACE("(%s, %u, %p)\n", debugstr_w(filename), access, stream);
+
     if(!stream || !filename)
         return InvalidParameter;
 
@@ -887,12 +906,17 @@ GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
 
 GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
 {
+    TRACE("(%p)\n", graphics);
+
     if(!graphics) return InvalidParameter;
+    if(graphics->busy) return ObjectBusy;
+
     if(graphics->hwnd)
         ReleaseDC(graphics->hwnd, graphics->hdc);
 
+    GdipDeleteRegion(graphics->clip);
     GdipDeleteMatrix(graphics->worldtrans);
-    HeapFree(GetProcessHeap(), 0, graphics);
+    GdipFree(graphics);
 
     return Ok;
 }
@@ -904,9 +928,15 @@ GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x,
     GpPointF points[MAX_ARC_PTS];
     GpStatus retval;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
+          width, height, startAngle, sweepAngle);
+
     if(!graphics || !pen || width <= 0 || height <= 0)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     num_pts = arc2polybezier(points, x, y, width, height, startAngle, sweepAngle);
 
     save_state = prepare_dc(graphics, pen);
@@ -921,6 +951,9 @@ GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x,
 GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x,
     INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
+          width, height, startAngle, sweepAngle);
+
     return GdipDrawArc(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
 }
 
@@ -931,9 +964,15 @@ GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1,
     GpPointF pt[4];
     GpStatus retval;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1,
+          x2, y2, x3, y3, x4, y4);
+
     if(!graphics || !pen)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pt[0].X = x1;
     pt[0].Y = y1;
     pt[1].X = x2;
@@ -959,9 +998,15 @@ GpStatus WINGDIPAPI GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1,
     GpPointF pt[4];
     GpStatus retval;
 
+    TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", graphics, pen, x1, y1,
+          x2, y2, x3, y3, x4, y4);
+
     if(!graphics || !pen)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pt[0].X = x1;
     pt[0].Y = y1;
     pt[1].X = x2;
@@ -986,9 +1031,14 @@ GpStatus WINGDIPAPI GdipDrawBeziers(GpGraphics *graphics, GpPen *pen,
     INT i;
     GpStatus ret;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     if(!graphics || !pen || !points || (count <= 0))
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     for(i = 0; i < floor(count / 4); i++){
         ret = GdipDrawBezier(graphics, pen,
                              points[4*i].X, points[4*i].Y,
@@ -1009,9 +1059,14 @@ GpStatus WINGDIPAPI GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     if(!graphics || !pen || !points || (count <= 0))
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pts = GdipAlloc(sizeof(GpPointF) * count);
     if(!pts)
         return OutOfMemory;
@@ -1031,36 +1086,45 @@ GpStatus WINGDIPAPI GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen,
 GpStatus WINGDIPAPI GdipDrawClosedCurve(GpGraphics *graphics, GpPen *pen,
     GDIPCONST GpPointF *points, INT count)
 {
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     return GdipDrawClosedCurve2(graphics, pen, points, count, 1.0);
 }
 
 GpStatus WINGDIPAPI GdipDrawClosedCurveI(GpGraphics *graphics, GpPen *pen,
     GDIPCONST GpPoint *points, INT count)
 {
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     return GdipDrawClosedCurve2I(graphics, pen, points, count, 1.0);
 }
 
 GpStatus WINGDIPAPI GdipDrawClosedCurve2(GpGraphics *graphics, GpPen *pen,
     GDIPCONST GpPointF *points, INT count, REAL tension)
 {
-    GpPointF *ptf;
+    GpPath *path;
     GpStatus stat;
 
+    TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
+
     if(!graphics || !pen || !points || count <= 0)
         return InvalidParameter;
 
-    /* make a full points copy.. */
-    ptf = GdipAlloc(sizeof(GpPointF)*(count+1));
-    if(!ptf)
-        return OutOfMemory;
-    memcpy(ptf, points, sizeof(GpPointF)*count);
+    if(graphics->busy)
+        return ObjectBusy;
 
-    /* ..and add a first point as a last one */
-    ptf[count] = ptf[0];
+    if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok)
+        return stat;
 
-    stat = GdipDrawCurve2(graphics, pen, ptf, count + 1, tension);
+    stat = GdipAddPathClosedCurve2(path, points, count, tension);
+    if(stat != Ok){
+        GdipDeletePath(path);
+        return stat;
+    }
 
-    GdipFree(ptf);
+    stat = GdipDrawPath(graphics, pen, path);
+
+    GdipDeletePath(path);
 
     return stat;
 }
@@ -1072,6 +1136,8 @@ GpStatus WINGDIPAPI GdipDrawClosedCurve2I(GpGraphics *graphics, GpPen *pen,
     GpStatus stat;
     INT i;
 
+    TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
+
     if(!points || count <= 0)
         return InvalidParameter;
 
@@ -1094,6 +1160,8 @@ GpStatus WINGDIPAPI GdipDrawClosedCurve2I(GpGraphics *graphics, GpPen *pen,
 GpStatus WINGDIPAPI GdipDrawCurve(GpGraphics *graphics, GpPen *pen,
     GDIPCONST GpPointF *points, INT count)
 {
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     return GdipDrawCurve2(graphics,pen,points,count,1.0);
 }
 
@@ -1104,6 +1172,8 @@ GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics *graphics, GpPen *pen,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     if(!points || count <= 0)
         return InvalidParameter;
 
@@ -1132,9 +1202,14 @@ GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen,
     REAL x1, x2, y1, y2;
     GpStatus retval;
 
+    TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
+
     if(!graphics || !pen)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pt = GdipAlloc(len_pt * sizeof(GpPointF));
     tension = tension * TENSION_CONST;
 
@@ -1182,6 +1257,8 @@ GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
+
     if(!points || count <= 0)
         return InvalidParameter;
 
@@ -1207,9 +1284,14 @@ GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x,
     GpPointF ptf[2];
     POINT pti[2];
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
+
     if(!graphics || !pen)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf[0].X = x;
     ptf[0].Y = y;
     ptf[1].X = x + width;
@@ -1230,12 +1312,16 @@ GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x,
 GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x,
     INT y, INT width, INT height)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
+
     return GdipDrawEllipse(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
 }
 
 
 GpStatus WINGDIPAPI GdipDrawImage(GpGraphics *graphics, GpImage *image, REAL x, REAL y)
 {
+    TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y);
+
     /* IPicture::Render uses LONG coords */
     return GdipDrawImageI(graphics,image,roundr(x),roundr(y));
 }
@@ -1245,6 +1331,8 @@ GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
 {
     UINT width, height, srcw, srch;
 
+    TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y);
+
     if(!graphics || !image)
         return InvalidParameter;
 
@@ -1277,8 +1365,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
     POINT pti[3];
     REAL dx, dy;
 
-    TRACE("%p %p %p %d %f %f %f %f %d %p %p %p\n", graphics, image, points, count,
-          srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
+    TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points,
+          count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
           callbackData);
 
     if(!graphics || !image || !points || count != 3)
@@ -1328,6 +1416,10 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRectI(GpGraphics *graphics, GpImage *imag
     GpPointF pointsF[3];
     INT i;
 
+    TRACE("(%p, %p, %p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", graphics, image, points, count,
+          srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
+          callbackData);
+
     if(!points || count!=3)
         return InvalidParameter;
 
@@ -1349,6 +1441,10 @@ GpStatus WINGDIPAPI GdipDrawImageRectRect(GpGraphics *graphics, GpImage *image,
 {
     GpPointF points[3];
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p, %p, %p)\n",
+          graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy,
+          srcwidth, srcheight, srcUnit, imageattr, callback, callbackData);
+
     points[0].X = dstx;
     points[0].Y = dsty;
     points[1].X = dstx + dstwidth;
@@ -1366,7 +1462,11 @@ GpStatus WINGDIPAPI GdipDrawImageRectRectI(GpGraphics *graphics, GpImage *image,
        GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback,
        VOID * callbackData)
 {
-   GpPointF points[3];
+    GpPointF points[3];
+
+    TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
+          graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy,
+          srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData);
 
     points[0].X = dstx;
     points[0].Y = dsty;
@@ -1386,6 +1486,8 @@ GpStatus WINGDIPAPI GdipDrawImageRect(GpGraphics *graphics, GpImage *image,
     GpUnit unit;
     GpStatus ret;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, image, x, y, width, height);
+
     if(!graphics || !image)
         return InvalidParameter;
 
@@ -1401,6 +1503,8 @@ GpStatus WINGDIPAPI GdipDrawImageRect(GpGraphics *graphics, GpImage *image,
 GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image,
     INT x, INT y, INT width, INT height)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, image, x, y, width, height);
+
     return GdipDrawImageRect(graphics, image, (REAL)x, (REAL)y, (REAL)width, (REAL)height);
 }
 
@@ -1411,9 +1515,14 @@ GpStatus WINGDIPAPI GdipDrawLine(GpGraphics *graphics, GpPen *pen, REAL x1,
     GpPointF pt[2];
     GpStatus retval;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2);
+
     if(!pen || !graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pt[0].X = x1;
     pt[0].Y = y1;
     pt[1].X = x2;
@@ -1435,9 +1544,14 @@ GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1,
     GpPointF pt[2];
     GpStatus retval;
 
+    TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x1, y1, x2, y2);
+
     if(!pen || !graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pt[0].X = (REAL)x1;
     pt[0].Y = (REAL)y1;
     pt[1].X = (REAL)x2;
@@ -1458,9 +1572,14 @@ GpStatus WINGDIPAPI GdipDrawLines(GpGraphics *graphics, GpPen *pen, GDIPCONST
     INT save_state;
     GpStatus retval;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     if(!pen || !graphics || (count < 2))
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     save_state = prepare_dc(graphics, pen);
 
     retval = draw_polyline(graphics, pen, points, count, TRUE);
@@ -1478,9 +1597,14 @@ GpStatus WINGDIPAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, GDIPCONST
     GpPointF *ptf = NULL;
     int i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     if(!pen || !graphics || (count < 2))
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf = GdipAlloc(count * sizeof(GpPointF));
     if(!ptf) return OutOfMemory;
 
@@ -1504,9 +1628,14 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
     INT save_state;
     GpStatus retval;
 
+    TRACE("(%p, %p, %p)\n", graphics, pen, path);
+
     if(!pen || !graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     save_state = prepare_dc(graphics, pen);
 
     retval = draw_poly(graphics, pen, path->pathdata.Points,
@@ -1522,9 +1651,15 @@ GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
 {
     INT save_state;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
+            width, height, startAngle, sweepAngle);
+
     if(!graphics || !pen)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     save_state = prepare_dc(graphics, pen);
     SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
 
@@ -1538,6 +1673,9 @@ GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
 GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x,
     INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
+            width, height, startAngle, sweepAngle);
+
     return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
 }
 
@@ -1548,9 +1686,14 @@ GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x,
     GpPointF ptf[4];
     POINT pti[4];
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
+
     if(!pen || !graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf[0].X = x;
     ptf[0].Y = y;
     ptf[1].X = x + width;
@@ -1574,6 +1717,8 @@ GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x,
 GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
     INT y, INT width, INT height)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
+
     return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
 }
 
@@ -1584,9 +1729,14 @@ GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen,
     POINT *pti;
     INT save_state, i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count);
+
     if(!graphics || !pen || !rects || count < 1)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf = GdipAlloc(4 * count * sizeof(GpPointF));
     pti = GdipAlloc(4 * count * sizeof(POINT));
 
@@ -1626,6 +1776,8 @@ GpStatus WINGDIPAPI GdipDrawRectanglesI(GpGraphics *graphics, GpPen *pen,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count);
+
     if(!rects || count<=0)
         return InvalidParameter;
 
@@ -1801,6 +1953,71 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipFillClosedCurve2(GpGraphics *graphics, GpBrush *brush,
+    GDIPCONST GpPointF *points, INT count, REAL tension, GpFillMode fill)
+{
+    GpPath *path;
+    GpStatus stat;
+
+    TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points,
+            count, tension, fill);
+
+    if(!graphics || !brush || !points)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    stat = GdipCreatePath(fill, &path);
+    if(stat != Ok)
+        return stat;
+
+    stat = GdipAddPathClosedCurve2(path, points, count, tension);
+    if(stat != Ok){
+        GdipDeletePath(path);
+        return stat;
+    }
+
+    stat = GdipFillPath(graphics, brush, path);
+    if(stat != Ok){
+        GdipDeletePath(path);
+        return stat;
+    }
+
+    GdipDeletePath(path);
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipFillClosedCurve2I(GpGraphics *graphics, GpBrush *brush,
+    GDIPCONST GpPoint *points, INT count, REAL tension, GpFillMode fill)
+{
+    GpPointF *ptf;
+    GpStatus stat;
+    INT i;
+
+    TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points,
+            count, tension, fill);
+
+    if(!points || count <= 0)
+        return InvalidParameter;
+
+    ptf = GdipAlloc(sizeof(GpPointF)*count);
+    if(!ptf)
+        return OutOfMemory;
+
+    for(i = 0;i < count;i++){
+        ptf[i].X = (REAL)points[i].X;
+        ptf[i].Y = (REAL)points[i].Y;
+    }
+
+    stat = GdipFillClosedCurve2(graphics, brush, ptf, count, tension, fill);
+
+    GdipFree(ptf);
+
+    return stat;
+}
+
 GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x,
     REAL y, REAL width, REAL height)
 {
@@ -1808,9 +2025,14 @@ GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x
     GpPointF ptf[2];
     POINT pti[2];
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
+
     if(!graphics || !brush)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf[0].X = x;
     ptf[0].Y = y;
     ptf[1].X = x + width;
@@ -1833,6 +2055,8 @@ GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x
 GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x,
     INT y, INT width, INT height)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
+
     return GdipFillEllipse(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
 }
 
@@ -1841,9 +2065,14 @@ GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *p
     INT save_state;
     GpStatus retval;
 
+    TRACE("(%p, %p, %p)\n", graphics, brush, path);
+
     if(!brush || !graphics || !path)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, brush->gdibrush);
@@ -1873,9 +2102,15 @@ GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
 {
     INT save_state;
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
+            graphics, brush, x, y, width, height, startAngle, sweepAngle);
+
     if(!graphics || !brush)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, brush->gdibrush);
@@ -1891,6 +2126,9 @@ GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
 GpStatus WINGDIPAPI GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x,
     INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
 {
+    TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n",
+            graphics, brush, x, y, width, height, startAngle, sweepAngle);
+
     return GdipFillPie(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
 }
 
@@ -1902,9 +2140,14 @@ GpStatus WINGDIPAPI GdipFillPolygon(GpGraphics *graphics, GpBrush *brush,
     POINT *pti = NULL;
     GpStatus retval = Ok;
 
+    TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode);
+
     if(!graphics || !brush || !points || !count)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf = GdipAlloc(count * sizeof(GpPointF));
     pti = GdipAlloc(count * sizeof(POINT));
     if(!ptf || !pti){
@@ -1941,9 +2184,14 @@ GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
     POINT *pti = NULL;
     GpStatus retval = Ok;
 
+    TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode);
+
     if(!graphics || !brush || !points || !count)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf = GdipAlloc(count * sizeof(GpPointF));
     pti = GdipAlloc(count * sizeof(POINT));
     if(!ptf || !pti){
@@ -1978,12 +2226,16 @@ end:
 GpStatus WINGDIPAPI GdipFillPolygon2(GpGraphics *graphics, GpBrush *brush,
     GDIPCONST GpPointF *points, INT count)
 {
+    TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count);
+
     return GdipFillPolygon(graphics, brush, points, count, FillModeAlternate);
 }
 
 GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush,
     GDIPCONST GpPoint *points, INT count)
 {
+    TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count);
+
     return GdipFillPolygonI(graphics, brush, points, count, FillModeAlternate);
 }
 
@@ -1994,9 +2246,14 @@ GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
     GpPointF ptf[4];
     POINT pti[4];
 
+    TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
+
     if(!graphics || !brush)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf[0].X = x;
     ptf[0].Y = y;
     ptf[1].X = x + width;
@@ -2027,9 +2284,14 @@ GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
     GpPointF ptf[4];
     POINT pti[4];
 
+    TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
+
     if(!graphics || !brush)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     ptf[0].X = x;
     ptf[0].Y = y;
     ptf[1].X = x + width;
@@ -2059,6 +2321,8 @@ GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDI
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
+
     if(!rects)
         return InvalidParameter;
 
@@ -2077,6 +2341,8 @@ GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics *graphics, GpBrush *brush, GD
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
+
     if(!rects || count <= 0)
         return InvalidParameter;
 
@@ -2103,6 +2369,9 @@ GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
     if (!(graphics && brush && region))
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     FIXME("(%p, %p, %p): stub\n", graphics, brush, region);
 
     return NotImplemented;
@@ -2115,6 +2384,9 @@ GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention)
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     if(!(calls++))
         FIXME("not implemented\n");
 
@@ -2125,9 +2397,14 @@ GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention)
 GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics,
     CompositingMode *mode)
 {
+    TRACE("(%p, %p)\n", graphics, mode);
+
     if(!graphics || !mode)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *mode = graphics->compmode;
 
     return Ok;
@@ -2137,9 +2414,14 @@ GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics,
 GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics *graphics,
     CompositingQuality *quality)
 {
+    TRACE("(%p, %p)\n", graphics, quality);
+
     if(!graphics || !quality)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *quality = graphics->compqual;
 
     return Ok;
@@ -2149,9 +2431,14 @@ GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics *graphics,
 GpStatus WINGDIPAPI GdipGetInterpolationMode(GpGraphics *graphics,
     InterpolationMode *mode)
 {
+    TRACE("(%p, %p)\n", graphics, mode);
+
     if(!graphics || !mode)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *mode = graphics->interpolation;
 
     return Ok;
@@ -2159,9 +2446,14 @@ GpStatus WINGDIPAPI GdipGetInterpolationMode(GpGraphics *graphics,
 
 GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics *graphics, REAL *scale)
 {
+    TRACE("(%p, %p)\n", graphics, scale);
+
     if(!graphics || !scale)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *scale = graphics->scale;
 
     return Ok;
@@ -2169,9 +2461,14 @@ GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics *graphics, REAL *scale)
 
 GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics *graphics, GpUnit *unit)
 {
+    TRACE("(%p, %p)\n", graphics, unit);
+
     if(!graphics || !unit)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *unit = graphics->unit;
 
     return Ok;
@@ -2181,9 +2478,14 @@ GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics *graphics, GpUnit *unit)
 GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
     *mode)
 {
+    TRACE("(%p, %p)\n", graphics, mode);
+
     if(!graphics || !mode)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *mode = graphics->pixeloffset;
 
     return Ok;
@@ -2192,9 +2494,14 @@ GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
 /* FIXME: Smoothing mode is not used anywhere except the getter/setter. */
 GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics *graphics, SmoothingMode *mode)
 {
+    TRACE("(%p, %p)\n", graphics, mode);
+
     if(!graphics || !mode)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *mode = graphics->smoothing;
 
     return Ok;
@@ -2204,9 +2511,14 @@ GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics *graphics, SmoothingMode *mo
 GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics,
     TextRenderingHint *hint)
 {
+    TRACE("(%p, %p)\n", graphics, hint);
+
     if(!graphics || !hint)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *hint = graphics->texthint;
 
     return Ok;
@@ -2214,13 +2526,63 @@ GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics,
 
 GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
 {
+    TRACE("(%p, %p)\n", graphics, matrix);
+
     if(!graphics || !matrix)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *matrix = *graphics->worldtrans;
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color)
+{
+    GpSolidFill *brush;
+    GpStatus stat;
+    RECT rect;
+
+    TRACE("(%p, %x)\n", graphics, color);
+
+    if(!graphics)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    if((stat = GdipCreateSolidFill(color, &brush)) != Ok)
+        return stat;
+
+    if(graphics->hwnd){
+        if(!GetWindowRect(graphics->hwnd, &rect)){
+            GdipDeleteBrush((GpBrush*)brush);
+            return GenericError;
+        }
+
+        GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)(rect.right  - rect.left),
+                                                               (REAL)(rect.bottom - rect.top));
+    }
+    else
+        GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)GetDeviceCaps(graphics->hdc, HORZRES),
+                                                               (REAL)GetDeviceCaps(graphics->hdc, VERTRES));
+
+    GdipDeleteBrush((GpBrush*)brush);
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics *graphics, BOOL *res)
+{
+    TRACE("(%p, %p)\n", graphics, res);
+
+    if(!graphics || !res)
+        return InvalidParameter;
+
+    return GdipIsEmptyRegion(graphics->clip, graphics, res);
+}
+
 GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
         GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font,
         GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat,
@@ -2343,6 +2705,39 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipResetClip(GpGraphics *graphics)
+{
+    TRACE("(%p)\n", graphics);
+
+    if(!graphics)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    return GdipSetInfinite(graphics->clip);
+}
+
+GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
+{
+    TRACE("(%p)\n", graphics);
+
+    if(!graphics)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    graphics->worldtrans->matrix[0] = 1.0;
+    graphics->worldtrans->matrix[1] = 0.0;
+    graphics->worldtrans->matrix[2] = 0.0;
+    graphics->worldtrans->matrix[3] = 1.0;
+    graphics->worldtrans->matrix[4] = 0.0;
+    graphics->worldtrans->matrix[5] = 0.0;
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
 {
     static int calls;
@@ -2359,9 +2754,14 @@ GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState stat
 GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
     GpMatrixOrder order)
 {
+    TRACE("(%p, %.2f, %d)\n", graphics, angle, order);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     return GdipRotateMatrix(graphics->worldtrans, angle, order);
 }
 
@@ -2381,18 +2781,28 @@ GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
 GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,
     REAL sy, GpMatrixOrder order)
 {
+    TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     return GdipScaleMatrix(graphics->worldtrans, sx, sy, order);
 }
 
 GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics,
     CompositingMode mode)
 {
+    TRACE("(%p, %d)\n", graphics, mode);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->compmode = mode;
 
     return Ok;
@@ -2401,9 +2811,14 @@ GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics,
 GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics,
     CompositingQuality quality)
 {
+    TRACE("(%p, %d)\n", graphics, quality);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->compqual = quality;
 
     return Ok;
@@ -2412,9 +2827,14 @@ GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics,
 GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
     InterpolationMode mode)
 {
+    TRACE("(%p, %d)\n", graphics, mode);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->interpolation = mode;
 
     return Ok;
@@ -2422,9 +2842,14 @@ GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
 
 GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
 {
+    TRACE("(%p, %.2f)\n", graphics, scale);
+
     if(!graphics || (scale <= 0.0))
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->scale = scale;
 
     return Ok;
@@ -2432,7 +2857,15 @@ GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
 
 GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
 {
-    if(!graphics || (unit == UnitWorld))
+    TRACE("(%p, %d)\n", graphics, unit);
+
+    if(!graphics)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    if(unit == UnitWorld)
         return InvalidParameter;
 
     graphics->unit = unit;
@@ -2443,9 +2876,14 @@ GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
 GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
     mode)
 {
+    TRACE("(%p, %d)\n", graphics, mode);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->pixeloffset = mode;
 
     return Ok;
@@ -2453,9 +2891,14 @@ GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
 
 GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode)
 {
+    TRACE("(%p, %d)\n", graphics, mode);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->smoothing = mode;
 
     return Ok;
@@ -2464,9 +2907,14 @@ GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mod
 GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics,
     TextRenderingHint hint)
 {
+    TRACE("(%p, %d)\n", graphics, hint);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     graphics->texthint = hint;
 
     return Ok;
@@ -2474,9 +2922,14 @@ GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics,
 
 GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
 {
+    TRACE("(%p, %p)\n", graphics, matrix);
+
     if(!graphics || !matrix)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     GdipDeleteMatrix(graphics->worldtrans);
     return GdipCloneMatrix(matrix, &graphics->worldtrans);
 }
@@ -2484,9 +2937,14 @@ GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix
 GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
     REAL dy, GpMatrixOrder order)
 {
+    TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order);
+
     if(!graphics)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     return GdipTranslateMatrix(graphics->worldtrans, dx, dy, order);
 }
 
@@ -2496,6 +2954,12 @@ GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
 {
     static int calls;
 
+    if(!graphics)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
     if(!(calls++))
         FIXME("not implemented\n");
 
@@ -2503,17 +2967,20 @@ GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
 }
 
 GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
-                                     CombineMode combineMode)
+                                      CombineMode mode)
 {
-    static int calls;
+    TRACE("(%p, %p, %d)\n", graphics, region, mode);
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if(!graphics || !region)
+        return InvalidParameter;
 
-    return NotImplemented;
+    if(graphics->busy)
+        return ObjectBusy;
+
+    return GdipCombineRegionRegion(graphics->clip, region, mode);
 }
 
-GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpGraphics *graphics,
+GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
     UINT limitDpi)
 {
     static int calls;
@@ -2530,9 +2997,14 @@ GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST Gp
     INT save_state;
     POINT *pti;
 
+    TRACE("(%p, %p, %d)\n", graphics, points, count);
+
     if(!graphics || !pen || count<=0)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     pti = GdipAlloc(sizeof(POINT) * count);
 
     save_state = prepare_dc(graphics, pen);
@@ -2554,6 +3026,8 @@ GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST G
     GpPointF *ptf;
     INT i;
 
+    TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
+
     if(count<=0)    return InvalidParameter;
     ptf = GdipAlloc(sizeof(GpPointF) * count);
 
@@ -2570,9 +3044,14 @@ GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST G
 
 GpStatus WINGDIPAPI GdipGetDpiX(GpGraphics *graphics, REAL* dpi)
 {
+    TRACE("(%p, %p)\n", graphics, dpi);
+
     if(!graphics || !dpi)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX);
 
     return Ok;
@@ -2580,9 +3059,14 @@ GpStatus WINGDIPAPI GdipGetDpiX(GpGraphics *graphics, REAL* dpi)
 
 GpStatus WINGDIPAPI GdipGetDpiY(GpGraphics *graphics, REAL* dpi)
 {
+    TRACE("(%p, %p)\n", graphics, dpi);
+
     if(!graphics || !dpi)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSY);
 
     return Ok;
@@ -2594,9 +3078,14 @@ GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST G
     GpMatrix m;
     GpStatus ret;
 
+    TRACE("(%p, %p, %d)\n", graphics, matrix, order);
+
     if(!graphics || !matrix)
         return InvalidParameter;
 
+    if(graphics->busy)
+        return ObjectBusy;
+
     m = *(graphics->worldtrans);
 
     ret = GdipMultiplyMatrix(&m, (GpMatrix*)matrix, order);
@@ -2608,29 +3097,67 @@ GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST G
 
 GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc)
 {
-    FIXME("(%p, %p): stub\n", graphics, hdc);
+    TRACE("(%p, %p)\n", graphics, hdc);
 
-    *hdc = NULL;
-    return NotImplemented;
+    if(!graphics || !hdc)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    *hdc = graphics->hdc;
+    graphics->busy = TRUE;
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc)
 {
-    FIXME("(%p, %p): stub\n", graphics, hdc);
+    TRACE("(%p, %p)\n", graphics, hdc);
 
-    return NotImplemented;
+    if(!graphics)
+        return InvalidParameter;
+
+    if(graphics->hdc != hdc || !(graphics->busy))
+        return InvalidParameter;
+
+    graphics->busy = FALSE;
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
 {
-   FIXME("(%p, %p): stub\n", graphics, region);
+    GpRegion *clip;
+    GpStatus status;
+
+    TRACE("(%p, %p)\n", graphics, region);
+
+    if(!graphics || !region)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    if((status = GdipCloneRegion(graphics->clip, &clip)) != Ok)
+        return status;
+
+    /* free everything except root node and header */
+    delete_element(&region->node);
+    memcpy(region, clip, sizeof(GpRegion));
 
-   return NotImplemented;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
                                         GpCoordinateSpace src_space, GpPointF *points, INT count)
 {
+    if(!graphics || !points || count <= 0)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
     FIXME("(%p, %d, %d, %p, %d): stub\n", graphics, dst_space, src_space, points, count);
 
     return NotImplemented;
index 136afe7..68606a6 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
-/* make sure path has enough space for len more points */
-static BOOL lengthen_path(GpPath *path, INT len)
+typedef struct path_list_node_t path_list_node_t;
+struct path_list_node_t {
+    GpPointF pt;
+    BYTE type; /* PathPointTypeStart or PathPointTypeLine */
+    path_list_node_t *next;
+};
+
+/* init list */
+static BOOL init_path_list(path_list_node_t **node, REAL x, REAL y)
 {
-    /* initial allocation */
-    if(path->datalen == 0){
-        path->datalen = len * 2;
+    *node = GdipAlloc(sizeof(path_list_node_t));
+    if(!*node)
+        return FALSE;
 
-        path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
-        if(!path->pathdata.Points)   return FALSE;
+    (*node)->pt.X = x;
+    (*node)->pt.Y = y;
+    (*node)->type = PathPointTypeStart;
+    (*node)->next = NULL;
 
-        path->pathdata.Types = GdipAlloc(path->datalen);
-        if(!path->pathdata.Types){
-            GdipFree(path->pathdata.Points);
-            return FALSE;
-        }
+    return TRUE;
+}
+
+/* free all nodes including argument */
+static void free_path_list(path_list_node_t *node)
+{
+    path_list_node_t *n = node;
+
+    while(n){
+        n = n->next;
+        GdipFree(node);
+        node = n;
     }
-    /* reallocation, double size of arrays */
-    else if(path->datalen - path->pathdata.Count < len){
-        while(path->datalen - path->pathdata.Count < len)
-            path->datalen *= 2;
-
-        path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0,
-            path->pathdata.Points, path->datalen * sizeof(PointF));
-        if(!path->pathdata.Points)  return FALSE;
-
-        path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0,
-            path->pathdata.Types, path->datalen);
-        if(!path->pathdata.Types)   return FALSE;
+}
+
+/* Add a node after 'node' */
+/*
+ * Returns
+ *  pointer on success
+ *  NULL    on allocation problems
+ */
+static path_list_node_t* add_path_list_node(path_list_node_t *node, REAL x, REAL y, BOOL type)
+{
+    path_list_node_t *new;
+
+    new = GdipAlloc(sizeof(path_list_node_t));
+    if(!new)
+        return NULL;
+
+    new->pt.X  = x;
+    new->pt.Y  = y;
+    new->type  = type;
+    new->next  = node->next;
+    node->next = new;
+
+    return new;
+}
+
+/* returns element count */
+static INT path_list_count(path_list_node_t *node)
+{
+    INT count = 1;
+
+    while((node = node->next))
+        ++count;
+
+    return count;
+}
+
+/* GdipFlattenPath helper */
+/*
+ * Used to recursively flatten single Bezier curve
+ * Parameters:
+ *  - start   : pointer to start point node;
+ *  - (x2, y2): first control point;
+ *  - (x3, y3): second control point;
+ *  - end     : pointer to end point node
+ *  - flatness: admissible error of linear approximation.
+ *
+ * Return value:
+ *  TRUE : success
+ *  FALSE: out of memory
+ *
+ * TODO: used quality criteria should be revised to match native as
+ *       closer as possible.
+ */
+static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, REAL y3,
+                           path_list_node_t *end, REAL flatness)
+{
+    /* this 5 middle points with start/end define to half-curves */
+    GpPointF mp[5];
+    GpPointF pt, pt_st;
+    path_list_node_t *node;
+
+    /* calculate bezier curve middle points == new control points */
+    mp[0].X = (start->pt.X + x2) / 2.0;
+    mp[0].Y = (start->pt.Y + y2) / 2.0;
+    /* middle point between control points */
+    pt.X = (x2 + x3) / 2.0;
+    pt.Y = (y2 + y3) / 2.0;
+    mp[1].X = (mp[0].X + pt.X) / 2.0;
+    mp[1].Y = (mp[0].Y + pt.Y) / 2.0;
+    mp[4].X = (end->pt.X + x3) / 2.0;
+    mp[4].Y = (end->pt.Y + y3) / 2.0;
+    mp[3].X = (mp[4].X + pt.X) / 2.0;
+    mp[3].Y = (mp[4].Y + pt.Y) / 2.0;
+
+    mp[2].X = (mp[1].X + mp[3].X) / 2.0;
+    mp[2].Y = (mp[1].Y + mp[3].Y) / 2.0;
+
+    pt = end->pt;
+    pt_st = start->pt;
+    /* check flatness as a half of distance between middle point and a linearized path */
+    if(fabs(((pt.Y - pt_st.Y)*mp[2].X + (pt_st.X - pt.X)*mp[2].Y +
+        (pt_st.Y*pt.X - pt_st.X*pt.Y))) <=
+        (0.5 * flatness*sqrt((powf(pt.Y - pt_st.Y, 2.0) + powf(pt_st.X - pt.X, 2.0))))){
+        return TRUE;
     }
+    else
+        /* add a middle point */
+        if(!(node = add_path_list_node(start, mp[2].X, mp[2].Y, PathPointTypeLine)))
+            return FALSE;
+
+    /* do the same with halfs */
+    flatten_bezier(start, mp[0].X, mp[0].Y, mp[1].X, mp[1].Y, node, flatness);
+    flatten_bezier(node,  mp[3].X, mp[3].Y, mp[4].X, mp[4].Y, end,  flatness);
 
     return TRUE;
 }
@@ -71,6 +167,9 @@ GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
 {
     INT count, old_count, i;
 
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
+          path, x1, y1, x2, y2, startAngle, sweepAngle);
+
     if(!path)
         return InvalidParameter;
 
@@ -100,6 +199,9 @@ GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
 GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
    INT y2, REAL startAngle, REAL sweepAngle)
 {
+    TRACE("(%p, %d, %d, %d, %d, %.2f, %.2f)\n",
+          path, x1, y1, x2, y2, startAngle, sweepAngle);
+
     return GdipAddPathArc(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,startAngle,sweepAngle);
 }
 
@@ -108,6 +210,9 @@ GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2,
 {
     INT old_count;
 
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
+          path, x1, y1, x2, y2, x3, y3, x4, y4);
+
     if(!path)
         return InvalidParameter;
 
@@ -140,6 +245,9 @@ GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2,
 GpStatus WINGDIPAPI GdipAddPathBezierI(GpPath *path, INT x1, INT y1, INT x2,
     INT y2, INT x3, INT y3, INT x4, INT y4)
 {
+    TRACE("(%p, %d, %d, %d, %d, %d, %d, %d, %d)\n",
+          path, x1, y1, x2, y2, x3, y3, x4, y4);
+
     return GdipAddPathBezier(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,(REAL)x3,(REAL)y3,
                                   (REAL)x4,(REAL)y4);
 }
@@ -149,6 +257,8 @@ GpStatus WINGDIPAPI GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points,
 {
     INT i, old_count;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!path || !points || ((count - 1) % 3))
         return InvalidParameter;
 
@@ -178,6 +288,8 @@ GpStatus WINGDIPAPI GdipAddPathBeziersI(GpPath *path, GDIPCONST GpPoint *points,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!points || ((count - 1) % 3))
         return InvalidParameter;
 
@@ -199,12 +311,16 @@ GpStatus WINGDIPAPI GdipAddPathBeziersI(GpPath *path, GDIPCONST GpPoint *points,
 GpStatus WINGDIPAPI GdipAddPathClosedCurve(GpPath *path, GDIPCONST GpPointF *points,
     INT count)
 {
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     return GdipAddPathClosedCurve2(path, points, count, 1.0);
 }
 
 GpStatus WINGDIPAPI GdipAddPathClosedCurveI(GpPath *path, GDIPCONST GpPoint *points,
     INT count)
 {
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     return GdipAddPathClosedCurve2I(path, points, count, 1.0);
 }
 
@@ -217,6 +333,8 @@ GpStatus WINGDIPAPI GdipAddPathClosedCurve2(GpPath *path, GDIPCONST GpPointF *po
     REAL x1, x2, y1, y2;
     GpStatus stat;
 
+    TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
+
     if(!path || !points || count <= 1)
         return InvalidParameter;
 
@@ -284,6 +402,8 @@ GpStatus WINGDIPAPI GdipAddPathClosedCurve2I(GpPath *path, GDIPCONST GpPoint *po
     INT i;
     GpStatus stat;
 
+    TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
+
     if(!path || !points || count <= 1)
         return InvalidParameter;
 
@@ -305,18 +425,22 @@ GpStatus WINGDIPAPI GdipAddPathClosedCurve2I(GpPath *path, GDIPCONST GpPoint *po
 
 GpStatus WINGDIPAPI GdipAddPathCurve(GpPath *path, GDIPCONST GpPointF *points, INT count)
 {
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!path || !points || count <= 1)
         return InvalidParameter;
 
-   return GdipAddPathCurve2(path, points, count, 1.0);
+    return GdipAddPathCurve2(path, points, count, 1.0);
 }
 
 GpStatus WINGDIPAPI GdipAddPathCurveI(GpPath *path, GDIPCONST GpPoint *points, INT count)
 {
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!path || !points || count <= 1)
         return InvalidParameter;
 
-   return GdipAddPathCurve2I(path, points, count, 1.0);
+    return GdipAddPathCurve2I(path, points, count, 1.0);
 }
 
 GpStatus WINGDIPAPI GdipAddPathCurve2(GpPath *path, GDIPCONST GpPointF *points, INT count,
@@ -327,6 +451,8 @@ GpStatus WINGDIPAPI GdipAddPathCurve2(GpPath *path, GDIPCONST GpPointF *points,
     REAL x1, x2, y1, y2;
     GpStatus stat;
 
+    TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
+
     if(!path || !points || count <= 1)
         return InvalidParameter;
 
@@ -377,6 +503,8 @@ GpStatus WINGDIPAPI GdipAddPathCurve2I(GpPath *path, GDIPCONST GpPoint *points,
     INT i;
     GpStatus stat;
 
+    TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
+
     if(!path || !points || count <= 1)
         return InvalidParameter;
 
@@ -401,6 +529,8 @@ GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width,
 {
     INT old_count, numpts;
 
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x, y, width, height);
+
     if(!path)
         return InvalidParameter;
 
@@ -429,6 +559,8 @@ GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width,
 GpStatus WINGDIPAPI GdipAddPathEllipseI(GpPath *path, INT x, INT y, INT width,
     INT height)
 {
+    TRACE("(%p, %d, %d, %d, %d)\n", path, x, y, width, height);
+
     return GdipAddPathEllipse(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
 }
 
@@ -437,6 +569,8 @@ GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points,
 {
     INT i, old_count;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!path || !points)
         return InvalidParameter;
 
@@ -467,6 +601,8 @@ GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath *path, GDIPCONST GpPoint *points, I
     INT i;
     GpStatus stat;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(count <= 0)
         return InvalidParameter;
 
@@ -489,6 +625,8 @@ GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REA
 {
     INT old_count;
 
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x1, y1, x2, y2);
+
     if(!path)
         return InvalidParameter;
 
@@ -514,6 +652,8 @@ GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REA
 
 GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
 {
+    TRACE("(%p, %d, %d, %d, %d)\n", path, x1, y1, x2, y2);
+
     return GdipAddPathLine(path, (REAL)x1, (REAL)y1, (REAL)x2, (REAL)y2);
 }
 
@@ -522,6 +662,8 @@ GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath* addingPath,
 {
     INT old_count, count;
 
+    TRACE("(%p, %p, %d)\n", path, addingPath, connect);
+
     if(!path || !addingPath)
         return InvalidParameter;
 
@@ -546,10 +688,69 @@ GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath* addingPath,
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipAddPathPie(GpPath *path, REAL x, REAL y, REAL width, REAL height,
+    REAL startAngle, REAL sweepAngle)
+{
+    GpPointF *ptf;
+    GpStatus status;
+    INT i, count;
+
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
+          path, x, y, width, height, startAngle, sweepAngle);
+
+    if(!path)
+        return InvalidParameter;
+
+    count = arc2polybezier(NULL, x, y, width, height, startAngle, sweepAngle);
+
+    if(count == 0)
+        return Ok;
+
+    ptf = GdipAlloc(sizeof(GpPointF)*count);
+    if(!ptf)
+        return OutOfMemory;
+
+    arc2polybezier(ptf, x, y, width, height, startAngle, sweepAngle);
+
+    status = GdipAddPathLine(path, (width - x)/2, (height - y)/2, ptf[0].X, ptf[0].Y);
+    if(status != Ok){
+        GdipFree(ptf);
+        return status;
+    }
+    /* one spline is already added as a line endpoint */
+    if(!lengthen_path(path, count - 1)){
+        GdipFree(ptf);
+        return OutOfMemory;
+    }
+
+    memcpy(&(path->pathdata.Points[path->pathdata.Count]), &(ptf[1]),sizeof(GpPointF)*(count-1));
+    for(i = 0; i < count-1; i++)
+        path->pathdata.Types[path->pathdata.Count+i] = PathPointTypeBezier;
+
+    path->pathdata.Count += count-1;
+
+    GdipClosePathFigure(path);
+
+    GdipFree(ptf);
+
+    return status;
+}
+
+GpStatus WINGDIPAPI GdipAddPathPieI(GpPath *path, INT x, INT y, INT width, INT height,
+    REAL startAngle, REAL sweepAngle)
+{
+    TRACE("(%p, %d, %d, %d, %d, %.2f, %.2f)\n",
+          path, x, y, width, height, startAngle, sweepAngle);
+
+    return GdipAddPathPieI(path, (REAL)x, (REAL)y, (REAL)width, (REAL)height, startAngle, sweepAngle);
+}
+
 GpStatus WINGDIPAPI GdipAddPathPolygon(GpPath *path, GDIPCONST GpPointF *points, INT count)
 {
     INT old_count;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!path || !points || count < 3)
         return InvalidParameter;
 
@@ -576,6 +777,8 @@ GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points,
     GpStatus status;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!points || count < 3)
         return InvalidParameter;
 
@@ -597,6 +800,8 @@ GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points,
 
 GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
 {
+    TRACE("(%p, %p)\n", path, clone);
+
     if(!path || !clone)
         return InvalidParameter;
 
@@ -623,6 +828,8 @@ GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
 
 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path)
 {
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
@@ -638,6 +845,8 @@ GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
 {
     INT i;
 
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
@@ -653,6 +862,8 @@ GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
 
 GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
 {
+    TRACE("(%d, %p)\n", fill, path);
+
     if(!path)
         return InvalidParameter;
 
@@ -668,6 +879,8 @@ GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
 GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF* points,
     GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
 {
+    TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
+
     if(!path)
         return InvalidParameter;
 
@@ -702,6 +915,8 @@ GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint* points,
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
+
     ptF = GdipAlloc(sizeof(GpPointF)*count);
 
     for(i = 0;i < count; i++){
@@ -718,6 +933,8 @@ GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint* points,
 
 GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
 {
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
@@ -728,8 +945,114 @@ GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipFlattenPath(GpPath *path, GpMatrix* matrix, REAL flatness)
+{
+    path_list_node_t *list, *node;
+    GpPointF pt;
+    INT i = 1;
+    INT startidx = 0;
+
+    TRACE("(%p, %p, %.2f)\n", path, matrix, flatness);
+
+    if(!path)
+        return InvalidParameter;
+
+    if(matrix){
+        WARN("transformation not supported yet!\n");
+        return NotImplemented;
+    }
+
+    if(path->pathdata.Count == 0)
+        return Ok;
+
+    pt = path->pathdata.Points[0];
+    if(!init_path_list(&list, pt.X, pt.Y))
+        return OutOfMemory;
+
+    node = list;
+
+    while(i < path->pathdata.Count){
+
+        BYTE type = path->pathdata.Types[i] & PathPointTypePathTypeMask;
+        path_list_node_t *start;
+
+        pt = path->pathdata.Points[i];
+
+        /* save last start point index */
+        if(type == PathPointTypeStart)
+            startidx = i;
+
+        /* always add line points and start points */
+        if((type == PathPointTypeStart) || (type == PathPointTypeLine)){
+            type = (path->pathdata.Types[i] & ~PathPointTypeBezier) | PathPointTypeLine;
+            if(!add_path_list_node(node, pt.X, pt.Y, type))
+                goto memout;
+
+            node = node->next;
+            continue;
+        }
+
+        /* Bezier curve always stored as 4 points */
+        if((path->pathdata.Types[i-1] & PathPointTypePathTypeMask) != PathPointTypeStart){
+            type = (path->pathdata.Types[i] & ~PathPointTypeBezier) | PathPointTypeLine;
+            if(!add_path_list_node(node, pt.X, pt.Y, type))
+                goto memout;
+
+            node = node->next;
+        }
+
+        /* test for closed figure */
+        if(path->pathdata.Types[i+1] & PathPointTypeCloseSubpath){
+            pt = path->pathdata.Points[startidx];
+            ++i;
+        }
+        else
+        {
+            i += 2;
+            pt = path->pathdata.Points[i];
+        };
+
+        start = node;
+        /* add Bezier end point */
+        type = (path->pathdata.Types[i] & ~PathPointTypeBezier) | PathPointTypeLine;
+        if(!add_path_list_node(node, pt.X, pt.Y, type))
+            goto memout;
+        node = node->next;
+
+        /* flatten curve */
+        if(!flatten_bezier(start, path->pathdata.Points[i-2].X, path->pathdata.Points[i-2].Y,
+                                  path->pathdata.Points[i-1].X, path->pathdata.Points[i-1].Y,
+                           node, flatness))
+            goto memout;
+
+        ++i;
+    }/* while */
+
+    /* store path data back */
+    i = path_list_count(list);
+    if(!lengthen_path(path, i))
+        goto memout;
+    path->pathdata.Count = i;
+
+    node = list;
+    for(i = 0; i < path->pathdata.Count; i++){
+        path->pathdata.Points[i] = node->pt;
+        path->pathdata.Types[i]  = node->type;
+        node = node->next;
+    }
+
+    free_path_list(list);
+    return Ok;
+
+memout:
+    free_path_list(list);
+    return OutOfMemory;
+}
+
 GpStatus WINGDIPAPI GdipGetPathData(GpPath *path, GpPathData* pathData)
 {
+    TRACE("(%p, %p)\n", path, pathData);
+
     if(!path || !pathData)
         return InvalidParameter;
 
@@ -743,6 +1066,8 @@ GpStatus WINGDIPAPI GdipGetPathData(GpPath *path, GpPathData* pathData)
 
 GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath *path, GpFillMode *fillmode)
 {
+    TRACE("(%p, %p)\n", path, fillmode);
+
     if(!path || !fillmode)
         return InvalidParameter;
 
@@ -755,6 +1080,8 @@ GpStatus WINGDIPAPI GdipGetPathLastPoint(GpPath* path, GpPointF* lastPoint)
 {
     INT count;
 
+    TRACE("(%p, %p)\n", path, lastPoint);
+
     if(!path || !lastPoint)
         return InvalidParameter;
 
@@ -767,6 +1094,8 @@ GpStatus WINGDIPAPI GdipGetPathLastPoint(GpPath* path, GpPointF* lastPoint)
 
 GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count)
 {
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(!path)
         return InvalidParameter;
 
@@ -784,6 +1113,8 @@ GpStatus WINGDIPAPI GdipGetPathPointsI(GpPath *path, GpPoint* points, INT count)
     GpPointF *ptf;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", path, points, count);
+
     if(count <= 0)
         return InvalidParameter;
 
@@ -803,6 +1134,8 @@ GpStatus WINGDIPAPI GdipGetPathPointsI(GpPath *path, GpPoint* points, INT count)
 
 GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count)
 {
+    TRACE("(%p, %p, %d)\n", path, types, count);
+
     if(!path)
         return InvalidParameter;
 
@@ -825,6 +1158,8 @@ GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
     INT count, i;
     REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
 
+    TRACE("(%p, %p, %p, %p)\n", path, bounds, matrix, pen);
+
     /* Matrix and pen can be null. */
     if(!path || !bounds)
         return InvalidParameter;
@@ -905,6 +1240,8 @@ GpStatus WINGDIPAPI GdipGetPathWorldBoundsI(GpPath* path, GpRect* bounds,
     GpStatus ret;
     GpRectF boundsF;
 
+    TRACE("(%p, %p, %p, %p)\n", path, bounds, matrix, pen);
+
     ret = GdipGetPathWorldBounds(path,&boundsF,matrix,pen);
 
     if(ret == Ok){
@@ -919,6 +1256,8 @@ GpStatus WINGDIPAPI GdipGetPathWorldBoundsI(GpPath* path, GpRect* bounds,
 
 GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
 {
+    TRACE("(%p, %p)\n", path, count);
+
     if(!path)
         return InvalidParameter;
 
@@ -927,9 +1266,67 @@ GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipReversePath(GpPath* path)
+{
+    INT i, count;
+    INT start = 0; /* position in reversed path */
+    GpPathData revpath;
+
+    TRACE("(%p)\n", path);
+
+    if(!path)
+        return InvalidParameter;
+
+    count = path->pathdata.Count;
+
+    if(count == 0) return Ok;
+
+    revpath.Points = GdipAlloc(sizeof(GpPointF)*count);
+    revpath.Types  = GdipAlloc(sizeof(BYTE)*count);
+    revpath.Count  = count;
+    if(!revpath.Points || !revpath.Types){
+        GdipFree(revpath.Points);
+        GdipFree(revpath.Types);
+        return OutOfMemory;
+    }
+
+    for(i = 0; i < count; i++){
+
+        /* find next start point */
+        if(path->pathdata.Types[count-i-1] == PathPointTypeStart){
+            INT j;
+            for(j = start; j <= i; j++){
+                revpath.Points[j] = path->pathdata.Points[count-j-1];
+                revpath.Types[j] = path->pathdata.Types[count-j-1];
+            }
+            /* mark start point */
+            revpath.Types[start] = PathPointTypeStart;
+            /* set 'figure' endpoint type */
+            if(i-start > 1){
+                revpath.Types[i] = path->pathdata.Types[count-start-1] & ~PathPointTypePathTypeMask;
+                revpath.Types[i] |= revpath.Types[i-1];
+            }
+            else
+                revpath.Types[i] = path->pathdata.Types[start];
+
+            start = i+1;
+        }
+    }
+
+    memcpy(path->pathdata.Points, revpath.Points, sizeof(GpPointF)*count);
+    memcpy(path->pathdata.Types,  revpath.Types,  sizeof(BYTE)*count);
+
+    GdipFree(revpath.Points);
+    GdipFree(revpath.Types);
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath* path, INT x, INT y,
     GpPen *pen, GpGraphics *graphics, BOOL *result)
 {
+    TRACE("(%p, %d, %d, %p, %p, %p)\n", path, x, y, pen, graphics, result);
+
     return GdipIsOutlineVisiblePathPoint(path, x, y, pen, graphics, result);
 }
 
@@ -949,6 +1346,8 @@ GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPoint(GpPath* path, REAL x, REAL y,
 
 GpStatus WINGDIPAPI GdipIsVisiblePathPointI(GpPath* path, INT x, INT y, GpGraphics *graphics, BOOL *result)
 {
+    TRACE("(%p, %d, %d, %p, %p)\n", path, x, y, graphics, result);
+
     return GdipIsVisiblePathPoint(path, x, y, graphics, result);
 }
 
@@ -966,6 +1365,8 @@ GpStatus WINGDIPAPI GdipIsVisiblePathPoint(GpPath* path, REAL x, REAL y, GpGraph
 
 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
 {
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
@@ -976,6 +1377,8 @@ GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
 
 GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
 {
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
@@ -988,6 +1391,8 @@ GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
 
 GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
 {
+    TRACE("(%p, %d)\n", path, fill);
+
     if(!path)
         return InvalidParameter;
 
@@ -998,6 +1403,8 @@ GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
 
 GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
 {
+    TRACE("(%p, %p)\n", path, matrix);
+
     if(!path)
         return InvalidParameter;
 
@@ -1016,6 +1423,8 @@ GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath *path, REAL x, REAL y,
     GpStatus retstat;
     BOOL old_new;
 
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x, y, width, height);
+
     if(!path || width < 0.0 || height < 0.0)
         return InvalidParameter;
 
@@ -1055,6 +1464,8 @@ fail:
 GpStatus WINGDIPAPI GdipAddPathRectangleI(GpPath *path, INT x, INT y,
     INT width, INT height)
 {
+    TRACE("(%p, %d, %d, %d, %d)\n", path, x, y, width, height);
+
     return GdipAddPathRectangle(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
 }
 
@@ -1064,6 +1475,8 @@ GpStatus WINGDIPAPI GdipAddPathRectangles(GpPath *path, GDIPCONST GpRectF *rects
     GpStatus retstat;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", path, rects, count);
+
     /* count == 0 - verified condition  */
     if(!path || !rects || count == 0)
         return InvalidParameter;
@@ -1099,6 +1512,8 @@ GpStatus WINGDIPAPI GdipAddPathRectanglesI(GpPath *path, GDIPCONST GpRect *rects
     GpStatus retstat;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", path, rects, count);
+
     if(!rects || count == 0)
         return InvalidParameter;
 
@@ -1124,6 +1539,8 @@ GpStatus WINGDIPAPI GdipSetPathMarker(GpPath* path)
 {
     INT count;
 
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
@@ -1141,6 +1558,8 @@ GpStatus WINGDIPAPI GdipClearPathMarkers(GpPath* path)
     INT count;
     INT i;
 
+    TRACE("(%p)\n", path);
+
     if(!path)
         return InvalidParameter;
 
index 197665d..bcdc64f 100644 (file)
@@ -242,11 +242,50 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
 
 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
 {
-    if (!(image && cloneImage)) return InvalidParameter;
+    IStream* stream;
+    HRESULT hr;
+    INT size;
 
-    FIXME("stub: %p, %p\n", image, cloneImage);
+    TRACE("%p, %p\n", image, cloneImage);
 
-    return NotImplemented;
+    if (!image || !cloneImage)
+        return InvalidParameter;
+
+    hr = CreateStreamOnHGlobal(0, TRUE, &stream);
+    if (FAILED(hr))
+        return GenericError;
+
+    *cloneImage = GdipAlloc(sizeof(GpImage));
+    if (!*cloneImage)
+    {
+        IStream_Release(stream);
+        return OutOfMemory;
+    }
+    (*cloneImage)->type = image->type;
+    (*cloneImage)->flags = image->flags;
+
+    hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
+    if(FAILED(hr))
+    {
+        WARN("Failed to save image on stream\n");
+        goto out;
+    }
+
+    hr = OleLoadPicture(stream, size, FALSE, &IID_IPicture,
+            (LPVOID*) &(*cloneImage)->picture);
+    if (FAILED(hr))
+    {
+        WARN("Failed to load image from stream\n");
+        goto out;
+    }
+
+    IStream_Release(stream);
+    return Ok;
+out:
+    IStream_Release(stream);
+    GdipFree(*cloneImage);
+    *cloneImage = NULL;
+    return GenericError;
 }
 
 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
index dcee68b..55bff18 100644 (file)
@@ -30,6 +30,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 GpStatus WINGDIPAPI GdipCloneImageAttributes(GDIPCONST GpImageAttributes *imageattr,
     GpImageAttributes **cloneImageattr)
 {
+    TRACE("(%p, %p)\n", imageattr, cloneImageattr);
+
     if(!imageattr || !cloneImageattr)
         return InvalidParameter;
 
@@ -40,6 +42,8 @@ GpStatus WINGDIPAPI GdipCloneImageAttributes(GDIPCONST GpImageAttributes *imagea
 
 GpStatus WINGDIPAPI GdipCreateImageAttributes(GpImageAttributes **imageattr)
 {
+    TRACE("(%p)\n", imageattr);
+
     if(!imageattr)
         return InvalidParameter;
 
@@ -51,6 +55,8 @@ GpStatus WINGDIPAPI GdipCreateImageAttributes(GpImageAttributes **imageattr)
 
 GpStatus WINGDIPAPI GdipDisposeImageAttributes(GpImageAttributes *imageattr)
 {
+    TRACE("(%p)\n", imageattr);
+
     if(!imageattr)
         return InvalidParameter;
 
index a29508d..d2e1511 100644 (file)
@@ -27,6 +27,9 @@
 
 #include "gdiplus.h"
 #include "gdiplus_private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
 /* Multiplies two matrices of the form
  *
@@ -58,6 +61,8 @@ static REAL matrix_det(GDIPCONST GpMatrix *matrix)
 GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22,
     REAL dx, REAL dy, GpMatrix **matrix)
 {
+    TRACE("(%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p)\n", m11, m12, m21, m22, dx, dy, matrix);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -80,6 +85,8 @@ GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22,
 GpStatus WINGDIPAPI GdipCreateMatrix3(GDIPCONST GpRectF *rect,
     GDIPCONST GpPointF *pt, GpMatrix **matrix)
 {
+    TRACE("(%p, %p, %p)\n", rect, pt, matrix);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -100,6 +107,8 @@ GpStatus WINGDIPAPI GdipCreateMatrix3I(GDIPCONST GpRect *rect, GDIPCONST GpPoint
     GpRectF rectF;
     GpPointF ptF;
 
+    TRACE("(%p, %p, %p)\n", rect, pt, matrix);
+
     rectF.X = (REAL)rect->X;
     rectF.Y = (REAL)rect->Y;
     rectF.Width = (REAL)rect->Width;
@@ -113,6 +122,8 @@ GpStatus WINGDIPAPI GdipCreateMatrix3I(GDIPCONST GpRect *rect, GDIPCONST GpPoint
 
 GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix *matrix, GpMatrix **clone)
 {
+    TRACE("(%p, %p)\n", matrix, clone);
+
     if(!matrix || !clone)
         return InvalidParameter;
 
@@ -126,6 +137,8 @@ GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix *matrix, GpMatrix **clone)
 
 GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix)
 {
+    TRACE("(%p)\n", matrix);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -144,6 +157,8 @@ GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix)
 
 GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix)
 {
+    TRACE("(%p)\n", matrix);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -155,6 +170,8 @@ GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix)
 GpStatus WINGDIPAPI GdipGetMatrixElements(GDIPCONST GpMatrix *matrix,
     REAL *out)
 {
+    TRACE("(%p, %p)\n", matrix, out);
+
     if(!matrix || !out)
         return InvalidParameter;
 
@@ -169,6 +186,8 @@ GpStatus WINGDIPAPI GdipInvertMatrix(GpMatrix *matrix)
     REAL det;
     BOOL invertible;
 
+    TRACE("(%p)\n", matrix);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -192,6 +211,8 @@ GpStatus WINGDIPAPI GdipInvertMatrix(GpMatrix *matrix)
 
 GpStatus WINGDIPAPI GdipIsMatrixInvertible(GDIPCONST GpMatrix *matrix, BOOL *result)
 {
+    TRACE("(%p, %p)\n", matrix, result);
+
     if(!matrix || !result)
         return InvalidParameter;
 
@@ -203,6 +224,8 @@ GpStatus WINGDIPAPI GdipIsMatrixInvertible(GDIPCONST GpMatrix *matrix, BOOL *res
 GpStatus WINGDIPAPI GdipMultiplyMatrix(GpMatrix *matrix, GpMatrix* matrix2,
     GpMatrixOrder order)
 {
+    TRACE("(%p, %p, %d)\n", matrix, matrix2, order);
+
     if(!matrix || !matrix2)
         return InvalidParameter;
 
@@ -219,6 +242,8 @@ GpStatus WINGDIPAPI GdipRotateMatrix(GpMatrix *matrix, REAL angle,
 {
     REAL cos_theta, sin_theta, rotate[6];
 
+    TRACE("(%p, %.2f, %d)\n", matrix, angle, order);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -246,6 +271,8 @@ GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY,
 {
     REAL scale[6];
 
+    TRACE("(%p, %.2f, %.2f, %d)\n", matrix, scaleX, scaleY, order);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -267,6 +294,9 @@ GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY,
 GpStatus WINGDIPAPI GdipSetMatrixElements(GpMatrix *matrix, REAL m11, REAL m12,
     REAL m21, REAL m22, REAL dx, REAL dy)
 {
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", matrix, m11, m12,
+            m21, m22, dx, dy);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -285,6 +315,8 @@ GpStatus WINGDIPAPI GdipShearMatrix(GpMatrix *matrix, REAL shearX, REAL shearY,
 {
     REAL shear[6];
 
+    TRACE("(%p, %.2f, %.2f, %d)\n", matrix, shearX, shearY, order);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -310,6 +342,8 @@ GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts,
     REAL x, y;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", matrix, pts, count);
+
     if(!matrix || !pts || count <= 0)
         return InvalidParameter;
 
@@ -331,6 +365,8 @@ GpStatus WINGDIPAPI GdipTransformMatrixPointsI(GpMatrix *matrix, GpPoint *pts, I
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", matrix, pts, count);
+
     if(count <= 0)
         return InvalidParameter;
 
@@ -360,6 +396,8 @@ GpStatus WINGDIPAPI GdipTranslateMatrix(GpMatrix *matrix, REAL offsetX,
 {
     REAL translate[6];
 
+    TRACE("(%p, %.2f, %.2f, %d)\n", matrix, offsetX, offsetY, order);
+
     if(!matrix)
         return InvalidParameter;
 
@@ -383,6 +421,8 @@ GpStatus WINGDIPAPI GdipVectorTransformMatrixPoints(GpMatrix *matrix, GpPointF *
     REAL x, y;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", matrix, pts, count);
+
     if(!matrix || !pts || count <= 0)
         return InvalidParameter;
 
@@ -404,6 +444,8 @@ GpStatus WINGDIPAPI GdipVectorTransformMatrixPointsI(GpMatrix *matrix, GpPoint *
     GpStatus ret;
     INT i;
 
+    TRACE("(%p, %p, %d)\n", matrix, pts, count);
+
     if(count <= 0)
         return InvalidParameter;
 
@@ -431,6 +473,8 @@ GpStatus WINGDIPAPI GdipVectorTransformMatrixPointsI(GpMatrix *matrix, GpPoint *
 GpStatus WINGDIPAPI GdipIsMatrixEqual(GDIPCONST GpMatrix *matrix, GDIPCONST GpMatrix *matrix2,
     BOOL *result)
 {
+    TRACE("(%p, %p, %p)\n", matrix, matrix2, result);
+
     if(!matrix || !matrix2 || !result)
         return InvalidParameter;
     /* based on single array member of GpMatrix */
@@ -445,6 +489,8 @@ GpStatus WINGDIPAPI GdipIsMatrixIdentity(GDIPCONST GpMatrix *matrix, BOOL *resul
     GpStatus ret;
     BOOL isIdentity;
 
+    TRACE("(%p, %p)\n", matrix, result);
+
     if(!matrix || !result)
         return InvalidParameter;
 
index 95f1774..d0a4ed1 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2007 Google (Evan Stade)
+ * Copyright (C) 2008 Nikolay Sivov <bunglehead at gmail dot com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include "gdiplus.h"
 #include "gdiplus_private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
 GpStatus WINGDIPAPI GdipCreatePathIter(GpPathIterator **iterator, GpPath* path)
 {
     INT size;
 
+    TRACE("(%p, %p)\n", iterator, path);
+
     if(!iterator)
         return InvalidParameter;
 
@@ -62,6 +68,8 @@ GpStatus WINGDIPAPI GdipCreatePathIter(GpPathIterator **iterator, GpPath* path)
 
 GpStatus WINGDIPAPI GdipDeletePathIter(GpPathIterator *iter)
 {
+    TRACE("(%p)\n", iter);
+
     if(!iter)
         return InvalidParameter;
 
@@ -75,6 +83,9 @@ GpStatus WINGDIPAPI GdipDeletePathIter(GpPathIterator *iter)
 GpStatus WINGDIPAPI GdipPathIterCopyData(GpPathIterator* iterator,
     INT* resultCount, GpPointF* points, BYTE* types, INT startIndex, INT endIndex)
 {
+    TRACE("(%p, %p, %p, %p, %d, %d)\n", iterator, resultCount, points, types,
+           startIndex, endIndex);
+
     if(!iterator || !types || !points)
         return InvalidParameter;
 
@@ -97,6 +108,8 @@ GpStatus WINGDIPAPI GdipPathIterHasCurve(GpPathIterator* iterator, BOOL* hasCurv
 {
     INT i;
 
+    TRACE("(%p, %p)\n", iterator, hasCurve);
+
     if(!iterator)
         return InvalidParameter;
 
@@ -115,6 +128,8 @@ GpStatus WINGDIPAPI GdipPathIterGetSubpathCount(GpPathIterator* iterator, INT* c
 {
     INT i;
 
+    TRACE("(%p, %p)\n", iterator, count);
+
     if(!iterator || !count)
         return InvalidParameter;
 
@@ -132,6 +147,8 @@ GpStatus WINGDIPAPI GdipPathIterNextMarker(GpPathIterator* iterator, INT *result
 {
     INT i;
 
+    TRACE("(%p, %p, %p, %p)\n", iterator, resultCount, startIndex, endIndex);
+
     if(!iterator || !startIndex || !endIndex)
         return InvalidParameter;
 
@@ -153,19 +170,50 @@ GpStatus WINGDIPAPI GdipPathIterNextMarker(GpPathIterator* iterator, INT *result
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipPathIterNextMarkerPath(GpPathIterator* iterator, INT* result,
+    GpPath* path)
+{
+    INT start, end;
+
+    TRACE("(%p, %p, %p)\n", iterator, result, path);
+
+    if(!iterator || !result)
+        return InvalidParameter;
+
+    GdipPathIterNextMarker(iterator, result, &start, &end);
+    /* return path */
+    if(((*result) > 0) && path){
+        GdipResetPath(path);
+
+        if(!lengthen_path(path, *result))
+            return OutOfMemory;
+
+        memcpy(path->pathdata.Points, &(iterator->pathdata.Points[start]), sizeof(GpPointF)*(*result));
+        memcpy(path->pathdata.Types,  &(iterator->pathdata.Types[start]),  sizeof(BYTE)*(*result));
+        path->pathdata.Count = *result;
+    }
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipPathIterNextSubpath(GpPathIterator* iterator,
     INT *resultCount, INT* startIndex, INT* endIndex, BOOL* isClosed)
 {
     INT i, count;
 
+    TRACE("(%p, %p, %p, %p, %p)\n", iterator, resultCount, startIndex,
+           endIndex, isClosed);
+
     if(!iterator || !startIndex || !endIndex || !isClosed || !resultCount)
         return InvalidParameter;
 
     count = iterator->pathdata.Count;
 
     /* iterator created with NULL path */
-    if(count == 0)
+    if(count == 0){
+        *resultCount = 0;
         return Ok;
+    }
 
     if(iterator->subpath_pos == count){
         *startIndex = *endIndex = *resultCount = 0;
@@ -192,6 +240,8 @@ GpStatus WINGDIPAPI GdipPathIterNextSubpath(GpPathIterator* iterator,
 }
 GpStatus WINGDIPAPI GdipPathIterRewind(GpPathIterator *iterator)
 {
+    TRACE("(%p)\n", iterator);
+
     if(!iterator)
         return InvalidParameter;
 
@@ -204,6 +254,8 @@ GpStatus WINGDIPAPI GdipPathIterRewind(GpPathIterator *iterator)
 
 GpStatus WINGDIPAPI GdipPathIterGetCount(GpPathIterator* iterator, INT* count)
 {
+    TRACE("(%p, %p)\n", iterator, count);
+
     if(!iterator || !count)
         return InvalidParameter;
 
@@ -215,6 +267,8 @@ GpStatus WINGDIPAPI GdipPathIterGetCount(GpPathIterator* iterator, INT* count)
 GpStatus WINGDIPAPI GdipPathIterEnumerate(GpPathIterator* iterator, INT* resultCount,
     GpPointF *points, BYTE *types, INT count)
 {
+    TRACE("(%p, %p, %p, %p, %d)\n", iterator, resultCount, points, types, count);
+
     if((count < 0) || !resultCount)
         return InvalidParameter;
 
@@ -225,3 +279,52 @@ GpStatus WINGDIPAPI GdipPathIterEnumerate(GpPathIterator* iterator, INT* resultC
 
     return GdipPathIterCopyData(iterator, resultCount, points, types, 0, count-1);
 }
+
+GpStatus WINGDIPAPI GdipPathIterIsValid(GpPathIterator* iterator, BOOL* valid)
+{
+    TRACE("(%p, %p)\n", iterator, valid);
+
+    if(!iterator || !valid)
+        return InvalidParameter;
+
+    *valid = TRUE;
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipPathIterNextPathType(GpPathIterator* iter, INT* result,
+    BYTE* type, INT* start, INT* end)
+{
+    FIXME("(%p, %p, %p, %p, %p) stub\n", iter, result, type, start, end);
+
+    if(!iter || !result || !type || !start || !end)
+        return InvalidParameter;
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipPathIterNextSubpathPath(GpPathIterator* iter, INT* result,
+    GpPath* path, BOOL* closed)
+{
+    INT start, end;
+
+    TRACE("(%p, %p, %p, %p)\n", iter, result, path, closed);
+
+    if(!iter || !result || !closed)
+        return InvalidParameter;
+
+    GdipPathIterNextSubpath(iter, result, &start, &end, closed);
+    /* return path */
+    if(((*result) > 0) && path){
+        GdipResetPath(path);
+
+        if(!lengthen_path(path, *result))
+            return OutOfMemory;
+
+        memcpy(path->pathdata.Points, &(iter->pathdata.Points[start]), sizeof(GpPointF)*(*result));
+        memcpy(path->pathdata.Types,  &(iter->pathdata.Types[start]),  sizeof(BYTE)*(*result));
+        path->pathdata.Count = *result;
+    }
+
+    return Ok;
+}
index c4007b3..90aaf9e 100644 (file)
@@ -73,19 +73,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
  *
  */
 
-typedef enum RegionType
-{
-    RegionDataRect          = 0x10000000,
-    RegionDataPath          = 0x10000001,
-    RegionDataEmptyRect     = 0x10000002,
-    RegionDataInfiniteRect  = 0x10000003,
-} RegionType;
+#define FLAGS_NOFLAGS   0x0
+#define FLAGS_INTPATH   0x4000
 
 /* Header size as far as header->size is concerned. This doesn't include
  * header->size or header->checksum
  */
 static const INT sizeheader_size = sizeof(DWORD) * 2;
 
+typedef struct packed_point
+{
+    short X;
+    short Y;
+} packed_point;
+
+/* Everything is measured in DWORDS; round up if there's a remainder */
+static inline INT get_pathtypes_size(const GpPath* path)
+{
+    INT needed = path->pathdata.Count / sizeof(DWORD);
+
+    if (path->pathdata.Count % sizeof(DWORD) > 0)
+        needed++;
+
+    return needed * sizeof(DWORD);
+}
+
 static inline INT get_element_size(const region_element* element)
 {
     INT needed = sizeof(DWORD); /* DWORD for the type */
@@ -121,72 +133,265 @@ static inline GpStatus init_region(GpRegion* region, const RegionType type)
     return Ok;
 }
 
-static inline void delete_element(region_element* element)
+static inline GpStatus clone_element(const region_element* element,
+        region_element** element2)
 {
-    switch(element->type)
+    GpStatus stat;
+
+    /* root node is allocated with GpRegion */
+    if(!*element2){
+        *element2 = GdipAlloc(sizeof(region_element));
+        if (!*element2)
+            return OutOfMemory;
+    }
+
+    (*element2)->type = element->type;
+
+    switch (element->type)
     {
         case RegionDataRect:
-            break;
-        case RegionDataPath:
-            GdipDeletePath(element->elementdata.pathdata.path);
+            (*element2)->elementdata.rect = element->elementdata.rect;
             break;
         case RegionDataEmptyRect:
         case RegionDataInfiniteRect:
             break;
+        case RegionDataPath:
+            (*element2)->elementdata.pathdata.pathheader = element->elementdata.pathdata.pathheader;
+            stat = GdipClonePath(element->elementdata.pathdata.path,
+                    &(*element2)->elementdata.pathdata.path);
+            if (stat != Ok) goto clone_out;
+            break;
         default:
-            delete_element(element->elementdata.combine.left);
-            delete_element(element->elementdata.combine.right);
-            GdipFree(element->elementdata.combine.left);
-            GdipFree(element->elementdata.combine.right);
+            (*element2)->elementdata.combine.left  = NULL;
+            (*element2)->elementdata.combine.right = NULL;
+
+            stat = clone_element(element->elementdata.combine.left,
+                    &(*element2)->elementdata.combine.left);
+            if (stat != Ok) goto clone_out;
+            stat = clone_element(element->elementdata.combine.right,
+                    &(*element2)->elementdata.combine.right);
+            if (stat != Ok) goto clone_out;
             break;
     }
+
+    return Ok;
+
+clone_out:
+    delete_element(*element2);
+    *element2 = NULL;
+    return stat;
+}
+
+/* Common code for CombineRegion*
+ * All the caller has to do is get its format into an element
+ */
+static inline void fuse_region(GpRegion* region, region_element* left,
+        region_element* right, const CombineMode mode)
+{
+    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;
 }
 
 /*****************************************************************************
  * GdipCloneRegion [GDIPLUS.@]
+ *
+ * Creates a deep copy of the region
+ *
+ * PARAMS
+ *  region  [I] source region
+ *  clone   [O] resulting clone
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParameter or OutOfMemory
  */
 GpStatus WINGDIPAPI GdipCloneRegion(GpRegion *region, GpRegion **clone)
 {
-    FIXME("(%p %p): stub\n", region, clone);
+    region_element *element;
 
-    *clone = NULL;
-    return NotImplemented;
+    TRACE("%p %p\n", region, clone);
+
+    if (!(region && clone))
+        return InvalidParameter;
+
+    *clone = GdipAlloc(sizeof(GpRegion));
+    if (!*clone)
+        return OutOfMemory;
+    element = &(*clone)->node;
+
+    (*clone)->header = region->header;
+    return clone_element(&region->node, &element);
 }
 
+/*****************************************************************************
+ * GdipCombineRegionPath [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipCombineRegionPath(GpRegion *region, GpPath *path, CombineMode mode)
 {
-    FIXME("(%p %p %d): stub\n", region, path, mode);
-    return NotImplemented;
+    GpRegion *path_region;
+    region_element *left, *right = NULL;
+    GpStatus stat;
+
+    TRACE("%p %p %d\n", region, path, mode);
+
+    if (!(region && path))
+        return InvalidParameter;
+
+    stat = GdipCreateRegionPath(path, &path_region);
+    if (stat != Ok)
+        return stat;
+
+    /* simply replace region data */
+    if(mode == CombineModeReplace){
+        delete_element(&region->node);
+        memcpy(region, path_region, sizeof(GpRegion));
+        return Ok;
+    }
+
+    left = GdipAlloc(sizeof(region_element));
+    if (!left)
+        goto out;
+    *left = region->node;
+
+    stat = clone_element(&path_region->node, &right);
+    if (stat != Ok)
+        goto out;
+
+    fuse_region(region, left, right, mode);
+
+    GdipDeleteRegion(path_region);
+    return Ok;
+
+out:
+    GdipFree(left);
+    delete_element(right);
+    GdipDeleteRegion(path_region);
+    return stat;
 }
 
-GpStatus WINGDIPAPI GdipCombineRegionRect(GpRegion *region, GDIPCONST GpRectF *rect,
-                                          CombineMode mode)
+/*****************************************************************************
+ * GdipCombineRegionRect [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipCombineRegionRect(GpRegion *region,
+        GDIPCONST GpRectF *rect, CombineMode mode)
 {
-    FIXME("(%p %p %d): stub\n", region, rect, mode);
-    return NotImplemented;
+    GpRegion *rect_region;
+    region_element *left, *right = NULL;
+    GpStatus stat;
+
+    TRACE("%p %p %d\n", region, rect, mode);
+
+    if (!(region && rect))
+        return InvalidParameter;
+
+    stat = GdipCreateRegionRect(rect, &rect_region);
+    if (stat != Ok)
+        return stat;
+
+    /* simply replace region data */
+    if(mode == CombineModeReplace){
+        delete_element(&region->node);
+        memcpy(region, rect_region, sizeof(GpRegion));
+        return Ok;
+    }
+
+    left = GdipAlloc(sizeof(region_element));
+    if (!left)
+        goto out;
+    memcpy(left, &region->node, sizeof(region_element));
+
+    stat = clone_element(&rect_region->node, &right);
+    if (stat != Ok)
+        goto out;
+
+    fuse_region(region, left, right, mode);
+
+    GdipDeleteRegion(rect_region);
+    return Ok;
+
+out:
+    GdipFree(left);
+    delete_element(right);
+    GdipDeleteRegion(rect_region);
+    return stat;
 }
 
-GpStatus WINGDIPAPI GdipCombineRegionRectI(GpRegion *region, GDIPCONST GpRect *rect,
-                                           CombineMode mode)
+/*****************************************************************************
+ * GdipCombineRegionRectI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipCombineRegionRectI(GpRegion *region,
+        GDIPCONST GpRect *rect, CombineMode mode)
 {
-    FIXME("(%p %p %d): stub\n", region, rect, mode);
-    return NotImplemented;
+    GpRectF rectf;
+
+    TRACE("%p %p %d\n", region, rect, mode);
+
+    if (!rect)
+        return InvalidParameter;
+
+    rectf.X = (REAL)rect->X;
+    rectf.Y = (REAL)rect->Y;
+    rectf.Height = (REAL)rect->Height;
+    rectf.Width = (REAL)rect->Width;
+
+    return GdipCombineRegionRect(region, &rectf, mode);
 }
 
-GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1, GpRegion *region2,
-                                            CombineMode mode)
+GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1,
+        GpRegion *region2, CombineMode mode)
 {
-    FIXME("(%p %p %d): stub\n", region1, region2, mode);
-    return NotImplemented;
+    region_element *left, *right = NULL;
+    GpStatus stat;
+    GpRegion *reg2copy;
+
+    TRACE("%p %p %d\n", region1, region2, mode);
+
+    if(!(region1 && region2))
+        return InvalidParameter;
+
+    /* simply replace region data */
+    if(mode == CombineModeReplace){
+        stat = GdipCloneRegion(region2, &reg2copy);
+        if(stat != Ok)  return stat;
+
+        delete_element(&region1->node);
+        memcpy(region1, reg2copy, sizeof(GpRegion));
+        return Ok;
+    }
+
+    left  = GdipAlloc(sizeof(region_element));
+    if (!left)
+        return OutOfMemory;
+
+    *left = region1->node;
+    stat = clone_element(&region2->node, &right);
+    if (stat != Ok)
+    {
+        GdipFree(left);
+        delete_element(right);
+        return OutOfMemory;
+    }
+
+    fuse_region(region1, left, right, mode);
+    region1->header.num_children += region2->header.num_children;
+
+    return Ok;
 }
 
+/*****************************************************************************
+ * GdipCreateRegion [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
 {
+    TRACE("%p\n", region);
+
     if(!region)
         return InvalidParameter;
 
-    TRACE("%p\n", region);
-
     *region = GdipAlloc(sizeof(GpRegion));
     if(!*region)
         return OutOfMemory;
@@ -194,28 +399,166 @@ GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
     return init_region(*region, RegionDataInfiniteRect);
 }
 
+/*****************************************************************************
+ * GdipCreateRegionPath [GDIPLUS.@]
+ *
+ * Creates a GpRegion from a GpPath
+ *
+ * PARAMS
+ *  path    [I] path to base the region on
+ *  region  [O] pointer to the newly allocated region
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParameter
+ *
+ * NOTES
+ *  If a path has no floating point points, its points will be stored as shorts
+ *  (INTPATH)
+ *
+ *  If a path is empty, it is considered to be an INTPATH
+ */
 GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
 {
-    FIXME("(%p, %p): stub\n", path, region);
+    region_element* element;
+    GpPoint  *pointsi;
+    GpPointF *pointsf;
 
-    *region = NULL;
-    return NotImplemented;
+    GpStatus stat;
+    DWORD flags = FLAGS_INTPATH;
+    INT count, i;
+
+    TRACE("%p, %p\n", path, region);
+
+    if (!(path && region))
+        return InvalidParameter;
+
+    *region = GdipAlloc(sizeof(GpRegion));
+    if(!*region)
+        return OutOfMemory;
+    stat = init_region(*region, RegionDataPath);
+    if (stat != Ok)
+    {
+        GdipDeleteRegion(*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);
+    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;
 }
 
-GpStatus WINGDIPAPI GdipCreateRegionRect(GDIPCONST GpRectF *rect, GpRegion **region)
+/*****************************************************************************
+ * GdipCreateRegionRect [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipCreateRegionRect(GDIPCONST GpRectF *rect,
+        GpRegion **region)
 {
-    FIXME("(%p, %p): stub\n", rect, region);
+    GpStatus stat;
 
-    *region = NULL;
-    return NotImplemented;
+    TRACE("%p, %p\n", rect, region);
+
+    if (!(rect && region))
+        return InvalidParameter;
+
+    *region = GdipAlloc(sizeof(GpRegion));
+    stat = init_region(*region, RegionDataRect);
+    if(stat != Ok)
+    {
+        GdipDeleteRegion(*region);
+        return stat;
+    }
+
+    (*region)->node.elementdata.rect.X = rect->X;
+    (*region)->node.elementdata.rect.Y = rect->Y;
+    (*region)->node.elementdata.rect.Width = rect->Width;
+    (*region)->node.elementdata.rect.Height = rect->Height;
+
+    return Ok;
 }
 
-GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect, GpRegion **region)
+GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect,
+        GpRegion **region)
 {
-    FIXME("(%p, %p): stub\n", rect, region);
+    GpRectF rectf;
 
-    *region = NULL;
-    return NotImplemented;
+    TRACE("%p, %p\n", rect, region);
+
+    rectf.X = (REAL)rect->X;
+    rectf.Y = (REAL)rect->Y;
+    rectf.Width = (REAL)rect->Width;
+    rectf.Height = (REAL)rect->Height;
+
+    return GdipCreateRegionRect(&rectf, region);
 }
 
 GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
@@ -261,20 +604,161 @@ GpStatus WINGDIPAPI GdipGetRegionBoundsI(GpRegion *region, GpGraphics *graphics,
     return NotImplemented;
 }
 
-GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, UINT *needed)
+static inline void write_dword(DWORD* location, INT* offset, const DWORD write)
 {
-    FIXME("(%p, %p, %d, %p): stub\n", region, buffer, size, needed);
+    location[*offset] = write;
+    (*offset)++;
+}
 
-    return NotImplemented;
+static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
+{
+    ((FLOAT*)location)[*offset] = write;
+    (*offset)++;
 }
 
-GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
+static inline void write_packed_point(DWORD* location, INT* offset,
+        const GpPointF* write)
 {
-    if (!(region && needed))
+    packed_point point;
+
+    point.X = write->X;
+    point.Y = write->Y;
+    memcpy(location + *offset, &point, sizeof(packed_point));
+    (*offset)++;
+}
+
+static inline void write_path_types(DWORD* location, INT* offset,
+        const GpPath* 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))
+        ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
+                path->pathdata.Count,
+                sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD));
+    *offset += (get_pathtypes_size(path) / sizeof(DWORD));
+}
+
+static void write_element(const region_element* element, DWORD *buffer,
+        INT* filled)
+{
+    write_dword(buffer, filled, element->type);
+    switch (element->type)
+    {
+        case CombineModeReplace:
+        case CombineModeIntersect:
+        case CombineModeUnion:
+        case CombineModeXor:
+        case CombineModeExclude:
+        case CombineModeComplement:
+            write_element(element->elementdata.combine.left, buffer, filled);
+            write_element(element->elementdata.combine.right, buffer, filled);
+            break;
+        case RegionDataRect:
+            write_float(buffer, filled, element->elementdata.rect.X);
+            write_float(buffer, filled, element->elementdata.rect.Y);
+            write_float(buffer, filled, element->elementdata.rect.Width);
+            write_float(buffer, filled, element->elementdata.rect.Height);
+            break;
+        case RegionDataPath:
+        {
+            INT i;
+            const GpPath* path = element->elementdata.pathdata.path;
+
+            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)
+            {
+                case FLAGS_NOFLAGS:
+                    for (i = 0; i < path->pathdata.Count; i++)
+                    {
+                        write_float(buffer, filled, path->pathdata.Points[i].X);
+                        write_float(buffer, filled, path->pathdata.Points[i].Y);
+                    }
+                    break;
+                case FLAGS_INTPATH:
+                    for (i = 0; i < path->pathdata.Count; i++)
+                    {
+                        write_packed_point(buffer, filled,
+                                &path->pathdata.Points[i]);
+                    }
+            }
+            write_path_types(buffer, filled, path);
+            break;
+        }
+        case RegionDataEmptyRect:
+        case RegionDataInfiniteRect:
+            break;
+    }
+}
+
+/*****************************************************************************
+ * GdipGetRegionData [GDIPLUS.@]
+ *
+ * Returns the header, followed by combining ops and region elements.
+ *
+ * PARAMS
+ *  region  [I] region to retrieve from
+ *  buffer  [O] buffer to hold the resulting data
+ *  size    [I] size of the buffer
+ *  needed  [O] (optional) how much data was written
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParamter
+ *
+ * NOTES
+ *  The header contains the size, a checksum, a version string, and the number
+ *  of children. The size does not count itself or the checksum.
+ *  Version is always something like 0xdbc01001 or 0xdbc01002
+ *
+ *  An element is a RECT, or PATH; Combining ops are stored as their
+ *  CombineMode value. Special regions (infinite, empty) emit just their
+ *  op-code; GpRectFs emit their code followed by their points; GpPaths emit
+ *  their code followed by a second header for the path followed by the actual
+ *  path data. Followed by the flags for each point. The pathheader contains
+ *  the size of the data to follow, a version number again, followed by a count
+ *  of how many points, and any special flags which may apply. 0x4000 means its
+ *  a path of shorts instead of FLOAT.
+ *
+ *  Combining Ops are stored in reverse order from when they were constructed;
+ *  the output is a tree where the left side combining area is always taken
+ *  first.
+ */
+GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
+        UINT *needed)
+{
+    INT filled = 0;
+
+    TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
+
+    if (!(region && buffer && size))
         return InvalidParameter;
 
+    memcpy(buffer, &region->header, sizeof(region->header));
+    filled += sizeof(region->header) / sizeof(DWORD);
+    /* With few exceptions, everything written is DWORD aligned,
+     * so use that as our base */
+    write_element(&region->node, (DWORD*)buffer, &filled);
+
+    if (needed)
+        *needed = filled * sizeof(DWORD);
+
+    return Ok;
+}
+
+/*****************************************************************************
+ * GdipGetRegionDataSize [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
+{
     TRACE("%p, %p\n", region, needed);
 
+    if (!(region && needed))
+        return InvalidParameter;
+
     /* header.size doesn't count header.size and header.checksum */
     *needed = region->header.size + sizeof(DWORD) * 2;
 
@@ -294,9 +778,14 @@ GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HR
 
 GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
 {
-    FIXME("(%p, %p, %p): stub\n", region, graphics, res);
+    TRACE("(%p, %p, %p)\n", region, graphics, res);
 
-    return NotImplemented;
+    if(!region || !graphics || !res)
+        return InvalidParameter;
+
+    *res = (region->node.type == RegionDataEmptyRect);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *region, GpRegion *region2, GpGraphics *graphics,
@@ -307,13 +796,25 @@ GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *region, GpRegion *region2, GpGra
     return NotImplemented;
 }
 
+/*****************************************************************************
+ * GdipIsInfiniteRegion [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
 {
-    FIXME("(%p, %p, %p): stub\n", region, graphics, res);
+    /* I think graphics is ignored here */
+    TRACE("(%p, %p, %p)\n", region, graphics, res);
 
-    return NotImplemented;
+    if(!region || !graphics || !res)
+        return InvalidParameter;
+
+    *res = (region->node.type == RegionDataInfiniteRect);
+
+    return Ok;
 }
 
+/*****************************************************************************
+ * GdipSetEmpty [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipSetEmpty(GpRegion *region)
 {
     GpStatus stat;
@@ -333,11 +834,11 @@ GpStatus WINGDIPAPI GdipSetInfinite(GpRegion *region)
 {
     GpStatus stat;
 
+    TRACE("%p\n", region);
+
     if (!region)
         return InvalidParameter;
 
-    TRACE("%p\n", region);
-
     delete_element(&region->node);
     stat = init_region(region, RegionDataInfiniteRect);
 
index dc938ac..cbb59e5 100644 (file)
@@ -100,6 +100,8 @@ GpStatus WINGDIPAPI GdipDrawCurve(GpGraphics*,GpPen*,GDIPCONST GpPointF*,INT);
 GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics*,GpPen*,GDIPCONST GpPoint*,INT);
 GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics*,GpPen*,GDIPCONST GpPointF*,INT,REAL);
 GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics*,GpPen*,GDIPCONST GpPoint*,INT,REAL);
+GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics*,GpPen*,REAL,REAL,REAL,REAL);
+GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics*,GpPen*,INT,INT,INT,INT);
 GpStatus WINGDIPAPI GdipDrawImage(GpGraphics*,GpImage*,REAL,REAL);
 GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics*,GpImage*,INT,INT);
 GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics*,GpImage*,
@@ -132,6 +134,11 @@ GpStatus WINGDIPAPI GdipDrawRectanglesI(GpGraphics*,GpPen*,GDIPCONST GpRect*,INT
 GpStatus WINGDIPAPI GdipDrawString(GpGraphics*,GDIPCONST WCHAR*,INT,
     GDIPCONST GpFont*,GDIPCONST RectF*, GDIPCONST GpStringFormat*,
     GDIPCONST GpBrush*);
+
+GpStatus WINGDIPAPI GdipFillClosedCurve2(GpGraphics*,GpBrush*,GDIPCONST GpPointF*,INT,
+    REAL,GpFillMode);
+GpStatus WINGDIPAPI GdipFillClosedCurve2I(GpGraphics*,GpBrush*,GDIPCONST GpPoint*,INT,
+    REAL,GpFillMode);
 GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics*,GpBrush*,REAL,REAL,REAL,REAL);
 GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics*,GpBrush*,INT,INT,INT,INT);
 GpStatus WINGDIPAPI GdipFillPath(GpGraphics*,GpBrush*,GpPath*);
@@ -149,6 +156,9 @@ GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics*,GpBrush*,GDIPCONST GpRectF*,I
 GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics*,GpBrush*,GDIPCONST GpRect*,INT);
 GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics*,CompositingMode*);
 GpStatus WINGDIPAPI GdipGetClip(GpGraphics*,GpRegion*);
+GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics*,GpRegion*,CombineMode);
+GpStatus WINGDIPAPI GdipResetClip(GpGraphics*);
+GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics*, BOOL*);
 GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics*,CompositingQuality*);
 GpStatus WINGDIPAPI GdipGetDC(GpGraphics*,HDC*);
 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage*,REAL*,REAL*);
@@ -159,6 +169,7 @@ GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics*,PixelOffsetMode*);
 GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics*,SmoothingMode*);
 GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics*,TextRenderingHint*);
 GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics*,GpMatrix*);
+GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics*,ARGB);
 GpStatus WINGDIPAPI GdipMeasureString(GpGraphics*,GDIPCONST WCHAR*,INT,
     GDIPCONST GpFont*,GDIPCONST RectF*,GDIPCONST GpStringFormat*,RectF*,INT*,INT*);
 GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics*, GDIPCONST WCHAR*,
@@ -166,6 +177,7 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics*, GDIPCONST WCHAR*,
     GpRegion**);
 
 GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics*,HDC);
+GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics*);
 GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics*,GraphicsState);
 GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics*,REAL,GpMatrixOrder);
 GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics*,GraphicsState*);
@@ -261,6 +273,8 @@ GpStatus WINGDIPAPI GdipAddPathLine2(GpPath*,GDIPCONST GpPointF*,INT);
 GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath*,GDIPCONST GpPoint*,INT);
 GpStatus WINGDIPAPI GdipAddPathLineI(GpPath*,INT,INT,INT,INT);
 GpStatus WINGDIPAPI GdipAddPathPath(GpPath*,GDIPCONST GpPath*,BOOL);
+GpStatus WINGDIPAPI GdipAddPathPie(GpPath*,REAL,REAL,REAL,REAL,REAL,REAL);
+GpStatus WINGDIPAPI GdipAddPathPieI(GpPath*,INT,INT,INT,INT,REAL,REAL);
 GpStatus WINGDIPAPI GdipAddPathPolygon(GpPath*,GDIPCONST GpPointF*,INT);
 GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath*,GDIPCONST GpPoint*,INT);
 GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath*,REAL,REAL,REAL,REAL);
@@ -275,6 +289,7 @@ GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF*,GDIPCONST BYTE*,INT,
     GpFillMode,GpPath**);
 GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint*,GDIPCONST BYTE*,INT,GpFillMode,GpPath**);
 GpStatus WINGDIPAPI GdipDeletePath(GpPath*);
+GpStatus WINGDIPAPI GdipFlattenPath(GpPath*,GpMatrix*,REAL);
 GpStatus WINGDIPAPI GdipGetPathData(GpPath*,GpPathData*);
 GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath*,GpFillMode*);
 GpStatus WINGDIPAPI GdipGetPathLastPoint(GpPath*,GpPointF*);
@@ -291,6 +306,7 @@ GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath*,INT,INT,GpPen*,
 GpStatus WINGDIPAPI GdipIsVisiblePathPoint(GpPath*,REAL,REAL,GpGraphics*,BOOL*);
 GpStatus WINGDIPAPI GdipIsVisiblePathPointI(GpPath*,INT,INT,GpGraphics*,BOOL*);
 GpStatus WINGDIPAPI GdipResetPath(GpPath*);
+GpStatus WINGDIPAPI GdipReversePath(GpPath*);
 GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath*,GpFillMode);
 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath*);
 GpStatus WINGDIPAPI GdipTransformPath(GpPath*,GpMatrix*);
@@ -324,12 +340,16 @@ GpStatus WINGDIPAPI GdipDeletePathIter(GpPathIterator*);
 GpStatus WINGDIPAPI GdipPathIterCopyData(GpPathIterator*,INT*,GpPointF*,BYTE*,
     INT,INT);
 GpStatus WINGDIPAPI GdipPathIterNextMarker(GpPathIterator*,INT*,INT*,INT*);
+GpStatus WINGDIPAPI GdipPathIterNextMarkerPath(GpPathIterator*,INT*,GpPath*);
+GpStatus WINGDIPAPI GdipPathIterNextPathType(GpPathIterator*,INT*,BYTE*,INT*,INT*);
 GpStatus WINGDIPAPI GdipPathIterNextSubpath(GpPathIterator*,INT*,INT*,INT*,BOOL*);
+GpStatus WINGDIPAPI GdipPathIterNextSubpathPath(GpPathIterator*,INT*,GpPath*,BOOL*);
 GpStatus WINGDIPAPI GdipPathIterRewind(GpPathIterator*);
 GpStatus WINGDIPAPI GdipPathIterGetCount(GpPathIterator*,INT*);
 GpStatus WINGDIPAPI GdipPathIterGetSubpathCount(GpPathIterator*,INT*);
 GpStatus WINGDIPAPI GdipPathIterEnumerate(GpPathIterator*,INT*,GpPointF*,BYTE*,INT);
 GpStatus WINGDIPAPI GdipPathIterHasCurve(GpPathIterator*,BOOL*);
+GpStatus WINGDIPAPI GdipPathIterIsValid(GpPathIterator*,BOOL*);
 
 GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap*,GpCustomLineCap**);
 GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath*,GpPath*,GpLineCap,REAL,
@@ -418,8 +438,12 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC,GDIPCONST LOGFONTW*,GpFont**)
 GpStatus WINGDIPAPI GdipDeleteFont(GpFont*);
 GpStatus WINGDIPAPI GdipGetLogFontW(GpFont*,GpGraphics*,LOGFONTW*);
 GpStatus WINGDIPAPI GdipCloneFont(GpFont*,GpFont**);
+GpStatus WINGDIPAPI GdipGetFamily(GpFont*, GpFontFamily**);
 GpStatus WINGDIPAPI GdipGetFontUnit(GpFont*, Unit*);
 GpStatus WINGDIPAPI GdipGetFontSize(GpFont*, REAL*);
+GpStatus WINGDIPAPI GdipGetFontStyle(GpFont*, INT*);
+GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont*, GDIPCONST GpGraphics*,
+        REAL*);
 GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont*, REAL, REAL*);
 
 GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR*,
@@ -499,6 +523,19 @@ GpStatus WINGDIPAPI GdipTranslateRegion(GpRegion *, REAL, REAL);
 GpStatus WINGDIPAPI GdipTranslateRegionI(GpRegion *, INT, INT);
 
 GpStatus WINGDIPAPI GdipFlush(GpGraphics*, GpFlushIntention);
+GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile*,UINT);
+GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics*,INT,INT,INT,INT,CombineMode);
+GpStatus WINGDIPAPI GdipFillRegion(GpGraphics*,GpBrush*,GpRegion*);
+
+GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL,REAL,BOOL,GpAdjustableArrowCap**);
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap*,BOOL*);
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap*,REAL*);
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap*,REAL*);
+GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap*,REAL*);
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap*,BOOL);
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap*,REAL);
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap*,REAL);
+GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap*,REAL);
 
 #ifdef __cplusplus
 }
index bb7c47f..917097e 100644 (file)
@@ -28,6 +28,7 @@ class GpPath {};
 class GpMatrix {};
 class GpPathIterator {};
 class GpCustomLineCap {};
+class GpAdjustableArrowCap : public GpCustomLineCap {};
 class GpImage {};
 class GpMetafile : public GpImage {};
 class GpImageAttributes {};
@@ -52,6 +53,7 @@ typedef struct GpPath GpPath;
 typedef struct GpMatrix GpMatrix;
 typedef struct GpPathIterator GpPathIterator;
 typedef struct GpCustomLineCap GpCustomLineCap;
+typedef struct GpAdjustableArrowCap GpAdjustableArrowCap;
 typedef struct GpImage GpImage;
 typedef struct GpMetafile GpMetafile;
 typedef struct GpImageAttributes GpImageAttributes;