- Sync gdiplus with Wine 1.1.29
authorDmitry Chapyshev <dmitry@reactos.org>
Thu, 3 Sep 2009 15:07:25 +0000 (15:07 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Thu, 3 Sep 2009 15:07:25 +0000 (15:07 +0000)
svn path=/trunk/; revision=42989

reactos/dll/win32/gdiplus/brush.c
reactos/dll/win32/gdiplus/gdiplus.c
reactos/dll/win32/gdiplus/gdiplus.rbuild
reactos/dll/win32/gdiplus/gdiplus.spec
reactos/dll/win32/gdiplus/gdiplus_private.h
reactos/dll/win32/gdiplus/graphics.c
reactos/dll/win32/gdiplus/image.c
reactos/dll/win32/gdiplus/imageattributes.c
reactos/dll/win32/gdiplus/region.c
reactos/include/psdk/gdiplusflat.h

index cdbc17d..6220443 100644 (file)
@@ -288,6 +288,17 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
     (*line)->rect.Width  = fabs(startpoint->X - endpoint->X);
     (*line)->rect.Height = fabs(startpoint->Y - endpoint->Y);
 
+    if ((*line)->rect.Width == 0)
+    {
+        (*line)->rect.X -= (*line)->rect.Height / 2.0f;
+        (*line)->rect.Width = (*line)->rect.Height;
+    }
+    else if ((*line)->rect.Height == 0)
+    {
+        (*line)->rect.Y -= (*line)->rect.Width / 2.0f;
+        (*line)->rect.Height = (*line)->rect.Width;
+    }
+
     (*line)->blendcount = 1;
     (*line)->blendfac = GdipAlloc(sizeof(REAL));
     (*line)->blendpos = GdipAlloc(sizeof(REAL));
@@ -686,9 +697,9 @@ GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
        n_y + n_height > ((GpBitmap*)image)->height)
         return InvalidParameter;
 
-    IPicture_get_Handle(image->picture, (OLE_HANDLE*)&hbm);
+    hbm = ((GpBitmap*)image)->hbitmap;
     if(!hbm)   return GenericError;
-    IPicture_get_CurDC(image->picture, &hdc);
+    hdc = ((GpBitmap*)image)->hdc;
     bm_is_selected = (hdc != 0);
 
     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
@@ -1342,6 +1353,13 @@ GpStatus WINGDIPAPI GdipSetPathGradientBlend(GpPathGradient *brush, GDIPCONST RE
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipSetPathGradientPresetBlend(GpPathGradient *brush,
+    GDIPCONST ARGB *blend, GDIPCONST REAL *pos, INT count)
+{
+    FIXME("(%p,%p,%p,%i): stub\n", brush, blend, pos, count);
+    return NotImplemented;
+}
+
 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
     ARGB argb)
 {
@@ -1551,12 +1569,33 @@ GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture* brush, REAL angle,
 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
     REAL scale)
 {
-    static int calls;
+    REAL factors[3];
+    REAL positions[3];
+    int num_points = 0;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    TRACE("(%p,%.2f,%.2f)\n", brush, focus, scale);
 
-    return NotImplemented;
+    if (!brush) return InvalidParameter;
+
+    if (focus != 0.0)
+    {
+        factors[num_points] = 0.0;
+        positions[num_points] = 0.0;
+        num_points++;
+    }
+
+    factors[num_points] = scale;
+    positions[num_points] = focus;
+    num_points++;
+
+    if (focus != 1.0)
+    {
+        factors[num_points] = 0.0;
+        positions[num_points] = 1.0;
+        num_points++;
+    }
+
+    return GdipSetLineBlend(brush, factors, positions, num_points);
 }
 
 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
index 06019a2..ec956f3 100644 (file)
@@ -399,6 +399,25 @@ BOOL lengthen_path(GpPath *path, INT len)
     return TRUE;
 }
 
+void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
+    BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride)
+{
+    UINT x, y;
+    for (y=0; y<height; y++)
+    {
+        const BYTE *src=src_bits+y*src_stride;
+        BYTE *dst=dst_bits+y*dst_stride;
+        for (x=0; x<width; x++)
+        {
+            BYTE alpha=src[3];
+            *dst++ = *src++ * alpha / 255;
+            *dst++ = *src++ * alpha / 255;
+            *dst++ = *src++ * alpha / 255;
+            *dst++ = *src++;
+        }
+    }
+}
+
 /* recursive deletion of GpRegion nodes */
 inline void delete_element(region_element* element)
 {
index ca5b7c3..cbf035e 100644 (file)
@@ -27,6 +27,7 @@
        <library>user32</library>
        <library>gdi32</library>
        <library>kernel32</library>
+       <library>windowscodecs</library>
        <library>ntdll</library>
 </module>
 </group>
index c658e00..bda241e 100644 (file)
 @ stdcall GdipDrawClosedCurveI(ptr ptr ptr long)
 @ stdcall GdipDrawCurve2(ptr ptr ptr long long)
 @ stdcall GdipDrawCurve2I(ptr ptr ptr long long)
-@ stub GdipDrawCurve3
-@ stub GdipDrawCurve3I
+@ stdcall GdipDrawCurve3(ptr ptr ptr long long long long)
+@ stdcall GdipDrawCurve3I(ptr ptr ptr long long long long)
 @ stdcall GdipDrawCurve(ptr ptr ptr long)
 @ stdcall GdipDrawCurveI(ptr ptr ptr long)
-@ stub GdipDrawDriverString
+@ stdcall GdipDrawDriverString(ptr ptr long ptr ptr ptr long ptr)
 @ stdcall GdipDrawEllipse(ptr ptr long long long long)
 @ stdcall GdipDrawEllipseI(ptr ptr long long long long)
 @ stdcall GdipDrawImage(ptr ptr long long)
 @ stdcall GdipGetImageHeight(ptr ptr)
 @ stdcall GdipGetImageHorizontalResolution(ptr ptr)
 @ stub GdipGetImageItemData
-@ stub GdipGetImagePalette
+@ stdcall GdipGetImagePalette(ptr ptr long)
 @ stdcall GdipGetImagePaletteSize(ptr ptr)
 @ stdcall GdipGetImagePixelFormat(ptr ptr)
 @ stdcall GdipGetImageRawFormat(ptr ptr)
 @ stub GdipGetTextureImage
 @ stdcall GdipGetTextureTransform(ptr ptr)
 @ stdcall GdipGetTextureWrapMode(ptr ptr)
-@ stub GdipGetVisibleClipBounds
-@ stub GdipGetVisibleClipBoundsI
+@ stdcall GdipGetVisibleClipBounds(ptr ptr)
+@ stdcall GdipGetVisibleClipBoundsI(ptr ptr)
 @ stdcall GdipGetWorldTransform(ptr ptr)
 @ stdcall GdipGraphicsClear(ptr long)
 @ stub GdipGraphicsSetAbort
 @ stdcall GdipIsVisiblePathPointI(ptr long long ptr ptr)
 @ stdcall GdipIsVisiblePoint(ptr long long ptr)
 @ stdcall GdipIsVisiblePointI(ptr long long ptr)
-@ stub GdipIsVisibleRect
-@ stub GdipIsVisibleRectI
-@ stub GdipIsVisibleRegionPoint
-@ stub GdipIsVisibleRegionPointI
-@ stub GdipIsVisibleRegionRect
-@ stub GdipIsVisibleRegionRectI
+@ stdcall GdipIsVisibleRect(ptr long long long long ptr)
+@ stdcall GdipIsVisibleRectI(ptr long long long long ptr)
+@ stdcall GdipIsVisibleRegionPoint(ptr long long ptr ptr)
+@ stdcall GdipIsVisibleRegionPointI(ptr long long ptr ptr)
+@ stdcall GdipIsVisibleRegionRect(ptr long long long long ptr ptr)
+@ stdcall GdipIsVisibleRegionRectI(ptr long long long long ptr ptr)
 @ stdcall GdipLoadImageFromFile(wstr ptr)
 @ stdcall GdipLoadImageFromFileICM(wstr ptr)
 @ stdcall GdipLoadImageFromStream(ptr ptr)
 @ stdcall GdipLoadImageFromStreamICM(ptr ptr)
 @ stdcall GdipMeasureCharacterRanges(ptr wstr long ptr ptr ptr long ptr)
-@ stub GdipMeasureDriverString
+@ stdcall GdipMeasureDriverString(ptr ptr long ptr ptr long ptr ptr)
 @ stdcall GdipMeasureString(ptr wstr long ptr ptr ptr ptr ptr ptr)
 @ stub GdipMultiplyLineTransform
 @ stdcall GdipMultiplyMatrix(ptr ptr long)
 @ stub GdipRecordMetafile
 @ stdcall GdipRecordMetafileFileName(wstr long long ptr long wstr ptr)
 @ stdcall GdipRecordMetafileFileNameI(wstr long long ptr long wstr ptr)
-@ stub GdipRecordMetafileI
+@ stdcall GdipRecordMetafileI(long long ptr long wstr ptr)
 @ stub GdipRecordMetafileStream
 @ stub GdipRecordMetafileStreamI
 @ stdcall GdipReleaseDC(ptr ptr)
 @ stdcall GdipSetPathGradientGammaCorrection(ptr long)
 @ stub GdipSetPathGradientLinearBlend
 @ stub GdipSetPathGradientPath
-@ stub GdipSetPathGradientPresetBlend
+@ stdcall GdipSetPathGradientPresetBlend(ptr ptr ptr long)
 @ stdcall GdipSetPathGradientSigmaBlend(ptr long long)
 @ stdcall GdipSetPathGradientSurroundColorsWithCount(ptr ptr ptr)
 @ stub GdipSetPathGradientTransform
index 95133ca..e87176e 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "objbase.h"
 #include "ocidl.h"
+#include "wine/list.h"
 
 #include "gdiplus.h"
 
@@ -67,6 +68,11 @@ static inline INT roundr(REAL x)
     return (INT) floorf(x + 0.5);
 }
 
