[GDIPLUS] Sync with Wine Staging 1.7.47. CORE-9924
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 19 Jul 2015 13:31:15 +0000 (13:31 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 19 Jul 2015 13:31:15 +0000 (13:31 +0000)
svn path=/trunk/; revision=68437

reactos/dll/win32/gdiplus/font.c
reactos/dll/win32/gdiplus/gdiplus.rc
reactos/dll/win32/gdiplus/gdiplus.spec
reactos/dll/win32/gdiplus/gdiplus11.manifest [new file with mode: 0644]
reactos/dll/win32/gdiplus/gdiplus_private.h
reactos/dll/win32/gdiplus/graphics.c
reactos/dll/win32/gdiplus/image.c
reactos/dll/win32/gdiplus/metafile.c
reactos/dll/win32/gdiplus/region.c
reactos/media/doc/README.WINE

index 97df0d5..5630972 100644 (file)
@@ -450,7 +450,7 @@ GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, LOGFONTW
 
     matrix = graphics->worldtrans;
 
-    if (font->unit == UnitPixel)
+    if (font->unit == UnitPixel || font->unit == UnitWorld)
     {
         height = units_to_pixels(font->emSize, graphics->unit, graphics->yres);
         if (graphics->unit != UnitDisplay)
index 56f6c22..5c7e2cf 100644 (file)
@@ -20,3 +20,6 @@
 
 /* @makedep: gdiplus.manifest */
 WINE_MANIFEST 24 gdiplus.manifest
+
+/* @makedep: gdiplus11.manifest */
+WINE_MANIFEST11 24 gdiplus11.manifest
index cee3ea6..64c9b95 100644 (file)
 610 stdcall GdipFindFirstImageItem(ptr ptr)
 611 stub GdipFindNextImageItem
 612 stdcall GdipGetImageItemData(ptr ptr)
-613 stub GdipCreateEffect
+613 stdcall -stub GdipCreateEffect(ptr ptr)
 614 stdcall GdipDeleteEffect(ptr)
 615 stub GdipGetEffectParameterSize
 616 stub GdipGetEffectParameters
 621 stub GdipBitmapGetHistogram
 622 stub GdipBitmapGetHistogramSize
 623 stub GdipBitmapConvertFormat
-624 stub GdipImageSetAbort
+624 stdcall GdipImageSetAbort(ptr ptr)
 625 stub GdipGraphicsSetAbort
 626 stub GdipDrawImageFX
 627 stdcall GdipConvertToEmfPlus(ptr ptr ptr long ptr ptr)
diff --git a/reactos/dll/win32/gdiplus/gdiplus11.manifest b/reactos/dll/win32/gdiplus/gdiplus11.manifest
new file mode 100644 (file)
index 0000000..c39804b
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <assemblyIdentity type="win32" name="Microsoft.Windows.GdiPlus" version="1.1.7601.23038" processorArchitecture="" publicKeyToken="6595b64144ccf1df"/>
+  <file name="gdiplus.dll"/>
+</assembly>
index b983492..54e7664 100644 (file)
@@ -47,9 +47,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 #define MAX_DASHLEN (16) /* this is a limitation of gdi */
 #define INCH_HIMETRIC (2540)
 
-#define VERSION_MAGIC 0xdbc01001
+#define VERSION_MAGIC  0xdbc01001
+#define VERSION_MAGIC2 0xdbc01002
 #define TENSION_CONST (0.3)
 
+#define GIF_DISPOSE_UNSPECIFIED 0
+#define GIF_DISPOSE_DO_NOT_DISPOSE 1
+#define GIF_DISPOSE_RESTORE_TO_BKGND 2
+#define GIF_DISPOSE_RESTORE_TO_PREV 3
+
 COLORREF ARGB2COLORREF(ARGB color) DECLSPEC_HIDDEN;
 HBITMAP ARGB2BMP(ARGB color) DECLSPEC_HIDDEN;
 extern INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2,
@@ -124,6 +130,26 @@ static inline ARGB color_over(ARGB bg, ARGB fg)
     return (a<<24)|(r<<16)|(g<<8)|b;
 }
 
+/* fg is premult, bg and return value are not */
+static inline ARGB color_over_fgpremult(ARGB bg, ARGB fg)
+{
+    BYTE b, g, r, a;
+    BYTE bg_alpha, fg_alpha;
+
+    fg_alpha = (fg>>24)&0xff;
+
+    if (fg_alpha == 0) return bg;
+
+    bg_alpha = (((bg>>24)&0xff) * (0xff-fg_alpha)) / 0xff;
+
+    a = bg_alpha + fg_alpha;
+    b = ((bg&0xff)*bg_alpha + (fg&0xff)*0xff)/a;
+    g = (((bg>>8)&0xff)*bg_alpha + ((fg>>8)&0xff)*0xff)/a;
+    r = (((bg>>16)&0xff)*bg_alpha + ((fg>>16)&0xff)*0xff)/a;
+
+    return (a<<24)|(r<<16)|(g<<8)|b;
+}
+
 extern const char *debugstr_rectf(const RectF* rc) DECLSPEC_HIDDEN;
 
 extern const char *debugstr_pointf(const PointF* pt) DECLSPEC_HIDDEN;
@@ -278,7 +304,7 @@ struct GpAdustableArrowCap{
 
 struct GpImage{
     IPicture *picture;
-    IStream *stream; /* source stream */
+    IWICBitmapDecoder *decoder;
     ImageType type;
     GUID format;
     UINT flags;
index 0e796ab..cdb5541 100644 (file)
@@ -247,6 +247,7 @@ static INT prepare_dc(GpGraphics *graphics, GpPen *pen)
                      (pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
 
         width *= units_to_pixels(pen->width, pen->unit == UnitWorld ? graphics->unit : pen->unit, graphics->xres);
+        width *= graphics->scale;
     }
 
     if(pen->dash == DashStyleCustom){
@@ -349,21 +350,28 @@ static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
     return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
 }
 
-/* Draw non-premultiplied ARGB data to the given graphics object */
+/* Draw ARGB data to the given graphics object */
 static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
-    const BYTE *src, INT src_width, INT src_height, INT src_stride)
+    const BYTE *src, INT src_width, INT src_height, INT src_stride, const PixelFormat fmt)
 {
     GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
     INT x, y;
 
-    for (x=0; x<src_width; x++)
+    for (y=0; y<src_height; y++)
     {
-        for (y=0; y<src_height; y++)
+        for (x=0; x<src_width; x++)
         {
             ARGB dst_color, src_color;
-            GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
             src_color = ((ARGB*)(src + src_stride * y))[x];
-            GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
+
+            if (!(src_color & 0xff000000))
+                continue;
+
+            GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
+            if (fmt & PixelFormatPAlpha)
+                GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over_fgpremult(dst_color, src_color));
+            else
+                GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
         }
     }
 
@@ -371,7 +379,7 @@ static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_
 }
 
 static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
-    const BYTE *src, INT src_width, INT src_height, INT src_stride)
+    const BYTE *src, INT src_width, INT src_height, INT src_stride, PixelFormat fmt)
 {
     HDC hdc;
     HBITMAP hbitmap;
@@ -395,7 +403,8 @@ static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_
     hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
         (void**)&temp_bits, NULL, 0);
 
-    if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE)
+    if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE ||
+            fmt & PixelFormatPAlpha)
         memcpy(temp_bits, src, src_width * src_height * 4);
     else
         convert_32bppARGB_to_32bppPARGB(src_width, src_height, temp_bits,
@@ -411,7 +420,7 @@ static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_
 }
 
 static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst_y,
-    const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion)
+    const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion, PixelFormat fmt)
 {
     GpStatus stat=Ok;
 
@@ -461,7 +470,7 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst
             stat = alpha_blend_bmp_pixels(graphics, rects[i].left, rects[i].top,
                 &src[(rects[i].left - dst_x) * 4 + (rects[i].top - dst_y) * src_stride],
                 rects[i].right - rects[i].left, rects[i].bottom - rects[i].top,
-                src_stride);
+                src_stride, fmt);
         }
 
         GdipFree(rgndata);
