From 3f043d113a524e8c7db4f563f2d11851ed171d59 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Fri, 19 Aug 2016 09:28:13 +0000 Subject: [PATCH] [GDIPLUS] Sync with Wine Staging 1.9.16. CORE-11866 svn path=/trunk/; revision=72341 --- reactos/dll/win32/gdiplus/brush.c | 2 +- reactos/dll/win32/gdiplus/gdiplus.spec | 2 +- reactos/dll/win32/gdiplus/gdiplus_private.h | 11 +- reactos/dll/win32/gdiplus/graphics.c | 33 ++- reactos/dll/win32/gdiplus/image.c | 114 +++++++- reactos/dll/win32/gdiplus/imageattributes.c | 15 ++ reactos/dll/win32/gdiplus/metafile.c | 275 +++++++++++++++++++- reactos/dll/win32/gdiplus/region.c | 14 +- reactos/media/doc/README.WINE | 2 +- 9 files changed, 441 insertions(+), 27 deletions(-) diff --git a/reactos/dll/win32/gdiplus/brush.c b/reactos/dll/win32/gdiplus/brush.c index 62523d3c79c..8b1b5dad396 100644 --- a/reactos/dll/win32/gdiplus/brush.c +++ b/reactos/dll/win32/gdiplus/brush.c @@ -191,7 +191,7 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) if (stat == Ok) { new_texture->transform = texture->transform; - *clone = (GpBrush*)new_texture; + *clone = &new_texture->brush; } else *clone = NULL; diff --git a/reactos/dll/win32/gdiplus/gdiplus.spec b/reactos/dll/win32/gdiplus/gdiplus.spec index 893796ee31a..db0a49a8b34 100644 --- a/reactos/dll/win32/gdiplus/gdiplus.spec +++ b/reactos/dll/win32/gdiplus/gdiplus.spec @@ -264,7 +264,7 @@ 264 stdcall GdipGetHatchForegroundColor(ptr ptr) 265 stdcall GdipGetHatchStyle(ptr ptr) 266 stdcall GdipGetHemfFromMetafile(ptr ptr) -267 stub GdipGetImageAttributesAdjustedPalette +267 stdcall GdipGetImageAttributesAdjustedPalette(ptr ptr long) 268 stdcall GdipGetImageBounds(ptr ptr ptr) 269 stdcall GdipGetImageDecoders(long long ptr) 270 stdcall GdipGetImageDecodersSize(ptr ptr) diff --git a/reactos/dll/win32/gdiplus/gdiplus_private.h b/reactos/dll/win32/gdiplus/gdiplus_private.h index 316e25a4750..188b19d8d54 100644 --- a/reactos/dll/win32/gdiplus/gdiplus_private.h +++ b/reactos/dll/win32/gdiplus/gdiplus_private.h @@ -94,9 +94,12 @@ extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLS extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN; extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN; extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN; +extern GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color) DECLSPEC_HIDDEN; extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush, GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN; extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN; +extern GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) DECLSPEC_HIDDEN; +extern GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile) DECLSPEC_HIDDEN; extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN; extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1, @@ -184,6 +187,9 @@ extern GpStatus convert_pixels(INT width, INT height, INT dst_stride, BYTE *dst_bits, PixelFormat dst_format, INT src_stride, const BYTE *src_bits, PixelFormat src_format, ColorPalette *palette) DECLSPEC_HIDDEN; +extern PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data, + UINT width, UINT height, INT stride, ColorAdjustType type, PixelFormat fmt) DECLSPEC_HIDDEN; + struct GpMatrix{ REAL matrix[6]; }; @@ -322,7 +328,7 @@ struct GpCustomLineCap{ REAL scale; }; -struct GpAdustableArrowCap{ +struct GpAdjustableArrowCap{ GpCustomLineCap cap; }; @@ -351,6 +357,8 @@ struct GpMetafile{ DWORD comment_data_size; DWORD comment_data_length; IStream *record_stream; + BOOL auto_frame; /* If true, determine the frame automatically */ + GpPointF auto_frame_min, auto_frame_max; /* playback */ GpGraphics *playback_graphics; @@ -362,6 +370,7 @@ struct GpMetafile{ GpMatrix *world_transform; GpUnit page_unit; REAL page_scale; + GpRegion *base_clip; /* clip region in device space for all metafile output */ }; struct GpBitmap{ diff --git a/reactos/dll/win32/gdiplus/graphics.c b/reactos/dll/win32/gdiplus/graphics.c index b6daf843070..320664eab08 100644 --- a/reactos/dll/win32/gdiplus/graphics.c +++ b/reactos/dll/win32/gdiplus/graphics.c @@ -657,7 +657,7 @@ static BOOL color_is_gray(ARGB color) } /* returns preferred pixel format for the applied attributes */ -static PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data, +PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data, UINT width, UINT height, INT stride, ColorAdjustType type, PixelFormat fmt) { UINT x, y; @@ -4277,6 +4277,7 @@ GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect { GpRegion *clip_rgn; GpStatus stat; + GpMatrix device_to_world; TRACE("(%p, %p)\n", graphics, rect); @@ -4293,6 +4294,13 @@ GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok) goto cleanup; + /* transform to world coordinates */ + if((stat = get_graphics_transform(graphics, CoordinateSpaceWorld, CoordinateSpaceDevice, &device_to_world)) != Ok) + goto cleanup; + + if((stat = GdipTransformRegion(clip_rgn, &device_to_world)) != Ok) + goto cleanup; + /* get bounds of the region */ stat = GdipGetRegionBounds(clip_rgn, graphics, rect); @@ -4351,10 +4359,13 @@ GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color) if(graphics->busy) return ObjectBusy; + if (graphics->image && graphics->image->type == ImageTypeMetafile) + return METAFILE_GraphicsClear((GpMetafile*)graphics->image, color); + if((stat = GdipCreateSolidFill(color, &brush)) != Ok) return stat; - if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){ + if((stat = GdipGetVisibleClipBounds(graphics, &wnd_rect)) != Ok){ GdipDeleteBrush((GpBrush*)brush); return stat; } @@ -5097,6 +5108,8 @@ GpStatus WINGDIPAPI GdipResetClip(GpGraphics *graphics) GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics) { + GpStatus stat; + TRACE("(%p)\n", graphics); if(!graphics) @@ -5105,6 +5118,13 @@ GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics) if(graphics->busy) return ObjectBusy; + if (graphics->image && graphics->image->type == ImageTypeMetafile) { + stat = METAFILE_ResetWorldTransform((GpMetafile*)graphics->image); + + if (stat != Ok) + return stat; + } + return GdipSetMatrixElements(&graphics->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); } @@ -5211,6 +5231,8 @@ GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer sta GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx, REAL sy, GpMatrixOrder order) { + GpStatus stat; + TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order); if(!graphics) @@ -5219,6 +5241,13 @@ GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx, if(graphics->busy) return ObjectBusy; + if (graphics->image && graphics->image->type == ImageTypeMetafile) { + stat = METAFILE_ScaleWorldTransform((GpMetafile*)graphics->image, sx, sy, order); + + if (stat != Ok) + return stat; + } + return GdipScaleMatrix(&graphics->worldtrans, sx, sy, order); } diff --git a/reactos/dll/win32/gdiplus/image.c b/reactos/dll/win32/gdiplus/image.c index 12fe0929c14..aa6ea9e495b 100644 --- a/reactos/dll/win32/gdiplus/image.c +++ b/reactos/dll/win32/gdiplus/image.c @@ -1245,7 +1245,7 @@ GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height, } if (stat != Ok) - GdipDisposeImage((GpImage*)*dstBitmap); + GdipDisposeImage(&(*dstBitmap)->image); } if (stat != Ok) @@ -1445,8 +1445,8 @@ GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap, if (!bitmap || !hbmReturn) return InvalidParameter; - GdipGetImageWidth((GpImage*)bitmap, &width); - GdipGetImageHeight((GpImage*)bitmap, &height); + GdipGetImageWidth(&bitmap->image, &width); + GdipGetImageHeight(&bitmap->image, &height); bih.biSize = sizeof(bih); bih.biWidth = width; @@ -1570,7 +1570,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap) if (stat != Ok) { DeleteObject(iinfo.hbmColor); DeleteObject(iinfo.hbmMask); - GdipDisposeImage((GpImage*)*bitmap); + GdipDisposeImage(&(*bitmap)->image); return stat; } @@ -2932,7 +2932,7 @@ static void add_property(GpBitmap *bitmap, PropertyItem *item) UINT i; char *item_value; - GdipGetPropertySize((GpImage *)bitmap, &prop_size, &prop_count); + GdipGetPropertySize(&bitmap->image, &prop_size, &prop_count); prop_item = heap_alloc_zero(prop_size + item->length + sizeof(PropertyItem)); if (!prop_item) return; @@ -3388,7 +3388,7 @@ static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI { "Source", PropertyTagEquipModel }, { "Comment", PropertyTagExifUserComment }, }; - BOOL seen_gamma=FALSE; + BOOL seen_gamma=FALSE, seen_whitepoint=FALSE, seen_chrm=FALSE; hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame); if (hr != S_OK) return; @@ -3457,6 +3457,57 @@ static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI } } } + else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkcHRM, &format)) + { + PropertyItem* item; + + if (!seen_whitepoint) + { + item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 4); + if (item) + { + ULONG *rational; + item->length = sizeof(ULONG) * 4; + item->type = PropertyTagTypeRational; + item->id = PropertyTagWhitePoint; + rational = item->value = item + 1; + rational[0] = get_ulong_by_index(reader, 0); + rational[1] = 100000; + rational[2] = get_ulong_by_index(reader, 1); + rational[3] = 100000; + add_property(bitmap, item); + seen_whitepoint = TRUE; + GdipFree(item); + } + } + if (!seen_chrm) + { + item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 12); + if (item) + { + ULONG *rational; + item->length = sizeof(ULONG) * 12; + item->type = PropertyTagTypeRational; + item->id = PropertyTagPrimaryChromaticities; + rational = item->value = item + 1; + rational[0] = get_ulong_by_index(reader, 2); + rational[1] = 100000; + rational[2] = get_ulong_by_index(reader, 3); + rational[3] = 100000; + rational[4] = get_ulong_by_index(reader, 4); + rational[5] = 100000; + rational[6] = get_ulong_by_index(reader, 5); + rational[7] = 100000; + rational[8] = get_ulong_by_index(reader, 6); + rational[9] = 100000; + rational[10] = get_ulong_by_index(reader, 7); + rational[11] = 100000; + add_property(bitmap, item); + seen_chrm = TRUE; + GdipFree(item); + } + } + } IWICMetadataReader_Release(reader); } @@ -3568,11 +3619,11 @@ static GpStatus decode_frame_wic(IWICBitmapDecoder *decoder, BOOL force_conversi } if (SUCCEEDED(hr) && status == Ok) - *image = (GpImage*)bitmap; + *image = &bitmap->image; else { *image = NULL; - GdipDisposeImage((GpImage*)bitmap); + GdipDisposeImage(&bitmap->image); } if (SUCCEEDED(hr) && status == Ok) @@ -3614,7 +3665,14 @@ static GpStatus decode_frame_wic(IWICBitmapDecoder *decoder, BOOL force_conversi if (status == Ok) { /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */ - bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB; + bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI; + if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat2bppGray) || + IsEqualGUID(&wic_format, &GUID_WICPixelFormat4bppGray) || + IsEqualGUID(&wic_format, &GUID_WICPixelFormat8bppGray) || + IsEqualGUID(&wic_format, &GUID_WICPixelFormat16bppGray)) + bitmap->image.flags |= ImageFlagsColorSpaceGRAY; + else + bitmap->image.flags |= ImageFlagsColorSpaceRGB; bitmap->image.frame_count = frame_count; bitmap->image.current_frame = active_frame; bitmap->image.decoder = decoder; @@ -3856,7 +3914,37 @@ static GpStatus decode_image_jpeg(IStream* stream, GpImage **image) static GpStatus decode_image_png(IStream* stream, GpImage **image) { - return decode_image_wic(stream, &GUID_ContainerFormatPng, png_metadata_reader, image); + IWICBitmapDecoder *decoder; + IWICBitmapFrameDecode *frame; + GpStatus status; + HRESULT hr; + GUID format; + BOOL force_conversion = FALSE; + + status = initialize_decoder_wic(stream, &GUID_ContainerFormatPng, &decoder); + if (status != Ok) + return status; + + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + if (hr == S_OK) + { + hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &format); + if (hr == S_OK) + { + if (IsEqualGUID(&format, &GUID_WICPixelFormat8bppGray)) + force_conversion = TRUE; + status = decode_frame_wic(decoder, force_conversion, 0, png_metadata_reader, image); + } + else + status = hresult_to_status(hr); + + IWICBitmapFrameDecode_Release(frame); + } + else + status = hresult_to_status(hr); + + IWICBitmapDecoder_Release(decoder); + return status; } static GpStatus decode_image_gif(IStream* stream, GpImage **image) @@ -4987,7 +5075,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi entry[i].peGreen << 8 | entry[i].peBlue; } - retval = GdipSetImagePalette((GpImage*)*bitmap, palette); + retval = GdipSetImagePalette(&(*bitmap)->image, palette); } heap_free(palette); @@ -4995,7 +5083,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi if (retval != Ok) { - GdipDisposeImage((GpImage*)*bitmap); + GdipDisposeImage(&(*bitmap)->image); *bitmap = NULL; } } @@ -5250,7 +5338,7 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type) if (stat == Ok) move_bitmap(bitmap, new_bitmap, FALSE); else - GdipDisposeImage((GpImage*)new_bitmap); + GdipDisposeImage(&new_bitmap->image); return stat; } diff --git a/reactos/dll/win32/gdiplus/imageattributes.c b/reactos/dll/win32/gdiplus/imageattributes.c index 4c9972f884f..d6dd9b61d19 100644 --- a/reactos/dll/win32/gdiplus/imageattributes.c +++ b/reactos/dll/win32/gdiplus/imageattributes.c @@ -68,6 +68,21 @@ GpStatus WINGDIPAPI GdipDisposeImageAttributes(GpImageAttributes *imageattr) return Ok; } +GpStatus WINGDIPAPI GdipGetImageAttributesAdjustedPalette(GpImageAttributes *imageattr, + ColorPalette *palette, ColorAdjustType type) +{ + TRACE("(%p,%p,%u)\n", imageattr, palette, type); + + if (!imageattr || !palette || !palette->Count || + type >= ColorAdjustTypeCount || type == ColorAdjustTypeDefault) + return InvalidParameter; + + apply_image_attributes(imageattr, (LPBYTE)palette->Entries, palette->Count, 1, 0, + type, PixelFormat32bppARGB); + + return Ok; +} + GpStatus WINGDIPAPI GdipSetImageAttributesColorKeys(GpImageAttributes *imageattr, ColorAdjustType type, BOOL enableFlag, ARGB colorLow, ARGB colorHigh) { diff --git a/reactos/dll/win32/gdiplus/metafile.c b/reactos/dll/win32/gdiplus/metafile.c index 77c9eb3e1c5..a99729a6ba7 100644 --- a/reactos/dll/win32/gdiplus/metafile.c +++ b/reactos/dll/win32/gdiplus/metafile.c @@ -35,6 +35,12 @@ typedef struct EmfPlusHeader DWORD LogicalDpiY; } EmfPlusHeader; +typedef struct EmfPlusClear +{ + EmfPlusRecordHeader Header; + DWORD Color; +} EmfPlusClear; + typedef struct EmfPlusFillRects { EmfPlusRecordHeader Header; @@ -56,6 +62,13 @@ typedef struct EmfPlusRect SHORT Height; } EmfPlusRect; +typedef struct EmfPlusScaleWorldTransform +{ + EmfPlusRecordHeader Header; + REAL Sx; + REAL Sy; +} EmfPlusScaleWorldTransform; + static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result) { DWORD size_needed; @@ -248,6 +261,15 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF (*metafile)->comment_data_length = 0; (*metafile)->hemf = NULL; + if (!frameRect) + { + (*metafile)->auto_frame = TRUE; + (*metafile)->auto_frame_min.X = 0; + (*metafile)->auto_frame_min.Y = 0; + (*metafile)->auto_frame_max.X = -1; + (*metafile)->auto_frame_max.Y = -1; + } + stat = METAFILE_WriteHeader(*metafile, hdc); if (stat != Ok) @@ -306,6 +328,30 @@ GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType t return stat; } +static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points, + UINT num_points) +{ + int i; + + if (!metafile->auto_frame || !num_points) + return; + + if (metafile->auto_frame_max.X < metafile->auto_frame_min.X) + metafile->auto_frame_max = metafile->auto_frame_min = points[0]; + + for (i=0; iauto_frame_min.X) + metafile->auto_frame_min.X = points[i].X; + if (points[i].X > metafile->auto_frame_max.X) + metafile->auto_frame_max.X = points[i].X; + if (points[i].Y < metafile->auto_frame_min.Y) + metafile->auto_frame_min.Y = points[i].Y; + if (points[i].Y > metafile->auto_frame_max.Y) + metafile->auto_frame_max.Y = points[i].Y; + } +} + GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) { GpStatus stat; @@ -347,6 +393,27 @@ GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) return Ok; } +GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color) +{ + if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) + { + EmfPlusClear *record; + GpStatus stat; + + stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusClear), (void**)&record); + if (stat != Ok) + return stat; + + record->Header.Type = EmfPlusRecordTypeClear; + record->Header.Flags = 0; + record->Color = color; + + METAFILE_WriteRecords(metafile); + } + + return Ok; +} + static BOOL is_integer_rect(const GpRectF *rect) { SHORT x, y, width, height; @@ -423,6 +490,29 @@ GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush, METAFILE_WriteRecords(metafile); } + if (metafile->auto_frame) + { + GpPointF corners[4]; + int i; + + for (i=0; irecord_graphics, CoordinateSpaceDevice, + CoordinateSpaceWorld, corners, 4); + + METAFILE_AdjustFrame(metafile, corners, 4); + } + } + return Ok; } @@ -449,6 +539,52 @@ GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale return Ok; } +GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) +{ + if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) + { + EmfPlusScaleWorldTransform *record; + GpStatus stat; + + stat = METAFILE_AllocateRecord(metafile, + sizeof(EmfPlusScaleWorldTransform), + (void**)&record); + if (stat != Ok) + return stat; + + record->Header.Type = EmfPlusRecordTypeScaleWorldTransform; + record->Header.Flags = (order == MatrixOrderAppend ? 4 : 0); + record->Sx = sx; + record->Sy = sy; + + METAFILE_WriteRecords(metafile); + } + + return Ok; +} + +GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile) +{ + if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) + { + EmfPlusRecordHeader *record; + GpStatus stat; + + stat = METAFILE_AllocateRecord(metafile, + sizeof(EmfPlusRecordHeader), + (void**)&record); + if (stat != Ok) + return stat; + + record->Type = EmfPlusRecordTypeResetWorldTransform; + record->Flags = 0; + + METAFILE_WriteRecords(metafile); + } + + return Ok; +} + GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) { if (hdc != metafile->record_dc) @@ -476,6 +612,57 @@ GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) MetafileHeader header; stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header); + if (stat == Ok && metafile->auto_frame && + metafile->auto_frame_max.X >= metafile->auto_frame_min.X) + { + RECTL bounds_rc, gdi_bounds_rc; + REAL x_scale = 2540.0 / header.DpiX; + REAL y_scale = 2540.0 / header.DpiY; + BYTE* buffer; + UINT buffer_size; + + bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale); + bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale); + bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale); + bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale); + + gdi_bounds_rc = header.u.EmfHeader.rclBounds; + if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top) + { + bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left); + bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top); + bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right); + bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom); + } + + buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL); + buffer = heap_alloc(buffer_size); + if (buffer) + { + HENHMETAFILE new_hemf; + + GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer); + + ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc; + + new_hemf = SetEnhMetaFileBits(buffer_size, buffer); + + if (new_hemf) + { + DeleteEnhMetaFile(metafile->hemf); + metafile->hemf = new_hemf; + } + else + stat = OutOfMemory; + + heap_free(buffer); + } + else + stat = OutOfMemory; + + if (stat == Ok) + stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header); + } if (stat == Ok) { metafile->bounds.X = header.X; @@ -568,6 +755,11 @@ static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile) } } +static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile) +{ + return GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace); +} + static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile) { GpMatrix *real_transform; @@ -645,6 +837,12 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, case EmfPlusRecordTypeGetDC: METAFILE_PlaybackGetDC((GpMetafile*)metafile); break; + case EmfPlusRecordTypeClear: + { + EmfPlusClear *record = (EmfPlusClear*)header; + + return GdipGraphicsClear(metafile->playback_graphics, record->Color); + } case EmfPlusRecordTypeFillRects: { EmfPlusFillRects *record = (EmfPlusFillRects*)header; @@ -724,6 +922,24 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, return METAFILE_PlaybackUpdateWorldTransform(real_metafile); } + case EmfPlusRecordTypeScaleWorldTransform: + { + EmfPlusScaleWorldTransform *record = (EmfPlusScaleWorldTransform*)header; + MatrixOrder order = (flags & 0x4) ? MatrixOrderAppend : MatrixOrderPrepend; + + if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusScaleWorldTransform)) + return InvalidParameter; + + GdipScaleMatrix(real_metafile->world_transform, record->Sx, record->Sy, order); + + return METAFILE_PlaybackUpdateWorldTransform(real_metafile); + } + case EmfPlusRecordTypeResetWorldTransform: + { + GdipSetMatrixElements(real_metafile->world_transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + + return METAFILE_PlaybackUpdateWorldTransform(real_metafile); + } default: FIXME("Not implemented for record type %x\n", recordType); return NotImplemented; @@ -799,6 +1015,7 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, GpStatus stat; GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */ GraphicsContainer state; + GpPath *dst_path; TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile, destPoints, count, srcRect, srcUnit, callback, callbackData, @@ -838,6 +1055,38 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, if (stat == Ok) stat = GdipSetPageUnit(graphics, UnitPixel); + if (stat == Ok) + stat = GdipResetWorldTransform(graphics); + + if (stat == Ok) + stat = GdipCreateRegion(&real_metafile->base_clip); + + if (stat == Ok) + stat = GdipGetClip(graphics, real_metafile->base_clip); + + if (stat == Ok) + stat = GdipCreatePath(FillModeAlternate, &dst_path); + + if (stat == Ok) + { + GpPointF clip_points[4]; + + clip_points[0] = real_metafile->playback_points[0]; + clip_points[1] = real_metafile->playback_points[1]; + clip_points[2].X = real_metafile->playback_points[1].X + real_metafile->playback_points[2].X + - real_metafile->playback_points[0].X; + clip_points[2].Y = real_metafile->playback_points[1].Y + real_metafile->playback_points[2].Y + - real_metafile->playback_points[0].Y; + clip_points[3] = real_metafile->playback_points[2]; + + stat = GdipAddPathPolygon(dst_path, clip_points, 4); + + if (stat == Ok) + stat = GdipCombineRegionPath(real_metafile->base_clip, dst_path, CombineModeIntersect); + + GdipDeletePath(dst_path); + } + if (stat == Ok) stat = GdipCreateMatrix(&real_metafile->world_transform); @@ -848,6 +1097,11 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile); } + if (stat == Ok) + { + stat = METAFILE_PlaybackUpdateClip(real_metafile); + } + if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf || metafile->metafile_type == MetafileTypeWmfPlaceable || metafile->metafile_type == MetafileTypeWmf)) @@ -861,6 +1115,9 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, GdipDeleteMatrix(real_metafile->world_transform); real_metafile->world_transform = NULL; + GdipDeleteRegion(real_metafile->base_clip); + real_metafile->base_clip = NULL; + GdipEndContainer(graphics, state); } @@ -1205,8 +1462,22 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file, GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file, GpMetafile **metafile) { - FIXME("(%p, %p): stub\n", file, metafile); - return NotImplemented; + GpStatus status; + IStream *stream; + + TRACE("(%p, %p)\n", file, metafile); + + if (!file || !metafile) return InvalidParameter; + + *metafile = NULL; + + status = GdipCreateStreamOnFile(file, GENERIC_READ, &stream); + if (status == Ok) + { + status = GdipCreateMetafileFromStream(stream, metafile); + IStream_Release(stream); + } + return status; } GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream, diff --git a/reactos/dll/win32/gdiplus/region.c b/reactos/dll/win32/gdiplus/region.c index 858d03d2965..255237e4876 100644 --- a/reactos/dll/win32/gdiplus/region.c +++ b/reactos/dll/win32/gdiplus/region.c @@ -809,7 +809,7 @@ static void write_element(const region_element* element, DWORD *buffer, * their code followed by a second header for the path followed by the actual * path data. Followed by the flags for each point. The pathheader contains * the size of the data to follow, a version number again, followed by a count - * of how many points, and any special flags which may apply. 0x4000 means its + * of how many points, and any special flags which may apply. 0x4000 means it's * a path of shorts instead of FLOAT. * * Combining Ops are stored in reverse order from when they were constructed; @@ -1102,6 +1102,12 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn) GpStatus stat; INT save_state; + if (!path->pathdata.Count) /* PathToRegion doesn't support empty paths */ + { + *hrgn = CreateRectRgn( 0, 0, 0, 0 ); + return *hrgn ? Ok : OutOfMemory; + } + if (!graphics) { new_hdc = CreateCompatibleDC(0); @@ -1384,11 +1390,7 @@ GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion* region, REAL x, REAL y, RE return Ok; } - rect.left = ceilr(x); - rect.top = ceilr(y); - rect.right = ceilr(x + w); - rect.bottom = ceilr(y + h); - + SetRect(&rect, ceilr(x), ceilr(y), ceilr(x + w), ceilr(y + h)); *res = RectInRegion(hrgn, &rect); DeleteObject(hrgn); diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 6bd885fdbc6..fc448f51100 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -68,7 +68,7 @@ reactos/dll/win32/dciman32 # Synced to WineStaging-1.9.11 reactos/dll/win32/faultrep # Synced to WineStaging-1.9.11 reactos/dll/win32/fontsub # Synced to WineStaging-1.9.13 reactos/dll/win32/fusion # Synced to WineStaging-1.9.11 -reactos/dll/win32/gdiplus # Synced to WineStaging-1.9.11 +reactos/dll/win32/gdiplus # Synced to WineStaging-1.9.16 reactos/dll/win32/hhctrl.ocx # Synced to WineStaging-1.9.16 reactos/dll/win32/hlink # Synced to WineStaging-1.9.16 reactos/dll/win32/hnetcfg # Synced to WineStaging-1.9.11