+static inline INT ceilr(REAL x)
+{
+    return (INT) ceilf(x);
+}
+
 static inline REAL deg2rad(REAL degrees)
 {
     return M_PI * degrees / 180.0;
@@ -74,6 +80,9 @@ static inline REAL deg2rad(REAL degrees)
 
 extern const char *debugstr_rectf(CONST RectF* rc);
 
+extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
+    BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride);
+
 struct GpPen{
     UINT style;
     GpUnit unit;
@@ -109,6 +118,8 @@ struct GpGraphics{
     BOOL busy;      /* hdc handle obtained by GdipGetDC */
     GpRegion *clip;
     UINT textcontrast; /* not used yet. get/set only */
+    struct list containers;
+    GraphicsContainer contid; /* last-issued container ID */
 };
 
 struct GpBrush{
@@ -214,14 +225,25 @@ struct GpBitmap{
     ImageLockMode lockmode;
     INT numlocks;
     BYTE *bitmapbits;   /* pointer to the buffer we passed in BitmapLockBits */
+    HBITMAP hbitmap;
+    HDC hdc;
+    BYTE *bits; /* actual image bits if this is a DIB */
+    INT stride; /* stride of bits if this is a DIB */
 };
 
 struct GpCachedBitmap{
     GpImage *image;
 };
 
+struct color_key{
+    BOOL enabled;
+    ARGB low;
+    ARGB high;
+};
+
 struct GpImageAttributes{
     WrapMode wrap;
+    struct color_key colorkeys[ColorAdjustTypeCount];
 };
 
 struct GpFont{
index 2698159..1df3eee 100644 (file)
@@ -38,6 +38,7 @@
 #include "gdiplus.h"
 #include "gdiplus_private.h"
 #include "wine/debug.h"
+#include "wine/list.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
@@ -941,6 +942,153 @@ GpStatus trace_path(GpGraphics *graphics, GpPath *path)
     return result;
 }
 
+typedef struct _GraphicsContainerItem {
+    struct list entry;
+    GraphicsContainer contid;
+
+    SmoothingMode smoothing;
+    CompositingQuality compqual;
+    InterpolationMode interpolation;
+    CompositingMode compmode;
+    TextRenderingHint texthint;
+    REAL scale;
+    GpUnit unit;
+    PixelOffsetMode pixeloffset;
+    UINT textcontrast;
+    GpMatrix* worldtrans;
+    GpRegion* clip;
+} GraphicsContainerItem;
+
+static GpStatus init_container(GraphicsContainerItem** container,
+        GDIPCONST GpGraphics* graphics){
+    GpStatus sts;
+
+    *container = GdipAlloc(sizeof(GraphicsContainerItem));
+    if(!(*container))
+        return OutOfMemory;
+
+    (*container)->contid = graphics->contid + 1;
+
+    (*container)->smoothing = graphics->smoothing;
+    (*container)->compqual = graphics->compqual;
+    (*container)->interpolation = graphics->interpolation;
+    (*container)->compmode = graphics->compmode;
+    (*container)->texthint = graphics->texthint;
+    (*container)->scale = graphics->scale;
+    (*container)->unit = graphics->unit;
+    (*container)->textcontrast = graphics->textcontrast;
+    (*container)->pixeloffset = graphics->pixeloffset;
+
+    sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans);
+    if(sts != Ok){
+        GdipFree(*container);
+        *container = NULL;
+        return sts;
+    }
+
+    sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
+    if(sts != Ok){
+        GdipDeleteMatrix((*container)->worldtrans);
+        GdipFree(*container);
+        *container = NULL;
+        return sts;
+    }
+
+    return Ok;
+}
+
+static void delete_container(GraphicsContainerItem* container){
+    GdipDeleteMatrix(container->worldtrans);
+    GdipDeleteRegion(container->clip);
+    GdipFree(container);
+}
+
+static GpStatus restore_container(GpGraphics* graphics,
+        GDIPCONST GraphicsContainerItem* container){
+    GpStatus sts;
+    GpMatrix *newTrans;
+    GpRegion *newClip;
+
+    sts = GdipCloneMatrix(container->worldtrans, &newTrans);
+    if(sts != Ok)
+        return sts;
+
+    sts = GdipCloneRegion(container->clip, &newClip);
+    if(sts != Ok){
+        GdipDeleteMatrix(newTrans);
+        return sts;
+    }
+
+    GdipDeleteMatrix(graphics->worldtrans);
+    graphics->worldtrans = newTrans;
+
+    GdipDeleteRegion(graphics->clip);
+    graphics->clip = newClip;
+
+    graphics->contid = container->contid - 1;
+
+    graphics->smoothing = container->smoothing;
+    graphics->compqual = container->compqual;
+    graphics->interpolation = container->interpolation;
+    graphics->compmode = container->compmode;
+    graphics->texthint = container->texthint;
+    graphics->scale = container->scale;
+    graphics->unit = container->unit;
+    graphics->textcontrast = container->textcontrast;
+    graphics->pixeloffset = container->pixeloffset;
+
+    return Ok;
+}
+
+static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
+{
+    RECT wnd_rect;
+
+    if(graphics->hwnd) {
+        if(!GetClientRect(graphics->hwnd, &wnd_rect))
+            return GenericError;
+
+        rect->X = wnd_rect.left;
+        rect->Y = wnd_rect.top;
+        rect->Width = wnd_rect.right - wnd_rect.left;
+        rect->Height = wnd_rect.bottom - wnd_rect.top;
+    }else{
+        rect->X = 0;
+        rect->Y = 0;
+        rect->Width = GetDeviceCaps(graphics->hdc, HORZRES);
+        rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
+    }
+
+    return Ok;
+}
+
+/* on success, rgn will contain the region of the graphics object which
+ * is visible after clipping has been applied */
+static GpStatus get_visible_clip_region(GpGraphics *graphics, GpRegion *rgn)
+{
+    GpStatus stat;
+    GpRectF rectf;
+    GpRegion* tmp;
+
+    if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
+        return stat;
+
+    if((stat = GdipCreateRegion(&tmp)) != Ok)
+        return stat;
+
+    if((stat = GdipCombineRegionRect(tmp, &rectf, CombineModeReplace)) != Ok)
+        goto end;
+
+    if((stat = GdipCombineRegionRegion(tmp, graphics->clip, CombineModeIntersect)) != Ok)
+        goto end;
+
+    stat = GdipCombineRegionRegion(rgn, tmp, CombineModeReplace);
+
+end:
+    GdipDeleteRegion(tmp);
+    return stat;
+}
+
 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
 {
     TRACE("(%p, %p)\n", hdc, graphics);
@@ -955,7 +1103,7 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
     TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics);
 
     if(hDevice != NULL) {
-        FIXME("Don't know how to hadle parameter hDevice\n");
+        FIXME("Don't know how to handle parameter hDevice\n");
         return NotImplemented;
     }
 
@@ -991,6 +1139,8 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
     (*graphics)->scale = 1.0;
     (*graphics)->busy = FALSE;
     (*graphics)->textcontrast = 4;
+    list_init(&(*graphics)->containers);
+    (*graphics)->contid = 0;
 
     return Ok;
 }
@@ -1155,6 +1305,7 @@ GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
 
 GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
 {
+    GraphicsContainerItem *cont, *next;
     TRACE("(%p)\n", graphics);
 
     if(!graphics) return InvalidParameter;
@@ -1163,6 +1314,11 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
     if(graphics->owndc)
         ReleaseDC(graphics->hwnd, graphics->hdc);
 
+    LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){
+        list_remove(&cont->entry);
+        delete_container(cont);
+    }
+
     GdipDeleteRegion(graphics->clip);
     GdipDeleteMatrix(graphics->worldtrans);
     GdipFree(graphics);
@@ -1423,7 +1579,7 @@ GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics *graphics, GpPen *pen,
 
     TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
 
-    if(!points || count <= 0)
+    if(!points)
         return InvalidParameter;
 
     pointsF = GdipAlloc(sizeof(GpPointF)*count);
@@ -1459,7 +1615,13 @@ GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen,
     if(graphics->busy)
         return ObjectBusy;
 
+    if(count < 2)
+        return InvalidParameter;
+
     pt = GdipAlloc(len_pt * sizeof(GpPointF));
+    if(!pt)
+        return OutOfMemory;
+
     tension = tension * TENSION_CONST;
 
     calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
@@ -1508,7 +1670,7 @@ GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen,
 
     TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
 
-    if(!points || count <= 0)
+    if(!points)
         return InvalidParameter;
 
     pointsF = GdipAlloc(sizeof(GpPointF)*count);
@@ -1526,6 +1688,36 @@ GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen,
     return ret;
 }
 
+GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics *graphics, GpPen *pen,
+    GDIPCONST GpPointF *points, INT count, INT offset, INT numberOfSegments,
+    REAL tension)
+{
+    TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
+
+    if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
+        return InvalidParameter;
+    }
+
+    return GdipDrawCurve2(graphics, pen, points + offset, numberOfSegments + 1, tension);
+}
+
+GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics *graphics, GpPen *pen,
+    GDIPCONST GpPoint *points, INT count, INT offset, INT numberOfSegments,
+    REAL tension)
+{
+    TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
+
+    if(count < 0){
+        return OutOfMemory;
+    }
+
+    if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
+        return InvalidParameter;
+    }
+
+    return GdipDrawCurve2I(graphics, pen, points + offset, numberOfSegments + 1, tension);
+}
+
 GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x,
     REAL y, REAL width, REAL height)
 {
@@ -1569,18 +1761,10 @@ GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x,
 
 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));
-}
-
-GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
-    INT y)
-{
-    UINT width, height, srcw, srch;
+    UINT width, height;
+    GpPointF points[3];
 
-    TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y);
+    TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y);
 
     if(!graphics || !image)
         return InvalidParameter;
@@ -1588,20 +1772,23 @@ GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
     GdipGetImageWidth(image, &width);
     GdipGetImageHeight(image, &height);
 
-    srcw = width * (((REAL) INCH_HIMETRIC) /
-            ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX)));
-    srch = height * (((REAL) INCH_HIMETRIC) /
-            ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY)));
+    /* FIXME: we should use the graphics and image dpi, somehow */
 
-    if(image->type != ImageTypeMetafile){
-        y += height;
-        height *= -1;
-    }
+    points[0].X = points[2].X = x;
+    points[0].Y = points[1].Y = y;
+    points[1].X = x + width;
+    points[2].Y = y + height;
 
-    IPicture_Render(image->picture, graphics->hdc, x, y, width, height,
-                    0, 0, srcw, srch, NULL);
+    return GdipDrawImagePointsRect(graphics, image, points, 3, 0, 0, width, height,
+        UnitPixel, NULL, NULL, NULL);
+}
 
-    return Ok;
+GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
+    INT y)
+{
+    TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y);
+
+    return GdipDrawImage(graphics, image, (REAL)x, (REAL)y);
 }
 
 GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image,
@@ -1651,37 +1838,127 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
     if(!graphics || !image || !points || count != 3)
          return InvalidParameter;
 
-    if(srcUnit == UnitInch)
-        dx = dy = (REAL) INCH_HIMETRIC;
-    else if(srcUnit == UnitPixel){
-        dx = ((REAL) INCH_HIMETRIC) /
-             ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX));
-        dy = ((REAL) INCH_HIMETRIC) /
-             ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY));
-    }
-    else
-        return NotImplemented;
-
     memcpy(ptf, points, 3 * sizeof(GpPointF));
     transform_and_round_points(graphics, pti, ptf, 3);
 
-    /* IPicture renders bitmaps with the y-axis reversed
-     * FIXME: flipping for unknown image type might not be correct. */
-    if(image->type != ImageTypeMetafile){
-        INT temp;
-        temp = pti[0].y;
-        pti[0].y = pti[2].y;
-        pti[2].y = temp;
-    }
-
-    if(IPicture_Render(image->picture, graphics->hdc,
-        pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
-        srcx * dx, srcy * dy,
-        srcwidth * dx, srcheight * dy,
-        NULL) != S_OK){
-        if(callback)
-            callback(callbackData);
-        return GenericError;
+    if (image->picture)
+    {
+        if(srcUnit == UnitInch)
+            dx = dy = (REAL) INCH_HIMETRIC;
+        else if(srcUnit == UnitPixel){
+            dx = ((REAL) INCH_HIMETRIC) /
+                 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX));
+            dy = ((REAL) INCH_HIMETRIC) /
+                 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY));
+        }
+        else
+            return NotImplemented;
+
+        /* IPicture renders bitmaps with the y-axis reversed
+         * FIXME: flipping for unknown image type might not be correct. */
+        if(image->type != ImageTypeMetafile){
+            INT temp;
+            temp = pti[0].y;
+            pti[0].y = pti[2].y;
+            pti[2].y = temp;
+        }
+
+        if(IPicture_Render(image->picture, graphics->hdc,
+            pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
+            srcx * dx, srcy * dy,
+            srcwidth * dx, srcheight * dy,
+            NULL) != S_OK){
+            if(callback)
+                callback(callbackData);
+            return GenericError;
+        }
+    }
+    else if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
+    {
+        HDC hdc;
+        GpBitmap* bitmap = (GpBitmap*)image;
+        int temp_hdc=0, temp_bitmap=0;
+        HBITMAP hbitmap, old_hbm=NULL;
+
+        if (srcUnit == UnitInch)
+            dx = dy = 96.0; /* FIXME: use the image resolution */
+        else if (srcUnit == UnitPixel)
+            dx = dy = 1.0;
+        else
+            return NotImplemented;
+
+        if (bitmap->format == PixelFormat32bppARGB)
+        {
+            BITMAPINFOHEADER bih;
+            BYTE *temp_bits;
+
+            /* we need a bitmap with premultiplied alpha */
+            hdc = CreateCompatibleDC(0);
+            temp_hdc = 1;
+            temp_bitmap = 1;
+
+            bih.biSize = sizeof(BITMAPINFOHEADER);
+            bih.biWidth = bitmap->width;
+            bih.biHeight = -bitmap->height;
+            bih.biPlanes = 1;
+            bih.biBitCount = 32;
+            bih.biCompression = BI_RGB;
+            bih.biSizeImage = 0;
+            bih.biXPelsPerMeter = 0;
+            bih.biYPelsPerMeter = 0;
+            bih.biClrUsed = 0;
+            bih.biClrImportant = 0;
+
+            hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
+                (void**)&temp_bits, NULL, 0);
+
+            convert_32bppARGB_to_32bppPARGB(bitmap->width, bitmap->height,
+                temp_bits, bitmap->width*4, bitmap->bits, bitmap->stride);
+        }
+        else
+        {
+            hbitmap = bitmap->hbitmap;
+            hdc = bitmap->hdc;
+            temp_hdc = (hdc == 0);
+        }
+
+        if (temp_hdc)
+        {
+            if (!hdc) hdc = CreateCompatibleDC(0);
+            old_hbm = SelectObject(hdc, hbitmap);
+        }
+
+        if (bitmap->format == PixelFormat32bppARGB || bitmap->format == PixelFormat32bppPARGB)
+        {
+            BLENDFUNCTION bf;
+
+            bf.BlendOp = AC_SRC_OVER;
+            bf.BlendFlags = 0;
+            bf.SourceConstantAlpha = 255;
+            bf.AlphaFormat = AC_SRC_ALPHA;
+
+            GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
+                hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf);
+        }
+        else
+        {
+            StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
+                hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY);
+        }
+
+        if (temp_hdc)
+        {
+            SelectObject(hdc, old_hbm);
+            DeleteDC(hdc);
+        }
+
+        if (temp_bitmap)
+            DeleteObject(hbitmap);
+    }
+    else
+    {
+        ERR("GpImage with no IPicture or HBITMAP?!\n");
+        return NotImplemented;
     }
 
     return Ok;