@@ -494,7 +503,7 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst
             ExtSelectClipRgn(graphics->hdc, hregion, RGN_AND);
 
         stat = alpha_blend_hdc_pixels(graphics, dst_x, dst_y, src, src_width,
-            src_height, src_stride);
+            src_height, src_stride, fmt);
 
         RestoreDC(graphics->hdc, save);
 
@@ -505,27 +514,29 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst
 }
 
 static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
-    const BYTE *src, INT src_width, INT src_height, INT src_stride)
+    const BYTE *src, INT src_width, INT src_height, INT src_stride, PixelFormat fmt)
 {
-    return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL);
+    return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL, fmt);
 }
 
 static ARGB blend_colors(ARGB start, ARGB end, REAL position)
 {
-    ARGB result=0;
-    ARGB i;
-    INT a1, a2, a3;
+    INT start_a, end_a, final_a;
+    INT pos;
 
-    a1 = (start >> 24) & 0xff;
-    a2 = (end >> 24) & 0xff;
+    pos = gdip_round(position * 0xff);
 
-    a3 = (int)(a1*(1.0f - position)+a2*(position));
+    start_a = ((start >> 24) & 0xff) * (pos ^ 0xff);
+    end_a = ((end >> 24) & 0xff) * pos;
 
-    result |= a3 << 24;
+    final_a = start_a + end_a;
 
-    for (i=0xff; i<=0xff0000; i = i << 8)
-        result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
-    return result;
+    if (final_a < 0xff) return 0;
+
+    return (final_a / 0xff) << 24 |
+        ((((start >> 16) & 0xff) * start_a + (((end >> 16) & 0xff) * end_a)) / final_a) << 16 |
+        ((((start >> 8) & 0xff) * start_a + (((end >> 8) & 0xff) * end_a)) / final_a) << 8 |
+        (((start & 0xff) * start_a + ((end & 0xff) * end_a)) / final_a);
 }
 
 static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
@@ -645,8 +656,9 @@ static BOOL color_is_gray(ARGB color)
     return (r == g) && (g == b);
 }
 
-static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
-    UINT width, UINT height, INT stride, ColorAdjustType type)
+/* returns preferred pixel format for the applied attributes */
+static PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
+    UINT width, UINT height, INT stride, ColorAdjustType type, PixelFormat fmt)
 {
     UINT x, y;
     INT i;
@@ -658,6 +670,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
         BYTE min_blue, min_green, min_red;
         BYTE max_blue, max_green, max_red;
 
+        if (!data || fmt != PixelFormat32bppARGB)
+            return PixelFormat32bppARGB;
+
         if (attributes->colorkeys[type].enabled)
             key = &attributes->colorkeys[type];
         else
@@ -691,6 +706,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
     {
         const struct color_remap_table *table;
 
+        if (!data || fmt != PixelFormat32bppARGB)
+            return PixelFormat32bppARGB;
+
         if (attributes->colorremaptables[type].enabled)
             table = &attributes->colorremaptables[type];
         else
@@ -720,6 +738,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
         int gray_matrix[5][5];
         BOOL identity;
 
+        if (!data || fmt != PixelFormat32bppARGB)
+            return PixelFormat32bppARGB;
+
         if (attributes->colormatrices[type].enabled)
             colormatrices = &attributes->colormatrices[type];
         else
@@ -758,6 +779,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
     {
         REAL gamma;
 
+        if (!data || fmt != PixelFormat32bppARGB)
+            return PixelFormat32bppARGB;
+
         if (attributes->gamma_enabled[type])
             gamma = attributes->gamma[type];
         else
@@ -782,6 +806,8 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
                 *src_color = (*src_color & 0xff000000) | (red << 16) | (green << 8) | blue;
             }
     }
+
+    return fmt;
 }
 
 /* Given a bitmap and its source rectangle, find the smallest rectangle in the
@@ -1226,7 +1252,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
             if (stat == Ok)
                 apply_image_attributes(fill->imageattributes, fill->bitmap_bits,
                     bitmap->width, bitmap->height,
-                    src_stride, ColorAdjustTypeBitmap);
+                    src_stride, ColorAdjustTypeBitmap, lockeddata.PixelFormat);
 
             if (stat != Ok)
             {
@@ -2115,7 +2141,7 @@ static void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font,
     HFONT unscaled_font;
     TEXTMETRICW textmet;
 
-    if (font->unit == UnitPixel)
+    if (font->unit == UnitPixel || font->unit == UnitWorld)
         font_height = font->emSize;
     else
     {
@@ -2138,8 +2164,8 @@ static void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font,
         GpMatrix xform = *matrix;
         GdipTransformMatrixPoints(&xform, pt, 3);
     }
-    if (graphics)
-        GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+
+    GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
     angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
     rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+
                      (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X));
@@ -2979,15 +3005,18 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
                 return OutOfMemory;
             src_stride = sizeof(ARGB) * src_area.Width;
 
-            /* Read the bits we need from the source bitmap into an ARGB buffer. */
+            /* Read the bits we need from the source bitmap into a compatible buffer. */
             lockeddata.Width = src_area.Width;
             lockeddata.Height = src_area.Height;
             lockeddata.Stride = src_stride;
-            lockeddata.PixelFormat = PixelFormat32bppARGB;
             lockeddata.Scan0 = src_data;
+            if (!do_resampling && bitmap->format == PixelFormat32bppPARGB)
+                lockeddata.PixelFormat = apply_image_attributes(imageAttributes, NULL, 0, 0, 0, ColorAdjustTypeBitmap, bitmap->format);
+            else
+                lockeddata.PixelFormat = PixelFormat32bppARGB;
 
             stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf,
-                PixelFormat32bppARGB, &lockeddata);
+                lockeddata.PixelFormat, &lockeddata);
 
             if (stat == Ok)
                 stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
@@ -3000,7 +3029,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
 
             apply_image_attributes(imageAttributes, src_data,
                 src_area.Width, src_area.Height,
-                src_stride, ColorAdjustTypeBitmap);
+                src_stride, ColorAdjustTypeBitmap, lockeddata.PixelFormat);
 
             if (do_resampling)
             {
@@ -3048,7 +3077,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             }
 
             stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
-                dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride);
+                dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride,
+                lockeddata.PixelFormat);
 
             GdipFree(src_data);
 
@@ -3998,7 +4028,8 @@ static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
             if (stat == Ok)
                 stat = alpha_blend_pixels_hrgn(graphics, gp_bound_rect.X,
                     gp_bound_rect.Y, (BYTE*)pixel_data, gp_bound_rect.Width,
-                    gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion);
+                    gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion,
+                    PixelFormat32bppARGB);
 
             GdipFree(pixel_data);
         }
@@ -4730,6 +4761,9 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
     scaled_rect.Width = layoutRect->Width * args.rel_width;
     scaled_rect.Height = layoutRect->Height * args.rel_height;
 
+    if (scaled_rect.Width >= 1 << 23) scaled_rect.Width = 1 << 23;
+    if (scaled_rect.Height >= 1 << 23) scaled_rect.Height = 1 << 23;
+
     get_font_hfont(graphics, font, stringFormat, &gdifont, NULL);
     oldfont = SelectObject(hdc, gdifont);
 
@@ -5705,7 +5739,7 @@ GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc)
     {
         stat = METAFILE_GetDC((GpMetafile*)graphics->image, hdc);
     }
-    else if (!graphics->hdc || graphics->alpha_hdc ||
+    else if (!graphics->hdc ||
         (graphics->image && graphics->image->type == ImageTypeBitmap && ((GpBitmap*)graphics->image)->format & PixelFormatAlpha))
     {
         /* Create a fake HDC and fill it with a constant color. */
@@ -5797,7 +5831,7 @@ GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc)
         /* Write the changed pixels to the real target. */
         alpha_blend_pixels(graphics, 0, 0, graphics->temp_bits,
             graphics->temp_hbitmap_width, graphics->temp_hbitmap_height,
-            graphics->temp_hbitmap_width * 4);
+            graphics->temp_hbitmap_width * 4, PixelFormat32bppARGB);
 
         /* Clean up. */
         DeleteDC(graphics->temp_hdc);
@@ -6352,7 +6386,7 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
 
     /* draw the result */
     stat = alpha_blend_pixels(graphics, min_x, min_y, pixel_data, pixel_area.Width,
-        pixel_area.Height, pixel_data_stride);
+        pixel_area.Height, pixel_data_stride, PixelFormat32bppARGB);
 
     GdipFree(pixel_data);
 
