https://git.reactos.org/?p=reactos.git;a=commitdiff;h=007122e7743763b2534f8…
commit 007122e7743763b2534f8b2d1525e473e653d57c
Author: Amine Khaldi <amine.khaldi(a)reactos.org>
AuthorDate: Fri Jan 19 00:17:41 2018 +0100
Commit: Amine Khaldi <amine.khaldi(a)reactos.org>
CommitDate: Fri Jan 19 00:17:41 2018 +0100
[GDIPLUS] Sync with Wine 3.0. CORE-14225
---
dll/win32/gdiplus/brush.c | 14 +-
dll/win32/gdiplus/font.c | 38 +-
dll/win32/gdiplus/gdiplus.spec | 2 +-
dll/win32/gdiplus/gdiplus_private.h | 70 +-
dll/win32/gdiplus/graphics.c | 323 +++---
dll/win32/gdiplus/image.c | 137 +--
dll/win32/gdiplus/imageattributes.c | 11 +-
dll/win32/gdiplus/metafile.c | 1856 +++++++++++++++++++++++++++++++----
dll/win32/gdiplus/region.c | 24 -
media/doc/README.WINE | 2 +-
10 files changed, 1905 insertions(+), 572 deletions(-)
diff --git a/dll/win32/gdiplus/brush.c b/dll/win32/gdiplus/brush.c
index 7e6d7efbad..dfacfbcb03 100644
--- a/dll/win32/gdiplus/brush.c
+++ b/dll/win32/gdiplus/brush.c
@@ -243,7 +243,7 @@ static const char HatchBrushes[][8] = {
{ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
};
-GpStatus get_hatch_data(HatchStyle hatchstyle, const char **result)
+GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result)
{
if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0]))
{
@@ -257,12 +257,15 @@ GpStatus get_hatch_data(HatchStyle hatchstyle, const char **result)
/******************************************************************************
* GdipCreateHatchBrush [GDIPLUS.@]
*/
-GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, ARGB
backcol, GpHatch **brush)
+GpStatus WINGDIPAPI GdipCreateHatchBrush(GpHatchStyle hatchstyle, ARGB forecol, ARGB
backcol, GpHatch **brush)
{
TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush);
if(!brush) return InvalidParameter;
+ if(hatchstyle < HatchStyleMin || hatchstyle > HatchStyleMax)
+ return InvalidParameter;
+
*brush = heap_alloc_zero(sizeof(GpHatch));
if (!*brush) return OutOfMemory;
@@ -491,9 +494,12 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST
GpRectF* rect
TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor,
angle, isAngleScalable,
wrap, line);
- if (!rect || !rect->Width || !rect->Height)
+ if (!rect || !line || wrap == WrapModeClamp)
return InvalidParameter;
+ if (!rect->Width || !rect->Height)
+ return OutOfMemory;
+
angle = fmodf(angle, 360);
if (angle < 0)
angle += 360;
@@ -951,7 +957,7 @@ GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch *brush, ARGB
*forecol)
return Ok;
}
-GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, HatchStyle *hatchstyle)
+GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, GpHatchStyle *hatchstyle)
{
TRACE("(%p, %p)\n", brush, hatchstyle);
diff --git a/dll/win32/gdiplus/font.c b/dll/win32/gdiplus/font.c
index 57f90e7caa..c0fb51c076 100644
--- a/dll/win32/gdiplus/font.c
+++ b/dll/win32/gdiplus/font.c
@@ -1378,33 +1378,36 @@ static int match_name_table_language( const tt_name_record *name,
LANGID lang )
return 0;
}
-static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data, WCHAR
*ret, DWORD len )
+static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data )
{
WORD name_len = GET_BE_WORD(name->length);
WORD codepage;
+ WCHAR *ret;
+ int len;
switch (GET_BE_WORD(name->platform_id))
{
case TT_PLATFORM_APPLE_UNICODE:
case TT_PLATFORM_MICROSOFT:
- if (name_len >= len*sizeof(WCHAR))
- return NULL;
+ ret = heap_alloc((name_len / 2 + 1) * sizeof(WCHAR));
for (len = 0; len < name_len / 2; len++)
ret[len] = (data[len * 2] << 8) | data[len * 2 + 1];
ret[len] = 0;
return ret;
case TT_PLATFORM_MACINTOSH:
codepage = get_mac_code_page( name );
- len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len-1 );
+ len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, NULL, 0 ) + 1;
if (!len)
return NULL;
+ ret = heap_alloc(len * sizeof(WCHAR));
+ len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len - 1 );
ret[len] = 0;
return ret;
}
return NULL;
}
-static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id, WCHAR *ret,
DWORD len )
+static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id )
{
LANGID lang = GetSystemDefaultLangID();
const tt_header *header;
@@ -1465,8 +1468,9 @@ static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size,
DWORD id, WCHAR
if (best_lang)
{
+ WCHAR *ret;
name_record = (const tt_name_record*)(name_table + 1) + best_index;
- ret = copy_name_table_string( name_record,
mem+ofs+GET_BE_WORD(name_record->offset), ret, len );
+ ret = copy_name_table_string( name_record,
mem+ofs+GET_BE_WORD(name_record->offset) );
TRACE( "name %u found platform %u lang %04x %s\n",
GET_BE_WORD(name_record->name_id),
GET_BE_WORD(name_record->platform_id),
GET_BE_WORD(name_record->language_id), debugstr_w( ret ));
return ret;
@@ -1482,43 +1486,45 @@ static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const
TEXTMETRICW *ntm, D
GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection,
GDIPCONST void* memory, INT length)
{
- WCHAR buf[32], *name;
+ WCHAR *name;
DWORD count = 0;
HANDLE font;
+ GpStatus ret = Ok;
TRACE("%p, %p, %d\n", fontCollection, memory, length);
if (!fontCollection || !memory || !length)
return InvalidParameter;
- name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME, buf,
sizeof(buf)/sizeof(*buf));
+ name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME);
if (!name)
return OutOfMemory;
font = AddFontMemResourceEx((void*)memory, length, NULL, &count);
TRACE("%s: %p/%u\n", debugstr_w(name), font, count);
if (!font || !count)
- return InvalidParameter;
-
- if (count)
+ ret = InvalidParameter;
+ else
{
HDC hdc;
LOGFONTW lfw;
hdc = CreateCompatibleDC(0);
+ /* Truncate name if necessary, GDI32 can't deal with long names */
+ if(lstrlenW(name) > LF_FACESIZE - 1)
+ name[LF_FACESIZE - 1] = 0;
+
lfw.lfCharSet = DEFAULT_CHARSET;
lstrcpyW(lfw.lfFaceName, name);
lfw.lfPitchAndFamily = 0;
if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)fontCollection,
0))
- {
- DeleteDC(hdc);
- return OutOfMemory;
- }
+ ret = OutOfMemory;
DeleteDC(hdc);
}
- return Ok;
+ heap_free(name);
+ return ret;
}
/*****************************************************************************
diff --git a/dll/win32/gdiplus/gdiplus.spec b/dll/win32/gdiplus/gdiplus.spec
index b29e41ebfa..0e7a78f30c 100644
--- a/dll/win32/gdiplus/gdiplus.spec
+++ b/dll/win32/gdiplus/gdiplus.spec
@@ -615,7 +615,7 @@
615 stub GdipGetEffectParameterSize
616 stub GdipGetEffectParameters
617 stdcall GdipSetEffectParameters(ptr ptr long)
-618 stdcall GdipInitializePalette(ptr long long long ptr)
+618 stdcall -stub GdipInitializePalette(ptr long long long ptr)
619 stdcall GdipBitmapCreateApplyEffect(ptr long ptr ptr ptr ptr long ptr ptr)
620 stdcall GdipBitmapApplyEffect(ptr ptr ptr long ptr ptr)
621 stdcall GdipBitmapGetHistogram(ptr long long ptr ptr ptr ptr)
diff --git a/dll/win32/gdiplus/gdiplus_private.h b/dll/win32/gdiplus/gdiplus_private.h
index 633ef14b41..192e36756a 100644
--- a/dll/win32/gdiplus/gdiplus_private.h
+++ b/dll/win32/gdiplus/gdiplus_private.h
@@ -129,6 +129,7 @@ extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile,
GpImage *imag
extern GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val)
DECLSPEC_HIDDEN;
extern GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path)
DECLSPEC_HIDDEN;
extern GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path)
DECLSPEC_HIDDEN;
+extern void METAFILE_Free(GpMetafile *metafile) DECLSPEC_HIDDEN;
extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
@@ -147,7 +148,7 @@ extern GpStatus trace_path(GpGraphics *graphics, GpPath *path)
DECLSPEC_HIDDEN;
typedef struct region_element region_element;
extern void delete_element(region_element *element) DECLSPEC_HIDDEN;
-extern GpStatus get_hatch_data(HatchStyle hatchstyle, const char **result)
DECLSPEC_HIDDEN;
+extern GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result)
DECLSPEC_HIDDEN;
static inline INT gdip_round(REAL x)
{
@@ -270,6 +271,7 @@ struct GpGraphics{
INT origin_x, origin_y;
INT gdi_transform_acquire_count, gdi_transform_save;
GpMatrix gdi_transform;
+ HRGN gdi_clip;
/* For giving the caller an HDC when we technically can't: */
HBITMAP temp_hbitmap;
int temp_hbitmap_width;
@@ -284,7 +286,7 @@ struct GpBrush{
struct GpHatch{
GpBrush brush;
- HatchStyle hatchstyle;
+ GpHatchStyle hatchstyle;
ARGB forecol;
ARGB backcol;
};
@@ -378,6 +380,38 @@ struct GpImage{
LONG busy;
};
+#define EmfPlusObjectTableSize 64
+
+typedef enum EmfPlusObjectType
+{
+ ObjectTypeInvalid,
+ ObjectTypeBrush,
+ ObjectTypePen,
+ ObjectTypePath,
+ ObjectTypeRegion,
+ ObjectTypeImage,
+ ObjectTypeFont,
+ ObjectTypeStringFormat,
+ ObjectTypeImageAttributes,
+ ObjectTypeCustomLineCap,
+ ObjectTypeMax = ObjectTypeCustomLineCap,
+} EmfPlusObjectType;
+
+/* Deserialized EmfPlusObject record. */
+struct emfplus_object {
+ EmfPlusObjectType type;
+ union {
+ GpBrush *brush;
+ GpPen *pen;
+ GpPath *path;
+ GpRegion *region;
+ GpImage *image;
+ GpFont *font;
+ GpImageAttributes *image_attributes;
+ void *object;
+ } u;
+};
+
struct GpMetafile{
GpImage image;
GpRectF bounds;
@@ -411,6 +445,7 @@ struct GpMetafile{
GpRegion *base_clip; /* clip region in device space for all metafile output */
GpRegion *clip; /* clip region within the metafile */
struct list containers;
+ struct emfplus_object objtable[EmfPlusObjectTableSize];
};
struct GpBitmap{
@@ -454,6 +489,12 @@ struct color_remap_table{
ColorMap *colormap;
};
+enum imageattr_noop{
+ IMAGEATTR_NOOP_UNDEFINED,
+ IMAGEATTR_NOOP_SET,
+ IMAGEATTR_NOOP_CLEAR,
+};
+
struct GpImageAttributes{
WrapMode wrap;
ARGB outside_color;
@@ -463,6 +504,7 @@ struct GpImageAttributes{
struct color_remap_table colorremaptables[ColorAdjustTypeCount];
BOOL gamma_enabled[ColorAdjustTypeCount];
REAL gamma[ColorAdjustTypeCount];
+ enum imageattr_noop noop[ColorAdjustTypeCount];
};
struct GpFont{
@@ -535,6 +577,30 @@ struct GpRegion{
region_element node;
};
+struct memory_buffer
+{
+ const BYTE *buffer;
+ INT size, pos;
+};
+
+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;
+}
+
typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
diff --git a/dll/win32/gdiplus/graphics.c b/dll/win32/gdiplus/graphics.c
index 79f9b11248..71ea19cbb5 100644
--- a/dll/win32/gdiplus/graphics.c
+++ b/dll/win32/gdiplus/graphics.c
@@ -302,13 +302,6 @@ static void round_points(POINT *pti, GpPointF *ptf, INT count)
}
}
-static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
- GpPointF *ptf, INT count)
-{
- gdip_transform_points(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, ptf,
count);
- round_points(pti, ptf, count);
-}
-
static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_width,
INT dst_height,
HDC hdc, INT src_x, INT src_y, INT src_width, INT
src_height)
{
@@ -355,6 +348,17 @@ static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
GdipDeleteRegion(rgn);
}
+ if (stat == Ok && graphics->gdi_clip)
+ {
+ if (*hrgn)
+ CombineRgn(*hrgn, *hrgn, graphics->gdi_clip, RGN_AND);
+ else
+ {
+ *hrgn = CreateRectRgn(0,0,0,0);
+ CombineRgn(*hrgn, graphics->gdi_clip, graphics->gdi_clip, RGN_COPY);
+ }
+ }
+
return stat;
}
@@ -505,8 +509,6 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT
dst_x, INT dst
save = SaveDC(graphics->hdc);
- SetViewportOrgEx(graphics->hdc, 0, 0, NULL);
-
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
if (hregion)
@@ -529,23 +531,12 @@ static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x,
INT dst_y,
return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height,
src_stride, NULL, fmt);
}
-/* NOTE: start and end pixels must be in pre-multiplied ARGB format */
-static inline ARGB blend_colors_premult(ARGB start, ARGB end, REAL position)
-{
- UINT pos = position * 255.0f + 0.5f;
- return
- (((((start >> 24) ) << 8) + (((end >> 24) ) -
((start >> 24) )) * pos) >> 8) << 24 |
- (((((start >> 16) & 0xff) << 8) + (((end >> 16) & 0xff)
- ((start >> 16) & 0xff)) * pos) >> 8) << 16 |
- (((((start >> 8) & 0xff) << 8) + (((end >> 8) & 0xff)
- ((start >> 8) & 0xff)) * pos) >> 8) << 8 |
- (((((start ) & 0xff) << 8) + (((end ) & 0xff) - ((start
) & 0xff)) * pos) >> 8);
-}
-
static ARGB blend_colors(ARGB start, ARGB end, REAL position)
{
INT start_a, end_a, final_a;
INT pos;
- pos = (INT)(position * 255.0f + 0.5f);
+ pos = gdip_round(position * 0xff);
start_a = ((start >> 24) & 0xff) * (pos ^ 0xff);
end_a = ((end >> 24) & 0xff) * pos;
@@ -685,6 +676,11 @@ PixelFormat apply_image_attributes(const GpImageAttributes
*attributes, LPBYTE d
UINT x, y;
INT i;
+ if ((attributes->noop[type] == IMAGEATTR_NOOP_UNDEFINED &&
+ attributes->noop[ColorAdjustTypeDefault] == IMAGEATTR_NOOP_SET) ||
+ (attributes->noop[type] == IMAGEATTR_NOOP_SET))
+ return fmt;
+
if (attributes->colorkeys[type].enabled ||
attributes->colorkeys[ColorAdjustTypeDefault].enabled)
{
@@ -946,11 +942,6 @@ static ARGB sample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE
bits, UINT wi
return ((DWORD*)(bits))[(x - src_rect->X) + (y - src_rect->Y) *
src_rect->Width];
}
-static inline int positive_ceilf(float f)
-{
- return f - (int)f > 0.0f ? f + 1.0f : f;
-}
-
static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width,
UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes,
InterpolationMode interpolation, PixelOffsetMode offset_mode)
@@ -971,12 +962,12 @@ static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE
bits, UINT
ARGB top, bottom;
float x_offset;
- leftx = (INT)point->X;
- leftxf = (REAL)leftx;
- rightx = positive_ceilf(point->X);
- topy = (INT)point->Y;
- topyf = (REAL)topy;
- bottomy = positive_ceilf(point->Y);
+ leftxf = floorf(point->X);
+ leftx = (INT)leftxf;
+ rightx = (INT)ceilf(point->X);
+ topyf = floorf(point->Y);
+ topy = (INT)topyf;
+ bottomy = (INT)ceilf(point->Y);
if (leftx == rightx && topy == bottomy)
return sample_bitmap_pixel(src_rect, bits, width, height,
@@ -1020,75 +1011,6 @@ static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect,
LPBYTE bits, UINT
}
}
-static ARGB resample_bitmap_pixel_premult(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT
width,
- UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes,
- InterpolationMode interpolation, PixelOffsetMode offset_mode)
-{
- static int fixme;
-
- switch (interpolation)
- {
- default:
- if (!fixme++)
- FIXME("Unimplemented interpolation %i\n", interpolation);
- /* fall-through */
- case InterpolationModeBilinear:
- {
- REAL leftxf, topyf;
- INT leftx, rightx, topy, bottomy;
- ARGB topleft, topright, bottomleft, bottomright;
- ARGB top, bottom;
- float x_offset;
-
- leftx = (INT)point->X;
- leftxf = (REAL)leftx;
- rightx = positive_ceilf(point->X);
- topy = (INT)point->Y;
- topyf = (REAL)topy;
- bottomy = positive_ceilf(point->Y);
-
- if (leftx == rightx && topy == bottomy)
- return sample_bitmap_pixel(src_rect, bits, width, height,
- leftx, topy, attributes);
-
- topleft = sample_bitmap_pixel(src_rect, bits, width, height,
- leftx, topy, attributes);
- topright = sample_bitmap_pixel(src_rect, bits, width, height,
- rightx, topy, attributes);
- bottomleft = sample_bitmap_pixel(src_rect, bits, width, height,
- leftx, bottomy, attributes);
- bottomright = sample_bitmap_pixel(src_rect, bits, width, height,
- rightx, bottomy, attributes);
-
- x_offset = point->X - leftxf;
- top = blend_colors_premult(topleft, topright, x_offset);
- bottom = blend_colors_premult(bottomleft, bottomright, x_offset);
-
- return blend_colors_premult(top, bottom, point->Y - topyf);
- }
- case InterpolationModeNearestNeighbor:
- {
- FLOAT pixel_offset;
- switch (offset_mode)
- {
- default:
- case PixelOffsetModeNone:
- case PixelOffsetModeHighSpeed:
- pixel_offset = 0.5;
- break;
-
- case PixelOffsetModeHalf:
- case PixelOffsetModeHighQuality:
- pixel_offset = 0.0;
- break;
- }
- return sample_bitmap_pixel(src_rect, bits, width, height,
- floorf(point->X + pixel_offset), point->Y + pixel_offset, attributes);
- }
-
- }
-}
-
static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL y)
{
return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X;
@@ -2312,7 +2234,7 @@ static void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont
*font,
GdipTransformMatrixPoints(&xform, pt, 3);
}
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, 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));
@@ -2342,6 +2264,20 @@ GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics
**graphics)
return GdipCreateFromHDC2(hdc, NULL, graphics);
}
+static void get_gdi_transform(GpGraphics *graphics, GpMatrix *matrix)
+{
+ XFORM xform;
+
+ if (graphics->hdc == NULL)
+ {
+ GdipSetMatrixElements(matrix, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+ return;
+ }
+
+ GetTransform(graphics->hdc, 0x204, &xform);
+ GdipSetMatrixElements(matrix, xform.eM11, xform.eM12, xform.eM21, xform.eM22,
xform.eDx, xform.eDy);
+}
+
GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **graphics)
{
GpStatus retval;
@@ -2391,7 +2327,19 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice,
GpGraphics **gra
(*graphics)->busy = FALSE;
(*graphics)->textcontrast = 4;
list_init(&(*graphics)->containers);
+#ifdef __REACTOS__
(*graphics)->contid = GDIP_GET_NEW_CONTID_FOR(*graphics);
+#else
+ (*graphics)->contid = 0;
+#endif
+ get_gdi_transform(*graphics, &(*graphics)->gdi_transform);
+
+ (*graphics)->gdi_clip = CreateRectRgn(0,0,0,0);
+ if (!GetClipRgn(hdc, (*graphics)->gdi_clip))
+ {
+ DeleteObject((*graphics)->gdi_clip);
+ (*graphics)->gdi_clip = NULL;
+ }
TRACE("<-- %p\n", *graphics);
@@ -2406,6 +2354,7 @@ GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics)
if(!*graphics) return OutOfMemory;
GdipSetMatrixElements(&(*graphics)->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0,
0.0);
+ GdipSetMatrixElements(&(*graphics)->gdi_transform, 1.0, 0.0, 0.0, 1.0, 0.0,
0.0);
if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
heap_free(*graphics);
@@ -2431,7 +2380,11 @@ GpStatus graphics_from_image(GpImage *image, GpGraphics
**graphics)
(*graphics)->busy = FALSE;
(*graphics)->textcontrast = 4;
list_init(&(*graphics)->containers);
+#ifdef __REACTOS__
(*graphics)->contid = GDIP_GET_NEW_CONTID_FOR(*graphics);
+#else
+ (*graphics)->contid = 0;
+#endif
TRACE("<-- %p\n", *graphics);
@@ -2516,6 +2469,8 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
GdipDeleteRegion(graphics->clip);
+ DeleteObject(graphics->gdi_clip);
+
/* Native returns ObjectBusy on the second free, instead of crashing as we'd
* do otherwise, but we can't have that in the test suite because it means
* accessing freed memory. */
@@ -3151,10 +3106,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics,
GpImage *image
lockeddata.Scan0 = src_data;
if (!do_resampling && bitmap->format == PixelFormat32bppPARGB)
lockeddata.PixelFormat = apply_image_attributes(imageAttributes, NULL, 0,
0, 0, ColorAdjustTypeBitmap, bitmap->format);
- else if (imageAttributes != &defaultImageAttributes)
- lockeddata.PixelFormat = PixelFormat32bppARGB;
else
- lockeddata.PixelFormat = PixelFormat32bppPARGB;
+ lockeddata.PixelFormat = PixelFormat32bppARGB;
stat = GdipBitmapLockBits(bitmap, &src_area,
ImageLockModeRead|ImageLockModeUserInputBuf,
lockeddata.PixelFormat, &lockeddata);
@@ -3174,8 +3127,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics,
GpImage *image
if (do_resampling)
{
- REAL delta_xx, delta_xy, delta_yx, delta_yy;
-
/* Transform the bits as needed to the destination. */
dst_data = dst_dyn_data = heap_alloc_zero(sizeof(ARGB) * (dst_area.right
- dst_area.left) * (dst_area.bottom - dst_area.top));
if (!dst_data)
@@ -3193,42 +3144,24 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics,
GpImage *image
y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
- delta_yy = dst_area.top * y_dy;
- delta_yx = dst_area.top * y_dx;
-
- for (y=dst_area.top; y<dst_area.bottom; y++)
+ for (x=dst_area.left; x<dst_area.right; x++)
{
- delta_xx = dst_area.left * x_dx;
- delta_xy = dst_area.left * x_dy;
-
- for (x=dst_area.left; x<dst_area.right; x++)
+ for (y=dst_area.top; y<dst_area.bottom; y++)
{
GpPointF src_pointf;
ARGB *dst_color;
- src_pointf.X = dst_to_src_points[0].X + delta_xx + delta_yx;
- src_pointf.Y = dst_to_src_points[0].Y + delta_xy + delta_yy;
+ src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx;
+ src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy;
dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) +
sizeof(ARGB) * (x - dst_area.left));
if (src_pointf.X >= srcx && src_pointf.X < srcx +
srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight)
- {
- if (lockeddata.PixelFormat != PixelFormat32bppPARGB)
- *dst_color = resample_bitmap_pixel(&src_area,
src_data, bitmap->width, bitmap->height, &src_pointf,
- imageAttributes,
interpolation, offset_mode);
- else
- *dst_color = resample_bitmap_pixel_premult(&src_area,
src_data, bitmap->width, bitmap->height, &src_pointf,
-
imageAttributes, interpolation, offset_mode);
- }
+ *dst_color = resample_bitmap_pixel(&src_area, src_data,
bitmap->width, bitmap->height, &src_pointf,
+ imageAttributes,
interpolation, offset_mode);
else
*dst_color = 0;
-
- delta_xx += x_dx;
- delta_yx += y_dx;
}
-
- delta_xy += x_dy;
- delta_yy += y_dy;
}
}
else
@@ -3322,9 +3255,9 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics,
GpImage *image
stat = get_clip_hrgn(graphics, &hrgn);
- if (stat == Ok && hrgn)
+ if (stat == Ok)
{
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
DeleteObject(hrgn);
}
@@ -3565,8 +3498,7 @@ static GpStatus GDI32_GdipDrawPath(GpGraphics *graphics, GpPen *pen,
GpPath *pat
if (retval != Ok)
goto end;
- if (hrgn)
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
gdi_transform_acquire(graphics);
@@ -3907,7 +3839,7 @@ static GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen
*pen, GpPath *
points[1].X = pen->width;
points[2].Y = pen->width;
- stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
+ stat = gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, points, 3);
if (stat != Ok)
@@ -3931,7 +3863,7 @@ static GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen
*pen, GpPath *
stat = GdipCreateMatrix(&transform);
if (stat == Ok)
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, transform);
}
else
@@ -3939,7 +3871,7 @@ static GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen
*pen, GpPath *
/* Set flatness based on the final coordinate space */
GpMatrix t;
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, &t);
if (stat != Ok)
@@ -4254,8 +4186,7 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush
*brush, GpPath
if (retval != Ok)
goto end;
- if (hrgn)
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
gdi_transform_acquire(graphics);
@@ -4542,32 +4473,30 @@ static GpStatus GDI32_GdipFillRegion(GpGraphics* graphics,
GpBrush* brush,
if(!graphics->hdc || !brush_can_fill_path(brush, TRUE))
return NotImplemented;
- status = GdipGetRegionHRgn(region, graphics, &hrgn);
- if(status != Ok)
- return status;
-
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
-
- DeleteObject(hrgn);
-
hrgn = NULL;
status = get_clip_hrgn(graphics, &hrgn);
-
if (status != Ok)
{
RestoreDC(graphics->hdc, save_state);
return status;
}
- if (hrgn)
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
+ DeleteObject(hrgn);
+
+ status = GdipGetRegionHRgn(region, graphics, &hrgn);
+ if (status != Ok)
{
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
- DeleteObject(hrgn);
+ RestoreDC(graphics->hdc, save_state);
+ return status;
}
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ DeleteObject(hrgn);
+
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
{
BeginPath(graphics->hdc);
@@ -5371,7 +5300,7 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics*
graphics,
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld,
pt, 3);
args.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));
args.rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
@@ -5400,9 +5329,13 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics*
graphics,
args.regions = regions;
+ gdi_transform_acquire(graphics);
+
stat = gdip_format_string(hdc, string, length, font, &scaled_rect, stringFormat,
(stringFormat->attr & StringFormatFlagsNoClip) != 0,
measure_ranges_callback, &args);
+ gdi_transform_release(graphics);
+
SelectObject(hdc, oldfont);
DeleteObject(gdifont);
@@ -5490,7 +5423,7 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld,
pt, 3);
args.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));
args.rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
@@ -5525,9 +5458,13 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
args.linesfilled = &lines;
lines = glyphs = 0;
+ gdi_transform_acquire(graphics);
+
gdip_format_string(hdc, string, length, font, &scaled_rect, format, TRUE,
measure_string_callback, &args);
+ gdi_transform_release(graphics);
+
if (linesfilled) *linesfilled = lines;
if (codepointsfitted) *codepointsfitted = glyphs;
@@ -5657,7 +5594,7 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST
WCHAR *string
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld,
pt, 3);
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));
rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
@@ -5667,7 +5604,8 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST
WCHAR *string
rectcpy[1].Y = rectcpy[0].Y = rect->Y;
rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
rectcpy[3].Y = rectcpy[2].Y = rect->Y + rect->Height;
- transform_and_round_points(graphics, corners, rectcpy, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld,
rectcpy, 4);
+ round_points(corners, rectcpy, 4);
margin_x = (format && format->generic_typographic) ? 0.0 : font->emSize
/ 6.0;
margin_x *= units_scale(font->unit, graphics->unit, graphics->xres);
@@ -5706,12 +5644,16 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST
WCHAR *string
args.rel_width = rel_width;
args.rel_height = rel_height;
+ gdi_transform_acquire(graphics);
+
GetTextMetricsW(hdc, &textmetric);
args.ascent = textmetric.tmAscent / rel_height;
gdip_format_string(hdc, string, length, font, &scaled_rect, format, TRUE,
draw_string_callback, &args);
+ gdi_transform_release(graphics);
+
DeleteObject(rgn);
DeleteObject(gdifont);
@@ -6311,6 +6253,7 @@ GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn,
CombineMode
{
GpRegion *region;
GpStatus status;
+ GpMatrix transform;
TRACE("(%p, %p, %d)\n", graphics, hrgn, mode);
@@ -6320,14 +6263,21 @@ GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN
hrgn, CombineMode
if(graphics->busy)
return ObjectBusy;
- /* hrgn is already in device units */
+ /* hrgn is in gdi32 device units */
status = GdipCreateRegionHrgn(hrgn, ®ion);
- if(status != Ok)
- return status;
- status = GdipCombineRegionRegion(graphics->clip, region, mode);
+ if (status == Ok)
+ {
+ status = get_graphics_transform(graphics, CoordinateSpaceDevice,
WineCoordinateSpaceGdiDevice, &transform);
+
+ if (status == Ok)
+ status = GdipTransformRegion(region, &transform);
+
+ if (status == Ok)
+ status = GdipCombineRegionRegion(graphics->clip, region, mode);
- GdipDeleteRegion(region);
+ GdipDeleteRegion(region);
+ }
return status;
}
@@ -6723,31 +6673,10 @@ GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion
*region)
return Ok;
}
-static void get_gdi_transform(GpGraphics *graphics, GpMatrix *matrix)
-{
- XFORM xform;
-
- if (graphics->hdc == NULL)
- {
- GdipSetMatrixElements(matrix, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
- return;
- }
-
- if (graphics->gdi_transform_acquire_count)
- {
- *matrix = graphics->gdi_transform;
- return;
- }
-
- GetTransform(graphics->hdc, 0x204, &xform);
- GdipSetMatrixElements(matrix, xform.eM11, xform.eM12, xform.eM21, xform.eM22,
xform.eDx, xform.eDy);
-}
-
GpStatus gdi_transform_acquire(GpGraphics *graphics)
{
if (graphics->gdi_transform_acquire_count == 0 && graphics->hdc)
{
- get_gdi_transform(graphics, &graphics->gdi_transform);
graphics->gdi_transform_save = SaveDC(graphics->hdc);
SetGraphicsMode(graphics->hdc, GM_COMPATIBLE);
SetMapMode(graphics->hdc, MM_TEXT);
@@ -6762,7 +6691,7 @@ GpStatus gdi_transform_release(GpGraphics *graphics)
{
if (graphics->gdi_transform_acquire_count <= 0)
{
- ERR("called without matching gdi_transform_acquire");
+ ERR("called without matching gdi_transform_acquire\n");
return GenericError;
}
if (graphics->gdi_transform_acquire_count == 1 && graphics->hdc)
@@ -6800,7 +6729,7 @@ GpStatus get_graphics_transform(GpGraphics *graphics,
GpCoordinateSpace dst_spac
case WineCoordinateSpaceGdiDevice:
{
GpMatrix gdixform;
- get_gdi_transform(graphics, &gdixform);
+ gdixform = graphics->gdi_transform;
stat = GdipInvertMatrix(&gdixform);
if (stat != Ok)
break;
@@ -6841,9 +6770,7 @@ GpStatus get_graphics_transform(GpGraphics *graphics,
GpCoordinateSpace dst_spac
/* else fall-through */
case CoordinateSpaceDevice:
{
- GpMatrix gdixform;
- get_gdi_transform(graphics, &gdixform);
- GdipMultiplyMatrix(matrix, &gdixform, MatrixOrderAppend);
+ GdipMultiplyMatrix(matrix, &graphics->gdi_transform,
MatrixOrderAppend);
break;
}
}
@@ -7015,7 +6942,7 @@ GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics,
GDIPCONST UINT
GpMatrix xform = *matrix;
GdipTransformMatrixPoints(&xform, pt, 3);
}
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld,
pt, 3);
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));
rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
@@ -7102,22 +7029,26 @@ static GpStatus GDI32_GdipDrawDriverString(GpGraphics *graphics,
GDIPCONST UINT1
status = get_clip_hrgn(graphics, &hrgn);
- if (status == Ok && hrgn)
+ if (status == Ok)
{
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
DeleteObject(hrgn);
}
pt = positions[0];
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &pt,
1);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld,
&pt, 1);
get_font_hfont(graphics, font, format, &hfont, matrix);
SelectObject(graphics->hdc, hfont);
SetTextAlign(graphics->hdc, TA_BASELINE|TA_LEFT);
+ gdi_transform_acquire(graphics);
+
ExtTextOutW(graphics->hdc, gdip_round(pt.X), gdip_round(pt.Y), eto_flags, NULL,
text, length, NULL);
+ gdi_transform_release(graphics);
+
RestoreDC(graphics->hdc, save_state);
DeleteObject(hfont);
@@ -7165,7 +7096,8 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics,
GDIPCONST UI
{
real_position = positions[0];
- transform_and_round_points(graphics, pti, &real_position, 1);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, &real_position, 1);
+ round_points(pti, &real_position, 1);
}
else
{
@@ -7178,7 +7110,8 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics,
GDIPCONST UI
memcpy(real_positions, positions, sizeof(PointF) * length);
- transform_and_round_points(graphics, pti, real_positions, length);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, real_positions, length);
+ round_points(pti, real_positions, length);
heap_free(real_positions);
}
@@ -7318,10 +7251,14 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics
*graphics, GDIPCONST UI
heap_free(text_mask);
+ gdi_transform_acquire(graphics);
+
/* draw the result */
stat = alpha_blend_pixels(graphics, min_x, min_y, pixel_data, pixel_area.Width,
pixel_area.Height, pixel_data_stride, PixelFormat32bppARGB);
+ gdi_transform_release(graphics);
+
heap_free(pixel_data);
return stat;
diff --git a/dll/win32/gdiplus/image.c b/dll/win32/gdiplus/image.c
index 214b95f40e..6390bff288 100644
--- a/dll/win32/gdiplus/image.c
+++ b/dll/win32/gdiplus/image.c
@@ -38,19 +38,13 @@ static const struct
{
{ &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed,
WICBitmapPaletteTypeFixedBW },
{ &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed,
WICBitmapPaletteTypeFixedBW },
- { &GUID_WICPixelFormat4bppIndexed, PixelFormat4bppIndexed,
WICBitmapPaletteTypeFixedHalftone8 },
{ &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed,
WICBitmapPaletteTypeFixedGray256 },
{ &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed,
WICBitmapPaletteTypeFixedHalftone256 },
{ &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555,
WICBitmapPaletteTypeFixedHalftone256 },
{ &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB,
WICBitmapPaletteTypeFixedHalftone256 },
{ &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB,
WICBitmapPaletteTypeFixedHalftone256 },
- { &GUID_WICPixelFormat48bppRGB, PixelFormat48bppRGB,
WICBitmapPaletteTypeFixedHalftone256 },
{ &GUID_WICPixelFormat32bppBGRA, PixelFormat32bppARGB,
WICBitmapPaletteTypeFixedHalftone256 },
{ &GUID_WICPixelFormat32bppPBGRA, PixelFormat32bppPARGB,
WICBitmapPaletteTypeFixedHalftone256 },
- { &GUID_WICPixelFormat32bppCMYK, PixelFormat32bppCMYK,
WICBitmapPaletteTypeFixedHalftone256 },
- { &GUID_WICPixelFormat32bppGrayFloat, PixelFormat32bppARGB,
WICBitmapPaletteTypeFixedGray256 },
- { &GUID_WICPixelFormat64bppCMYK, PixelFormat48bppRGB,
WICBitmapPaletteTypeFixedHalftone256 },
- { &GUID_WICPixelFormat64bppRGBA, PixelFormat48bppRGB,
WICBitmapPaletteTypeFixedHalftone256 },
{ NULL }
};
@@ -2074,24 +2068,7 @@ static GpStatus free_image_data(GpImage *image)
heap_free(((GpBitmap*)image)->prop_item);
}
else if (image->type == ImageTypeMetafile)
- {
- GpMetafile *metafile = (GpMetafile*)image;
- heap_free(metafile->comment_data);
- DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
- if (!metafile->preserve_hemf)
- DeleteEnhMetaFile(metafile->hemf);
- if (metafile->record_graphics)
- {
- WARN("metafile closed while recording\n");
- /* not sure what to do here; for now just prevent the graphics from
functioning or using this object */
- metafile->record_graphics->image = NULL;
- metafile->record_graphics->busy = TRUE;
- }
- if (metafile->record_stream)
- {
- IStream_Release(metafile->record_stream);
- }
- }
+ METAFILE_Free((GpMetafile *)image);
else
{
WARN("invalid image: %p\n", image);
@@ -4568,7 +4545,7 @@ static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
static GpStatus encode_image_gif(GpImage *image, IStream* stream,
GDIPCONST EncoderParameters* params)
{
- return encode_image_wic(image, stream, &GUID_ContainerFormatGif, params);
+ return encode_image_wic(image, stream, &CLSID_WICGifEncoder, params);
}
/*****************************************************************************
@@ -4581,7 +4558,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream*
stream,
encode_image_func encode_image;
int i;
- TRACE("%p %p %s %p\n", image, stream, wine_dbgstr_guid(clsid), params);
+ TRACE("%p %p %p %p\n", image, stream, clsid, params);
if(!image || !stream)
return InvalidParameter;
@@ -5595,111 +5572,3 @@ GpStatus WINGDIPAPI GdipBitmapGetHistogramSize(HistogramFormat
format, UINT *num
*num_of_entries = 256;
return Ok;
}
-
-static GpStatus create_optimal_palette(ColorPalette *palette, INT desired,
- BOOL transparent, GpBitmap *bitmap)
-{
- GpStatus status;
- BitmapData data;
- HRESULT hr;
- IWICImagingFactory *factory;
- IWICPalette *wic_palette;
-
- if (!bitmap) return InvalidParameter;
- if (palette->Count < desired) return GenericError;
-
- status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB,
&data);
- if (status != Ok) return status;
-
- hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
- if (hr != S_OK)
- {
- GdipBitmapUnlockBits(bitmap, &data);
- return hresult_to_status(hr);
- }
-
- hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
- if (hr == S_OK)
- {
- IWICBitmap *bitmap;
-
- /* PixelFormat24bppRGB actually stores the bitmap bits as BGR. */
- hr = IWICImagingFactory_CreateBitmapFromMemory(factory, data.Width, data.Height,
- &GUID_WICPixelFormat24bppBGR, data.Stride, data.Stride * data.Width,
data.Scan0, &bitmap);
- if (hr == S_OK)
- {
- hr = IWICPalette_InitializeFromBitmap(wic_palette, (IWICBitmapSource
*)bitmap, desired, transparent);
- if (hr == S_OK)
- {
- palette->Flags = 0;
- IWICPalette_GetColorCount(wic_palette, &palette->Count);
- IWICPalette_GetColors(wic_palette, palette->Count,
palette->Entries, &palette->Count);
- }
-
- IWICBitmap_Release(bitmap);
- }
-
- IWICPalette_Release(wic_palette);
- }
-
- IWICImagingFactory_Release(factory);
- GdipBitmapUnlockBits(bitmap, &data);
-
- return hresult_to_status(hr);
-}
-
-/*****************************************************************************
- * GdipInitializePalette [GDIPLUS.@]
- */
-GpStatus WINGDIPAPI GdipInitializePalette(ColorPalette *palette,
- PaletteType type, INT desired, BOOL transparent, GpBitmap *bitmap)
-{
- TRACE("(%p,%d,%d,%d,%p)\n", palette, type, desired, transparent, bitmap);
-
- if (!palette) return InvalidParameter;
-
- switch (type)
- {
- case PaletteTypeCustom:
- return Ok;
-
- case PaletteTypeOptimal:
- return create_optimal_palette(palette, desired, transparent, bitmap);
-
- /* WIC palette type enumeration matches these gdiplus enums */
- case PaletteTypeFixedBW:
- case PaletteTypeFixedHalftone8:
- case PaletteTypeFixedHalftone27:
- case PaletteTypeFixedHalftone64:
- case PaletteTypeFixedHalftone125:
- case PaletteTypeFixedHalftone216:
- case PaletteTypeFixedHalftone252:
- case PaletteTypeFixedHalftone256:
- {
- ColorPalette *wic_palette;
- GpStatus status = Ok;
-
- wic_palette = get_palette(NULL, type);
- if (!wic_palette) return OutOfMemory;
-
- if (palette->Count >= wic_palette->Count)
- {
- palette->Flags = wic_palette->Flags;
- palette->Count = wic_palette->Count;
- memcpy(palette->Entries, wic_palette->Entries, wic_palette->Count *
sizeof(wic_palette->Entries[0]));
- }
- else
- status = GenericError;
-
- heap_free(wic_palette);
-
- return status;
- }
-
- default:
- FIXME("unknown palette type %d\n", type);
- break;
- }
-
- return InvalidParameter;
-}
diff --git a/dll/win32/gdiplus/imageattributes.c b/dll/win32/gdiplus/imageattributes.c
index 12941f7b9a..b30eba9444 100644
--- a/dll/win32/gdiplus/imageattributes.c
+++ b/dll/win32/gdiplus/imageattributes.c
@@ -209,14 +209,14 @@ GpStatus WINGDIPAPI GdipSetImageAttributesGamma(GpImageAttributes
*imageAttr,
GpStatus WINGDIPAPI GdipSetImageAttributesNoOp(GpImageAttributes *imageAttr,
ColorAdjustType type, BOOL enableFlag)
{
- static int calls;
-
TRACE("(%p,%u,%i)\n", imageAttr, type, enableFlag);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (type >= ColorAdjustTypeCount)
+ return InvalidParameter;
- return NotImplemented;
+ imageAttr->noop[type] = enableFlag ? IMAGEATTR_NOOP_SET : IMAGEATTR_NOOP_CLEAR;
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipSetImageAttributesOutputChannel(GpImageAttributes *imageAttr,
@@ -323,6 +323,7 @@ GpStatus WINGDIPAPI GdipResetImageAttributes(GpImageAttributes
*imageAttr,
GdipSetImageAttributesColorKeys(imageAttr, type, FALSE, 0, 0);
GdipSetImageAttributesRemapTable(imageAttr, type, FALSE, 0, NULL);
GdipSetImageAttributesGamma(imageAttr, type, FALSE, 0.0);
+ imageAttr->noop[type] = IMAGEATTR_NOOP_UNDEFINED;
return Ok;
}
diff --git a/dll/win32/gdiplus/metafile.c b/dll/win32/gdiplus/metafile.c
index 6171352d97..165a55dc8c 100644
--- a/dll/win32/gdiplus/metafile.c
+++ b/dll/win32/gdiplus/metafile.c
@@ -21,13 +21,9 @@
#include <assert.h>
#include <ole2.h>
-typedef struct EmfPlusARGB
-{
- BYTE Blue;
- BYTE Green;
- BYTE Red;
- BYTE Alpha;
-} EmfPlusARGB;
+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
+
+typedef ARGB EmfPlusARGB;
typedef struct EmfPlusRecordHeader
{
@@ -175,6 +171,30 @@ enum LineStyle
LineStyleCustom
};
+typedef struct EmfPlusDashedLineData
+{
+ DWORD DashedLineDataSize;
+ BYTE data[1];
+} EmfPlusDashedLineData;
+
+typedef struct EmfPlusCompoundLineData
+{
+ DWORD CompoundLineDataSize;
+ BYTE data[1];
+} EmfPlusCompoundLineData;
+
+typedef struct EmfPlusCustomStartCapData
+{
+ DWORD CustomStartCapSize;
+ BYTE data[1];
+} EmfPlusCustomStartCapData;
+
+typedef struct EmfPlusCustomEndCapData
+{
+ DWORD CustomEndCapSize;
+ BYTE data[1];
+} EmfPlusCustomEndCapData;
+
typedef struct EmfPlusPenData
{
DWORD PenDataFlags;
@@ -183,17 +203,66 @@ typedef struct EmfPlusPenData
BYTE OptionalData[1];
} EmfPlusPenData;
+enum BrushDataFlags
+{
+ BrushDataPath = 1 << 0,
+ BrushDataTransform = 1 << 1,
+ BrushDataPresetColors = 1 << 2,
+ BrushDataBlendFactorsH = 1 << 3,
+ BrushDataBlendFactorsV = 1 << 4,
+ BrushDataFocusScales = 1 << 6,
+ BrushDataIsGammaCorrected = 1 << 7,
+ BrushDataDoNotTransform = 1 << 8,
+};
+
typedef struct EmfPlusSolidBrushData
{
EmfPlusARGB SolidColor;
} EmfPlusSolidBrushData;
+typedef struct EmfPlusHatchBrushData
+{
+ DWORD HatchStyle;
+ EmfPlusARGB ForeColor;
+ EmfPlusARGB BackColor;
+} EmfPlusHatchBrushData;
+
+typedef struct EmfPlusTextureBrushData
+{
+ DWORD BrushDataFlags;
+ INT WrapMode;
+ BYTE OptionalData[1];
+} EmfPlusTextureBrushData;
+
+typedef struct EmfPlusRectF
+{
+ float X;
+ float Y;
+ float Width;
+ float Height;
+} EmfPlusRectF;
+
+typedef struct EmfPlusLinearGradientBrushData
+{
+ DWORD BrushDataFlags;
+ INT WrapMode;
+ EmfPlusRectF RectF;
+ EmfPlusARGB StartColor;
+ EmfPlusARGB EndColor;
+ DWORD Reserved1;
+ DWORD Reserved2;
+ BYTE OptionalData[1];
+} EmfPlusLinearGradientBrushData;
+
typedef struct EmfPlusBrush
{
DWORD Version;
DWORD Type;
union {
EmfPlusSolidBrushData solid;
+ EmfPlusHatchBrushData hatch;
+ EmfPlusTextureBrushData texture;
+ EmfPlusLinearGradientBrushData lineargradient;
} BrushData;
} EmfPlusBrush;
@@ -217,6 +286,12 @@ typedef struct EmfPlusPath
BYTE data[1];
} EmfPlusPath;
+typedef struct EmfPlusRegionNodePath
+{
+ DWORD RegionNodePathLength;
+ EmfPlusPath RegionNodePath;
+} EmfPlusRegionNodePath;
+
typedef struct EmfPlusRegion
{
DWORD Version;
@@ -224,6 +299,13 @@ typedef struct EmfPlusRegion
BYTE RegionNode[1];
} EmfPlusRegion;
+typedef struct EmfPlusPalette
+{
+ DWORD PaletteStyleFlags;
+ DWORD PaletteCount;
+ BYTE PaletteEntries[1];
+} EmfPlusPalette;
+
typedef enum
{
BitmapDataTypePixel,
@@ -275,20 +357,6 @@ typedef struct EmfPlusImageAttributes
DWORD Reserved2;
} EmfPlusImageAttributes;
-typedef enum ObjectType
-{
- ObjectTypeInvalid,
- ObjectTypeBrush,
- ObjectTypePen,
- ObjectTypePath,
- ObjectTypeRegion,
- ObjectTypeImage,
- ObjectTypeFont,
- ObjectTypeStringFormat,
- ObjectTypeImageAttributes,
- ObjectTypeCustomLineCap,
-} ObjectType;
-
typedef struct EmfPlusObject
{
EmfPlusRecordHeader Header;
@@ -303,13 +371,17 @@ typedef struct EmfPlusObject
} ObjectData;
} EmfPlusObject;
-typedef struct EmfPlusRectF
+typedef struct EmfPlusPointR7
{
- float X;
- float Y;
- float Width;
- float Height;
-} EmfPlusRectF;
+ BYTE X;
+ BYTE Y;
+} EmfPlusPointR7;
+
+typedef struct EmfPlusPoint
+{
+ short X;
+ short Y;
+} EmfPlusPoint;
typedef struct EmfPlusPointF
{
@@ -317,6 +389,19 @@ typedef struct EmfPlusPointF
float Y;
} EmfPlusPointF;
+typedef struct EmfPlusDrawImage
+{
+ EmfPlusRecordHeader Header;
+ DWORD ImageAttributesID;
+ DWORD SrcUnit;
+ EmfPlusRectF SrcRect;
+ union
+ {
+ EmfPlusRect rect;
+ EmfPlusRectF rectF;
+ } RectData;
+} EmfPlusDrawImage;
+
typedef struct EmfPlusDrawImagePoints
{
EmfPlusRecordHeader Header;
@@ -326,10 +411,10 @@ typedef struct EmfPlusDrawImagePoints
DWORD count;
union
{
- /*EmfPlusPointR pointR;
- EmfPlusPoint point;*/
- EmfPlusPointF pointF;
- } PointData[3];
+ EmfPlusPointR7 pointsR[3];
+ EmfPlusPoint points[3];
+ EmfPlusPointF pointsF[3];
+ } PointData;
} EmfPlusDrawImagePoints;
typedef struct EmfPlusDrawPath
@@ -338,6 +423,51 @@ typedef struct EmfPlusDrawPath
DWORD PenId;
} EmfPlusDrawPath;
+typedef struct EmfPlusDrawArc
+{
+ EmfPlusRecordHeader Header;
+ float StartAngle;
+ float SweepAngle;
+ union
+ {
+ EmfPlusRect rect;
+ EmfPlusRectF rectF;
+ } RectData;
+} EmfPlusDrawArc;
+
+typedef struct EmfPlusDrawEllipse
+{
+ EmfPlusRecordHeader Header;
+ union
+ {
+ EmfPlusRect rect;
+ EmfPlusRectF rectF;
+ } RectData;
+} EmfPlusDrawEllipse;
+
+typedef struct EmfPlusDrawPie
+{
+ EmfPlusRecordHeader Header;
+ float StartAngle;
+ float SweepAngle;
+ union
+ {
+ EmfPlusRect rect;
+ EmfPlusRectF rectF;
+ } RectData;
+} EmfPlusDrawPie;
+
+typedef struct EmfPlusDrawRects
+{
+ EmfPlusRecordHeader Header;
+ DWORD Count;
+ union
+ {
+ EmfPlusRect rect[1];
+ EmfPlusRectF rectF[1];
+ } RectData;
+} EmfPlusDrawRects;
+
typedef struct EmfPlusFillPath
{
EmfPlusRecordHeader Header;
@@ -348,9 +478,119 @@ typedef struct EmfPlusFillPath
} data;
} EmfPlusFillPath;
+typedef struct EmfPlusFillClosedCurve
+{
+ EmfPlusRecordHeader Header;
+ DWORD BrushId;
+ float Tension;
+ DWORD Count;
+ union
+ {
+ EmfPlusPointR7 pointsR[1];
+ EmfPlusPoint points[1];
+ EmfPlusPointF pointsF[1];
+ } PointData;
+} EmfPlusFillClosedCurve;
+
+typedef struct EmfPlusFillEllipse
+{
+ EmfPlusRecordHeader Header;
+ DWORD BrushId;
+ union
+ {
+ EmfPlusRect rect;
+ EmfPlusRectF rectF;
+ } RectData;
+} EmfPlusFillEllipse;
+
+typedef struct EmfPlusFillPie
+{
+ EmfPlusRecordHeader Header;
+ DWORD BrushId;
+ float StartAngle;
+ float SweepAngle;
+ union
+ {
+ EmfPlusRect rect;
+ EmfPlusRectF rectF;
+ } RectData;
+} EmfPlusFillPie;
+
+typedef struct EmfPlusFont
+{
+ DWORD Version;
+ float EmSize;
+ DWORD SizeUnit;
+ DWORD FontStyleFlags;
+ DWORD Reserved;
+ DWORD Length;
+ WCHAR FamilyName[1];
+} EmfPlusFont;
+
+static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
+{
+ struct emfplus_object *object = &metafile->objtable[id];
+
+ switch (object->type)
+ {
+ case ObjectTypeInvalid:
+ break;
+ case ObjectTypeBrush:
+ GdipDeleteBrush(object->u.brush);
+ break;
+ case ObjectTypePen:
+ GdipDeletePen(object->u.pen);
+ break;
+ case ObjectTypePath:
+ GdipDeletePath(object->u.path);
+ break;
+ case ObjectTypeRegion:
+ GdipDeleteRegion(object->u.region);
+ break;
+ case ObjectTypeImage:
+ GdipDisposeImage(object->u.image);
+ break;
+ case ObjectTypeFont:
+ GdipDeleteFont(object->u.font);
+ break;
+ case ObjectTypeImageAttributes:
+ GdipDisposeImageAttributes(object->u.image_attributes);
+ break;
+ default:
+ FIXME("not implemented for object type %u.\n", object->type);
+ return;
+ }
+
+ object->type = ObjectTypeInvalid;
+ object->u.object = NULL;
+}
+
+void METAFILE_Free(GpMetafile *metafile)
+{
+ unsigned int i;
+
+ heap_free(metafile->comment_data);
+ DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
+ if (!metafile->preserve_hemf)
+ DeleteEnhMetaFile(metafile->hemf);
+ if (metafile->record_graphics)
+ {
+ WARN("metafile closed while recording\n");
+ /* not sure what to do here; for now just prevent the graphics from functioning
or using this object */
+ metafile->record_graphics->image = NULL;
+ metafile->record_graphics->busy = TRUE;
+ }
+
+ if (metafile->record_stream)
+ IStream_Release(metafile->record_stream);
+
+ for (i = 0; i < sizeof(metafile->objtable)/sizeof(metafile->objtable[0]);
i++)
+ metafile_free_object_table_entry(metafile, i);
+}
+
static DWORD METAFILE_AddObjectId(GpMetafile *metafile)
{
- return (metafile->next_object_id++) % 64;
+ return (metafile->next_object_id++) % EmfPlusObjectTableSize;
}
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
@@ -718,6 +958,74 @@ static BOOL is_integer_rect(const GpRectF *rect)
return TRUE;
}
+static GpStatus METAFILE_PrepareBrushData(GpBrush *brush, DWORD *size)
+{
+ switch (brush->bt)
+ {
+ case BrushTypeSolidColor:
+ *size = FIELD_OFFSET(EmfPlusBrush, BrushData) + sizeof(EmfPlusSolidBrushData);
+ break;
+ case BrushTypeHatchFill:
+ *size = FIELD_OFFSET(EmfPlusBrush, BrushData) + sizeof(EmfPlusHatchBrushData);
+ break;
+ default:
+ FIXME("unsupported brush type: %d\n", brush->bt);
+ return NotImplemented;
+ }
+
+ return Ok;
+}
+
+static void METAFILE_FillBrushData(GpBrush *brush, EmfPlusBrush *data)
+{
+ data->Version = VERSION_MAGIC2;
+ data->Type = brush->bt;
+
+ switch (brush->bt)
+ {
+ case BrushTypeSolidColor:
+ {
+ GpSolidFill *solid = (GpSolidFill *)brush;
+ data->BrushData.solid.SolidColor = solid->color;
+ break;
+ }
+ case BrushTypeHatchFill:
+ {
+ GpHatch *hatch = (GpHatch *)brush;
+ data->BrushData.hatch.HatchStyle = hatch->hatchstyle;
+ data->BrushData.hatch.ForeColor = hatch->forecol;
+ data->BrushData.hatch.BackColor = hatch->backcol;
+ break;
+ }
+ default:
+ FIXME("unsupported brush type: %d\n", brush->bt);
+ }
+}
+
+static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GpBrush *brush, DWORD *id)
+{
+ EmfPlusObject *object_record;
+ GpStatus stat;
+ DWORD size;
+
+ *id = -1;
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly &&
metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ stat = METAFILE_PrepareBrushData(brush, &size);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData) + size, (void**)&object_record);
+ if (stat != Ok) return stat;
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | ObjectTypeBrush << 8;
+ METAFILE_FillBrushData(brush, &object_record->ObjectData.brush);
+ return Ok;
+}
+
GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
GDIPCONST GpRectF* rects, INT count)
{
@@ -737,8 +1045,9 @@ GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush*
brush,
}
else
{
- FIXME("brush serialization not implemented\n");
- return NotImplemented;
+ stat = METAFILE_AddBrushObject(metafile, brush, &brushid);
+ if (stat != Ok)
+ return stat;
}
for (i=0; i<count; i++)
@@ -1385,99 +1694,841 @@ static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile)
return stat;
}
-GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
- EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
+static void metafile_set_object_table_entry(GpMetafile *metafile, BYTE id, BYTE type,
void *object)
{
- GpStatus stat;
- GpMetafile *real_metafile = (GpMetafile*)metafile;
+ metafile_free_object_table_entry(metafile, id);
+ metafile->objtable[id].type = type;
+ metafile->objtable[id].u.object = object;
+}
- TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
+static GpStatus metafile_deserialize_image(const BYTE *record_data, UINT data_size,
GpImage **image)
+{
+ EmfPlusImage *data = (EmfPlusImage *)record_data;
+ GpStatus status;
- if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
+ *image = NULL;
+
+ if (data_size < FIELD_OFFSET(EmfPlusImage, ImageData))
return InvalidParameter;
+ data_size -= FIELD_OFFSET(EmfPlusImage, ImageData);
- if (recordType >= 1 && recordType <= 0x7a)
+ switch (data->Type)
{
- /* regular EMF record */
- if (metafile->playback_dc)
- {
- switch (recordType)
- {
- case EMR_SETMAPMODE:
- case EMR_SAVEDC:
- case EMR_RESTOREDC:
- case EMR_SETWINDOWORGEX:
- case EMR_SETWINDOWEXTEX:
- case EMR_SETVIEWPORTORGEX:
- case EMR_SETVIEWPORTEXTEX:
- case EMR_SCALEVIEWPORTEXTEX:
- case EMR_SCALEWINDOWEXTEX:
- case EMR_MODIFYWORLDTRANSFORM:
- FIXME("not implemented for record type %x\n", recordType);
- break;
- case EMR_SETWORLDTRANSFORM:
- {
- const XFORM* xform = (void*)data;
- real_metafile->gdiworldtransform = *xform;
- METAFILE_PlaybackUpdateGdiTransform(real_metafile);
- break;
- }
- case EMR_EXTSELECTCLIPRGN:
- {
- DWORD rgndatasize = *(DWORD*)data;
- DWORD mode = *(DWORD*)(data + 4);
- const RGNDATA *rgndata = (const RGNDATA*)(data + 8);
- HRGN hrgn = NULL;
+ case ImageDataTypeBitmap:
+ {
+ EmfPlusBitmap *bitmapdata = &data->ImageData.bitmap;
- if (dataSize > 8)
- {
- XFORM final;
+ if (data_size <= FIELD_OFFSET(EmfPlusBitmap, BitmapData))
+ return InvalidParameter;
+ data_size -= FIELD_OFFSET(EmfPlusBitmap, BitmapData);
- METAFILE_GetFinalGdiTransform(metafile, &final);
+ switch (bitmapdata->Type)
+ {
+ case BitmapDataTypePixel:
+ {
+ ColorPalette *palette;
+ BYTE *scan0;
- hrgn = ExtCreateRegion(&final, rgndatasize, rgndata);
- }
+ if (bitmapdata->PixelFormat & PixelFormatIndexed)
+ {
+ EmfPlusPalette *palette_obj = (EmfPlusPalette
*)bitmapdata->BitmapData;
+ UINT palette_size = FIELD_OFFSET(EmfPlusPalette, PaletteEntries);
- ExtSelectClipRgn(metafile->playback_dc, hrgn, mode);
+ if (data_size <= palette_size)
+ return InvalidParameter;
+ palette_size += palette_obj->PaletteCount * sizeof(EmfPlusARGB);
- DeleteObject(hrgn);
+ if (data_size < palette_size)
+ return InvalidParameter;
+ data_size -= palette_size;
- return Ok;
+ palette = (ColorPalette *)bitmapdata->BitmapData;
+ scan0 = (BYTE *)bitmapdata->BitmapData + palette_size;
}
- default:
+ else
{
- ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
-
- if (record)
- {
- record->iType = recordType;
- record->nSize = dataSize + 8;
- memcpy(record->dParm, data, dataSize);
+ palette = NULL;
+ scan0 = bitmapdata->BitmapData;
+ }
- if(PlayEnhMetaFileRecord(metafile->playback_dc,
metafile->handle_table,
- record, metafile->handle_count) == 0)
- ERR("PlayEnhMetaFileRecord failed\n");
+ if (data_size < bitmapdata->Height * bitmapdata->Stride)
+ return InvalidParameter;
- heap_free(record);
+ status = GdipCreateBitmapFromScan0(bitmapdata->Width,
bitmapdata->Height, bitmapdata->Stride,
+ bitmapdata->PixelFormat, scan0, (GpBitmap **)image);
+ if (status == Ok && palette)
+ {
+ status = GdipSetImagePalette(*image, palette);
+ if (status != Ok)
+ {
+ GdipDisposeImage(*image);
+ *image = NULL;
}
- else
- return OutOfMemory;
-
- break;
- }
}
+ break;
}
- }
- else
- {
- EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
+ case BitmapDataTypeCompressed:
+ {
+ IWICImagingFactory *factory;
+ IWICStream *stream;
+ HRESULT hr;
- METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
+ if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory) !=
S_OK)
+ return GenericError;
- switch(recordType)
- {
- case EmfPlusRecordTypeHeader:
- case EmfPlusRecordTypeEndOfFile:
+ hr = IWICImagingFactory_CreateStream(factory, &stream);
+ IWICImagingFactory_Release(factory);
+ if (hr != S_OK)
+ return GenericError;
+
+ if (IWICStream_InitializeFromMemory(stream, bitmapdata->BitmapData,
data_size) == S_OK)
+ status = GdipCreateBitmapFromStream((IStream *)stream, (GpBitmap
**)image);
+ else
+ status = GenericError;
+
+ IWICStream_Release(stream);
+ break;
+ }
+ default:
+ WARN("Invalid bitmap type %d.\n", bitmapdata->Type);
+ return InvalidParameter;
+ }
+ break;
+ }
+ default:
+ FIXME("image type %d not supported.\n", data->Type);
+ return NotImplemented;
+ }
+
+ return status;
+}
+
+static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_size, GpPath
**path)
+{
+ EmfPlusPath *data = (EmfPlusPath *)record_data;
+ GpStatus status;
+ BYTE *types;
+ UINT size;
+ DWORD i;
+
+ *path = NULL;
+
+ if (data_size <= FIELD_OFFSET(EmfPlusPath, data))
+ return InvalidParameter;
+ data_size -= FIELD_OFFSET(EmfPlusPath, data);
+
+ if (data->PathPointFlags & 0x800) /* R */
+ {
+ FIXME("RLE encoded path data is not supported.\n");
+ return NotImplemented;
+ }
+ else
+ {
+ if (data->PathPointFlags & 0x4000) /* C */
+ size = sizeof(EmfPlusPoint);
+ else
+ size = sizeof(EmfPlusPointF);
+ size += sizeof(BYTE); /* EmfPlusPathPointType */
+ size *= data->PathPointCount;
+ }
+
+ if (data_size < size)
+ return InvalidParameter;
+
+ status = GdipCreatePath(FillModeAlternate, path);
+ if (status != Ok)
+ return status;
+
+ (*path)->pathdata.Count = data->PathPointCount;
+ (*path)->pathdata.Points = GdipAlloc(data->PathPointCount *
sizeof(*(*path)->pathdata.Points));
+ (*path)->pathdata.Types = GdipAlloc(data->PathPointCount *
sizeof(*(*path)->pathdata.Types));
+ (*path)->datalen = (*path)->pathdata.Count;
+
+ if (!(*path)->pathdata.Points || !(*path)->pathdata.Types)
+ {
+ GdipDeletePath(*path);
+ return OutOfMemory;
+ }
+
+ if (data->PathPointFlags & 0x4000) /* C */
+ {
+ EmfPlusPoint *points = (EmfPlusPoint *)data->data;
+ for (i = 0; i < data->PathPointCount; i++)
+ {
+ (*path)->pathdata.Points[i].X = points[i].X;
+ (*path)->pathdata.Points[i].Y = points[i].Y;
+ }
+ types = (BYTE *)(points + i);
+ }
+ else
+ {
+ EmfPlusPointF *points = (EmfPlusPointF *)data->data;
+ memcpy((*path)->pathdata.Points, points, sizeof(*points) *
data->PathPointCount);
+ types = (BYTE *)(points + data->PathPointCount);
+ }
+
+ memcpy((*path)->pathdata.Types, types, sizeof(*types) * data->PathPointCount);
+
+ return Ok;
+}
+
+static GpStatus metafile_read_region_node(struct memory_buffer *mbuf, GpRegion *region,
region_element *node, UINT *count)
+{
+ const DWORD *type;
+ GpStatus status;
+
+ type = buffer_read(mbuf, sizeof(*type));
+ if (!type) return Ok;
+
+ node->type = *type;
+
+ switch (node->type)
+ {
+ case CombineModeReplace:
+ case CombineModeIntersect:
+ case CombineModeUnion:
+ case CombineModeXor:
+ case CombineModeExclude:
+ case CombineModeComplement:
+ {
+ region_element *left, *right;
+
+ left = heap_alloc_zero(sizeof(*left));
+ if (!left)
+ return OutOfMemory;
+
+ right = heap_alloc_zero(sizeof(*right));
+ if (!right)
+ {
+ heap_free(left);
+ return OutOfMemory;
+ }
+
+ status = metafile_read_region_node(mbuf, region, left, count);
+ if (status == Ok)
+ {
+ status = metafile_read_region_node(mbuf, region, right, count);
+ if (status == Ok)
+ {
+ node->elementdata.combine.left = left;
+ node->elementdata.combine.right = right;
+ region->num_children += 2;
+ return Ok;
+ }
+ }
+
+ heap_free(left);
+ heap_free(right);
+ return status;
+ }
+ case RegionDataRect:
+ {
+ const EmfPlusRectF *rect;
+
+ rect = buffer_read(mbuf, sizeof(*rect));
+ if (!rect)
+ return InvalidParameter;
+
+ memcpy(&node->elementdata.rect, rect, sizeof(*rect));
+ *count += 1;
+ return Ok;
+ }
+ case RegionDataPath:
+ {
+ const BYTE *path_data;
+ const UINT *data_size;
+ GpPath *path;
+
+ data_size = buffer_read(mbuf, FIELD_OFFSET(EmfPlusRegionNodePath,
RegionNodePath));
+ if (!data_size)
+ return InvalidParameter;
+
+ path_data = buffer_read(mbuf, *data_size);
+ if (!path_data)
+ return InvalidParameter;
+
+ status = metafile_deserialize_path(path_data, *data_size, &path);
+ if (status == Ok)
+ {
+ node->elementdata.path = path;
+ *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;
+}
+
+static GpStatus metafile_deserialize_region(const BYTE *record_data, UINT data_size,
GpRegion **region)
+{
+ struct memory_buffer mbuf;
+ GpStatus status;
+ UINT count;
+
+ *region = NULL;
+
+ init_memory_buffer(&mbuf, record_data, data_size);
+
+ if (!buffer_read(&mbuf, FIELD_OFFSET(EmfPlusRegion, RegionNode)))
+ return InvalidParameter;
+
+ status = GdipCreateRegion(region);
+ if (status != Ok)
+ return status;
+
+ count = 0;
+ status = metafile_read_region_node(&mbuf, *region, &(*region)->node,
&count);
+ if (status == Ok && !count)
+ status = InvalidParameter;
+
+ if (status != Ok)
+ {
+ GdipDeleteRegion(*region);
+ *region = NULL;
+ }
+
+ return status;
+}
+
+static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size,
GpBrush **brush)
+{
+ static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
+ EmfPlusBrush *data = (EmfPlusBrush *)record_data;
+ EmfPlusTransformMatrix *transform = NULL;
+ DWORD brushflags;
+ GpStatus status;
+ UINT offset;
+
+ *brush = NULL;
+
+ if (data_size < header_size)
+ return InvalidParameter;
+
+ switch (data->Type)
+ {
+ case BrushTypeSolidColor:
+ if (data_size != header_size + sizeof(EmfPlusSolidBrushData))
+ return InvalidParameter;
+
+ status = GdipCreateSolidFill(data->BrushData.solid.SolidColor, (GpSolidFill
**)brush);
+ break;
+ case BrushTypeHatchFill:
+ if (data_size != header_size + sizeof(EmfPlusHatchBrushData))
+ return InvalidParameter;
+
+ status = GdipCreateHatchBrush(data->BrushData.hatch.HatchStyle,
data->BrushData.hatch.ForeColor,
+ data->BrushData.hatch.BackColor, (GpHatch **)brush);
+ break;
+ case BrushTypeTextureFill:
+ {
+ GpImage *image;
+
+ offset = header_size + FIELD_OFFSET(EmfPlusTextureBrushData, OptionalData);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ brushflags = data->BrushData.texture.BrushDataFlags;
+ if (brushflags & BrushDataTransform)
+ {
+ if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
+ return InvalidParameter;
+ transform = (EmfPlusTransformMatrix *)(record_data + offset);
+ offset += sizeof(EmfPlusTransformMatrix);
+ }
+
+ status = metafile_deserialize_image(record_data + offset, data_size - offset,
&image);
+ if (status != Ok)
+ return status;
+
+ status = GdipCreateTexture(image, data->BrushData.texture.WrapMode, (GpTexture
**)brush);
+ if (status == Ok && transform && !(brushflags &
BrushDataDoNotTransform))
+ GdipSetTextureTransform((GpTexture *)*brush, (const GpMatrix *)transform);
+
+ GdipDisposeImage(image);
+ break;
+ }
+ case BrushTypeLinearGradient:
+ {
+ GpLineGradient *gradient = NULL;
+ GpPointF startpoint, endpoint;
+ UINT position_count = 0;
+
+ offset = header_size + FIELD_OFFSET(EmfPlusLinearGradientBrushData,
OptionalData);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ brushflags = data->BrushData.lineargradient.BrushDataFlags;
+ if ((brushflags & BrushDataPresetColors) && (brushflags &
(BrushDataBlendFactorsH | BrushDataBlendFactorsV)))
+ return InvalidParameter;
+
+ if (brushflags & BrushDataTransform)
+ {
+ if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
+ return InvalidParameter;
+ transform = (EmfPlusTransformMatrix *)(record_data + offset);
+ offset += sizeof(EmfPlusTransformMatrix);
+ }
+
+ if (brushflags & (BrushDataPresetColors | BrushDataBlendFactorsH |
BrushDataBlendFactorsV))
+ {
+ if (data_size <= offset + sizeof(DWORD)) /* Number of factors/preset
colors. */
+ return InvalidParameter;
+ position_count = *(DWORD *)(record_data + offset);
+ offset += sizeof(DWORD);
+ }
+
+ if (brushflags & BrushDataPresetColors)
+ {
+ if (data_size != offset + position_count * (sizeof(float) +
sizeof(EmfPlusARGB)))
+ return InvalidParameter;
+ }
+ else if (brushflags & BrushDataBlendFactorsH)
+ {
+ if (data_size != offset + position_count * 2 * sizeof(float))
+ return InvalidParameter;
+ }
+
+ startpoint.X = data->BrushData.lineargradient.RectF.X;
+ startpoint.Y = data->BrushData.lineargradient.RectF.Y;
+ endpoint.X = startpoint.X + data->BrushData.lineargradient.RectF.Width;
+ endpoint.Y = startpoint.Y + data->BrushData.lineargradient.RectF.Height;
+
+ status = GdipCreateLineBrush(&startpoint, &endpoint,
data->BrushData.lineargradient.StartColor,
+ data->BrushData.lineargradient.EndColor,
data->BrushData.lineargradient.WrapMode, &gradient);
+ if (status == Ok)
+ {
+ if (transform)
+ status = GdipSetLineTransform(gradient, (const GpMatrix *)transform);
+
+ if (status == Ok)
+ {
+ if (brushflags & BrushDataPresetColors)
+ status = GdipSetLinePresetBlend(gradient, (ARGB *)(record_data +
offset +
+ position_count * sizeof(REAL)), (REAL *)(record_data + offset),
position_count);
+ else if (brushflags & BrushDataBlendFactorsH)
+ status = GdipSetLineBlend(gradient, (REAL *)(record_data + offset +
position_count * sizeof(REAL)),
+ (REAL *)(record_data + offset), position_count);
+
+ if (brushflags & BrushDataIsGammaCorrected)
+ FIXME("BrushDataIsGammaCorrected is not handled.\n");
+ }
+ }
+
+ if (status == Ok)
+ *brush = (GpBrush *)gradient;
+ else
+ GdipDeleteBrush((GpBrush *)gradient);
+
+ break;
+ }
+ default:
+ FIXME("brush type %u is not supported.\n", data->Type);
+ return NotImplemented;
+ }
+
+ return status;
+}
+
+static GpStatus metafile_get_pen_brush_data_offset(EmfPlusPen *data, UINT data_size,
DWORD *ret)
+{
+ EmfPlusPenData *pendata = (EmfPlusPenData *)data->data;
+ DWORD offset = FIELD_OFFSET(EmfPlusPen, data);
+
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += FIELD_OFFSET(EmfPlusPenData, OptionalData);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ if (pendata->PenDataFlags & PenDataTransform)
+ offset += sizeof(EmfPlusTransformMatrix);
+
+ if (pendata->PenDataFlags & PenDataStartCap)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataEndCap)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataJoin)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataMiterLimit)
+ offset += sizeof(REAL);
+
+ if (pendata->PenDataFlags & PenDataLineStyle)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataDashedLineCap)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataDashedLineOffset)
+ offset += sizeof(REAL);
+
+ if (pendata->PenDataFlags & PenDataDashedLine)
+ {
+ EmfPlusDashedLineData *dashedline = (EmfPlusDashedLineData *)((BYTE *)data +
offset);
+
+ offset += FIELD_OFFSET(EmfPlusDashedLineData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += dashedline->DashedLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataNonCenter)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataCompoundLine)
+ {
+ EmfPlusCompoundLineData *compoundline = (EmfPlusCompoundLineData *)((BYTE *)data
+ offset);
+
+ offset += FIELD_OFFSET(EmfPlusCompoundLineData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += compoundline->CompoundLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomStartCap)
+ {
+ EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)data
+ offset);
+
+ offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += startcap->CustomStartCapSize;
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomEndCap)
+ {
+ EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)data +
offset);
+
+ offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += endcap->CustomEndCapSize;
+ }
+
+ *ret = offset;
+ return Ok;
+}
+
+static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT data_size,
const BYTE *record_data)
+{
+ BYTE type = (flags >> 8) & 0xff;
+ BYTE id = flags & 0xff;
+ void *object = NULL;
+ GpStatus status;
+
+ if (type > ObjectTypeMax || id >= EmfPlusObjectTableSize)
+ return InvalidParameter;
+
+ switch (type)
+ {
+ case ObjectTypeBrush:
+ status = metafile_deserialize_brush(record_data, data_size, (GpBrush
**)&object);
+ break;
+ case ObjectTypePen:
+ {
+ EmfPlusPen *data = (EmfPlusPen *)record_data;
+ EmfPlusPenData *pendata = (EmfPlusPenData *)data->data;
+ GpBrush *brush;
+ DWORD offset;
+ GpPen *pen;
+
+ status = metafile_get_pen_brush_data_offset(data, data_size, &offset);
+ if (status != Ok)
+ return status;
+
+ status = metafile_deserialize_brush(record_data + offset, data_size - offset,
&brush);
+ if (status != Ok)
+ return status;
+
+ status = GdipCreatePen2(brush, pendata->PenWidth, pendata->PenUnit,
&pen);
+ GdipDeleteBrush(brush);
+ if (status != Ok)
+ return status;
+
+ offset = FIELD_OFFSET(EmfPlusPenData, OptionalData);
+
+ if (pendata->PenDataFlags & PenDataTransform)
+ {
+ FIXME("PenDataTransform is not supported.\n");
+ offset += sizeof(EmfPlusTransformMatrix);
+ }
+
+ if (pendata->PenDataFlags & PenDataStartCap)
+ {
+ if ((status = GdipSetPenStartCap(pen, *(DWORD *)((BYTE *)pendata + offset)))
!= Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataEndCap)
+ {
+ if ((status = GdipSetPenEndCap(pen, *(DWORD *)((BYTE *)pendata + offset))) !=
Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataJoin)
+ {
+ if ((status = GdipSetPenLineJoin(pen, *(DWORD *)((BYTE *)pendata + offset)))
!= Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataMiterLimit)
+ {
+ if ((status = GdipSetPenMiterLimit(pen, *(REAL *)((BYTE *)pendata + offset)))
!= Ok)
+ goto penfailed;
+ offset += sizeof(REAL);
+ }
+
+ if (pendata->PenDataFlags & PenDataLineStyle)
+ {
+ if ((status = GdipSetPenDashStyle(pen, *(DWORD *)((BYTE *)pendata + offset)))
!= Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataDashedLineCap)
+ {
+ FIXME("PenDataDashedLineCap is not supported.\n");
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataDashedLineOffset)
+ {
+ if ((status = GdipSetPenDashOffset(pen, *(REAL *)((BYTE *)pendata + offset)))
!= Ok)
+ goto penfailed;
+ offset += sizeof(REAL);
+ }
+
+ if (pendata->PenDataFlags & PenDataDashedLine)
+ {
+ EmfPlusDashedLineData *dashedline = (EmfPlusDashedLineData *)((BYTE *)pendata
+ offset);
+ FIXME("PenDataDashedLine is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusDashedLineData, data) +
dashedline->DashedLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataNonCenter)
+ {
+ FIXME("PenDataNonCenter is not supported.\n");
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataCompoundLine)
+ {
+ EmfPlusCompoundLineData *compoundline = (EmfPlusCompoundLineData *)((BYTE
*)pendata + offset);
+ FIXME("PenDataCompundLine is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusCompoundLineData, data) +
compoundline->CompoundLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomStartCap)
+ {
+ EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE
*)pendata + offset);
+ FIXME("PenDataCustomStartCap is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data) +
startcap->CustomStartCapSize;
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomEndCap)
+ {
+ EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)pendata
+ offset);
+ FIXME("PenDataCustomEndCap is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data) +
endcap->CustomEndCapSize;
+ }
+
+ object = pen;
+ break;
+
+ penfailed:
+ GdipDeletePen(pen);
+ return status;
+ }
+ case ObjectTypePath:
+ status = metafile_deserialize_path(record_data, data_size, (GpPath
**)&object);
+ break;
+ case ObjectTypeRegion:
+ status = metafile_deserialize_region(record_data, data_size, (GpRegion
**)&object);
+ break;
+ case ObjectTypeImage:
+ status = metafile_deserialize_image(record_data, data_size, (GpImage
**)&object);
+ break;
+ case ObjectTypeFont:
+ {
+ EmfPlusFont *data = (EmfPlusFont *)record_data;
+ GpFontFamily *family;
+ WCHAR *familyname;
+
+ if (data_size <= FIELD_OFFSET(EmfPlusFont, FamilyName))
+ return InvalidParameter;
+ data_size -= FIELD_OFFSET(EmfPlusFont, FamilyName);
+
+ if (data_size < data->Length * sizeof(WCHAR))
+ return InvalidParameter;
+
+ if (!(familyname = GdipAlloc((data->Length + 1) * sizeof(*familyname))))
+ return OutOfMemory;
+
+ memcpy(familyname, data->FamilyName, data->Length * sizeof(*familyname));
+ familyname[data->Length] = 0;
+
+ status = GdipCreateFontFamilyFromName(familyname, NULL, &family);
+ GdipFree(familyname);
+ if (status != Ok)
+ return InvalidParameter;
+
+ status = GdipCreateFont(family, data->EmSize, data->FontStyleFlags,
data->SizeUnit, (GpFont **)&object);
+ GdipDeleteFontFamily(family);
+ break;
+ }
+ case ObjectTypeImageAttributes:
+ {
+ EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data;
+ GpImageAttributes *attributes = NULL;
+
+ if (data_size != sizeof(*data))
+ return InvalidParameter;
+
+ if ((status = GdipCreateImageAttributes(&attributes)) != Ok)
+ return status;
+
+ status = GdipSetImageAttributesWrapMode(attributes, data->WrapMode, *(DWORD
*)&data->ClampColor,
+ !!data->ObjectClamp);
+ if (status == Ok)
+ object = attributes;
+ else
+ GdipDisposeImageAttributes(attributes);
+ break;
+ }
+ default:
+ FIXME("not implemented for object type %d.\n", type);
+ return NotImplemented;
+ }
+
+ if (status == Ok)
+ metafile_set_object_table_entry(metafile, id, type, object);
+
+ return status;
+}
+
+static GpStatus metafile_set_clip_region(GpMetafile *metafile, GpRegion *region,
CombineMode mode)
+{
+ GpMatrix world_to_device;
+
+ get_graphics_transform(metafile->playback_graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, &world_to_device);
+
+ GdipTransformRegion(region, &world_to_device);
+ GdipCombineRegionRegion(metafile->clip, region, mode);
+
+ return METAFILE_PlaybackUpdateClip(metafile);
+}
+
+GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
+ EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
+{
+ GpStatus stat;
+ GpMetafile *real_metafile = (GpMetafile*)metafile;
+
+ TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
+
+ if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
+ return InvalidParameter;
+
+ if (recordType >= 1 && recordType <= 0x7a)
+ {
+ /* regular EMF record */
+ if (metafile->playback_dc)
+ {
+ switch (recordType)
+ {
+ case EMR_SETMAPMODE:
+ case EMR_SAVEDC:
+ case EMR_RESTOREDC:
+ case EMR_SETWINDOWORGEX:
+ case EMR_SETWINDOWEXTEX:
+ case EMR_SETVIEWPORTORGEX:
+ case EMR_SETVIEWPORTEXTEX:
+ case EMR_SCALEVIEWPORTEXTEX:
+ case EMR_SCALEWINDOWEXTEX:
+ case EMR_MODIFYWORLDTRANSFORM:
+ FIXME("not implemented for record type %x\n", recordType);
+ break;
+ case EMR_SETWORLDTRANSFORM:
+ {
+ const XFORM* xform = (void*)data;
+ real_metafile->gdiworldtransform = *xform;
+ METAFILE_PlaybackUpdateGdiTransform(real_metafile);
+ break;
+ }
+ case EMR_EXTSELECTCLIPRGN:
+ {
+ DWORD rgndatasize = *(DWORD*)data;
+ DWORD mode = *(DWORD*)(data + 4);
+ const RGNDATA *rgndata = (const RGNDATA*)(data + 8);
+ HRGN hrgn = NULL;
+
+ if (dataSize > 8)
+ {
+ XFORM final;
+
+ METAFILE_GetFinalGdiTransform(metafile, &final);
+
+ hrgn = ExtCreateRegion(&final, rgndatasize, rgndata);
+ }
+
+ ExtSelectClipRgn(metafile->playback_dc, hrgn, mode);
+
+ DeleteObject(hrgn);
+
+ return Ok;
+ }
+ default:
+ {
+ ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
+
+ if (record)
+ {
+ record->iType = recordType;
+ record->nSize = dataSize + 8;
+ memcpy(record->dParm, data, dataSize);
+
+ if(PlayEnhMetaFileRecord(metafile->playback_dc,
metafile->handle_table,
+ record, metafile->handle_count) == 0)
+ ERR("PlayEnhMetaFileRecord failed\n");
+
+ heap_free(record);
+ }
+ else
+ return OutOfMemory;
+
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
+
+ METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
+
+ switch(recordType)
+ {
+ case EmfPlusRecordTypeHeader:
+ case EmfPlusRecordTypeEndOfFile:
break;
case EmfPlusRecordTypeGetDC:
METAFILE_PlaybackGetDC((GpMetafile*)metafile);
@@ -1486,6 +2537,9 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile,
{
EmfPlusClear *record = (EmfPlusClear*)header;
+ if (dataSize != sizeof(record->Color))
+ return InvalidParameter;
+
return GdipGraphicsClear(metafile->playback_graphics, record->Color);
}
case EmfPlusRecordTypeFillRects:
@@ -1510,13 +2564,17 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile,
if (flags & 0x8000)
{
- stat = GdipCreateSolidFill((ARGB)record->BrushID,
(GpSolidFill**)&temp_brush);
+ stat = GdipCreateSolidFill(record->BrushID, (GpSolidFill
**)&temp_brush);
brush = temp_brush;
}
else
{
- FIXME("brush deserialization not implemented\n");
- return NotImplemented;
+ if (record->BrushID >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[record->BrushID].type !=
ObjectTypeBrush)
+ return InvalidParameter;
+
+ brush = real_metafile->objtable[record->BrushID].u.brush;
+ stat = Ok;
}
if (stat == Ok)
@@ -1546,39 +2604,74 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile,
if (stat == Ok)
{
- stat = GdipFillRectangles(metafile->playback_graphics, brush, rects,
record->Count);
+ stat = GdipFillRectangles(metafile->playback_graphics, brush, rects,
record->Count);
+ }
+
+ GdipDeleteBrush(temp_brush);
+ heap_free(temp_rects);
+
+ return stat;
+ }
+ case EmfPlusRecordTypeSetClipRect:
+ {
+ EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header;
+ CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
+ GpRegion *region;
+
+ if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
+ return InvalidParameter;
+
+ stat = GdipCreateRegionRect(&record->ClipRect, ®ion);
+
+ if (stat == Ok)
+ {
+ stat = metafile_set_clip_region(real_metafile, region, mode);
+ GdipDeleteRegion(region);
+ }
+
+ return stat;
+ }
+ case EmfPlusRecordTypeSetClipRegion:
+ {
+ CombineMode mode = (flags >> 8) & 0xf;
+ BYTE regionid = flags & 0xff;
+ GpRegion *region;
+
+ if (dataSize != 0)
+ return InvalidParameter;
+
+ if (regionid >= EmfPlusObjectTableSize ||
real_metafile->objtable[regionid].type != ObjectTypeRegion)
+ return InvalidParameter;
+
+ stat = GdipCloneRegion(real_metafile->objtable[regionid].u.region,
®ion);
+ if (stat == Ok)
+ {
+ stat = metafile_set_clip_region(real_metafile, region, mode);
+ GdipDeleteRegion(region);
}
- GdipDeleteBrush(temp_brush);
- heap_free(temp_rects);
-
return stat;
}
- case EmfPlusRecordTypeSetClipRect:
+ case EmfPlusRecordTypeSetClipPath:
{
- EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header;
- CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
+ CombineMode mode = (flags >> 8) & 0xf;
+ BYTE pathid = flags & 0xff;
GpRegion *region;
- GpMatrix world_to_device;
- if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
+ if (dataSize != 0)
return InvalidParameter;
- stat = GdipCreateRegionRect(&record->ClipRect, ®ion);
+ if (pathid >= EmfPlusObjectTableSize ||
real_metafile->objtable[pathid].type != ObjectTypePath)
+ return InvalidParameter;
+ stat = GdipCreateRegionPath(real_metafile->objtable[pathid].u.path,
®ion);
if (stat == Ok)
{
- get_graphics_transform(real_metafile->playback_graphics,
- CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
-
- GdipTransformRegion(region, &world_to_device);
-
- GdipCombineRegionRegion(real_metafile->clip, region, mode);
-
+ stat = metafile_set_clip_region(real_metafile, region, mode);
GdipDeleteRegion(region);
}
- return METAFILE_PlaybackUpdateClip(real_metafile);
+ return stat;
}
case EmfPlusRecordTypeSetPageTransform:
{
@@ -1810,6 +2903,447 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile,
break;
}
+ case EmfPlusRecordTypeSetPixelOffsetMode:
+ {
+ return GdipSetPixelOffsetMode(real_metafile->playback_graphics, flags
& 0xff);
+ }
+ case EmfPlusRecordTypeSetCompositingQuality:
+ {
+ return GdipSetCompositingQuality(real_metafile->playback_graphics, flags
& 0xff);
+ }
+ case EmfPlusRecordTypeSetInterpolationMode:
+ {
+ return GdipSetInterpolationMode(real_metafile->playback_graphics, flags
& 0xff);
+ }
+ case EmfPlusRecordTypeSetTextRenderingHint:
+ {
+ return GdipSetTextRenderingHint(real_metafile->playback_graphics, flags
& 0xff);
+ }
+ case EmfPlusRecordTypeSetAntiAliasMode:
+ {
+ return GdipSetSmoothingMode(real_metafile->playback_graphics, (flags
>> 1) & 0xff);
+ }
+ case EmfPlusRecordTypeSetCompositingMode:
+ {
+ return GdipSetCompositingMode(real_metafile->playback_graphics, flags
& 0xff);
+ }
+ case EmfPlusRecordTypeObject:
+ {
+ return METAFILE_PlaybackObject(real_metafile, flags, dataSize, data);
+ }
+ case EmfPlusRecordTypeDrawImage:
+ {
+ EmfPlusDrawImage *draw = (EmfPlusDrawImage *)header;
+ BYTE image = flags & 0xff;
+ GpPointF points[3];
+
+ if (image >= EmfPlusObjectTableSize ||
real_metafile->objtable[image].type != ObjectTypeImage)
+ return InvalidParameter;
+
+ if (dataSize != FIELD_OFFSET(EmfPlusDrawImage, RectData) -
sizeof(EmfPlusRecordHeader) +
+ (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (draw->ImageAttributesID >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[draw->ImageAttributesID].type !=
ObjectTypeImageAttributes)
+ return InvalidParameter;
+
+ if (flags & 0x4000) /* C */
+ {
+ points[0].X = draw->RectData.rect.X;
+ points[0].Y = draw->RectData.rect.Y;
+ points[1].X = points[0].X + draw->RectData.rect.Width;
+ points[1].Y = points[0].Y;
+ points[2].X = points[1].X;
+ points[2].Y = points[1].Y + draw->RectData.rect.Height;
+ }
+ else
+ {
+ points[0].X = draw->RectData.rectF.X;
+ points[0].Y = draw->RectData.rectF.Y;
+ points[1].X = points[0].X + draw->RectData.rectF.Width;
+ points[1].Y = points[0].Y;
+ points[2].X = points[1].X;
+ points[2].Y = points[1].Y + draw->RectData.rectF.Height;
+ }
+
+ return GdipDrawImagePointsRect(real_metafile->playback_graphics,
real_metafile->objtable[image].u.image,
+ points, 3, draw->SrcRect.X, draw->SrcRect.Y,
draw->SrcRect.Width, draw->SrcRect.Height, draw->SrcUnit,
+
real_metafile->objtable[draw->ImageAttributesID].u.image_attributes, NULL, NULL);
+ }
+ case EmfPlusRecordTypeDrawImagePoints:
+ {
+ EmfPlusDrawImagePoints *draw = (EmfPlusDrawImagePoints *)header;
+ static const UINT fixed_part_size = FIELD_OFFSET(EmfPlusDrawImagePoints,
PointData) -
+ FIELD_OFFSET(EmfPlusDrawImagePoints, ImageAttributesID);
+ BYTE image = flags & 0xff;
+ GpPointF points[3];
+ unsigned int i;
+ UINT size;
+
+ if (image >= EmfPlusObjectTableSize ||
real_metafile->objtable[image].type != ObjectTypeImage)
+ return InvalidParameter;
+
+ if (dataSize <= fixed_part_size)
+ return InvalidParameter;
+ dataSize -= fixed_part_size;
+
+ if (draw->ImageAttributesID >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[draw->ImageAttributesID].type !=
ObjectTypeImageAttributes)
+ return InvalidParameter;
+
+ if (draw->count != 3)
+ return InvalidParameter;
+
+ if ((flags >> 13) & 1) /* E */
+ FIXME("image effects are not supported.\n");
+
+ if ((flags >> 11) & 1) /* P */
+ size = sizeof(EmfPlusPointR7) * draw->count;
+ else if ((flags >> 14) & 1) /* C */
+ size = sizeof(EmfPlusPoint) * draw->count;
+ else
+ size = sizeof(EmfPlusPointF) * draw->count;
+
+ if (dataSize != size)
+ return InvalidParameter;
+
+ if ((flags >> 11) & 1) /* P */
+ {
+ points[0].X = draw->PointData.pointsR[0].X;
+ points[0].Y = draw->PointData.pointsR[0].Y;
+ for (i = 1; i < 3; i++)
+ {
+ points[i].X = points[i-1].X + draw->PointData.pointsR[i].X;
+ points[i].Y = points[i-1].Y + draw->PointData.pointsR[i].Y;
+ }
+ }
+ else if ((flags >> 14) & 1) /* C */
+ {
+ for (i = 0; i < 3; i++)
+ {
+ points[i].X = draw->PointData.points[i].X;
+ points[i].Y = draw->PointData.points[i].Y;
+ }
+ }
+ else
+ memcpy(points, draw->PointData.pointsF, sizeof(points));
+
+ return GdipDrawImagePointsRect(real_metafile->playback_graphics,
real_metafile->objtable[image].u.image,
+ points, 3, draw->SrcRect.X, draw->SrcRect.Y,
draw->SrcRect.Width, draw->SrcRect.Height, draw->SrcUnit,
+
real_metafile->objtable[draw->ImageAttributesID].u.image_attributes, NULL, NULL);
+ }
+ case EmfPlusRecordTypeFillPath:
+ {
+ EmfPlusFillPath *fill = (EmfPlusFillPath *)header;
+ GpSolidFill *solidfill = NULL;
+ BYTE path = flags & 0xff;
+ GpBrush *brush;
+
+ if (path >= EmfPlusObjectTableSize ||
real_metafile->objtable[path].type != ObjectTypePath)
+ return InvalidParameter;
+
+ if (dataSize != sizeof(fill->data.BrushId))
+ return InvalidParameter;
+
+ if (flags & 0x8000)
+ {
+ stat = GdipCreateSolidFill(fill->data.Color, (GpSolidFill
**)&solidfill);
+ if (stat != Ok)
+ return stat;
+ brush = (GpBrush *)solidfill;
+ }
+ else
+ {
+ if (fill->data.BrushId >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[fill->data.BrushId].type !=
ObjectTypeBrush)
+ return InvalidParameter;
+
+ brush = real_metafile->objtable[fill->data.BrushId].u.brush;
+ }
+
+ stat = GdipFillPath(real_metafile->playback_graphics, brush,
real_metafile->objtable[path].u.path);
+ GdipDeleteBrush((GpBrush *)solidfill);
+ return stat;
+ }
+ case EmfPlusRecordTypeFillClosedCurve:
+ {
+ static const UINT fixed_part_size = FIELD_OFFSET(EmfPlusFillClosedCurve,
PointData) -
+ sizeof(EmfPlusRecordHeader);
+ EmfPlusFillClosedCurve *fill = (EmfPlusFillClosedCurve *)header;
+ GpSolidFill *solidfill = NULL;
+ GpFillMode mode;
+ GpBrush *brush;
+ UINT size, i;
+
+ if (dataSize <= fixed_part_size)
+ return InvalidParameter;
+
+ if (fill->Count == 0)
+ return InvalidParameter;
+
+ if (flags & 0x800) /* P */
+ size = (fixed_part_size + sizeof(EmfPlusPointR7) * fill->Count + 3)
& ~3;
+ else if (flags & 0x4000) /* C */
+ size = fixed_part_size + sizeof(EmfPlusPoint) * fill->Count;
+ else
+ size = fixed_part_size + sizeof(EmfPlusPointF) * fill->Count;
+
+ if (dataSize != size)
+ return InvalidParameter;
+
+ mode = flags & 0x200 ? FillModeWinding : FillModeAlternate; /* W */
+
+ if (flags & 0x8000) /* S */
+ {
+ stat = GdipCreateSolidFill(fill->BrushId, (GpSolidFill
**)&solidfill);
+ if (stat != Ok)
+ return stat;
+ brush = (GpBrush *)solidfill;
+ }
+ else
+ {
+ if (fill->BrushId >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[fill->BrushId].type !=
ObjectTypeBrush)
+ return InvalidParameter;
+
+ brush = real_metafile->objtable[fill->BrushId].u.brush;
+ }
+
+ if (flags & (0x800 | 0x4000))
+ {
+ GpPointF *points = GdipAlloc(fill->Count * sizeof(*points));
+ if (points)
+ {
+ if (flags & 0x800) /* P */
+ {
+ for (i = 1; i < fill->Count; i++)
+ {
+ points[i].X = points[i - 1].X +
fill->PointData.pointsR[i].X;
+ points[i].Y = points[i - 1].Y +
fill->PointData.pointsR[i].Y;
+ }
+ }
+ else
+ {
+ for (i = 0; i < fill->Count; i++)
+ {
+ points[i].X = fill->PointData.points[i].X;
+ points[i].Y = fill->PointData.points[i].Y;
+ }
+ }
+
+ stat = GdipFillClosedCurve2(real_metafile->playback_graphics,
brush,
+ points, fill->Count, fill->Tension, mode);
+ GdipFree(points);
+ }
+ else
+ stat = OutOfMemory;
+ }
+ else
+ stat = GdipFillClosedCurve2(real_metafile->playback_graphics, brush,
+ (const GpPointF *)fill->PointData.pointsF, fill->Count,
fill->Tension, mode);
+
+ GdipDeleteBrush((GpBrush *)solidfill);
+ return stat;
+ }
+ case EmfPlusRecordTypeFillEllipse:
+ {
+ EmfPlusFillEllipse *fill = (EmfPlusFillEllipse *)header;
+ GpSolidFill *solidfill = NULL;
+ GpBrush *brush;
+
+ if (dataSize <= FIELD_OFFSET(EmfPlusFillEllipse, RectData) -
sizeof(EmfPlusRecordHeader))
+ return InvalidParameter;
+ dataSize -= FIELD_OFFSET(EmfPlusFillEllipse, RectData) -
sizeof(EmfPlusRecordHeader);
+
+ if (dataSize != (flags & 0x4000 ? sizeof(EmfPlusRect) :
sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (flags & 0x8000)
+ {
+ stat = GdipCreateSolidFill(fill->BrushId, (GpSolidFill
**)&solidfill);
+ if (stat != Ok)
+ return stat;
+ brush = (GpBrush *)solidfill;
+ }
+ else
+ {
+ if (fill->BrushId >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[fill->BrushId].type !=
ObjectTypeBrush)
+ return InvalidParameter;
+
+ brush = real_metafile->objtable[fill->BrushId].u.brush;
+ }
+
+ if (flags & 0x4000)
+ stat = GdipFillEllipseI(real_metafile->playback_graphics, brush,
fill->RectData.rect.X,
+ fill->RectData.rect.Y, fill->RectData.rect.Width,
fill->RectData.rect.Height);
+ else
+ stat = GdipFillEllipse(real_metafile->playback_graphics, brush,
fill->RectData.rectF.X,
+ fill->RectData.rectF.Y, fill->RectData.rectF.Width,
fill->RectData.rectF.Height);
+
+ GdipDeleteBrush((GpBrush *)solidfill);
+ return stat;
+ }
+ case EmfPlusRecordTypeFillPie:
+ {
+ EmfPlusFillPie *fill = (EmfPlusFillPie *)header;
+ GpSolidFill *solidfill = NULL;
+ GpBrush *brush;
+
+ if (dataSize <= FIELD_OFFSET(EmfPlusFillPie, RectData) -
sizeof(EmfPlusRecordHeader))
+ return InvalidParameter;
+ dataSize -= FIELD_OFFSET(EmfPlusFillPie, RectData) -
sizeof(EmfPlusRecordHeader);
+
+ if (dataSize != (flags & 0x4000 ? sizeof(EmfPlusRect) :
sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (flags & 0x8000) /* S */
+ {
+ stat = GdipCreateSolidFill(fill->BrushId, (GpSolidFill
**)&solidfill);
+ if (stat != Ok)
+ return stat;
+ brush = (GpBrush *)solidfill;
+ }
+ else
+ {
+ if (fill->BrushId >= EmfPlusObjectTableSize ||
+ real_metafile->objtable[fill->BrushId].type !=
ObjectTypeBrush)
+ return InvalidParameter;
+
+ brush = real_metafile->objtable[fill->BrushId].u.brush;
+ }
+
+ if (flags & 0x4000) /* C */
+ stat = GdipFillPieI(real_metafile->playback_graphics, brush,
fill->RectData.rect.X,
+ fill->RectData.rect.Y, fill->RectData.rect.Width,
fill->RectData.rect.Height,
+ fill->StartAngle, fill->SweepAngle);
+ else
+ stat = GdipFillPie(real_metafile->playback_graphics, brush,
fill->RectData.rectF.X,
+ fill->RectData.rectF.Y, fill->RectData.rectF.Width,
fill->RectData.rectF.Height,
+ fill->StartAngle, fill->SweepAngle);
+
+ GdipDeleteBrush((GpBrush *)solidfill);
+ return stat;
+ }
+ case EmfPlusRecordTypeDrawPath:
+ {
+ EmfPlusDrawPath *draw = (EmfPlusDrawPath *)header;
+ BYTE path = flags & 0xff;
+
+ if (dataSize != sizeof(draw->PenId))
+ return InvalidParameter;
+
+ if (path >= EmfPlusObjectTableSize || draw->PenId >=
EmfPlusObjectTableSize)
+ return InvalidParameter;
+
+ if (real_metafile->objtable[path].type != ObjectTypePath ||
+ real_metafile->objtable[draw->PenId].type != ObjectTypePen)
+ return InvalidParameter;
+
+ return GdipDrawPath(real_metafile->playback_graphics,
real_metafile->objtable[draw->PenId].u.pen,
+ real_metafile->objtable[path].u.path);
+ }
+ case EmfPlusRecordTypeDrawArc:
+ {
+ EmfPlusDrawArc *draw = (EmfPlusDrawArc *)header;
+ BYTE pen = flags & 0xff;
+
+ if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type
!= ObjectTypePen)
+ return InvalidParameter;
+
+ if (dataSize != FIELD_OFFSET(EmfPlusDrawArc, RectData) -
sizeof(EmfPlusRecordHeader) +
+ (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (flags & 0x4000) /* C */
+ return GdipDrawArcI(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ draw->RectData.rect.X, draw->RectData.rect.Y,
draw->RectData.rect.Width,
+ draw->RectData.rect.Height, draw->StartAngle,
draw->SweepAngle);
+ else
+ return GdipDrawArc(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ draw->RectData.rectF.X, draw->RectData.rectF.Y,
draw->RectData.rectF.Width,
+ draw->RectData.rectF.Height, draw->StartAngle,
draw->SweepAngle);
+ }
+ case EmfPlusRecordTypeDrawEllipse:
+ {
+ EmfPlusDrawEllipse *draw = (EmfPlusDrawEllipse *)header;
+ BYTE pen = flags & 0xff;
+
+ if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type
!= ObjectTypePen)
+ return InvalidParameter;
+
+ if (dataSize != (flags & 0x4000 ? sizeof(EmfPlusRect) :
sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (flags & 0x4000) /* C */
+ return GdipDrawEllipseI(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ draw->RectData.rect.X, draw->RectData.rect.Y,
draw->RectData.rect.Width,
+ draw->RectData.rect.Height);
+ else
+ return GdipDrawEllipse(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ draw->RectData.rectF.X, draw->RectData.rectF.Y,
draw->RectData.rectF.Width,
+ draw->RectData.rectF.Height);
+ }
+ case EmfPlusRecordTypeDrawPie:
+ {
+ EmfPlusDrawPie *draw = (EmfPlusDrawPie *)header;
+ BYTE pen = flags & 0xff;
+
+ if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type
!= ObjectTypePen)
+ return InvalidParameter;
+
+ if (dataSize != FIELD_OFFSET(EmfPlusDrawPie, RectData) -
sizeof(EmfPlusRecordHeader) +
+ (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (flags & 0x4000) /* C */
+ return GdipDrawPieI(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ draw->RectData.rect.X, draw->RectData.rect.Y,
draw->RectData.rect.Width,
+ draw->RectData.rect.Height, draw->StartAngle,
draw->SweepAngle);
+ else
+ return GdipDrawPie(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ draw->RectData.rectF.X, draw->RectData.rectF.Y,
draw->RectData.rectF.Width,
+ draw->RectData.rectF.Height, draw->StartAngle,
draw->SweepAngle);
+ }
+ case EmfPlusRecordTypeDrawRects:
+ {
+ EmfPlusDrawRects *draw = (EmfPlusDrawRects *)header;
+ BYTE pen = flags & 0xff;
+ GpRectF *rects = NULL;
+
+ if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type
!= ObjectTypePen)
+ return InvalidParameter;
+
+ if (dataSize <= FIELD_OFFSET(EmfPlusDrawRects, RectData) -
sizeof(EmfPlusRecordHeader))
+ return InvalidParameter;
+ dataSize -= FIELD_OFFSET(EmfPlusDrawRects, RectData) -
sizeof(EmfPlusRecordHeader);
+
+ if (dataSize != draw->Count * (flags & 0x4000 ? sizeof(EmfPlusRect) :
sizeof(EmfPlusRectF)))
+ return InvalidParameter;
+
+ if (flags & 0x4000)
+ {
+ DWORD i;
+
+ rects = GdipAlloc(draw->Count * sizeof(*rects));
+ if (!rects)
+ return OutOfMemory;
+
+ for (i = 0; i < draw->Count; i++)
+ {
+ rects[i].X = draw->RectData.rect[i].X;
+ rects[i].Y = draw->RectData.rect[i].Y;
+ rects[i].Width = draw->RectData.rect[i].Width;
+ rects[i].Height = draw->RectData.rect[i].Height;
+ }
+ }
+
+ stat = GdipDrawRectangles(real_metafile->playback_graphics,
real_metafile->objtable[pen].u.pen,
+ rects ? rects : (GpRectF *)draw->RectData.rectF, draw->Count);
+ GdipFree(rects);
+ return stat;
+ }
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;
@@ -2625,10 +4159,7 @@ static GpStatus METAFILE_AddImageAttributesObject(GpMetafile
*metafile, const Gp
attrs_record->Version = VERSION_MAGIC2;
attrs_record->Reserved1 = 0;
attrs_record->WrapMode = attrs->wrap;
- attrs_record->ClampColor.Blue = attrs->outside_color & 0xff;
- attrs_record->ClampColor.Green = (attrs->outside_color >> 8) & 0xff;
- attrs_record->ClampColor.Red = (attrs->outside_color >> 16) & 0xff;
- attrs_record->ClampColor.Alpha = attrs->outside_color >> 24;
+ attrs_record->ClampColor = attrs->outside_color;
attrs_record->ObjectClamp = attrs->clamp;
attrs_record->Reserved2 = 0;
return Ok;
@@ -2708,12 +4239,7 @@ GpStatus METAFILE_DrawImagePointsRect(GpMetafile *metafile, GpImage
*image,
draw_image_record->SrcRect.Width = units_to_pixels(srcwidth, srcUnit,
metafile->image.xres);
draw_image_record->SrcRect.Height = units_to_pixels(srcheight, srcUnit,
metafile->image.yres);
draw_image_record->count = 3;
- draw_image_record->PointData[0].pointF.X = points[0].X;
- draw_image_record->PointData[0].pointF.Y = points[0].Y;
- draw_image_record->PointData[1].pointF.X = points[1].X;
- draw_image_record->PointData[1].pointF.Y = points[1].Y;
- draw_image_record->PointData[2].pointF.X = points[2].X;
- draw_image_record->PointData[2].pointF.Y = points[2].Y;
+ memcpy(draw_image_record->PointData.pointsF, points, 3 * sizeof(*points));
METAFILE_WriteRecords(metafile);
return Ok;
}
@@ -2759,33 +4285,6 @@ static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath
*path, DWORD
return Ok;
}
-static GpStatus METAFILE_PrepareBrushData(GpBrush *brush, DWORD *size)
-{
- if (brush->bt == BrushTypeSolidColor)
- {
- *size = FIELD_OFFSET(EmfPlusBrush, BrushData.solid) +
sizeof(EmfPlusSolidBrushData);
- return Ok;
- }
-
- FIXME("unsupported brush type: %d\n", brush->bt);
- return NotImplemented;
-}
-
-static void METAFILE_FillBrushData(GpBrush *brush, EmfPlusBrush *data)
-{
- if (brush->bt == BrushTypeSolidColor)
- {
- GpSolidFill *solid = (GpSolidFill*)brush;
-
- data->Version = VERSION_MAGIC2;
- data->Type = solid->brush.bt;
- data->BrushData.solid.SolidColor.Blue = solid->color & 0xff;
- data->BrushData.solid.SolidColor.Green = (solid->color >> 8) &
0xff;
- data->BrushData.solid.SolidColor.Red = (solid->color >> 16) &
0xff;
- data->BrushData.solid.SolidColor.Alpha = solid->color >> 24;
- }
-}
-
static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id)
{
DWORD i, data_flags, pen_data_size, brush_size;
@@ -2981,30 +4480,6 @@ GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath
*path)
return Ok;
}
-static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GpBrush *brush, DWORD *id)
-{
- EmfPlusObject *object_record;
- GpStatus stat;
- DWORD size;
-
- *id = -1;
- if (metafile->metafile_type != MetafileTypeEmfPlusOnly &&
metafile->metafile_type != MetafileTypeEmfPlusDual)
- return Ok;
-
- stat = METAFILE_PrepareBrushData(brush, &size);
- if (stat != Ok) return stat;
-
- stat = METAFILE_AllocateRecord(metafile,
- FIELD_OFFSET(EmfPlusObject, ObjectData) + size, (void**)&object_record);
- if (stat != Ok) return stat;
-
- *id = METAFILE_AddObjectId(metafile);
- object_record->Header.Type = EmfPlusRecordTypeObject;
- object_record->Header.Flags = *id | ObjectTypeBrush << 8;
- METAFILE_FillBrushData(brush, &object_record->ObjectData.brush);
- return Ok;
-}
-
GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path)
{
EmfPlusFillPath *fill_path_record;
@@ -3035,10 +4510,7 @@ GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush,
GpPath *path)
if (inline_color)
{
fill_path_record->Header.Flags = 0x8000 | path_id;
- fill_path_record->data.Color.Blue = ((GpSolidFill*)brush)->color &
0xff;
- fill_path_record->data.Color.Green = (((GpSolidFill*)brush)->color >>
8) & 0xff;
- fill_path_record->data.Color.Red = (((GpSolidFill*)brush)->color >>
16) & 0xff;
- fill_path_record->data.Color.Alpha = ((GpSolidFill*)brush)->color >>
24;
+ fill_path_record->data.Color = ((GpSolidFill *)brush)->color;
}
else
{
diff --git a/dll/win32/gdiplus/region.c b/dll/win32/gdiplus/region.c
index b5fa5bcd92..c40882c7ad 100644
--- a/dll/win32/gdiplus/region.c
+++ b/dll/win32/gdiplus/region.c
@@ -64,12 +64,6 @@
#define FLAGS_INTPATH 0x4000
-struct memory_buffer
-{
- const BYTE *buffer;
- INT size, pos;
-};
-
struct region_header
{
DWORD magic;
@@ -766,24 +760,6 @@ 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;
diff --git a/media/doc/README.WINE b/media/doc/README.WINE
index 8b15f8045b..4cc97bd42a 100644
--- a/media/doc/README.WINE
+++ b/media/doc/README.WINE
@@ -68,7 +68,7 @@ reactos/dll/win32/dciman32 # Synced to WineStaging-2.9
reactos/dll/win32/faultrep # Synced to WineStaging-2.9
reactos/dll/win32/fontsub # Synced to WineStaging-2.9
reactos/dll/win32/fusion # Synced to Wine-3.0
-reactos/dll/win32/gdiplus # Synced to WineStaging-2.16
+reactos/dll/win32/gdiplus # Synced to Wine-3.0
reactos/dll/win32/hhctrl.ocx # Synced to WineStaging-2.9
reactos/dll/win32/hlink # Synced to WineStaging-2.9
reactos/dll/win32/hnetcfg # Synced to WineStaging-2.9