@@ -2090,8 +2367,10 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     WCHAR* stringdup;
     REAL angle, ang_cos, ang_sin, rel_width, rel_height;
     INT sum = 0, height = 0, offsety = 0, fit, fitcpy, save_state, i, j, lret, nwidth,
-        nheight;
+        nheight, lineend;
     SIZE size;
+    POINT drawbase;
+    UINT drawflags;
     RECT drawcoord;
 
     TRACE("(%p, %s, %i, %p, %s, %p, %p)\n", graphics, debugstr_wn(string, length),
@@ -2183,10 +2462,10 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     pt[1].X = 1.0;
     pt[1].Y = 0.0;
     GdipTransformMatrixPoints(graphics->worldtrans, pt, 2);
-    angle = gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
+    angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
     ang_cos = cos(angle);
     ang_sin = sin(angle);
-    lfw.lfEscapement = lfw.lfOrientation = -roundr((angle / M_PI) * 1800.0);
+    lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0);
 
     gdifont = CreateFontIndirectW(&lfw);
     DeleteObject(SelectObject(graphics->hdc, CreateFontIndirectW(&lfw)));
@@ -2201,17 +2480,35 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
 
     length = j;
 
+    if (!format || format->align == StringAlignmentNear)
+    {
+        drawbase.x = corners[0].x;
+        drawbase.y = corners[0].y;
+        drawflags = DT_NOCLIP | DT_EXPANDTABS;
+    }
+    else if (format->align == StringAlignmentCenter)
+    {
+        drawbase.x = (corners[0].x + corners[1].x)/2;
+        drawbase.y = (corners[0].y + corners[1].y)/2;
+        drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_CENTER;
+    }
+    else /* (format->align == StringAlignmentFar) */
+    {
+        drawbase.x = corners[1].x;
+        drawbase.y = corners[1].y;
+        drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_RIGHT;
+    }
+
     while(sum < length){
-        drawcoord.left = corners[0].x + roundr(ang_sin * (REAL) height);
-        drawcoord.top = corners[0].y + roundr(ang_cos * (REAL) height);
+        drawcoord.left = drawcoord.right = drawbase.x + roundr(ang_sin * (REAL) height);
+        drawcoord.top = drawcoord.bottom = drawbase.y + roundr(ang_cos * (REAL) height);
 
         GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
                               nwidth, &fit, NULL, &size);
         fitcpy = fit;
 
         if(fit == 0){
-            DrawTextW(graphics->hdc, stringdup + sum, 1, &drawcoord, DT_NOCLIP |
-                      DT_EXPANDTABS);
+            DrawTextW(graphics->hdc, stringdup + sum, 1, &drawcoord, drawflags);
             break;
         }
 
@@ -2221,7 +2518,7 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
 
         /* Line break code (may look strange, but it imitates windows). */
         if(lret < fit)
-            fit = lret;    /* this is not an off-by-one error */
+            lineend = fit = lret;    /* this is not an off-by-one error */
         else if(fit < (length - sum)){
             if(*(stringdup + sum + fit) == ' ')
                 while(*(stringdup + sum + fit) == ' ')
@@ -2238,9 +2535,15 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
                         break;
                     }
                 }
+            lineend = fit;
+            while(*(stringdup + sum + lineend - 1) == ' ' ||
+                  *(stringdup + sum + lineend - 1) == '\t')
+                lineend--;
         }
-        DrawTextW(graphics->hdc, stringdup + sum, min(length - sum, fit),
-                  &drawcoord, DT_NOCLIP | DT_EXPANDTABS);
+        else
+            lineend = fit;
+        DrawTextW(graphics->hdc, stringdup + sum, min(length - sum, lineend),
+                  &drawcoord, drawflags);
 
         sum += fit + (lret < fitcpy ? 1 : 0);
         height += size.cy;
@@ -2349,12 +2652,14 @@ GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, brush->gdibrush);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
     transform_and_round_points(graphics, pti, ptf, 2);
 
+    BeginPath(graphics->hdc);
     Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y);
+    EndPath(graphics->hdc);
+
+    brush_fill_path(graphics, brush);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -2421,10 +2726,12 @@ GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, brush->gdibrush);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
+    BeginPath(graphics->hdc);
     draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
+    EndPath(graphics->hdc);
+
+    brush_fill_path(graphics, brush);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -2467,13 +2774,16 @@ GpStatus WINGDIPAPI GdipFillPolygon(GpGraphics *graphics, GpBrush *brush,
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, brush->gdibrush);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
     SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
                                                                   : WINDING));
 
     transform_and_round_points(graphics, pti, ptf, count);
+
+    BeginPath(graphics->hdc);
     Polygon(graphics->hdc, pti, count);
+    EndPath(graphics->hdc);
+
+    brush_fill_path(graphics, brush);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -2514,13 +2824,16 @@ GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, brush->gdibrush);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
     SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
                                                                   : WINDING));
 
     transform_and_round_points(graphics, pti, ptf, count);
+
+    BeginPath(graphics->hdc);
     Polygon(graphics->hdc, pti, count);
+    EndPath(graphics->hdc);
+
+    brush_fill_path(graphics, brush);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -2613,12 +2926,14 @@ GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, brush->gdibrush);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
     transform_and_round_points(graphics, pti, ptf, 4);
 
+    BeginPath(graphics->hdc);
     Polygon(graphics->hdc, pti, 4);
+    EndPath(graphics->hdc);
+
+    brush_fill_path(graphics, brush);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -2682,6 +2997,7 @@ GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
     INT save_state;
     GpStatus status;
     HRGN hrgn;
+    RECT rc;
 
     TRACE("(%p, %p, %p)\n", graphics, brush, region);
 
@@ -2697,9 +3013,17 @@ GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
-    FillRgn(graphics->hdc, hrgn, brush->gdibrush);
+    ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+
+    if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
+    {
+        BeginPath(graphics->hdc);
+        Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom);
+        EndPath(graphics->hdc);
+
+        brush_fill_path(graphics, brush);
+    }
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -2912,6 +3236,56 @@ GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics,
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect)
+{
+    GpRegion *clip_rgn;
+    GpStatus stat;
+
+    TRACE("(%p, %p)\n", graphics, rect);
+
+    if(!graphics || !rect)
+        return InvalidParameter;
+
+    if(graphics->busy)
+        return ObjectBusy;
+
+    /* intersect window and graphics clipping regions */
+    if((stat = GdipCreateRegion(&clip_rgn)) != Ok)
+        return stat;
+
+    if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok)
+        goto cleanup;
+
+    /* get bounds of the region */
+    stat = GdipGetRegionBounds(clip_rgn, graphics, rect);
+
+cleanup:
+    GdipDeleteRegion(clip_rgn);
+
+    return stat;
+}
+
+GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics *graphics, GpRect *rect)
+{
+    GpRectF rectf;
+    GpStatus stat;
+
+    TRACE("(%p, %p)\n", graphics, rect);
+
+    if(!graphics || !rect)
+        return InvalidParameter;
+
+    if((stat = GdipGetVisibleClipBounds(graphics, &rectf)) == Ok)
+    {
+        rect->X = roundr(rectf.X);
+        rect->Y = roundr(rectf.Y);
+        rect->Width  = roundr(rectf.Width);
+        rect->Height = roundr(rectf.Height);
+    }
+
+    return stat;
+}
+
 GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
 {
     TRACE("(%p, %p)\n", graphics, matrix);
@@ -2930,7 +3304,7 @@ GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color)
 {
     GpSolidFill *brush;
     GpStatus stat;
-    RECT rect;
+    GpRectF wnd_rect;
 
     TRACE("(%p, %x)\n", graphics, color);
 
@@ -2943,18 +3317,13 @@ GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color)
     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));
+    if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){
+        GdipDeleteBrush((GpBrush*)brush);
+        return stat;
     }
-    else
-        GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)GetDeviceCaps(graphics->hdc, HORZRES),
-                                                               (REAL)GetDeviceCaps(graphics->hdc, VERTRES));
+
+    GdipFillRectangle(graphics, (GpBrush*)brush, wnd_rect.X, wnd_rect.Y,
+                                                 wnd_rect.Width, wnd_rect.Height);
 
     GdipDeleteBrush((GpBrush*)brush);
 
@@ -2973,7 +3342,11 @@ GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics *graphics, BOOL *res)
 
 GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOOL *result)
 {
-    FIXME("(%p, %.2f, %.2f, %p) stub\n", graphics, x, y, result);
+    GpStatus stat;
+    GpRegion* rgn;
+    GpPointF pt;
+
+    TRACE("(%p, %.2f, %.2f, %p)\n", graphics, x, y, result);
 
     if(!graphics || !result)
         return InvalidParameter;
@@ -2981,12 +3354,37 @@ GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOO
     if(graphics->busy)
         return ObjectBusy;
 
-    return NotImplemented;
+    pt.X = x;
+    pt.Y = y;
+    if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
+                   CoordinateSpaceWorld, &pt, 1)) != Ok)
+        return stat;
+
+    if((stat = GdipCreateRegion(&rgn)) != Ok)
+        return stat;
+
+    if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
+        goto cleanup;
+
+    stat = GdipIsVisibleRegionPoint(rgn, pt.X, pt.Y, graphics, result);
+
+cleanup:
+    GdipDeleteRegion(rgn);
+    return stat;
 }
 
 GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL *result)
 {
-    FIXME("(%p, %d, %d, %p) stub\n", graphics, x, y, result);
+    return GdipIsVisiblePoint(graphics, (REAL)x, (REAL)y, result);
+}
+
+GpStatus WINGDIPAPI GdipIsVisibleRect(GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, BOOL *result)
+{
+    GpStatus stat;
+    GpRegion* rgn;
+    GpPointF pts[2];
+
+    TRACE("(%p %.2f %.2f %.2f %.2f %p)\n", graphics, x, y, width, height, result);
 
     if(!graphics || !result)
         return InvalidParameter;
@@ -2994,7 +3392,34 @@ GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL
     if(graphics->busy)
         return ObjectBusy;
 
-    return NotImplemented;
+    pts[0].X = x;
+    pts[0].Y = y;
+    pts[1].X = x + width;
+    pts[1].Y = y + height;
+
+    if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
+                    CoordinateSpaceWorld, pts, 2)) != Ok)
+        return stat;
+
+    pts[1].X -= pts[0].X;
+    pts[1].Y -= pts[0].Y;
+
+    if((stat = GdipCreateRegion(&rgn)) != Ok)
+        return stat;
+
+    if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
+        goto cleanup;
+
+    stat = GdipIsVisibleRegionRect(rgn, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, graphics, result);
+
+cleanup:
+    GdipDeleteRegion(rgn);
+    return stat;
+}
+
+GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT width, INT height, BOOL *result)
+{
+    return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
 }
 
 GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
@@ -3023,7 +3448,7 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
     HFONT oldfont;
     WCHAR* stringdup;
     INT sum = 0, height = 0, fit, fitcpy, max_width = 0, i, j, lret, nwidth,
-        nheight;
+        nheight, lineend;
     SIZE size;
 
     TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics,
@@ -3076,7 +3501,7 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
 
         /* Line break code (may look strange, but it imitates windows). */
         if(lret < fit)
-            fit = lret;    /* this is not an off-by-one error */
+            lineend = fit = lret;    /* this is not an off-by-one error */
         else if(fit < (length - sum)){
             if(*(stringdup + sum + fit) == ' ')
                 while(*(stringdup + sum + fit) == ' ')
@@ -3093,9 +3518,15 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
                         break;
                     }
                 }
+            lineend = fit;
+            while(*(stringdup + sum + lineend - 1) == ' ' ||
+                  *(stringdup + sum + lineend - 1) == '\t')
+                lineend--;
         }
+        else
+            lineend = fit;
 
-        GetTextExtentExPointW(graphics->hdc, stringdup + sum, fit,
+        GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend,
                               nwidth, &j, NULL, &size);
 
         sum += fit + (lret < fitcpy ? 1 : 0);
@@ -3159,15 +3590,7 @@ GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
 
 GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
 {
-    static int calls;
-
-    if(!graphics)
-        return InvalidParameter;
-
-    if(!(calls++))
-        FIXME("graphics state not implemented\n");
-
-    return Ok;
+    return GdipEndContainer(graphics, state);
 }
 
 GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
@@ -3186,26 +3609,27 @@ GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
 
 GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
 {
-    static int calls;
-
-    if(!graphics || !state)
-        return InvalidParameter;
-
-    if(!(calls++))
-        FIXME("graphics state not implemented\n");
-
-    *state = 0xdeadbeef;
-    return Ok;
+    return GdipBeginContainer2(graphics, state);
 }
 
-GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics, GraphicsContainer *state)
+GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
+        GraphicsContainer *state)
 {
-    FIXME("(%p, %p)\n", graphics, state);
+    GraphicsContainerItem *container;
+    GpStatus sts;
+
+    TRACE("(%p, %p)\n", graphics, state);
 
     if(!graphics || !state)
         return InvalidParameter;
 
-    *state = 0xdeadbeef;
+    sts = init_container(&container, graphics);
+    if(sts != Ok)
+        return sts;
+
+    list_add_head(&graphics->containers, &container->entry);
+    *state = graphics->contid = container->contid;
+
     return Ok;
 }
 
@@ -3227,13 +3651,40 @@ GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST B
     return NotImplemented;
 }
 
-GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsState state)
+GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
 {
-    FIXME("(%p, 0x%x)\n", graphics, state);
+    GpStatus sts;
+    GraphicsContainerItem *container, *container2;
 
-    if(!graphics || !state)
+    TRACE("(%p, %x)\n", graphics, state);
+
+    if(!graphics)
         return InvalidParameter;
 
+    LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
+        if(container->contid == state)
+            break;
+    }
+
+    /* did not find a matching container */
+    if(&container->entry == &graphics->containers)
+        return Ok;
+
+    sts = restore_container(graphics, container);
+    if(sts != Ok)
+        return sts;
+
+    /* remove all of the containers on top of the found container */
+    LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){
+        if(container->contid == state)
+            break;
+        list_remove(&container->entry);
+        delete_container(container);
+    }
+
+    list_remove(&container->entry);
+    delete_container(container);
+
     return Ok;
 }
 
@@ -3839,3 +4290,37 @@ GpStatus WINGDIPAPI GdipTranslateClipI(GpGraphics *graphics, INT dx, INT dy)
 
     return GdipTranslateRegion(graphics->clip, (REAL)dx, (REAL)dy);
 }
+
+
+/*****************************************************************************
+ * GdipMeasureDriverString [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
+                                            GDIPCONST GpFont *font, GDIPCONST PointF *positions,
+                                            INT flags, GDIPCONST GpMatrix *matrix, RectF *boundingBox)
+{
+    FIXME("(%p %p %d %p %p %d %p %p): stub\n", graphics, text, length, font, positions, flags, matrix, boundingBox);
+    return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipDrawDriverString [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
+                                         GDIPCONST GpFont *font, GDIPCONST GpBrush *brush,
+                                         GDIPCONST PointF *positions, INT flags,
+                                         GDIPCONST GpMatrix *matrix )
+{
+    FIXME("(%p %p %d %p %p %p %d %p): stub\n", graphics, text, length, font, brush, positions, flags, matrix);
+    return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipRecordMetafileI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
+                                        MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
+{
+    FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile);
+    return NotImplemented;
+}
index 6df104e..b1e831f 100644 (file)
@@ -31,6 +31,7 @@
 #include "ole2.h"
 
 #include "initguid.h"
+#include "wincodec.h"
 #include "gdiplus.h"
 #include "gdiplus_private.h"
 #include "wine/debug.h"
@@ -167,8 +168,25 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     if(bitmap->lockmode)
         return WrongState;
 
-    IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
-    IPicture_get_CurDC(bitmap->image.picture, &hdc);
+    if (bitmap->bits && bitmap->format == format)
+    {
+        /* no conversion is necessary; just use the bits directly */
+        lockeddata->Width = act_rect.Width;
+        lockeddata->Height = act_rect.Height;
+        lockeddata->PixelFormat = format;
+        lockeddata->Reserved = flags;
+        lockeddata->Stride = bitmap->stride;
+        lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
+                            bitmap->stride * act_rect.Y;
+
+        bitmap->lockmode = flags;
+        bitmap->numlocks++;
+
+        return Ok;
+    }
+
+    hbm = bitmap->hbitmap;
+    hdc = bitmap->hdc;
     bm_is_selected = (hdc != 0);
 
     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
@@ -263,8 +281,15 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
         return Ok;
     }
 
-    IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
-    IPicture_get_CurDC(bitmap->image.picture, &hdc);
+    if (!bitmap->bitmapbits)
+    {
+        /* we passed a direct reference; no need to do anything */
+        bitmap->lockmode = 0;
+        return Ok;
+    }
+
+    hbm = bitmap->hbitmap;
+    hdc = bitmap->hdc;
     bm_is_selected = (hdc != 0);
 
     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
@@ -312,10 +337,6 @@ GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
 
 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
 {
-    IStream* stream;
-    HRESULT hr;
-    INT size;
-    LARGE_INTEGER move;
     GpStatus stat = GenericError;
 
     TRACE("%p, %p\n", image, cloneImage);
@@ -323,29 +344,82 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
     if (!image || !cloneImage)
         return InvalidParameter;
 
-    hr = CreateStreamOnHGlobal(0, TRUE, &stream);
-    if (FAILED(hr))
-        return GenericError;
-
-    hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
-    if(FAILED(hr))
+    if (image->picture)
     {
-        WARN("Failed to save image on stream\n");
-        goto out;
-    }
+        IStream* stream;
+        HRESULT hr;
+        INT size;
+        LARGE_INTEGER move;
 
-    /* Set seek pointer back to the beginning of the picture */
-    move.QuadPart = 0;
-    hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
-    if (FAILED(hr))
-        goto out;
+        hr = CreateStreamOnHGlobal(0, TRUE, &stream);
+        if (FAILED(hr))
+            return GenericError;
 
-    stat = GdipLoadImageFromStream(stream, cloneImage);
-    if (stat != Ok) WARN("Failed to load image from stream\n");
+        hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
+        if(FAILED(hr))
+        {
+            WARN("Failed to save image on stream\n");
+            goto out;
+        }
 
-out:
-    IStream_Release(stream);
-    return stat;
+        /* Set seek pointer back to the beginning of the picture */
+        move.QuadPart = 0;
+        hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
+        if (FAILED(hr))
+            goto out;
+
+        stat = GdipLoadImageFromStream(stream, cloneImage);
+        if (stat != Ok) WARN("Failed to load image from stream\n");
+
+    out:
+        IStream_Release(stream);
+        return stat;
+    }
+    else if (image->type == ImageTypeBitmap)
+    {
+        GpBitmap *bitmap = (GpBitmap*)image;
+        BitmapData lockeddata_src, lockeddata_dst;
+        int i;
+        UINT row_size;
+
+        stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
+            &lockeddata_src);
+        if (stat != Ok) return stat;
+
+        stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
+            0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
+        if (stat == Ok)
+        {
+            stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
+                lockeddata_src.PixelFormat, &lockeddata_dst);
+
+            if (stat == Ok)
+            {
+                /* copy the image data */
+                row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
+                for (i=0; i<lockeddata_src.Height; i++)
+                    memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
+                           (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
+                           row_size);
+
+                GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
+            }
+
+            GdipBitmapUnlockBits(bitmap, &lockeddata_src);
+        }
+
+        if (stat != Ok)
+        {
+            GdipDisposeImage(*cloneImage);
+            *cloneImage = NULL;
+        }
+        return stat;
+    }
+    else
+    {
+        ERR("GpImage with no IPicture or bitmap?!\n");
+        return NotImplemented;
+    }
 }
 
 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
@@ -447,11 +521,69 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
     HBITMAP* hbmReturn, ARGB background)
 {
-    FIXME("stub\n");
+    GpStatus stat;
+    HBITMAP result, oldbitmap;
+    UINT width, height;
+    HDC hdc;
+    GpGraphics *graphics;
+    BITMAPINFOHEADER bih;
+    void *bits;
+    TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
+
+    if (!bitmap || !hbmReturn) return InvalidParameter;
+
+    GdipGetImageWidth((GpImage*)bitmap, &width);
+    GdipGetImageHeight((GpImage*)bitmap, &height);
+
+    bih.biSize = sizeof(bih);
+    bih.biWidth = width;
+    bih.biHeight = height;
+    bih.biPlanes = 1;
+    bih.biBitCount = 32;
+    bih.biCompression = BI_RGB;
+    bih.biSizeImage = 0;
+    bih.biXPelsPerMeter = 0;
+    bih.biYPelsPerMeter = 0;
+    bih.biClrUsed = 0;
+    bih.biClrImportant = 0;
+
+    hdc = CreateCompatibleDC(NULL);
+    if (!hdc) return GenericError;
+
+    result = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, &bits,
+        NULL, 0);
+
+    if (result)
+    {
+        oldbitmap = SelectObject(hdc, result);
 
-    hbmReturn = NULL;
+        stat = GdipCreateFromHDC(hdc, &graphics);
+        if (stat == Ok)
+        {
+            stat = GdipGraphicsClear(graphics, background);
 
-    return NotImplemented;
+            if (stat == Ok)
+                stat = GdipDrawImage(graphics, (GpImage*)bitmap, 0, 0);
+
+            GdipDeleteGraphics(graphics);
+        }
+
+        SelectObject(hdc, oldbitmap);
+    }
+    else
+        stat = GenericError;
+
+    DeleteDC(hdc);
+
+    if (stat != Ok && result)
+    {
+        DeleteObject(result);
+        result = NULL;
+    }
+
+    *hbmReturn = result;
+
+    return stat;
 }
 
 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