index 795bdf0..c2ee585 100644 (file)
@@ -23,6 +23,8 @@
 #include <ole2.h>
 #include <olectl.h>
 
+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
+
 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
 
 static const struct
@@ -52,8 +54,7 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT
     IWICPalette *wic_palette;
     ColorPalette *palette = NULL;
 
-    hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
-                          &IID_IWICImagingFactory, (void **)&factory);
+    hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
     if (hr != S_OK) return NULL;
 
     hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
@@ -69,22 +70,36 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT
         }
         if (hr == S_OK)
         {
+            WICBitmapPaletteType type;
+            BOOL alpha;
             UINT count;
-            BOOL mono, gray;
-
-            IWICPalette_IsBlackWhite(wic_palette, &mono);
-            IWICPalette_IsGrayscale(wic_palette, &gray);
 
             IWICPalette_GetColorCount(wic_palette, &count);
             palette = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(UINT) + count * sizeof(ARGB));
             IWICPalette_GetColors(wic_palette, count, palette->Entries, &palette->Count);
 
-            if (mono)
-                palette->Flags = 0;
-            else if (gray)
-                palette->Flags = PaletteFlagsGrayScale;
-            else
-                palette->Flags = PaletteFlagsHalftone;
+            IWICPalette_GetType(wic_palette, &type);
+            switch(type) {
+                case WICBitmapPaletteTypeFixedGray4:
+                case WICBitmapPaletteTypeFixedGray16:
+                case WICBitmapPaletteTypeFixedGray256:
+                    palette->Flags = PaletteFlagsGrayScale;
+                    break;
+                case WICBitmapPaletteTypeFixedHalftone8:
+                case WICBitmapPaletteTypeFixedHalftone27:
+                case WICBitmapPaletteTypeFixedHalftone64:
+                case WICBitmapPaletteTypeFixedHalftone125:
+                case WICBitmapPaletteTypeFixedHalftone216:
+                case WICBitmapPaletteTypeFixedHalftone252:
+                case WICBitmapPaletteTypeFixedHalftone256:
+                    palette->Flags = PaletteFlagsHalftone;
+                    break;
+                default:
+                    palette->Flags = 0;
+            }
+            IWICPalette_HasAlpha(wic_palette, &alpha);
+            if(alpha)
+                palette->Flags |= PaletteFlagsHasAlpha;
         }
         IWICPalette_Release(wic_palette);
     }
@@ -120,6 +135,15 @@ static INT ipicture_pixel_width(IPicture *pic)
     return x;
 }
 
+#ifndef __REACTOS__
+GpStatus WINGDIPAPI GdipCreateEffect(const GUID guid, CGpEffect **effect)
+{
+    FIXME("(%s, %p): stub\n", debugstr_guid(&guid), effect);
+    *effect = NULL;
+    return NotImplemented;
+}
+#endif
+
 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
     RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
 {
@@ -1853,7 +1877,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->height = height;
     (*bitmap)->format = format;
     (*bitmap)->image.picture = NULL;
-    (*bitmap)->image.stream = NULL;
+    (*bitmap)->image.decoder = NULL;
     (*bitmap)->hbitmap = hbitmap;
     (*bitmap)->hdc = NULL;
     (*bitmap)->bits = bits;
@@ -2070,9 +2094,9 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
     GdipFree(dst->prop_item);
     dst->prop_item = src->prop_item;
     dst->prop_count = src->prop_count;
-    if (dst->image.stream)
-        IStream_Release(dst->image.stream);
-    dst->image.stream = src->image.stream;
+    if (dst->image.decoder)
+        IWICBitmapDecoder_Release(dst->image.decoder);
+    dst->image.decoder = src->image.decoder;
     dst->image.frame_count = src->image.frame_count;
     dst->image.current_frame = src->image.current_frame;
     dst->image.format = src->image.format;
@@ -2118,8 +2142,8 @@ static GpStatus free_image_data(GpImage *image)
     }
     if (image->picture)
         IPicture_Release(image->picture);
-    if (image->stream)
-        IStream_Release(image->stream);
+    if (image->decoder)
+        IWICBitmapDecoder_Release(image->decoder);
     GdipFree(image->palette);
 
     return Ok;
@@ -3026,8 +3050,8 @@ static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, cons
     PROPVARIANT id, value;
     BOOL ret = FALSE;
 
-    IWICMetadataReader_GetMetadataFormat(reader, &format);
-    if (!IsEqualGUID(&format, guid)) return FALSE;
+    hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
+    if (FAILED(hr) || !IsEqualGUID(&format, guid)) return FALSE;
 
     PropVariantInit(&id);
     PropVariantInit(&value);
@@ -3053,8 +3077,8 @@ static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid,
     PROPVARIANT id, value;
     PropertyItem *item = NULL;
 
-    IWICMetadataReader_GetMetadataFormat(reader, &format);
-    if (!IsEqualGUID(&format, guid)) return NULL;
+    hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
+    if (FAILED(hr) || !IsEqualGUID(&format, guid)) return NULL;
 
     PropVariantInit(&id);
     PropVariantInit(&value);
@@ -3162,8 +3186,7 @@ static PropertyItem *get_gif_palette(IWICBitmapDecoder *decoder, IWICMetadataRea
     if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
         return NULL;
 
-    hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
-                          &IID_IWICImagingFactory, (void **)&factory);
+    hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
     if (hr != S_OK) return NULL;
 
     hr = IWICImagingFactory_CreatePalette(factory, &palette);
@@ -3221,14 +3244,13 @@ static PropertyItem *get_gif_transparent_idx(IWICMetadataReader *reader)
     return index;
 }
 
-static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
+static LONG get_gif_frame_property(IWICBitmapFrameDecode *frame, const GUID *format, const WCHAR *property)
 {
-    static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
     HRESULT hr;
     IWICMetadataBlockReader *block_reader;
     IWICMetadataReader *reader;
     UINT block_count, i;
-    PropertyItem *delay;
+    PropertyItem *prop;
     LONG value = 0;
 
     hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
@@ -3242,13 +3264,15 @@ static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
                 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
                 if (hr == S_OK)
                 {
-                    delay = get_property(reader, &GUID_MetadataFormatGCE, delayW);
-                    if (delay)
+                    prop = get_property(reader, format, property);
+                    if (prop)
                     {
-                        if (delay->type == PropertyTagTypeShort && delay->length == 2)
-                            value = *(SHORT *)delay->value;
+                        if (prop->type == PropertyTagTypeByte && prop->length == 1)
+                            value = *(BYTE *)prop->value;
+                        else if (prop->type == PropertyTagTypeShort && prop->length == 2)
+                            value = *(SHORT *)prop->value;
 
-                        GdipFree(delay);
+                        GdipFree(prop);
                     }
                     IWICMetadataReader_Release(reader);
                 }
@@ -3262,6 +3286,7 @@ static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
 
 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
 {
+    static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
     HRESULT hr;
     IWICBitmapFrameDecode *frame;
     IWICMetadataBlockReader *block_reader;
@@ -3290,7 +3315,7 @@ static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI
                 hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
                 if (hr == S_OK)
                 {
-                    value[i] = get_gif_frame_delay(frame);
+                    value[i] = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, delayW);
                     IWICBitmapFrameDecode_Release(frame);
                 }
                 else value[i] = 0;
@@ -3384,15 +3409,174 @@ static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI
     IWICBitmapFrameDecode_Release(frame);
 }
 
+static PropertyItem* create_prop(PROPID propid, PROPVARIANT* value)
+{
+    PropertyItem *item = NULL;
+    UINT item_size = propvariant_size(value);
+
+    if (item_size)
+    {
+        item_size += sizeof(*item);
+        item = GdipAlloc(item_size);
+        if (propvariant_to_item(value, item, item_size, propid) != Ok)
+        {
+            GdipFree(item);
+            item = NULL;
+        }
+    }
+
+    return item;
+}
+
+static ULONG get_ulong_by_index(IWICMetadataReader* reader, ULONG index)
+{
+    PROPVARIANT value;
+    HRESULT hr;
+    ULONG result=0;
+
+    hr = IWICMetadataReader_GetValueByIndex(reader, index, NULL, NULL, &value);
+    if (SUCCEEDED(hr))
+    {
+        switch (value.vt)
+        {
+        case VT_UI4:
+            result = value.u.ulVal;
+            break;
+        default:
+            ERR("unhandled case %u\n", value.vt);
+            break;
+        }
+        PropVariantClear(&value);
+    }
+    return result;
+}
+
+static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
+{
+    HRESULT hr;
+    IWICBitmapFrameDecode *frame;
+    IWICMetadataBlockReader *block_reader;
+    IWICMetadataReader *reader;
+    UINT block_count, i, j;
+    struct keyword_info {
+        const char* name;
+        PROPID propid;
+        BOOL seen;
+    } keywords[] = {
+        { "Title", PropertyTagImageTitle },
+        { "Author", PropertyTagArtist },
+        { "Description", PropertyTagImageDescription },
+        { "Copyright", PropertyTagCopyright },
+        { "Software", PropertyTagSoftwareUsed },
+        { "Source", PropertyTagEquipModel },
+        { "Comment", PropertyTagExifUserComment },
+    };
+    BOOL seen_gamma=FALSE;
+
+    hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
+    if (hr != S_OK) return;
+
+    hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
+    if (hr == S_OK)
+    {
+        hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
+        if (hr == S_OK)
+        {
+            for (i = 0; i < block_count; i++)
+            {
+                hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
+                if (hr == S_OK)
+                {
+                    GUID format;
+
+                    hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
+                    if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunktEXt, &format))
+                    {
+                        PROPVARIANT name, value;
+                        PropertyItem* item;
+
+                        hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &name, &value);
+
+                        if (SUCCEEDED(hr))
+                        {
+                            if (name.vt == VT_LPSTR)
+                            {
+                                for (j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++)
+                                    if (!strcmp(keywords[j].name, name.u.pszVal))
+                                        break;
+                                if (j < sizeof(keywords)/sizeof(keywords[0]) && !keywords[j].seen)
+                                {
+                                    keywords[j].seen = TRUE;
+                                    item = create_prop(keywords[j].propid, &value);
+                                    if (item)
+                                        add_property(bitmap, item);
+                                    GdipFree(item);
+                                }
+                            }
+
+                            PropVariantClear(&name);
+                            PropVariantClear(&value);
+                        }
+                    }
+                    else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkgAMA, &format))
+                    {
+                        PropertyItem* item;
+
+                        if (!seen_gamma)
+                        {
+                            item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 2);
+                            if (item)
+                            {
+                                ULONG *rational;
+                                item->length = sizeof(ULONG) * 2;
+                                item->type = PropertyTagTypeRational;
+                                item->id = PropertyTagGamma;
+                                rational = item->value = item + 1;
+                                rational[0] = 100000;
+                                rational[1] = get_ulong_by_index(reader, 0);
+                                add_property(bitmap, item);
+                                seen_gamma = TRUE;
+                                GdipFree(item);
+                            }
+                        }
+                    }
+
+                    IWICMetadataReader_Release(reader);
+                }
+            }
+        }
+        IWICMetadataBlockReader_Release(block_reader);
+    }
+
+    IWICBitmapFrameDecode_Release(frame);
+}
+
+static GpStatus initialize_decoder_wic(IStream *stream, REFGUID container, IWICBitmapDecoder **decoder)
+{
+    IWICImagingFactory *factory;
+    HRESULT hr;
+
+    TRACE("%p,%s\n", stream, wine_dbgstr_guid(container));
+
+    hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
+    if (FAILED(hr)) return hresult_to_status(hr);
+    hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, decoder);
+    IWICImagingFactory_Release(factory);
+    if (FAILED(hr)) return hresult_to_status(hr);
+
+    hr = IWICBitmapDecoder_Initialize(*decoder, stream, WICDecodeMetadataCacheOnLoad);
+    if (FAILED(hr)) return hresult_to_status(hr);
+    return Ok;
+}
+
 typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame);
 
-static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid,
+static GpStatus decode_frame_wic(IWICBitmapDecoder *decoder, BOOL force_conversion,
     UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
 {
     GpStatus status=Ok;
     GpBitmap *bitmap;
     HRESULT hr;
-    IWICBitmapDecoder *decoder;
     IWICBitmapFrameDecode *frame;
     IWICBitmapSource *source=NULL;
     IWICMetadataBlockReader *block_reader;
@@ -3404,48 +3588,36 @@ static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid,
     UINT width, height, frame_count;
     BitmapData lockeddata;
     WICRect wrc;
-    HRESULT initresult;
 
-    TRACE("%p,%s,%u,%p\n", stream, wine_dbgstr_guid(clsid), active_frame, image);
-
-    initresult = CoInitialize(NULL);
-
-    hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
-        &IID_IWICBitmapDecoder, (void**)&decoder);
-    if (FAILED(hr)) goto end;
-
-    hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
-    if (SUCCEEDED(hr))
-    {
-        IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
-        hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
-    }
+    TRACE("%p,%u,%p\n", decoder, active_frame, image);
 
+    IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
+    hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
     if (SUCCEEDED(hr)) /* got frame */
     {
         hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
 
         if (SUCCEEDED(hr))
         {
-            IWICBitmapSource *bmp_source;
-            IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICBitmapSource, (void **)&bmp_source);
-
-            for (i=0; pixel_formats[i].wic_format; i++)
+            if (!force_conversion)
             {
-                if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
+                for (i=0; pixel_formats[i].wic_format; i++)
                 {
-                    source = bmp_source;
-                    gdip_format = pixel_formats[i].gdip_format;
-                    palette_type = pixel_formats[i].palette_type;
-                    break;
+                    if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
+                    {
+                        source = (IWICBitmapSource*)frame;
+                        IWICBitmapSource_AddRef(source);
+                        gdip_format = pixel_formats[i].gdip_format;
+                        palette_type = pixel_formats[i].palette_type;
+                        break;
+                    }
                 }
             }
             if (!source)
             {
                 /* unknown format; fall back on 32bppARGB */
-                hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bmp_source, &source);
+                hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
                 gdip_format = PixelFormat32bppARGB;
-                IWICBitmapSource_Release(bmp_source);
             }
             TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
         }
@@ -3520,11 +3692,6 @@ static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid,
         }
     }
 
-    IWICBitmapDecoder_Release(decoder);
-
-end:
-    if (SUCCEEDED(initresult)) CoUninitialize();
-
     if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
 
     if (status == Ok)
@@ -3533,7 +3700,8 @@ end:
         bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
         bitmap->image.frame_count = frame_count;
         bitmap->image.current_frame = active_frame;
-        bitmap->image.stream = stream;
+        bitmap->image.decoder = decoder;
+        IWICBitmapDecoder_AddRef(decoder);
         if (palette)
         {
             GdipFree(bitmap->image.palette);
@@ -3544,25 +3712,214 @@ end:
             if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
                 bitmap->image.palette->Flags = 0;
         }
-        /* Pin the source stream */
-        IStream_AddRef(stream);
         TRACE("=> %p\n", *image);
     }
 
     return status;
 }
 
-static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus decode_image_wic(IStream *stream, REFGUID container,
+        metadata_reader_func metadata_reader, GpImage **image)
 {
-    return decode_image_wic(stream, &CLSID_WICIcoDecoder, active_frame, NULL, image);
+    IWICBitmapDecoder *decoder;
+    GpStatus status;
+
+    status = initialize_decoder_wic(stream, container, &decoder);
+    if(status != Ok)
+        return status;
+
+    status = decode_frame_wic(decoder, FALSE, 0, metadata_reader, image);
+    IWICBitmapDecoder_Release(decoder);
+    return status;
 }
 