@@ -494,56 +626,182 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
 
 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
 {
-    HICON icon_copy;
+    GpStatus stat;
     ICONINFO iinfo;
-    PICTDESC desc;
+    BITMAP bm;
+    int ret;
+    UINT width, height;
+    GpRect rect;
+    BitmapData lockeddata;
+    HDC screendc;
+    BOOL has_alpha;
+    int x, y;
+    BYTE *bits;
+    BITMAPINFOHEADER bih;
+    DWORD *src;
+    BYTE *dst_row;
+    DWORD *dst;
 
     TRACE("%p, %p\n", hicon, bitmap);
 
     if(!bitmap || !GetIconInfo(hicon, &iinfo))
+    {
+        DeleteObject(iinfo.hbmColor);
+        DeleteObject(iinfo.hbmMask);
         return InvalidParameter;
+    }
 
-    *bitmap = GdipAlloc(sizeof(GpBitmap));
-    if(!*bitmap)    return OutOfMemory;
+    /* get the size of the icon */
+    ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
+    if (ret == 0) {
+        DeleteObject(iinfo.hbmColor);
+        DeleteObject(iinfo.hbmMask);
+        return GenericError;
+    }
 
-    icon_copy = CreateIconIndirect(&iinfo);
+    width = bm.bmWidth;
 
-    if(!icon_copy){
-        GdipFree(*bitmap);
-        return InvalidParameter;
+    if (iinfo.hbmColor)
+        height = abs(bm.bmHeight);
+    else /* combined bitmap + mask */
+        height = abs(bm.bmHeight) / 2;
+
+    bits = HeapAlloc(GetProcessHeap(), 0, 4*width*height);
+    if (!bits) {
+        DeleteObject(iinfo.hbmColor);
+        DeleteObject(iinfo.hbmMask);
+        return OutOfMemory;
     }
 
-    desc.cbSizeofstruct = sizeof(PICTDESC);
-    desc.picType = PICTYPE_ICON;
-    desc.u.icon.hicon = icon_copy;
+    stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB, NULL, bitmap);
+    if (stat != Ok) {
+        DeleteObject(iinfo.hbmColor);
+        DeleteObject(iinfo.hbmMask);
+        HeapFree(GetProcessHeap(), 0, bits);
+        return stat;
+    }
 
-    if(OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE,
-                                (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
-        DestroyIcon(icon_copy);
-        GdipFree(*bitmap);
-        return GenericError;
+    rect.X = 0;
+    rect.Y = 0;
+    rect.Width = width;
+    rect.Height = height;
+
+    stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
+    if (stat != Ok) {
+        DeleteObject(iinfo.hbmColor);
+        DeleteObject(iinfo.hbmMask);
+        HeapFree(GetProcessHeap(), 0, bits);
+        GdipDisposeImage((GpImage*)*bitmap);
+        return stat;
     }
 
-    (*bitmap)->format = PixelFormat32bppARGB;
-    (*bitmap)->image.type  = ImageTypeBitmap;
-    (*bitmap)->image.flags = ImageFlagsNone;
-    (*bitmap)->width  = ipicture_pixel_width((*bitmap)->image.picture);
-    (*bitmap)->height = ipicture_pixel_height((*bitmap)->image.picture);
+    bih.biSize = sizeof(bih);
+    bih.biWidth = width;
+    bih.biHeight = -height;
+    bih.biPlanes = 1;
+    bih.biBitCount = 32;
+    bih.biCompression = BI_RGB;
+    bih.biSizeImage = 0;
+    bih.biXPelsPerMeter = 0;
+    bih.biYPelsPerMeter = 0;
+    bih.biClrUsed = 0;
+    bih.biClrImportant = 0;
+
+    screendc = GetDC(0);
+    if (iinfo.hbmColor)
+    {
+        GetDIBits(screendc, iinfo.hbmColor, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+
+        if (bm.bmBitsPixel == 32)
+        {
+            has_alpha = FALSE;
+
+            /* If any pixel has a non-zero alpha, ignore hbmMask */
+            src = (DWORD*)bits;
+            for (x=0; x<width && !has_alpha; x++)
+                for (y=0; y<height && !has_alpha; y++)
+                    if ((*src++ & 0xff000000) != 0)
+                        has_alpha = TRUE;
+        }
+        else has_alpha = FALSE;
+    }
+    else
+    {
+        GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+        has_alpha = FALSE;
+    }
+
+    /* copy the image data to the Bitmap */
+    src = (DWORD*)bits;
+    dst_row = lockeddata.Scan0;
+    for (y=0; y<height; y++)
+    {
+        memcpy(dst_row, src, width*4);
+        src += width;
+        dst_row += lockeddata.Stride;
+    }
+
+    if (!has_alpha)
+    {
+        if (iinfo.hbmMask)
+        {
+            /* read alpha data from the mask */
+            if (iinfo.hbmColor)
+                GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+            else
+                GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+
+            src = (DWORD*)bits;
+            dst_row = lockeddata.Scan0;
+            for (y=0; y<height; y++)
+            {
+                dst = (DWORD*)dst_row;
+                for (x=0; x<height; x++)
+                {
+                    DWORD src_value = *src++;
+                    if (src_value)
+                        *dst++ = 0;
+                    else
+                        *dst++ |= 0xff000000;
+                }
+                dst_row += lockeddata.Stride;
+            }
+        }
+        else
+        {
+            /* set constant alpha of 255 */
+            dst_row = bits;
+            for (y=0; y<height; y++)
+            {
+                dst = (DWORD*)dst_row;
+                for (x=0; x<height; x++)
+                    *dst++ |= 0xff000000;
+                dst_row += lockeddata.Stride;
+            }
+        }
+    }
+
+    ReleaseDC(0, screendc);
 
     DeleteObject(iinfo.hbmColor);
     DeleteObject(iinfo.hbmMask);
 
+    GdipBitmapUnlockBits(*bitmap, &lockeddata);
+
+    HeapFree(GetProcessHeap(), 0, bits);
+
     return Ok;
 }
 
 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
 {
-    BITMAPFILEHEADER *bmfh;
-    BITMAPINFOHEADER *bmih;
-    BYTE *buff;
-    INT datalen, size;
-    IStream *stream;
+    BITMAPINFOHEADER bmih;
+    HBITMAP hbitmap;
+    INT row_size, dib_stride;
+    HDC hdc;
+    BYTE *bits;
+    int i;
 
     TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
 
@@ -557,71 +815,46 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     if(scan0 && !stride)
         return InvalidParameter;
 
-    *bitmap = GdipAlloc(sizeof(GpBitmap));
-    if(!*bitmap)    return OutOfMemory;
+    row_size = (width * PIXELFORMATBPP(format)+7) / 8;
+    dib_stride = (row_size + 3) & ~3;
 
-    if(stride == 0){
-        stride = width * (PIXELFORMATBPP(format) / 8);
-        stride = (stride + 3) & ~3;
-    }
+    if(stride == 0)
+        stride = dib_stride;
 
-    datalen = abs(stride * height);
-    size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datalen;
-    buff = GdipAlloc(size);
-    if(!buff){
-        GdipFree(*bitmap);
-        return OutOfMemory;
-    }
+    bmih.biSize = sizeof(BITMAPINFOHEADER);
+    bmih.biWidth = width;
+    bmih.biHeight = -height;
+    bmih.biPlanes = 1;
+    /* FIXME: use the rest of the data from format */
+    bmih.biBitCount = PIXELFORMATBPP(format);
+    bmih.biCompression = BI_RGB;
+    bmih.biSizeImage = 0;
+    bmih.biXPelsPerMeter = 0;
+    bmih.biYPelsPerMeter = 0;
+    bmih.biClrUsed = 0;
+    bmih.biClrImportant = 0;
 
-    bmfh = (BITMAPFILEHEADER*) buff;
-    bmih = (BITMAPINFOHEADER*) (bmfh + 1);
+    hdc = CreateCompatibleDC(NULL);
+    if (!hdc) return GenericError;
 
-    bmfh->bfType    = (((WORD)'M') << 8) + (WORD)'B';
-    bmfh->bfSize    = size;
-    bmfh->bfOffBits = size - datalen;
+    hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits,
+        NULL, 0);
 
-    bmih->biSize            = sizeof(BITMAPINFOHEADER);
-    bmih->biWidth           = width;
-    /* FIXME: use the rest of the data from format */
-    bmih->biBitCount        = PIXELFORMATBPP(format);
-    bmih->biCompression     = BI_RGB;
-    bmih->biSizeImage       = datalen;
+    DeleteDC(hdc);
 
-    if (scan0)
-    {
-        if (stride > 0)
-        {
-            bmih->biHeight = -height;
-            memcpy(bmih + 1, scan0, datalen);
-        }
-        else
-        {
-            bmih->biHeight = height;
-            memcpy(bmih + 1, scan0 + stride * (height - 1), datalen);
-        }
-    }
-    else
-    {
-        bmih->biHeight = height;
-        memset(bmih + 1, 0, datalen);
-    }
+    if (!hbitmap) return GenericError;
 
-    if(CreateStreamOnHGlobal(buff, TRUE, &stream) != S_OK){
-        ERR("could not make stream\n");
-        GdipFree(*bitmap);
-        GdipFree(buff);
-        *bitmap = NULL;
-        return GenericError;
-    }
+    /* copy bits to the dib if necessary */
+    /* FIXME: should reference the bits instead of copying them */
+    if (scan0)
+        for (i=0; i<height; i++)
+            memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
 
-    if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
-        (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
-        TRACE("Could not load picture\n");
-        IStream_Release(stream);
-        GdipFree(*bitmap);
-        GdipFree(buff);
-        *bitmap = NULL;
-        return GenericError;
+    *bitmap = GdipAlloc(sizeof(GpBitmap));
+    if(!*bitmap)
+    {
+        DeleteObject(hbitmap);
+        return OutOfMemory;
     }
 
     (*bitmap)->image.type = ImageTypeBitmap;
@@ -629,6 +862,11 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->width = width;
     (*bitmap)->height = height;
     (*bitmap)->format = format;
+    (*bitmap)->image.picture = NULL;
+    (*bitmap)->hbitmap = hbitmap;
+    (*bitmap)->hdc = NULL;
+    (*bitmap)->bits = bits;
+    (*bitmap)->stride = dib_stride;
 
     return Ok;
 }
@@ -646,8 +884,8 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
         return stat;
 
     if((*bitmap)->image.type != ImageTypeBitmap){
-        IPicture_Release((*bitmap)->image.picture);
-        GdipFree(bitmap);
+        GdipDisposeImage(&(*bitmap)->image);
+        *bitmap = NULL;
         return GenericError; /* FIXME: what error to return? */
     }
 
@@ -726,18 +964,18 @@ GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
 
 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
 {
-    HDC hdc;
-
     TRACE("%p\n", image);
 
     if(!image)
         return InvalidParameter;
 
-    IPicture_get_CurDC(image->picture, &hdc);
-    DeleteDC(hdc);
-    IPicture_Release(image->picture);
+    if (image->picture)
+        IPicture_Release(image->picture);
     if (image->type == ImageTypeBitmap)
+    {
         GdipFree(((GpBitmap*)image)->bitmapbits);
+        DeleteDC(((GpBitmap*)image)->hdc);
+    }
     GdipFree(image);
 
     return Ok;
@@ -829,11 +1067,12 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
         return NotImplemented;
     }
 
-    IPicture_get_CurDC(image->picture, &hdc);
+    hdc = ((GpBitmap*)image)->hdc;
 
     if(!hdc){
         hdc = CreateCompatibleDC(0);
-        IPicture_SelectPicture(image->picture, hdc, NULL, NULL);
+        SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
+        ((GpBitmap*)image)->hdc = hdc;
     }
 
     return GdipCreateFromHDC(hdc, graphics);
@@ -1143,10 +1382,148 @@ GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage *
     return GdipLoadImageFromFile(filename, image);
 }
 
-GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
+static const WICPixelFormatGUID *wic_pixel_formats[] = {
+    &GUID_WICPixelFormat16bppBGR555,
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormat32bppBGRA,
+    &GUID_WICPixelFormat32bppPBGRA,
+    NULL
+};
+
+static const PixelFormat wic_gdip_formats[] = {
+    PixelFormat16bppRGB555,
+    PixelFormat24bppRGB,
+    PixelFormat32bppRGB,
+    PixelFormat32bppARGB,
+    PixelFormat32bppPARGB,
+};
+
+static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+    GpStatus status=Ok;
+    GpBitmap *bitmap;
+    HRESULT hr;
+    IWICBitmapDecoder *decoder;
+    IWICBitmapFrameDecode *frame;
+    IWICBitmapSource *source=NULL;
+    WICPixelFormatGUID wic_format;
+    PixelFormat gdip_format=0;
+    int i;
+    UINT width, height;
+    BitmapData lockeddata;
+    WICRect wrc;
+    HRESULT initresult;
+
+    initresult = CoInitialize(NULL);
+
+    hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICBitmapDecoder, (void**)&decoder);
+    if (FAILED(hr)) goto end;
+
+    hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
+    if (SUCCEEDED(hr))
+        hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
+
+    if (SUCCEEDED(hr)) /* got frame */
+    {
+        hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
+
+        if (SUCCEEDED(hr))
+        {
+            for (i=0; wic_pixel_formats[i]; i++)
+            {
+                if (IsEqualGUID(&wic_format, wic_pixel_formats[i]))
+                {
+                    source = (IWICBitmapSource*)frame;
+                    IWICBitmapSource_AddRef(source);
+                    gdip_format = wic_gdip_formats[i];
+                    break;
+                }
+            }
+            if (!source)
+            {
+                /* unknown format; fall back on 32bppARGB */
+                hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
+                gdip_format = PixelFormat32bppARGB;
+            }
+        }
+
+        if (SUCCEEDED(hr)) /* got source */
+        {
+            hr = IWICBitmapSource_GetSize(source, &width, &height);
+
+            if (SUCCEEDED(hr))
+                status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
+                    NULL, &bitmap);
+
+            if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
+            {
+                status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
+                    gdip_format, &lockeddata);
+                if (status == Ok) /* locked bitmap */
+                {
+                    wrc.X = 0;
+                    wrc.Width = width;
+                    wrc.Height = 1;
+                    for (i=0; i<height; i++)
+                    {
+                        wrc.Y = i;
+                        hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
+                            abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
+                        if (FAILED(hr)) break;
+                    }
+
+                    GdipBitmapUnlockBits(bitmap, &lockeddata);
+                }
+
+                if (SUCCEEDED(hr) && status == Ok)
+                    *image = (GpImage*)bitmap;
+                else
+                {
+                    *image = NULL;
+                    GdipDisposeImage((GpImage*)bitmap);
+                }
+            }
+
+            IWICBitmapSource_Release(source);
+        }
+
+        IWICBitmapFrameDecode_Release(frame);
+    }
+
+    IWICBitmapDecoder_Release(decoder);
+
+end:
+    if (SUCCEEDED(initresult)) CoUninitialize();
+
+    if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
+
+    return status;
+}
+
+static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+    return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
+}
+
+static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+    return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
+}
+
+static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+    return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
+}
+
+static GpStatus decode_image_olepicture_bitmap(IStream* stream, REFCLSID clsid, GpImage **image)
 {
     IPicture *pic;
-    short type;
+    BITMAPINFO *pbmi;
+    BITMAPCOREHEADER* bmch;
+    HBITMAP hbm;
+    HDC hdc;
 
     TRACE("%p %p\n", stream, image);
 
@@ -1159,94 +1536,188 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
         return GenericError;
     }
 
-    IPicture_get_Type(pic, &type);
+    pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    if (!pbmi)
+        return OutOfMemory;
+    *image = GdipAlloc(sizeof(GpBitmap));
+    if(!*image){
+        GdipFree(pbmi);
+        return OutOfMemory;
+    }
+    (*image)->type = ImageTypeBitmap;
 