-static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus select_frame_wic(GpImage *image, UINT active_frame)
+{
+    GpImage *new_image;
+    GpStatus status;
+
+    status = decode_frame_wic(image->decoder, FALSE, active_frame, NULL, &new_image);
+    if(status != Ok)
+        return status;
+
+    memcpy(&new_image->format, &image->format, sizeof(GUID));
+    free_image_data(image);
+    if (image->type == ImageTypeBitmap)
+        *(GpBitmap *)image = *(GpBitmap *)new_image;
+    else if (image->type == ImageTypeMetafile)
+        *(GpMetafile *)image = *(GpMetafile *)new_image;
+    new_image->type = ~0;
+    GdipFree(new_image);
+    return Ok;
+}
+
+static HRESULT get_gif_frame_rect(IWICBitmapFrameDecode *frame,
+        UINT *left, UINT *top, UINT *width, UINT *height)
+{
+    static const WCHAR leftW[] = {'L','e','f','t',0};
+    static const WCHAR topW[] = {'T','o','p',0};
+
+    *left = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, leftW);
+    *top = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, topW);
+
+    return IWICBitmapFrameDecode_GetSize(frame, width, height);
+}
+
+static HRESULT blit_gif_frame(GpBitmap *bitmap, IWICBitmapFrameDecode *frame, BOOL first_frame)
+{
+    UINT i, j, left, top, width, height;
+    IWICBitmapSource *source;
+    BYTE *new_bits;
+    HRESULT hr;
+
+    hr = get_gif_frame_rect(frame, &left, &top, &width, &height);
+    if(FAILED(hr))
+        return hr;
+
+    hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
+    if(FAILED(hr))
+        return hr;
+
+    new_bits = GdipAlloc(width*height*4);
+    if(!new_bits)
+        return E_OUTOFMEMORY;
+
+    hr = IWICBitmapSource_CopyPixels(source, NULL, width*4, width*height*4, new_bits);
+    IWICBitmapSource_Release(source);
+    if(FAILED(hr)) {
+        GdipFree(new_bits);
+        return hr;
+    }
+
+    for(i=0; i<height && i+top<bitmap->height; i++) {
+        for(j=0; j<width && j+left<bitmap->width; j++) {
+            DWORD *src = (DWORD*)(new_bits+i*width*4+j*4);
+            DWORD *dst = (DWORD*)(bitmap->bits+(i+top)*bitmap->stride+(j+left)*4);
+
+            if(first_frame || *src>>24 != 0)
+                *dst = *src;
+        }
+    }
+    GdipFree(new_bits);
+    return hr;
+}
+
+static DWORD get_gif_background_color(GpBitmap *bitmap)
+{
+    BYTE bgcolor_idx = 0;
+    UINT i;
+
+    for(i=0; i<bitmap->prop_count; i++) {
+        if(bitmap->prop_item[i].id == PropertyTagIndexBackground) {
+            bgcolor_idx = *(BYTE*)bitmap->prop_item[i].value;
+            break;
+        }
+    }
+
+    for(i=0; i<bitmap->prop_count; i++) {
+        if(bitmap->prop_item[i].id == PropertyTagIndexTransparent) {
+            BYTE transparent_idx;
+            transparent_idx = *(BYTE*)bitmap->prop_item[i].value;
+
+            if(transparent_idx == bgcolor_idx)
+                return 0;
+        }
+    }
+
+    for(i=0; i<bitmap->prop_count; i++) {
+        if(bitmap->prop_item[i].id == PropertyTagGlobalPalette) {
+            if(bitmap->prop_item[i].length/3 > bgcolor_idx) {
+                BYTE *color = ((BYTE*)bitmap->prop_item[i].value)+bgcolor_idx*3;
+                return color[2] + (color[1]<<8) + (color[0]<<16) + (0xff<<24);
+            }
+            break;
+        }
+    }
+
+    FIXME("can't get gif background color\n");
+    return 0xffffffff;
+}
+
+static GpStatus select_frame_gif(GpImage* image, UINT active_frame)
+{
+    static const WCHAR disposalW[] = {'D','i','s','p','o','s','a','l',0};
+
+    GpBitmap *bitmap = (GpBitmap*)image;
+    IWICBitmapFrameDecode *frame;
+    int cur_frame=0, disposal;
+    BOOL bgcolor_set = FALSE;
+    DWORD bgcolor = 0;
+    HRESULT hr;
+
+    if(active_frame > image->current_frame) {
+        hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, image->current_frame, &frame);
+        if(FAILED(hr))
+            return hresult_to_status(hr);
+        disposal = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, disposalW);
+        IWICBitmapFrameDecode_Release(frame);
+
+        if(disposal == GIF_DISPOSE_RESTORE_TO_BKGND)
+            cur_frame = image->current_frame;
+        else if(disposal != GIF_DISPOSE_RESTORE_TO_PREV)
+            cur_frame = image->current_frame+1;
+    }
+
+    while(cur_frame != active_frame) {
+        hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, cur_frame, &frame);
+        if(FAILED(hr))
+            return hresult_to_status(hr);
+        disposal = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, disposalW);
+
+        if(disposal==GIF_DISPOSE_UNSPECIFIED || disposal==GIF_DISPOSE_DO_NOT_DISPOSE) {
+            hr = blit_gif_frame(bitmap, frame, cur_frame==0);
+            if(FAILED(hr))
+                return hresult_to_status(hr);
+        }else if(disposal == GIF_DISPOSE_RESTORE_TO_BKGND) {
+            UINT left, top, width, height, i, j;
+
+            if(!bgcolor_set) {
+                bgcolor = get_gif_background_color(bitmap);
+                bgcolor_set = TRUE;
+            }
+
+            hr = get_gif_frame_rect(frame, &left, &top, &width, &height);
+            if(FAILED(hr))
+                return hresult_to_status(hr);
+            for(i=top; i<top+height && i<bitmap->height; i++) {
+                DWORD *bits = (DWORD*)(bitmap->bits+i*bitmap->stride);
+                for(j=left; j<left+width && j<bitmap->width; j++)
+                    bits[j] = bgcolor;
+            }
+        }
+
+        IWICBitmapFrameDecode_Release(frame);
+        cur_frame++;
+    }
+
+    hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, active_frame, &frame);
+    if(FAILED(hr))
+        return hresult_to_status(hr);
+
+    hr = blit_gif_frame(bitmap, frame, cur_frame==0);
+    IWICBitmapFrameDecode_Release(frame);
+    if(FAILED(hr))
+        return hresult_to_status(hr);
+
+    image->current_frame = active_frame;
+    return Ok;
+}
+
+static GpStatus decode_image_icon(IStream* stream, GpImage **image)
+{
+    return decode_image_wic(stream, &GUID_ContainerFormatIco, NULL, image);
+}
+
+static GpStatus decode_image_bmp(IStream* stream, GpImage **image)
 {
     GpStatus status;
     GpBitmap* bitmap;
 
-    status = decode_image_wic(stream, &CLSID_WICBmpDecoder, active_frame, NULL, image);
+    status = decode_image_wic(stream, &GUID_ContainerFormatBmp, NULL, image);
 
     bitmap = (GpBitmap*)*image;
 
@@ -3575,27 +3932,49 @@ static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_fr
     return status;
 }
 
-static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus decode_image_jpeg(IStream* stream, GpImage **image)
 {
-    return decode_image_wic(stream, &CLSID_WICJpegDecoder, active_frame, NULL, image);
+    return decode_image_wic(stream, &GUID_ContainerFormatJpeg, NULL, image);
 }
 
-static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus decode_image_png(IStream* stream, GpImage **image)
 {
-    return decode_image_wic(stream, &CLSID_WICPngDecoder, active_frame, NULL, image);
+    return decode_image_wic(stream, &GUID_ContainerFormatPng, png_metadata_reader, image);
 }
 
-static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus decode_image_gif(IStream* stream, GpImage **image)
 {
-    return decode_image_wic(stream, &CLSID_WICGifDecoder, active_frame, gif_metadata_reader, image);
+    IWICBitmapDecoder *decoder;
+    UINT frame_count;
+    GpStatus status;
+    HRESULT hr;
+
+    status = initialize_decoder_wic(stream, &GUID_ContainerFormatGif, &decoder);
+    if(status != Ok)
+        return status;
+
+    hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
+    if(FAILED(hr))
+        return hresult_to_status(hr);
+
+    status = decode_frame_wic(decoder, frame_count > 1, 0, gif_metadata_reader, image);
+    IWICBitmapDecoder_Release(decoder);
+    if(status != Ok)
+        return status;
+
+    if(frame_count > 1) {
+        GdipFree((*image)->palette);
+        (*image)->palette = NULL;
+    }
+    return Ok;
 }
 
-static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus decode_image_tiff(IStream* stream, GpImage **image)
 {
-    return decode_image_wic(stream, &CLSID_WICTiffDecoder, active_frame, NULL, image);
+    return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image);
 }
 
-static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
+static GpStatus decode_image_olepicture_metafile(IStream* stream, GpImage **image)
 {
     IPicture *pic;
 
@@ -3614,7 +3993,7 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid
     *image = GdipAlloc(sizeof(GpMetafile));
     if(!*image) return OutOfMemory;
     (*image)->type = ImageTypeMetafile;
-    (*image)->stream = NULL;
+    (*image)->decoder = NULL;
     (*image)->picture = pic;
     (*image)->flags   = ImageFlagsNone;
     (*image)->frame_count = 1;
@@ -3629,12 +4008,15 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid
 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
 
-typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, UINT active_frame, GpImage **image);
+typedef GpStatus (*decode_image_func)(IStream *stream, GpImage **image);
+
+typedef GpStatus (*select_image_func)(GpImage *image, UINT active_frame);
 
 typedef struct image_codec {
     ImageCodecInfo info;
     encode_image_func encode_func;
     decode_image_func decode_func;
+    select_image_func select_func;
 } image_codec;
 
 typedef enum {
@@ -3699,14 +4081,28 @@ static GpStatus get_decoder_info(IStream* stream, const struct image_codec **res
     return GenericError;
 }
 
+static GpStatus get_decoder_info_from_image(GpImage *image, const struct image_codec **result)
+{
+    int i;
+
+    for (i = 0; i < NUM_CODECS; i++) {
+        if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
+                IsEqualIID(&codecs[i].info.FormatID, &image->format))
+        {
+            *result = &codecs[i];
+            return Ok;
+        }
+    }
+
+    TRACE("no match for format: %s\n", wine_dbgstr_guid(&image->format));
+    return GenericError;
+}
+
 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *dimensionID,
                                                UINT frame)
 {
     GpStatus stat;
-    LARGE_INTEGER seek;
-    HRESULT hr;
     const struct image_codec *codec = NULL;
-    GpImage *new_image;
 
     TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
 
@@ -3728,43 +4124,21 @@ GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *d
     if (image->current_frame == frame)
         return Ok;
 
-    if (!image->stream)
+    if (!image->decoder)
     {
-        TRACE("image doesn't have an associated stream\n");
+        TRACE("image doesn't have an associated decoder\n");
         return Ok;
     }
 
     /* choose an appropriate image decoder */
-    stat = get_decoder_info(image->stream, &codec);
+    stat = get_decoder_info_from_image(image, &codec);
     if (stat != Ok)
     {
         WARN("can't find decoder info\n");
         return stat;
     }
 
-    /* seek to the start of the stream */
-    seek.QuadPart = 0;
-    hr = IStream_Seek(image->stream, seek, STREAM_SEEK_SET, NULL);
-    if (FAILED(hr))
-        return hresult_to_status(hr);
-
-    /* call on the image decoder to do the real work */
-    stat = codec->decode_func(image->stream, &codec->info.Clsid, frame, &new_image);
-
-    if (stat == Ok)
-    {
-        memcpy(&new_image->format, &codec->info.FormatID, sizeof(GUID));
-        free_image_data(image);
-        if (image->type == ImageTypeBitmap)
-            *(GpBitmap *)image = *(GpBitmap *)new_image;
-        else if (image->type == ImageTypeMetafile)
-            *(GpMetafile *)image = *(GpMetafile *)new_image;
-        new_image->type = ~0;
-        GdipFree(new_image);
-        return Ok;
-    }
-
-    return stat;
+    return codec->select_func(image, frame);
 }
 
 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
@@ -3784,7 +4158,7 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
     if (FAILED(hr)) return hresult_to_status(hr);
 
     /* call on the image decoder to do the real work */
-    stat = codec->decode_func(stream, &codec->info.Clsid, 0, image);
+    stat = codec->decode_func(stream, image);
 
     /* take note of the original data format */
     if (stat == Ok)
@@ -3860,11 +4234,12 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam
  *   These functions encode an image in different image file formats.
  */
 
-static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
-    GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+static GpStatus encode_image_wic(GpImage *image, IStream* stream,
+    REFGUID container, GDIPCONST EncoderParameters* params)
 {
     GpStatus stat;
     GpBitmap *bitmap;
+    IWICImagingFactory *factory;
     IWICBitmapEncoder *encoder;
     IWICBitmapFrameEncode *frameencode;
     IPropertyBag2 *encoderoptions;
@@ -3875,7 +4250,6 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
     WICPixelFormatGUID wicformat;
     GpRect rc;
     BitmapData lockeddata;
-    HRESULT initresult;
     UINT i;
 
     if (image->type != ImageTypeBitmap)
@@ -3891,15 +4265,13 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
     rc.Width = width;
     rc.Height = height;
 
-    initresult = CoInitialize(NULL);
-
-    hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
-        &IID_IWICBitmapEncoder, (void**)&encoder);
+    hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
+    if (FAILED(hr))
+        return hresult_to_status(hr);
+    hr = IWICImagingFactory_CreateEncoder(factory, container, NULL, &encoder);
+    IWICImagingFactory_Release(factory);
     if (FAILED(hr))
-    {
-        if (SUCCEEDED(initresult)) CoUninitialize();
         return hresult_to_status(hr);
-    }
 
     hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
 
@@ -3994,34 +4366,37 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
         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);
+    return encode_image_wic(image, stream, &GUID_ContainerFormatBmp, params);
 }
 
 static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
 {
-    return encode_image_WIC(image, stream, &CLSID_WICTiffEncoder, params);
+    return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params);
 }
 
 static GpStatus encode_image_png(GpImage *image, IStream* stream,
     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
 {
-    return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
+    return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params);
 }
 
 static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
 {
-    return encode_image_WIC(image, stream, &CLSID_WICJpegEncoder, params);
+    return encode_image_wic(image, stream, &GUID_ContainerFormatJpeg, params);
+}
+
+static GpStatus encode_image_gif(GpImage *image, IStream* stream,
+    GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+{
+    return encode_image_wic(image, stream, &CLSID_WICGifEncoder, params);
 }
 
 /*****************************************************************************
@@ -4202,7 +4577,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            bmp_sig_mask,
         },
         encode_image_BMP,
-        decode_image_bmp
+        decode_image_bmp,
+        select_frame_wic
     },
     {
         { /* JPEG */
@@ -4221,7 +4597,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            jpeg_sig_mask,
         },
         encode_image_jpeg,
-        decode_image_jpeg
+        decode_image_jpeg,
+        select_frame_wic
     },
     {
         { /* GIF */
@@ -4232,15 +4609,16 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* FormatDescription */  gif_format,
             /* FilenameExtension */  gif_extension,
             /* MimeType */           gif_mimetype,
-            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
             /* Version */            1,
             /* SigCount */           2,
             /* SigSize */            6,
             /* SigPattern */         gif_sig_pattern,
             /* SigMask */            gif_sig_mask,
         },
-        NULL,
-        decode_image_gif
+        encode_image_gif,
+        decode_image_gif,
+        select_frame_gif
     },
     {
         { /* TIFF */
@@ -4259,7 +4637,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            tiff_sig_mask,
         },
         encode_image_tiff,
-        decode_image_tiff
+        decode_image_tiff,
+        select_frame_wic
     },
     {
         { /* EMF */
@@ -4278,7 +4657,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            emf_sig_mask,
         },
         NULL,
-        decode_image_olepicture_metafile
+        decode_image_olepicture_metafile,
+        NULL
     },
     {
         { /* WMF */
@@ -4297,7 +4677,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            wmf_sig_mask,
         },
         NULL,
-        decode_image_olepicture_metafile
+        decode_image_olepicture_metafile,
+        NULL
     },
     {
         { /* PNG */
@@ -4316,7 +4697,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            png_sig_mask,
         },
         encode_image_png,
-        decode_image_png
+        decode_image_png,
+        select_frame_wic
     },
     {
         { /* ICO */
@@ -4335,7 +4717,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            ico_sig_mask,
         },
         NULL,
-        decode_image_icon
+        decode_image_icon,
+        select_frame_wic
     },
 };
 
@@ -4850,3 +5233,12 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
 
     return stat;
 }