-    if(type == PICTYPE_BITMAP){
-        BITMAPINFO *pbmi;
-        BITMAPCOREHEADER* bmch;
-        HBITMAP hbm;
-        HDC hdc;
+    (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
+    (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
 
-        pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-        if (!pbmi)
-            return OutOfMemory;
-        *image = GdipAlloc(sizeof(GpBitmap));
-        if(!*image){
-            GdipFree(pbmi);
-            return OutOfMemory;
-        }
-        (*image)->type = ImageTypeBitmap;
+    /* get the pixel format */
+    IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
+    IPicture_get_CurDC(pic, &hdc);
 
-        (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
-        (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
+    (*((GpBitmap**) image))->hbitmap = hbm;
+    (*((GpBitmap**) image))->hdc = hdc;
+    (*((GpBitmap**) image))->bits = NULL;
 
-        /* get the pixel format */
-        IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
-        IPicture_get_CurDC(pic, &hdc);
+    bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
+    bmch->bcSize = sizeof(BITMAPCOREHEADER);
 
-        bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
-        bmch->bcSize = sizeof(BITMAPCOREHEADER);
+    if(!hdc){
+        HBITMAP old;
+        hdc = CreateCompatibleDC(0);
+        old = SelectObject(hdc, hbm);
+        GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+        SelectObject(hdc, old);
+        DeleteDC(hdc);
+    }
+    else
+        GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
 
-        if(!hdc){
-            HBITMAP old;
-            hdc = CreateCompatibleDC(0);
-            old = SelectObject(hdc, hbm);
-            GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
-            SelectObject(hdc, old);
-            DeleteDC(hdc);
-        }
-        else
-            GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+    switch(bmch->bcBitCount)
+    {
+        case 1:
+            (*((GpBitmap**) image))->format = PixelFormat1bppIndexed;
+            break;
+        case 4:
+            (*((GpBitmap**) image))->format = PixelFormat4bppIndexed;
+            break;
+        case 8:
+            (*((GpBitmap**) image))->format = PixelFormat8bppIndexed;
+            break;
+        case 16:
+            (*((GpBitmap**) image))->format = PixelFormat16bppRGB565;
+            break;
+        case 24:
+            (*((GpBitmap**) image))->format = PixelFormat24bppRGB;
+            break;
+        case 32:
+            (*((GpBitmap**) image))->format = PixelFormat32bppRGB;
+            break;
+        case 48:
+            (*((GpBitmap**) image))->format = PixelFormat48bppRGB;
+            break;
+        default:
+            FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount);
+            (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
+            break;
+    }
 
-        switch(bmch->bcBitCount)
-        {
-            case 1:
-                (*((GpBitmap**) image))->format = PixelFormat1bppIndexed;
-                break;
-            case 4:
-                (*((GpBitmap**) image))->format = PixelFormat4bppIndexed;
-                break;
-            case 8:
-                (*((GpBitmap**) image))->format = PixelFormat8bppIndexed;
-                break;
-            case 16:
-                (*((GpBitmap**) image))->format = PixelFormat16bppRGB565;
-                break;
-            case 24:
-                (*((GpBitmap**) image))->format = PixelFormat24bppRGB;
-                break;
-            case 32:
-                (*((GpBitmap**) image))->format = PixelFormat32bppRGB;
-                break;
-            case 48:
-                (*((GpBitmap**) image))->format = PixelFormat48bppRGB;
-                break;
-            default:
-                FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount);
-                (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
-                break;
-        }
+    GdipFree(pbmi);
 
-        GdipFree(pbmi);
-    }
-    else if(type == PICTYPE_METAFILE || type == PICTYPE_ENHMETAFILE){
-        /* FIXME: missing initialization code */
-        *image = GdipAlloc(sizeof(GpMetafile));
-        if(!*image) return OutOfMemory;
-        (*image)->type = ImageTypeMetafile;
-    }
-    else{
-        *image = GdipAlloc(sizeof(GpImage));
-        if(!*image) return OutOfMemory;
-        (*image)->type = ImageTypeUnknown;
+    (*image)->picture = pic;
+    (*image)->flags   = ImageFlagsNone;
+
+    return Ok;
+}
+
+static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+    IPicture *pic;
+
+    TRACE("%p %p\n", stream, image);
+
+    if(!stream || !image)
+        return InvalidParameter;
+
+    if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
+        (LPVOID*) &pic) != S_OK){
+        TRACE("Could not load picture\n");
+        return GenericError;
     }
 
+    /* FIXME: missing initialization code */
+    *image = GdipAlloc(sizeof(GpMetafile));
+    if(!*image) return OutOfMemory;
+    (*image)->type = ImageTypeMetafile;
     (*image)->picture = pic;
     (*image)->flags   = ImageFlagsNone;
 
     return Ok;
 }
 
+typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
+    GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
+
+typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image);
+
+typedef struct image_codec {
+    ImageCodecInfo info;
+    encode_image_func encode_func;
+    decode_image_func decode_func;
+} image_codec;
+
+typedef enum {
+    BMP,
+    JPEG,
+    GIF,
+    EMF,
+    WMF,
+    PNG,
+    ICO,
+    NUM_CODECS
+} ImageFormat;
+
+static const struct image_codec codecs[NUM_CODECS];
+
+static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
+{
+    BYTE signature[8];
+    LARGE_INTEGER seek;
+    HRESULT hr;
+    UINT bytesread;
+    int i, j;
+
+    /* seek to the start of the stream */
+    seek.QuadPart = 0;
+    hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) return hresult_to_status(hr);
+
+    /* read the first 8 bytes */
+    /* FIXME: This assumes all codecs have one signature <= 8 bytes in length */
+    hr = IStream_Read(stream, signature, 8, &bytesread);
+    if (FAILED(hr)) return hresult_to_status(hr);
+    if (hr == S_FALSE || bytesread == 0) return GenericError;
+
+    for (i = 0; i < NUM_CODECS; i++) {
+        if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
+            bytesread >= codecs[i].info.SigSize)
+        {
+            for (j=0; j<codecs[i].info.SigSize; j++)
+                if ((signature[j] & codecs[i].info.SigMask[j]) != codecs[i].info.SigPattern[j])
+                    break;
+            if (j == codecs[i].info.SigSize)
+            {
+                *result = &codecs[i];
+                return Ok;
+            }
+        }
+    }
+
+    TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
+        signature[0],signature[1],signature[2],signature[3],
+        signature[4],signature[5],signature[6],signature[7]);
+
+    return GenericError;
+}
+
+GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
+{
+    GpStatus stat;
+    LARGE_INTEGER seek;
+    HRESULT hr;
+    const struct image_codec *codec=NULL;
+
+    /* choose an appropriate image decoder */
+    stat = get_decoder_info(stream, &codec);
+    if (stat != Ok) return stat;
+
+    /* seek to the start of the stream */
+    seek.QuadPart = 0;
+    hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) return hresult_to_status(hr);
+
+    /* call on the image decoder to do the real work */
+    return codec->decode_func(stream, &codec->info.Clsid, image);
+}
+
 /* FIXME: no ICM */
 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
 {
@@ -1290,9 +1761,6 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam
     if (!image || !filename|| !clsidEncoder)
         return InvalidParameter;
 
-    if (!(image->picture))
-        return InvalidParameter;
-
     stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
     if (stat != Ok)
         return GenericError;
@@ -1313,62 +1781,139 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam
 #define BITMAP_FORMAT_PNG   0x5089
 #define BITMAP_FORMAT_APM   0xcdd7
 
-static GpStatus encode_image_BMP(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
-                                 void **output, unsigned int *output_size)
+static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
+    GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
 {
-    int num_palette_entries;
-    BITMAPFILEHEADER *bmp_file_hdr;
-    BITMAPINFO *bmp_info_hdr;
+    GpStatus stat;
+    GpBitmap *bitmap;
+    IWICBitmapEncoder *encoder;
+    IWICBitmapFrameEncode *frameencode;
+    IPropertyBag2 *encoderoptions;
+    HRESULT hr;
+    UINT width, height;
+    PixelFormat gdipformat=0;
+    WICPixelFormatGUID wicformat;
+    GpRect rc;
+    BitmapData lockeddata;
+    HRESULT initresult;
+    UINT i;
+
+    if (image->type != ImageTypeBitmap)
+        return GenericError;
 
-    if (bitmap_info->bmiHeader.biClrUsed) {
-        num_palette_entries = bitmap_info->bmiHeader.biClrUsed;
-        if (num_palette_entries > 256) num_palette_entries = 256;
-    } else {
-        if (bitmap_info->bmiHeader.biBitCount <= 8)
-            num_palette_entries = 1 << bitmap_info->bmiHeader.biBitCount;
-        else
-            num_palette_entries = 0;
+    bitmap = (GpBitmap*)image;
+
+    GdipGetImageWidth(image, &width);
+    GdipGetImageHeight(image, &height);
+
+    rc.X = 0;
+    rc.Y = 0;
+    rc.Width = width;
+    rc.Height = height;
+
+    initresult = CoInitialize(NULL);
+
+    hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICBitmapEncoder, (void**)&encoder);
+    if (FAILED(hr))
+    {
+        if (SUCCEEDED(initresult)) CoUninitialize();
+        return hresult_to_status(hr);
     }
 
-    *output_size =
-        sizeof(BITMAPFILEHEADER) +
-        sizeof(BITMAPINFOHEADER) +
-        num_palette_entries * sizeof(RGBQUAD) +
-        bitmap_info->bmiHeader.biSizeImage;
+    hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
 
-    *output = GdipAlloc(*output_size);
+    if (SUCCEEDED(hr))
+    {
+        hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
+    }
 
-    bmp_file_hdr = *output;
-    bmp_file_hdr->bfType = BITMAP_FORMAT_BMP;
-    bmp_file_hdr->bfSize = *output_size;
-    bmp_file_hdr->bfOffBits =
-        sizeof(BITMAPFILEHEADER) +
-        sizeof(BITMAPINFOHEADER) +
-        num_palette_entries * sizeof (RGBQUAD);
+    if (SUCCEEDED(hr)) /* created frame */
+    {
+        hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
 
-    bmp_info_hdr = (BITMAPINFO*) ((unsigned char*)(*output) + sizeof(BITMAPFILEHEADER));
-    memcpy(bmp_info_hdr, bitmap_info, sizeof(BITMAPINFOHEADER) + num_palette_entries * sizeof(RGBQUAD));
-    memcpy((unsigned char *)(*output) +
-           sizeof(BITMAPFILEHEADER) +
-           sizeof(BITMAPINFOHEADER) +
-           num_palette_entries * sizeof(RGBQUAD),
-           bitmap_bits, bitmap_info->bmiHeader.biSizeImage);
+        if (SUCCEEDED(hr))
+            hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
 
-    return Ok;
-}
+        if (SUCCEEDED(hr))
+            /* FIXME: use the resolution from the image */
+            hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0);
 
-typedef GpStatus encode_image_func(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
-                                   void **output, unsigned int *output_size);
+        if (SUCCEEDED(hr))
+        {
+            for (i=0; wic_pixel_formats[i]; i++)
+            {
+                if (wic_gdip_formats[i] == bitmap->format)
+                    break;
+            }
+            if (wic_pixel_formats[i])
+                memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID));
+            else
+                memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+
+            hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
+
+            for (i=0; wic_pixel_formats[i]; i++)
+            {
+                if (IsEqualGUID(&wicformat, wic_pixel_formats[i]))
+                    break;
+            }
+            if (wic_pixel_formats[i])
+                gdipformat = wic_gdip_formats[i];
+            else
+            {
+                ERR("cannot provide pixel format %s\n", debugstr_guid(&wicformat));
+                hr = E_FAIL;
+            }
+        }
 
-typedef enum {
-    BMP,
-    NUM_ENCODERS_SUPPORTED
-} ImageFormat;
+        if (SUCCEEDED(hr))
+        {
+            stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
+                &lockeddata);
+
+            if (stat == Ok)
+            {
+                UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
+                BYTE *row;
+
+                /* write one row at a time in case stride is negative */
+                row = lockeddata.Scan0;
+                for (i=0; i<lockeddata.Height; i++)
+                {
+                    hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
+                    if (FAILED(hr)) break;
+                    row += lockeddata.Stride;
+                }
+
+                GdipBitmapUnlockBits(bitmap, &lockeddata);
+            }
+            else
+                hr = E_FAIL;
+        }
 
-static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED];
-static encode_image_func *const encode_image_funcs[NUM_ENCODERS_SUPPORTED] = {
-    encode_image_BMP,
-};
+        if (SUCCEEDED(hr))
+            hr = IWICBitmapFrameEncode_Commit(frameencode);
+
+        IWICBitmapFrameEncode_Release(frameencode);
+        IPropertyBag2_Release(encoderoptions);
+    }
+
+    if (SUCCEEDED(hr))
+        hr = IWICBitmapEncoder_Commit(encoder);
+
+    IWICBitmapEncoder_Release(encoder);
+
+    if (SUCCEEDED(initresult)) CoUninitialize();
+
+    return hresult_to_status(hr);
+}
+
+static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
+    GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+{
+    return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
+}
 
 /*****************************************************************************
  * GdipSaveImageToStream [GDIPLUS.@]
@@ -1377,84 +1922,43 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
 {
     GpStatus stat;
-    HRESULT hr;
-    short type;
-    HBITMAP hbmp;
-    HBITMAP old_hbmp;
-    HDC hdc;
-    int bm_is_selected;
-    BITMAPINFO bmp_info;
-    LPVOID bmp_bits;
-    encode_image_func* encode_image;
-    LPVOID output;
-    unsigned int output_size;
-    unsigned int dummy;
+    encode_image_func encode_image;
     int i;
 
-    old_hbmp = 0;
-    output = NULL;
-    output_size = 0;
-
     TRACE("%p %p %p %p\n", image, stream, clsid, params);
 
     if(!image || !stream)
         return InvalidParameter;
 
-    if (!image->picture)
-        return GenericError;
-
-    hr = IPicture_get_Type(image->picture, &type);
-    if (FAILED(hr) || type != PICTYPE_BITMAP)
-        return GenericError;
-
     /* select correct encoder */
     encode_image = NULL;