+
+/*****************************************************************************
+ * GdipImageSetAbort [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipImageSetAbort(GpImage *image, GdiplusAbort *pabort)
+{
+    FIXME("(%p, %p): stub\n", image, pabort);
+    return NotImplemented;
+}
index 5d2cf49..4f82341 100644 (file)
@@ -1105,10 +1105,11 @@ GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
     TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
         debugstr_w(description), out_metafile);
 
-    if(!ref || !metafile || !out_metafile)
+    if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual)
         return InvalidParameter;
 
-    *succ = FALSE;
+    if(succ)
+        *succ = FALSE;
     *out_metafile = NULL;
 
     if(!(calls++))
index 98e0a6d..01c4f6f 100644 (file)
@@ -533,224 +533,6 @@ GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect,
     return GdipCreateRegionRect(&rectf, region);
 }
 
-static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
-{
-    mbuf->buffer = buffer;
-    mbuf->size = size;
-    mbuf->pos = 0;
-}
-
-static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
-{
-    if (mbuf->size - mbuf->pos >= size)
-    {
-        const void *data = mbuf->buffer + mbuf->pos;
-        mbuf->pos += size;
-        return data;
-    }
-    return NULL;
-}
-
-static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
-{
-    GpStatus status;
-    const DWORD *type;
-
-    type = buffer_read(mbuf, sizeof(DWORD));
-    if (!type) return Ok;
-
-    TRACE("type %#x\n", *type);
-
-    node->type = *type;
-
-    switch (node->type)
-    {
-    case CombineModeReplace:
-    case CombineModeIntersect:
-    case CombineModeUnion:
-    case CombineModeXor:
-    case CombineModeExclude:
-    case CombineModeComplement:
-    {
-        region_element *left, *right;
-
-        left = GdipAlloc(sizeof(region_element));
-        if (!left) return OutOfMemory;
-        right = GdipAlloc(sizeof(region_element));
-        if (!right)
-        {
-            GdipFree(left);
-            return OutOfMemory;
-        }
-
-        status = read_element(mbuf, region, left, count);
-        if (status == Ok)
-        {
-            status = read_element(mbuf, region, right, count);
-            if (status == Ok)
-            {
-                node->elementdata.combine.left = left;
-                node->elementdata.combine.right = right;
-                region->num_children += 2;
-                return Ok;
-            }
-        }
-
-        GdipFree(left);
-        GdipFree(right);
-        return status;
-    }
-
-    case RegionDataRect:
-    {
-        const GpRectF *rc;
-
-        rc = buffer_read(mbuf, sizeof(GpRectF));
-        if (!rc)
-        {
-            ERR("failed to read rect data\n");
-            return InvalidParameter;
-        }
-
-        node->elementdata.rect = *rc;
-        *count += 1;
-        return Ok;
-    }
-
-    case RegionDataPath:
-    {
-        GpPath *path;
-        const struct path_header *path_header;
-        const BYTE *types;
-
-        path_header = buffer_read(mbuf, sizeof(struct path_header));
-        if (!path_header)
-        {
-            ERR("failed to read path header\n");
-            return InvalidParameter;
-        }
-        if (path_header->magic != VERSION_MAGIC)
-        {
-            ERR("invalid path header magic %#x\n", path_header->magic);
-            return InvalidParameter;
-        }
-
-        /* Windows always fails to create an empty path in a region */
-        if (!path_header->count)
-        {
-            TRACE("refusing to create an empty path in a region\n");
-            return GenericError;
-        }
-
-        status = GdipCreatePath(FillModeAlternate, &path);
-        if (status) return status;
-
-        node->elementdata.path = path;
-
-        if (!lengthen_path(path, path_header->count))
-            return OutOfMemory;
-
-        path->pathdata.Count = path_header->count;
-
-        if (path_header->flags & ~FLAGS_INTPATH)
-            FIXME("unhandled path flags %#x\n", path_header->flags);
-
-        if (path_header->flags & FLAGS_INTPATH)
-        {
-            const packed_point *pt;
-            DWORD i;
-
-            pt = buffer_read(mbuf, sizeof(packed_point) * path_header->count);
-            if (!pt)
-            {
-                ERR("failed to read packed %u path points\n", path_header->count);
-                return InvalidParameter;
-            }
-
-            for (i = 0; i < path_header->count; i++)
-            {
-                path->pathdata.Points[i].X = (REAL)pt[i].X;
-                path->pathdata.Points[i].Y = (REAL)pt[i].Y;
-            }
-        }
-        else
-        {
-            const GpPointF *ptf;
-
-            ptf = buffer_read(mbuf, sizeof(GpPointF) * path_header->count);
-            if (!ptf)
-            {
-                ERR("failed to read %u path points\n", path_header->count);
-                return InvalidParameter;
-            }
-            memcpy(path->pathdata.Points, ptf, sizeof(GpPointF) * path_header->count);
-        }
-
-        types = buffer_read(mbuf, path_header->count);
-        if (!types)
-        {
-            ERR("failed to read %u path types\n", path_header->count);
-            return InvalidParameter;
-        }
-        memcpy(path->pathdata.Types, types, path_header->count);
-        if (path_header->count & 3)
-        {
-            if (!buffer_read(mbuf, 4 - (path_header->count & 3)))
-            {
-                ERR("failed to read rounding %u bytes\n", 4 - (path_header->count & 3));
-                return InvalidParameter;
-            }
-        }
-
-        *count += 1;
-        return Ok;
-    }
-
-    case RegionDataEmptyRect:
-    case RegionDataInfiniteRect:
-        *count += 1;
-        return Ok;
-
-    default:
-        FIXME("element type %#x is not supported\n", *type);
-        break;
-    }
-
-    return InvalidParameter;
-}
-
-GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
-{
-    GpStatus status;
-    struct memory_buffer mbuf;
-    const struct region_header *region_header;
-    INT count;
-
-    if (!data || !size) return InvalidParameter;
-
-    TRACE("%p, %d, %p\n", data, size, region);
-
-    init_memory_buffer(&mbuf, data, size);
-
-    region_header = buffer_read(&mbuf, sizeof(struct region_header));
-    if (!region_header || region_header->magic != VERSION_MAGIC)
-        return InvalidParameter;
-
-    status = GdipCreateRegion(region);
-    if (status != Ok) return status;
-
-    count = 0;
-    status = read_element(&mbuf, *region, &(*region)->node, &count);
-    if (status == Ok && !count)
-        status = InvalidParameter;
-
-    if (status != Ok)
-        GdipDeleteRegion(*region);
-
-    return status;
-}
-
-
 /******************************************************************************
  * GdipCreateRegionHrgn [GDIPLUS.@]
  */
@@ -1071,6 +853,232 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
     return Ok;
 }
 
+static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
+{
+    mbuf->buffer = buffer;
+    mbuf->size = size;
+    mbuf->pos = 0;
+}
+
+static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
+{
+    if (mbuf->size - mbuf->pos >= size)
+    {
+        const void *data = mbuf->buffer + mbuf->pos;
+        mbuf->pos += size;
+        return data;
+    }
+    return NULL;
+}
+
+static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
+{
+    GpStatus status;
+    const DWORD *type;
+
+    type = buffer_read(mbuf, sizeof(*type));
+    if (!type) return Ok;
+
+    TRACE("type %#x\n", *type);
+
+    node->type = *type;
+
+    switch (node->type)
+    {
+    case CombineModeReplace:
+    case CombineModeIntersect:
+    case CombineModeUnion:
+    case CombineModeXor:
+    case CombineModeExclude:
+    case CombineModeComplement:
+    {
+        region_element *left, *right;
+
+        left = GdipAlloc(sizeof(region_element));
+        if (!left) return OutOfMemory;
+        right = GdipAlloc(sizeof(region_element));
+        if (!right)
+        {
+            GdipFree(left);
+            return OutOfMemory;
+        }
+
+        status = read_element(mbuf, region, left, count);
+        if (status == Ok)
+        {
+            status = read_element(mbuf, region, right, count);
+            if (status == Ok)
+            {
+                node->elementdata.combine.left = left;
+                node->elementdata.combine.right = right;
+                region->num_children += 2;
+                return Ok;
+            }
+        }
+
+        GdipFree(left);
+        GdipFree(right);
+        return status;
+    }
+
+    case RegionDataRect:
+    {
+        const GpRectF *rc;
+
+        rc = buffer_read(mbuf, sizeof(*rc));
+        if (!rc)
+        {
+            ERR("failed to read rect data\n");
+            return InvalidParameter;
+        }
+
+        node->elementdata.rect = *rc;
+        *count += 1;
+        return Ok;
+    }
+
+    case RegionDataPath:
+    {
+        GpPath *path;
+        const struct path_header *path_header;
+        const BYTE *types;
+
+        path_header = buffer_read(mbuf, sizeof(*path_header));
+        if (!path_header)
+        {
+            ERR("failed to read path header\n");
+            return InvalidParameter;
+        }
+        if (path_header->magic != VERSION_MAGIC)
+        {
+            ERR("invalid path header magic %#x\n", path_header->magic);
+            return InvalidParameter;
+        }
+
+        /* Windows always fails to create an empty path in a region */
+        if (!path_header->count)
+        {
+            TRACE("refusing to create an empty path in a region\n");
+            return GenericError;
+        }
+
+        status = GdipCreatePath(FillModeAlternate, &path);
+        if (status) return status;
+
+        node->elementdata.path = path;
+
+        if (!lengthen_path(path, path_header->count))
+            return OutOfMemory;
+
+        path->pathdata.Count = path_header->count;
+
+        if (path_header->flags & ~FLAGS_INTPATH)
+            FIXME("unhandled path flags %#x\n", path_header->flags);
+
+        if (path_header->flags & FLAGS_INTPATH)
+        {
+            const packed_point *pt;
+            DWORD i;
+
+            pt = buffer_read(mbuf, sizeof(*pt) * path_header->count);
+            if (!pt)
+            {
+                ERR("failed to read packed %u path points\n", path_header->count);
+                return InvalidParameter;
+            }
+
+            for (i = 0; i < path_header->count; i++)
+            {
+                path->pathdata.Points[i].X = (REAL)pt[i].X;
+                path->pathdata.Points[i].Y = (REAL)pt[i].Y;
+            }
+        }
+        else
+        {
+            const GpPointF *ptf;
+
+            ptf = buffer_read(mbuf, sizeof(*ptf) * path_header->count);
+            if (!ptf)
+            {
+                ERR("failed to read %u path points\n", path_header->count);
+                return InvalidParameter;
+            }
+            memcpy(path->pathdata.Points, ptf, sizeof(*ptf) * path_header->count);
+        }
+
+        types = buffer_read(mbuf, path_header->count);
+        if (!types)
+        {
+            ERR("failed to read %u path types\n", path_header->count);
+            return InvalidParameter;
+        }
+        memcpy(path->pathdata.Types, types, path_header->count);
+        if (path_header->count & 3)
+        {
+            if (!buffer_read(mbuf, 4 - (path_header->count & 3)))
+            {
+                ERR("failed to read rounding %u bytes\n", 4 - (path_header->count & 3));
+                return InvalidParameter;
+            }
+        }
+
+        *count += 1;
+        return Ok;
+    }
+
+    case RegionDataEmptyRect:
+    case RegionDataInfiniteRect:
+        *count += 1;
+        return Ok;
+
+    default:
+        FIXME("element type %#x is not supported\n", *type);
+        break;
+    }
+
+    return InvalidParameter;
+}
+
+/*****************************************************************************
+ * GdipCreateRegionRgnData [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
+{
+    const struct region_header *region_header;
+    struct memory_buffer mbuf;
+    GpStatus status;
+    INT count;
+
+    TRACE("(%p, %d, %p)\n", data, size, region);
+
+    if (!data || !size)
+        return InvalidParameter;
+
+    init_memory_buffer(&mbuf, data, size);
+
+    region_header = buffer_read(&mbuf, sizeof(*region_header));
+    if (!region_header || (region_header->magic != VERSION_MAGIC &&
+                           region_header->magic != VERSION_MAGIC2))
+        return InvalidParameter;
+
+    status = GdipCreateRegion(region);
+    if (status != Ok)
+        return status;
+
+    count = 0;
+    status = read_element(&mbuf, *region, &(*region)->node, &count);
+    if (status == Ok && !count)
+        status = InvalidParameter;
+
+    if (status != Ok)
+    {
+        GdipDeleteRegion(*region);
+        *region = NULL;
+    }
+
+    return status;
+}
+
 /*****************************************************************************
  * GdipGetRegionDataSize [GDIPLUS.@]
  */
@@ -1098,16 +1106,12 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
     {
         new_hdc = CreateCompatibleDC(0);
         if (!new_hdc)
-        {
-            ERR("CreateCompatibleDC failed\n");
             return OutOfMemory;
-        }
 
         stat = GdipCreateFromHDC(new_hdc, &new_graphics);
         graphics = new_graphics;
         if (stat != Ok)
         {
-            ERR("GdipCreateFromHDC failed: 0x%x\n", stat);
             DeleteDC(new_hdc);
             return stat;
         }
@@ -1116,10 +1120,7 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
     {
         graphics->hdc = new_hdc = CreateCompatibleDC(0);
         if (!new_hdc)
-        {
-            ERR("CreateCompatibleDC failed\n");
             return OutOfMemory;
-        }
     }
 
     save_state = SaveDC(graphics->hdc);
@@ -1132,16 +1133,8 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
     if (stat == Ok)
     {
         *hrgn = PathToRegion(graphics->hdc);
-        if (*hrgn == NULL)
-        {
-            ERR("PathToRegion failed\n");
-        }
         stat = *hrgn ? Ok : OutOfMemory;
     }
-    else
-    {
-        ERR("trace_path failed: 0x%x\n", stat);
-    }
 
     RestoreDC(graphics->hdc, save_state);
     if (new_hdc)
@@ -1176,18 +1169,11 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
 
             stat = GdipCreatePath(FillModeAlternate, &path);
             if (stat != Ok)
-            {
-                ERR("GdipCreatePath failed: 0x%x\n", stat);
                 return stat;
-            }
             stat = GdipAddPathRectangle(path, rc->X, rc->Y, rc->Width, rc->Height);
 
             if (stat == Ok)
                 stat = get_path_hrgn(path, graphics, hrgn);
-            else
-            {
-                ERR("GdipAddPathRectangle failed: 0x%x\n", stat);
-            }
 
             GdipDeletePath(path);
 
@@ -1218,7 +1204,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
                     case CombineModeIntersect:
                         return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
                     case CombineModeXor: case CombineModeExclude:
-                        left = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+                        left = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
                         break;
                     case CombineModeUnion: case CombineModeComplement:
                         *hrgn = NULL;
@@ -1243,7 +1229,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
                         *hrgn = left;
                         return Ok;
                     case CombineModeXor: case CombineModeComplement:
-                        right = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+                        right = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
                         break;
                     case CombineModeUnion: case CombineModeExclude:
                         DeleteObject(left);
@@ -1297,18 +1283,12 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
  */
 GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
 {
-    GpStatus status;
     TRACE("(%p, %p, %p)\n", region, graphics, hrgn);
 
     if (!region || !hrgn)
         return InvalidParameter;
 
-    status = get_region_hrgn(&region->node, graphics, hrgn);
-    if (status != Ok)
-    {
-        ERR("get_region_hrgn() failed. region->node.type = 0x%x\n", region->node.type);
-    }
-    return status;
+    return get_region_hrgn(&region->node, graphics, hrgn);
 }
 
 GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
index 4319b4e..e44d093 100644 (file)
@@ -70,7 +70,7 @@ reactos/dll/win32/dwmapi              # Synced to WineStaging-1.7.37
 reactos/dll/win32/faultrep            # Synced to WineStaging-1.7.37
 reactos/dll/win32/fltlib              # Synced to WineStaging-1.7.47
 reactos/dll/win32/fusion              # Synced to WineStaging-1.7.47
-reactos/dll/win32/gdiplus             # Synced to WineStaging-1.7.37
+reactos/dll/win32/gdiplus             # Synced to WineStaging-1.7.47
 reactos/dll/win32/hhctrl.ocx          # Synced to WineStaging-1.7.47
 reactos/dll/win32/hlink               # Synced to WineStaging-1.7.37
 reactos/dll/win32/hnetcfg             # Synced to WineStaging-1.7.37