-    for (i = 0; i < NUM_ENCODERS_SUPPORTED; i++) {
-        if (IsEqualCLSID(clsid, &codecs[i].Clsid))
-            encode_image = encode_image_funcs[i];
+    for (i = 0; i < NUM_CODECS; i++) {
+        if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
+            IsEqualCLSID(clsid, &codecs[i].info.Clsid))
+            encode_image = codecs[i].encode_func;
     }
     if (encode_image == NULL)
         return UnknownImageFormat;
 
-    /* extract underlying hbitmap representation from the IPicture */
-    hr = IPicture_get_Handle(image->picture, (OLE_HANDLE*)&hbmp);
-    if (FAILED(hr) || !hbmp)
-        return GenericError;
-    hr = IPicture_get_CurDC(image->picture, &hdc);
-    if (FAILED(hr))
-        return GenericError;
-    bm_is_selected = (hdc != 0);
-    if (!bm_is_selected) {
-        hdc = CreateCompatibleDC(0);
-        old_hbmp = SelectObject(hdc, hbmp);
-    }
-
-    /* get bits from HBITMAP */
-    bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
-    bmp_info.bmiHeader.biBitCount = 0;
-    GetDIBits(hdc, hbmp, 0, 0, NULL, &bmp_info, DIB_RGB_COLORS);
-
-    bmp_bits = GdipAlloc(bmp_info.bmiHeader.biSizeImage);
+    stat = encode_image(image, stream, clsid, params);
 
-    if (bmp_bits)
-        GetDIBits(hdc, hbmp, 0, abs(bmp_info.bmiHeader.biHeight), bmp_bits, &bmp_info, DIB_RGB_COLORS);
-
-    if (!bm_is_selected) {
-        SelectObject(hdc, old_hbmp);
-        DeleteDC(hdc);
-    }
+    return stat;
+}
 
-    if (!bmp_bits)
-        return OutOfMemory;
+/*****************************************************************************
+ * GdipGetImagePalette [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
+{
+    static int calls = 0;
 
-    stat = encode_image(bmp_bits, &bmp_info, &output, &output_size);
-    if (stat == Ok)
-        IStream_Write(stream, output, output_size, &dummy);
+    if(!image)
+        return InvalidParameter;
 
-    GdipFree(output);
-    GdipFree(bmp_bits);
+    if(!(calls++))
+        FIXME("not implemented\n");
 
-    return stat;
+    return NotImplemented;
 }
 
 /*****************************************************************************
@@ -1487,7 +1991,49 @@ static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
 
-static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED] =
+static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
+static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
+static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
+static const WCHAR jpeg_format[] = {'J','P','E','G',0};
+static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
+static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
+
+static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
+static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
+static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
+static const WCHAR gif_format[] = {'G','I','F',0};
+static const BYTE gif_sig_pattern[4] = "GIF8";
+static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
+static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
+static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
+static const WCHAR emf_format[] = {'E','M','F',0};
+static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
+static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
+static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
+static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
+static const WCHAR wmf_format[] = {'W','M','F',0};
+static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
+static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
+
+static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
+static const WCHAR png_extension[] = {'*','.','P','N','G',0};
+static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
+static const WCHAR png_format[] = {'P','N','G',0};
+static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
+static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
+static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
+static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
+static const WCHAR ico_format[] = {'I','C','O',0};
+static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
+static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const struct image_codec codecs[NUM_CODECS] = {
     {
         { /* BMP */
             /* Clsid */              { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
@@ -1504,20 +2050,145 @@ static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED] =
             /* SigPattern */         bmp_sig_pattern,
             /* SigMask */            bmp_sig_mask,
         },
-    };
+        encode_image_BMP,
+        decode_image_olepicture_bitmap
+    },
+    {
+        { /* JPEG */
+            /* Clsid */              { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+            /* FormatID */           { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+            /* CodecName */          jpeg_codecname,
+            /* DllName */            NULL,
+            /* FormatDescription */  jpeg_format,
+            /* FilenameExtension */  jpeg_extension,
+            /* MimeType */           jpeg_mimetype,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+            /* Version */            1,
+            /* SigCount */           1,
+            /* SigSize */            2,
+            /* SigPattern */         jpeg_sig_pattern,
+            /* SigMask */            jpeg_sig_mask,
+        },
+        NULL,
+        decode_image_jpeg
+    },
+    {
+        { /* GIF */
+            /* Clsid */              { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+            /* FormatID */           { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+            /* CodecName */          gif_codecname,
+            /* DllName */            NULL,
+            /* FormatDescription */  gif_format,
+            /* FilenameExtension */  gif_extension,
+            /* MimeType */           gif_mimetype,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+            /* Version */            1,
+            /* SigCount */           1,
+            /* SigSize */            4,
+            /* SigPattern */         gif_sig_pattern,
+            /* SigMask */            gif_sig_mask,
+        },
+        NULL,
+        decode_image_gif
+    },
+    {
+        { /* EMF */
+            /* Clsid */              { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+            /* FormatID */           { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+            /* CodecName */          emf_codecname,
+            /* DllName */            NULL,
+            /* FormatDescription */  emf_format,
+            /* FilenameExtension */  emf_extension,
+            /* MimeType */           emf_mimetype,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
+            /* Version */            1,
+            /* SigCount */           1,
+            /* SigSize */            4,
+            /* SigPattern */         emf_sig_pattern,
+            /* SigMask */            emf_sig_mask,
+        },
+        NULL,
+        decode_image_olepicture_metafile
+    },
+    {
+        { /* WMF */
+            /* Clsid */              { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+            /* FormatID */           { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+            /* CodecName */          wmf_codecname,
+            /* DllName */            NULL,
+            /* FormatDescription */  wmf_format,
+            /* FilenameExtension */  wmf_extension,
+            /* MimeType */           wmf_mimetype,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
+            /* Version */            1,
+            /* SigCount */           1,
+            /* SigSize */            2,
+            /* SigPattern */         wmf_sig_pattern,
+            /* SigMask */            wmf_sig_mask,
+        },
+        NULL,
+        decode_image_olepicture_metafile
+    },
+    {
+        { /* PNG */
+            /* Clsid */              { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+            /* FormatID */           { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+            /* CodecName */          png_codecname,
+            /* DllName */            NULL,
+            /* FormatDescription */  png_format,
+            /* FilenameExtension */  png_extension,
+            /* MimeType */           png_mimetype,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+            /* Version */            1,
+            /* SigCount */           1,
+            /* SigSize */            8,
+            /* SigPattern */         png_sig_pattern,
+            /* SigMask */            png_sig_mask,
+        },
+        NULL,
+        decode_image_olepicture_bitmap
+    },
+    {
+        { /* ICO */
+            /* Clsid */              { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+            /* FormatID */           { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+            /* CodecName */          ico_codecname,
+            /* DllName */            NULL,
+            /* FormatDescription */  ico_format,
+            /* FilenameExtension */  ico_extension,
+            /* MimeType */           ico_mimetype,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+            /* Version */            1,
+            /* SigCount */           1,
+            /* SigSize */            4,
+            /* SigPattern */         ico_sig_pattern,
+            /* SigMask */            ico_sig_mask,
+        },
+        NULL,
+        decode_image_icon
+    },
+};
 
 /*****************************************************************************
  * GdipGetImageDecodersSize [GDIPLUS.@]
  */
 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
 {
-    FIXME("%p %p stub!\n", numDecoders, size);
+    int decoder_count=0;
+    int i;
+    TRACE("%p %p\n", numDecoders, size);
 
     if (!numDecoders || !size)
         return InvalidParameter;
 
-    *numDecoders = 0;
-    *size = 0;
+    for (i=0; i<NUM_CODECS; i++)
+    {
+        if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
+            decoder_count++;
+    }
+
+    *numDecoders = decoder_count;
+    *size = decoder_count * sizeof(ImageCodecInfo);
 
     return Ok;
 }
@@ -1527,12 +2198,26 @@ GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
  */
 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
 {
-    FIXME("%u %u %p stub!\n", numDecoders, size, decoders);
+    int i, decoder_count=0;
+    TRACE("%u %u %p\n", numDecoders, size, decoders);
 
-    if (!decoders)
+    if (!decoders ||
+        size != numDecoders * sizeof(ImageCodecInfo))
         return GenericError;
 
-    return NotImplemented;
+    for (i=0; i<NUM_CODECS; i++)
+    {
+        if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
+        {
+            if (decoder_count == numDecoders) return GenericError;
+            memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
+            decoder_count++;
+        }
+    }
+
+    if (decoder_count < numDecoders) return GenericError;
+
+    return Ok;
 }
 
 /*****************************************************************************
@@ -1540,13 +2225,21 @@ GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodec
  */
 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
 {
+    int encoder_count=0;
+    int i;
     TRACE("%p %p\n", numEncoders, size);
 
     if (!numEncoders || !size)
         return InvalidParameter;
 
-    *numEncoders = NUM_ENCODERS_SUPPORTED;
-    *size = sizeof (codecs);
+    for (i=0; i<NUM_CODECS; i++)
+    {
+        if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
+            encoder_count++;
+    }
+
+    *numEncoders = encoder_count;
+    *size = encoder_count * sizeof(ImageCodecInfo);
 
     return Ok;
 }
@@ -1556,14 +2249,24 @@ GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
  */
 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
 {
+    int i, encoder_count=0;
     TRACE("%u %u %p\n", numEncoders, size, encoders);
 
     if (!encoders ||
-        (numEncoders != NUM_ENCODERS_SUPPORTED) ||
-        (size != sizeof (codecs)))
+        size != numEncoders * sizeof(ImageCodecInfo))
         return GenericError;
 
-    memcpy(encoders, codecs, sizeof (codecs));
+    for (i=0; i<NUM_CODECS; i++)
+    {
+        if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
+        {
+            if (encoder_count == numEncoders) return GenericError;
+            memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
+            encoder_count++;
+        }
+    }
+
+    if (encoder_count < numEncoders) return GenericError;
 
     return Ok;
 }
index 55bff18..8f49c67 100644 (file)
@@ -68,15 +68,16 @@ GpStatus WINGDIPAPI GdipDisposeImageAttributes(GpImageAttributes *imageattr)
 GpStatus WINGDIPAPI GdipSetImageAttributesColorKeys(GpImageAttributes *imageattr,
     ColorAdjustType type, BOOL enableFlag, ARGB colorLow, ARGB colorHigh)
 {
-    static int calls;
+    TRACE("(%p,%u,%i,%08x,%08x)\n", imageattr, type, enableFlag, colorLow, colorHigh);
 
-    if(!imageattr)
+    if(!imageattr || type >= ColorAdjustTypeCount)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    imageattr->colorkeys[type].enabled = enableFlag;
+    imageattr->colorkeys[type].low = colorLow;
+    imageattr->colorkeys[type].high = colorHigh;
 
-    return NotImplemented;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipSetImageAttributesColorMatrix(GpImageAttributes *imageattr,
index 8fe5e26..197b68a 100644 (file)
@@ -579,51 +579,63 @@ GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRe
  */
 GpStatus WINGDIPAPI GdipCreateRegionHrgn(HRGN hrgn, GpRegion **region)
 {
-    union {
-        RGNDATA data;
-        char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
-    } rdata;
     DWORD size;
-    GpRectF rectf;
-    GpPath *path;
+    LPRGNDATA buf;
+    LPRECT rect;
     GpStatus stat;
+    GpPath* path;
+    GpRegion* local;
+    int i;
 
     TRACE("(%p, %p)\n", hrgn, region);
 
     if(!region || !(size = GetRegionData(hrgn, 0, NULL)))
         return InvalidParameter;
 
-    if(size > sizeof(RGNDATAHEADER) + sizeof(RECT)){
-        FIXME("Only simple rect regions supported.\n");
-        *region = NULL;
-        return NotImplemented;
-    }
+    buf = GdipAlloc(size);
+    if(!buf)
+        return OutOfMemory;
 
-    if(!GetRegionData(hrgn, sizeof(rdata), &rdata.data))
+    if(!GetRegionData(hrgn, size, buf)){
+        GdipFree(buf);
         return GenericError;
-
-    /* return empty region */
-    if(IsRectEmpty(&rdata.data.rdh.rcBound)){
-        stat = GdipCreateRegion(region);
-        if(stat == Ok)
-            GdipSetEmpty(*region);
-        return stat;
     }
 
-    rectf.X = (REAL)rdata.data.rdh.rcBound.left;
-    rectf.Y = (REAL)rdata.data.rdh.rcBound.top;
-    rectf.Width  = (REAL)rdata.data.rdh.rcBound.right - rectf.X;
-    rectf.Height = (REAL)rdata.data.rdh.rcBound.bottom - rectf.Y;
+    if(buf->rdh.nCount == 0){
+        if((stat = GdipCreateRegion(&local)) != Ok){
+            GdipFree(buf);
+            return stat;
+        }
+        if((stat = GdipSetEmpty(local)) != Ok){
+            GdipFree(buf);
+            GdipDeleteRegion(local);
+            return stat;
+        }
+        *region = local;
+        GdipFree(buf);
+        return Ok;
+    }
 
-    stat = GdipCreatePath(FillModeAlternate, &path);
-    if(stat != Ok)
+    if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok){
+        GdipFree(buf);
         return stat;
+    }
 
-    GdipAddPathRectangle(path, rectf.X, rectf.Y, rectf.Width, rectf.Height);
+    rect = (LPRECT)buf->Buffer;
+    for(i = 0; i < buf->rdh.nCount; i++){
+        if((stat = GdipAddPathRectangle(path, (REAL)rect->left, (REAL)rect->top,
+                        (REAL)(rect->right - rect->left), (REAL)(rect->bottom - rect->top))) != Ok){
+            GdipFree(buf);
+            GdipDeletePath(path);
+            return stat;
+        }
+        rect++;
+    }
 
     stat = GdipCreateRegionPath(path, region);
-    GdipDeletePath(path);
 
+    GdipFree(buf);
+    GdipDeletePath(path);
     return stat;
 }
 
@@ -657,7 +669,8 @@ GpStatus WINGDIPAPI GdipGetRegionBounds(GpRegion *region, GpGraphics *graphics,
     if(!region || !graphics || !rect)
         return InvalidParameter;
 
-    status = GdipGetRegionHRgn(region, graphics, &hrgn);
+    /* Contrary to MSDN, native ignores the graphics transform. */
+    status = GdipGetRegionHRgn(region, NULL, &hrgn);
     if(status != Ok)
         return status;
 
@@ -1114,6 +1127,92 @@ GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *region, GpGraphics *graphics,
     return Ok;
 }
 
+/*****************************************************************************
+ * GdipIsVisibleRegionRect [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion* region, REAL x, REAL y, REAL w, REAL h, GpGraphics *graphics, BOOL *res)
+{
+    HRGN hrgn;
+    GpStatus stat;
+    RECT rect;
+
+    TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %p, %p)\n", region, x, y, w, h, graphics, res);
+
+    if(!region || !res)
+        return InvalidParameter;
+
+    if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
+        return stat;
+
+    /* infinite */
+    if(!hrgn){
+        *res = TRUE;
+        return Ok;
+    }
+
+    rect.left = ceilr(x);
+    rect.top = ceilr(y);
+    rect.right = ceilr(x + w);
+    rect.bottom = ceilr(y + h);
+
+    *res = RectInRegion(hrgn, &rect);
+
+    DeleteObject(hrgn);
+
+    return Ok;
+}
+
+/*****************************************************************************
+ * GdipIsVisibleRegionRectI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion* region, INT x, INT y, INT w, INT h, GpGraphics *graphics, BOOL *res)
+{
+    TRACE("(%p, %d, %d, %d, %d, %p, %p)\n", region, x, y, w, h, graphics, res);
+    if(!region || !res)
+        return InvalidParameter;
+
+    return GdipIsVisibleRegionRect(region, (REAL)x, (REAL)y, (REAL)w, (REAL)h, graphics, res);
+}
+
+/*****************************************************************************
+ * GdipIsVisibleRegionPoint [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionPoint(GpRegion* region, REAL x, REAL y, GpGraphics *graphics, BOOL *res)
+{
+    HRGN hrgn;
+    GpStatus stat;
+
+    TRACE("(%p, %.2f, %.2f, %p, %p)\n", region, x, y, graphics, res);
+
+    if(!region || !res)
+        return InvalidParameter;
+
+    if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
+        return stat;
+
+    /* infinite */
+    if(!hrgn){
+        *res = TRUE;
+        return Ok;
+    }
+
+    *res = PtInRegion(hrgn, roundr(x), roundr(y));
+
+    DeleteObject(hrgn);
+
+    return Ok;
+}
+
+/*****************************************************************************
+ * GdipIsVisibleRegionPointI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion* region, INT x, INT y, GpGraphics *graphics, BOOL *res)
+{
+    TRACE("(%p, %d, %d, %p, %p)\n", region, x, y, graphics, res);
+
+    return GdipIsVisibleRegionPoint(region, (REAL)x, (REAL)y, graphics, res);
+}
+
 /*****************************************************************************
  * GdipSetEmpty [GDIPLUS.@]
  */
index a7ee536..c06d951 100644 (file)
@@ -39,11 +39,15 @@ GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap*,R
 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap*,REAL);
 
 /* Bitmap */
+GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap*,CGpEffect*,RECT*,BOOL,VOID**,INT*);
+GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap**,INT,CGpEffect*,RECT*,RECT*,GpBitmap**,BOOL,VOID**,INT*);
 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap*,INT,INT,ARGB*);
 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap*,GDIPCONST GpRect*,UINT,
     PixelFormat,BitmapData*);
 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap*,INT,INT,ARGB);
 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap*,BitmapData*);
+GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL,REAL,REAL,REAL,PixelFormat,GpBitmap*,GpBitmap**);
+GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT,INT,INT,INT,PixelFormat,GpBitmap*,GpBitmap**);
 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR*,GpBitmap**);
 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR*,GpBitmap**);
 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO*,VOID*,GpBitmap**);
@@ -55,6 +59,9 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT,INT,INT,PixelFormat,BYTE*,
     GpBitmap**);
 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream*,GpBitmap**);
 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream*,GpBitmap**);
+GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap*,HBITMAP*,ARGB);
+GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap*,HICON*);
+GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect*);
 
 /* Brush */
 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush*,GpBrush**);
@@ -118,6 +125,11 @@ GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily *, INT, BOOL*);
 
 /* Graphics */
 GpStatus WINGDIPAPI GdipFlush(GpGraphics*, GpFlushIntention);
+GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics*,GDIPCONST GpRectF*,GDIPCONST GpRectF*,GpUnit,GraphicsContainer*);
+GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics*,GraphicsContainer*);
+GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics*,GDIPCONST GpRect*,GDIPCONST GpRect*,GpUnit,GraphicsContainer*);
+GpStatus WINGDIPAPI GdipEndContainer(GpGraphics*,GraphicsContainer);
+GpStatus WINGDIPAPI GdipComment(GpGraphics*,UINT,GDIPCONST BYTE*);
 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC,GpGraphics**);
 GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC,HANDLE,GpGraphics**);
 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND,GpGraphics**);
@@ -137,10 +149,16 @@ 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 GdipDrawCurve3(GpGraphics*,GpPen*,GDIPCONST GpPointF*,INT,INT,INT,REAL);
+GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics*,GpPen*,GDIPCONST GpPoint*,INT,INT,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 GdipDrawImagePointRect(GpGraphics*,GpImage*,REAL,REAL,REAL,REAL,REAL,REAL,GpUnit);
+GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics*,GpImage*,INT,INT,INT,INT,INT,INT,GpUnit);
+GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics*,GpImage*,GDIPCONST GpPointF*,INT);
+GpStatus WINGDIPAPI GdipDrawImagePointsI(GpGraphics*,GpImage*,GDIPCONST GpPoint*,INT);
 GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics*,GpImage*,
     GDIPCONST GpPointF*,INT,REAL,REAL,REAL,REAL,GpUnit,
     GDIPCONST GpImageAttributes*,DrawImageAbort,VOID*);
@@ -210,9 +228,13 @@ GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics*,UINT*);
 GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics*,TextRenderingHint*);
 GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics*,GpMatrix*);
 GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics*,ARGB);
+GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics*,GpRectF*);
+GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics*,GpRect*);
 GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics*, BOOL*);
 GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics*,REAL,REAL,BOOL*);
 GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics*,INT,INT,BOOL*);
+GpStatus WINGDIPAPI GdipIsVisibleRect(GpGraphics*,REAL,REAL,REAL,REAL,BOOL*);
+GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics*,INT,INT,INT,INT,BOOL*);
 GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics*, GDIPCONST WCHAR*,
     INT, GDIPCONST GpFont*, GDIPCONST RectF*, GDIPCONST GpStringFormat*, INT,
     GpRegion**);
@@ -281,6 +303,8 @@ GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath*,REAL,REAL,REAL,REAL);
 GpStatus WINGDIPAPI GdipAddPathRectangleI(GpPath*,INT,INT,INT,INT);
 GpStatus WINGDIPAPI GdipAddPathRectangles(GpPath*,GDIPCONST GpRectF*,INT);
 GpStatus WINGDIPAPI GdipAddPathRectanglesI(GpPath*,GDIPCONST GpRect*,INT);
+GpStatus WINGDIPAPI GdipAddPathString(GpPath*,GDIPCONST WCHAR*,INT,GDIPCONST GpFontFamily*,INT,REAL,GDIPCONST RectF*,GDIPCONST GpStringFormat*);
+GpStatus WINGDIPAPI GdipAddPathStringI(GpPath*,GDIPCONST WCHAR*,INT,GDIPCONST GpFontFamily*,INT,REAL,GDIPCONST Rect*,GDIPCONST GpStringFormat*);
 GpStatus WINGDIPAPI GdipClearPathMarkers(GpPath*);
 GpStatus WINGDIPAPI GdipClonePath(GpPath*,GpPath**);
 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath*);
@@ -317,6 +341,7 @@ GpStatus WINGDIPAPI GdipTransformPath(GpPath*,GpMatrix*);
 GpStatus WINGDIPAPI GdipCloneImage(GpImage*, GpImage**);
 GpStatus WINGDIPAPI GdipCloneImageAttributes(GDIPCONST GpImageAttributes*,GpImageAttributes**);
 GpStatus WINGDIPAPI GdipDisposeImage(GpImage*);
+GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE,UINT,LPBYTE,INT,INT);
 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage*,ImageItemData*);
 GpStatus WINGDIPAPI GdipFindNextImageItem(GpImage*,ImageItemData*);
 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage*,UINT,UINT,PropertyItem*);
@@ -326,6 +351,7 @@ GpStatus WINGDIPAPI GdipGetImageFlags(GpImage*,UINT*);
 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage*,UINT*);
 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage*,REAL*);
 GpStatus WINGDIPAPI GdipGetImageItemData(GpImage*,ImageItemData*);
+GpStatus WINGDIPAPI GdipGetImagePalette(GpImage*,ColorPalette*,INT);
 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage*,PixelFormat*);
 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage*,GUID*);
 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage*,UINT,UINT,GpImage**,GetThumbnailImageAbort,VOID*);
@@ -389,6 +415,7 @@ GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient*,INT*);
 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient*,ARGB,ARGB);
 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient*,BOOL);
 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient*,REAL,REAL);
+GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient*,REAL,REAL);
 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient*,GpWrapMode);
 
 /* Matrix */
@@ -424,6 +451,8 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE,BOOL,
     GDIPCONST WmfPlaceableFileHeader*,GpMetafile**);
 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR*, GDIPCONST WmfPlaceableFileHeader*,
     GpMetafile**);
+GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR*,GpMetafile**);
+GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream*,GpMetafile**);
 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile*,UINT);
 
 /* MetafileHeader */
@@ -539,6 +568,10 @@ GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *, GpGraphics *, HRGN *);
 GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *, GpGraphics *, BOOL *);
 GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *, GpRegion *, GpGraphics *, BOOL *);
 GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *, GpGraphics *, BOOL *);
+GpStatus WINGDIPAPI GdipIsVisibleRegionPoint(GpRegion *, REAL, REAL, GpGraphics *, BOOL *);
+GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion *, INT, INT, GpGraphics *, BOOL *);
+GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion *, REAL, REAL, REAL, REAL, GpGraphics *, BOOL *);
+GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion *, INT, INT, INT, INT, GpGraphics *, BOOL *);
 GpStatus WINGDIPAPI GdipSetEmpty(GpRegion *);
 GpStatus WINGDIPAPI GdipSetInfinite(GpRegion *);
 GpStatus WINGDIPAPI GdipTransformRegion(GpRegion *, GpMatrix *);