/*
* Copyright (C) 2007 Google (Evan Stade)
+ * Copyright (C) 2003-2004,2007 Novell, Inc. http://www.novell.com (Ravindra (rkumar@novell.com))
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
return OutOfMemory;
}
+ dest->transform = src->transform;
+
memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
return Ok;
}
+static void linegradient_init_transform(GpLineGradient *line)
+{
+ float trans_x = line->rect.X + (line->rect.Width / 2.f);
+ float trans_y = line->rect.Y + (line->rect.Height / 2.f);
+ float dx = line->endpoint.X - line->startpoint.X;
+ float dy = line->endpoint.Y - line->startpoint.Y;
+ float t_cos, t_sin, w_ratio, h_ratio;
+ float h;
+ GpMatrix rot;
+
+ h = sqrtf(dx * dx + dy * dy);
+
+ t_cos = dx / h;
+ t_sin = dy / h;
+
+ w_ratio = (fabs(t_cos) * line->rect.Width + fabs(t_sin) * line->rect.Height) / line->rect.Width;
+ h_ratio = (fabs(t_sin) * line->rect.Width + fabs(t_cos) * line->rect.Height) / line->rect.Height;
+
+ GdipSetMatrixElements(&line->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+
+ GdipSetMatrixElements(&rot, t_cos, t_sin, -1.f * t_sin, t_cos, 0, 0);
+
+ /* center about the origin */
+ GdipTranslateMatrix(&line->transform, -trans_x, -trans_y, MatrixOrderAppend);
+
+ /* scale to normalize gradient along gradient line (?) */
+ GdipScaleMatrix(&line->transform, w_ratio, h_ratio, MatrixOrderAppend);
+
+ /* rotate so the gradient is horizontal */
+ GdipMultiplyMatrix(&line->transform, &rot, MatrixOrderAppend);
+
+ /* restore original offset in new coords */
+ GdipTranslateMatrix(&line->transform, trans_x, trans_y, MatrixOrderAppend);
+}
+
/******************************************************************************
* GdipCreateLineBrush [GDIPLUS.@]
*/
(*line)->pblendpos = NULL;
(*line)->pblendcount = 0;
+ linegradient_init_transform(*line);
+
TRACE("<-- %p\n", *line);
return Ok;
{
GpPointF start, end;
GpStatus stat;
+ float far_x, far_y;
TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
wrap, line);
if(!line || !rect)
return InvalidParameter;
+ far_x = rect->X + rect->Width;
+ far_y = rect->Y + rect->Height;
+
switch (mode)
{
case LinearGradientModeHorizontal:
- start.X = rect->X;
+ start.X = min(rect->X, far_x);
start.Y = rect->Y;
- end.X = rect->X + rect->Width;
+ end.X = max(rect->X, far_x);
end.Y = rect->Y;
break;
case LinearGradientModeVertical:
start.X = rect->X;
- start.Y = rect->Y;
+ start.Y = min(rect->Y, far_y);
end.X = rect->X;
- end.Y = rect->Y + rect->Height;
+ end.Y = max(rect->Y, far_y);
break;
case LinearGradientModeForwardDiagonal:
- start.X = rect->X;
- start.Y = rect->Y;
- end.X = rect->X + rect->Width;
- end.Y = rect->Y + rect->Height;
+ start.X = min(rect->X, far_x);
+ start.Y = min(rect->Y, far_y);
+ end.X = max(rect->X, far_x);
+ end.Y = max(rect->Y, far_y);
break;
case LinearGradientModeBackwardDiagonal:
- start.X = rect->X + rect->Width;
- start.Y = rect->Y;
- end.X = rect->X;
- end.Y = rect->Y + rect->Height;
+ start.X = max(rect->X, far_x);
+ start.Y = min(rect->Y, far_y);
+ end.X = min(rect->X, far_x);
+ end.Y = max(rect->Y, far_y);
break;
default:
return InvalidParameter;
(*line)->startpoint.X = rect->X + exofs;
(*line)->startpoint.Y = rect->Y + eyofs;
}
+
+ linegradient_init_transform(*line);
}
return stat;
GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
{
- static int calls;
-
TRACE("(%p)\n", brush);
- if(!(calls++))
- FIXME("not implemented\n");
+ if(!brush)
+ return InvalidParameter;
- return NotImplemented;
+ return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
}
GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
GDIPCONST GpMatrix *matrix)
{
- static int calls;
-
TRACE("(%p,%p)\n", brush, matrix);
- if(!(calls++))
- FIXME("not implemented\n");
+ if(!brush || !matrix)
+ return InvalidParameter;
- return NotImplemented;
+ brush->transform = *matrix;
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix)
{
- static int calls;
-
TRACE("(%p,%p)\n", brush, matrix);
- if(!(calls++))
- FIXME("not implemented\n");
+ if(!brush || !matrix)
+ return InvalidParameter;
- return NotImplemented;
+ *matrix = brush->transform;
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
GpMatrixOrder order)
{
- static int calls;
-
TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order);
- if(!(calls++))
- FIXME("not implemented\n");
+ if(!brush)
+ return InvalidParameter;
- return NotImplemented;
+ return GdipScaleMatrix(&brush->transform, sx, sy, order);
}
GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush,
GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
{
- static int calls;
-
TRACE("(%p,%p,%u)\n", brush, matrix, order);
- if(!(calls++))
- FIXME("not implemented\n");
+ if(!brush)
+ return InvalidParameter;
- return NotImplemented;
+ if(!matrix)
+ return Ok;
+
+ return GdipMultiplyMatrix(&brush->transform, matrix, order);
}
-GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
+GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient *brush,
REAL dx, REAL dy, GpMatrixOrder order)
{
- static int calls;
-
TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order);
- if(!(calls++))
- FIXME("not implemented\n");
+ if(!brush)
+ return InvalidParameter;
- return Ok;
+ return GdipTranslateMatrix(&brush->transform, dx, dy, order);
}
/******************************************************************************
622 stdcall GdipBitmapGetHistogramSize(long ptr)
623 stdcall GdipBitmapConvertFormat(ptr long long long ptr float)
624 stdcall GdipImageSetAbort(ptr ptr)
-625 stub GdipGraphicsSetAbort
+625 stdcall GdipGraphicsSetAbort(ptr ptr)
626 stub GdipDrawImageFX
627 stdcall GdipConvertToEmfPlus(ptr ptr ptr long ptr ptr)
628 stdcall GdipConvertToEmfPlusToFile(ptr ptr ptr ptr long ptr ptr)
#define VERSION_MAGIC 0xdbc01001
#define VERSION_MAGIC2 0xdbc01002
+#define VALID_MAGIC(x) (((x) & 0xfffff000) == 0xdbc01000)
#define TENSION_CONST (0.3)
#define GIF_DISPOSE_UNSPECIFIED 0
extern REAL pixels_to_units(REAL pixels, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
extern REAL units_scale(GpUnit from, GpUnit to, REAL dpi) DECLSPEC_HIDDEN;
+#define WineCoordinateSpaceGdiDevice ((GpCoordinateSpace)4)
+
+extern GpStatus gdi_transform_acquire(GpGraphics *graphics);
+extern GpStatus gdi_transform_release(GpGraphics *graphics);
extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
+extern GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space,
+ GpCoordinateSpace src_space, GpPointF *points, INT count) DECLSPEC_HIDDEN;
extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
+extern GpStatus encode_image_png(GpImage *image, IStream* stream, GDIPCONST EncoderParameters* params) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SetClipRect(GpMetafile* metafile,
REAL x, REAL y, REAL width, REAL height, CombineMode mode) DECLSPEC_HIDDEN;
+extern GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
+extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile, GpImage *image,
+ GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
+ REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
+ DrawImageAbort callback, VOID *callbackData) DECLSPEC_HIDDEN;
+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 calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
extern BOOL lengthen_path(GpPath *path, INT len) DECLSPEC_HIDDEN;
+extern DWORD write_region_data(const GpRegion *region, void *data) DECLSPEC_HIDDEN;
+extern DWORD write_path_data(GpPath *path, void *data) DECLSPEC_HIDDEN;
+
extern GpStatus trace_path(GpGraphics *graphics, GpPath *path) DECLSPEC_HIDDEN;
typedef struct region_element region_element;
struct list containers;
GraphicsContainer contid; /* last-issued container ID */
INT origin_x, origin_y;
+ INT gdi_transform_acquire_count, gdi_transform_save;
+ GpMatrix gdi_transform;
/* For giving the caller an HDC when we technically can't: */
HBITMAP temp_hbitmap;
int temp_hbitmap_width;
ARGB* pblendcolor; /* preset blend colors */
REAL* pblendpos; /* preset blend positions */
INT pblendcount;
+ GpMatrix transform;
};
struct GpTexture{
IStream *record_stream;
BOOL auto_frame; /* If true, determine the frame automatically */
GpPointF auto_frame_min, auto_frame_max;
+ DWORD next_object_id;
/* playback */
GpGraphics *playback_graphics;
#define GDIP_GET_NEW_CONTID_FOR(pGpGraphics) \
(UINT)(InterlockedExchangeAdd(&g_priv_contid,GDIP_CONTID_STEP))
+
+/* ReactOS FIXME: Inspect */
+#define fmax max
+
/* looks-right constants */
#define ANCHOR_WIDTH (2.0)
#define MAX_ITERS (50)
width *= units_to_pixels(pen->width, pen->unit == UnitWorld ? graphics->unit : pen->unit, graphics->xres);
width *= graphics->scale;
+
+ pt[0].X = 0.0;
+ pt[0].Y = 0.0;
+ pt[1].X = 1.0;
+ pt[1].Y = 1.0;
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, pt, 2);
+ width *= sqrt((pt[1].X - pt[0].X) * (pt[1].X - pt[0].X) +
+ (pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
}
if(pen->dash == DashStyleCustom){
RestoreDC(graphics->hdc, state);
}
-/* This helper applies all the changes that the points listed in ptf need in
- * order to be drawn on the device context. In the end, this should include at
- * least:
- * -scaling by page unit
- * -applying world transformation
- * -converting from float to int
- * Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx,
- * SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using
- * gdi to draw, and these functions would irreparably mess with line widths.
- */
-static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
- GpPointF *ptf, INT count)
+static void round_points(POINT *pti, GpPointF *ptf, INT count)
{
- REAL scale_x, scale_y;
- GpMatrix matrix;
int i;
- scale_x = units_to_pixels(1.0, graphics->unit, graphics->xres);
- scale_y = units_to_pixels(1.0, graphics->unit, graphics->yres);
-
- /* apply page scale */
- if(graphics->unit != UnitDisplay)
- {
- scale_x *= graphics->scale;
- scale_y *= graphics->scale;
- }
-
- matrix = graphics->worldtrans;
- GdipScaleMatrix(&matrix, scale_x, scale_y, MatrixOrderAppend);
- GdipTransformMatrixPoints(&matrix, ptf, count);
-
for(i = 0; i < count; i++){
pti[i].x = gdip_round(ptf[i].X);
pti[i].y = gdip_round(ptf[i].Y);
}
}
+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)
{
static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
{
- /* clipping region is in device coords */
- return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
+ GpRegion *rgn;
+ GpMatrix transform;
+ GpStatus stat;
+
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, &transform);
+
+ if (stat == Ok)
+ stat = GdipCloneRegion(graphics->clip, &rgn);
+
+ if (stat == Ok)
+ {
+ stat = GdipTransformRegion(rgn, &transform);
+
+ if (stat == Ok)
+ stat = GdipGetRegionHRgn(rgn, NULL, hrgn);
+
+ GdipDeleteRegion(rgn);
+ }
+
+ return stat;
}
/* Draw ARGB data to the given graphics object */
REAL blendfac;
/* clamp to between 0.0 and 1.0, using the wrap mode */
+ position = (position - brush->rect.X) / brush->rect.Width;
if (brush->wrap == WrapModeTile)
{
position = fmodf(position, 1.0f);
if (y < 0)
y = height*2 + y % (height * 2);
- if ((attributes->wrap & 1) == 1)
+ if (attributes->wrap & WrapModeTileFlipX)
{
- /* Flip X */
if ((x / width) % 2 == 0)
x = x % width;
else
else
x = x % width;
- if ((attributes->wrap & 2) == 2)
+ if (attributes->wrap & WrapModeTileFlipY)
{
- /* Flip Y */
if ((y / height) % 2 == 0)
y = y % height;
else
case BrushTypeLinearGradient:
{
GpLineGradient *fill = (GpLineGradient*)brush;
- GpPointF draw_points[3], line_points[3];
+ GpPointF draw_points[3];
GpStatus stat;
- static const GpRectF box_1 = { 0.0, 0.0, 1.0, 1.0 };
- GpMatrix *world_to_gradient; /* FIXME: Store this in the brush? */
int x, y;
draw_points[0].X = fill_area->X;
/* Transform the points to a co-ordinate space where X is the point's
* position in the gradient, 0.0 being the start point and 1.0 the
* end point. */
- stat = GdipTransformPoints(graphics, CoordinateSpaceWorld,
- CoordinateSpaceDevice, draw_points, 3);
+ stat = gdip_transform_points(graphics, CoordinateSpaceWorld,
+ WineCoordinateSpaceGdiDevice, draw_points, 3);
if (stat == Ok)
{
- line_points[0] = fill->startpoint;
- line_points[1] = fill->endpoint;
- line_points[2].X = fill->startpoint.X + (fill->startpoint.Y - fill->endpoint.Y);
- line_points[2].Y = fill->startpoint.Y + (fill->endpoint.X - fill->startpoint.X);
-
- stat = GdipCreateMatrix3(&box_1, line_points, &world_to_gradient);
- }
-
- if (stat == Ok)
- {
- stat = GdipInvertMatrix(world_to_gradient);
+ GpMatrix world_to_gradient = fill->transform;
+ stat = GdipInvertMatrix(&world_to_gradient);
if (stat == Ok)
- stat = GdipTransformMatrixPoints(world_to_gradient, draw_points, 3);
-
- GdipDeleteMatrix(world_to_gradient);
+ stat = GdipTransformMatrixPoints(&world_to_gradient, draw_points, 3);
}
if (stat == Ok)
draw_points[2].Y = fill_area->Y+1;
/* Transform the points to the co-ordinate space of the bitmap. */
- stat = GdipTransformPoints(graphics, CoordinateSpaceWorld,
- CoordinateSpaceDevice, draw_points, 3);
+ stat = gdip_transform_points(graphics, CoordinateSpaceWorld,
+ WineCoordinateSpaceGdiDevice, draw_points, 3);
if (stat == Ok)
{
if (stat != Ok)
return stat;
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, &world_to_device);
if (stat == Ok)
{
REAL blend_amount, pdy, pdx;
pdy = yf - center_point.Y;
pdx = xf - center_point.X;
- blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy );
- outer_color = blend_colors(start_color, end_color, blend_amount);
+
+ if (fabs(pdx) <= 0.001 && fabs(pdy) <= 0.001)
+ {
+ /* Too close to center point, don't try to calculate outer color */
+ outer_color = start_color;
+ }
+ else
+ {
+ blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy );
+ outer_color = blend_colors(start_color, end_color, blend_amount);
+ }
}
distance = (end_point.Y - start_point.Y) * (start_point.X - xf) +
ptf[3].X = x2 - dbig;
ptf[2].X = x2 + dsmall;
- transform_and_round_points(graphics, pt, ptf, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Polygon(graphics->hdc, pt, 4);
break;
ptf[2].X = x2;
ptf[2].Y = y2;
- transform_and_round_points(graphics, pt, ptf, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Polygon(graphics->hdc, pt, 3);
break;
ptf[1].X = x2 + dx;
ptf[1].Y = y2 + dy;
- transform_and_round_points(graphics, pt, ptf, 2);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
break;
ptf[2].X = x2 + dx;
ptf[2].Y = y2 + dy;
- transform_and_round_points(graphics, pt, ptf, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Polygon(graphics->hdc, pt, 3);
break;
ptf[3].X = x2 + dx;
ptf[3].Y = y2 + dy;
- transform_and_round_points(graphics, pt, ptf, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
pt[2].y, pt[3].x, pt[3].y);
GdipTranslateMatrix(&matrix, x2, y2, MatrixOrderAppend);
GdipTransformMatrixPoints(&matrix, custptf, count);
- transform_and_round_points(graphics, custpt, custptf, count);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
for(i = 0; i < count; i++)
tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
}
}
- transform_and_round_points(graphics, pti, ptcopy, count);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptcopy, count);
+
+ round_points(pti, ptcopy, count);
for(i = 0; i < count; i++){
tp[i] = convert_path_point_type(types[i]);
return Ok;
}
-static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
+static GpStatus get_graphics_device_bounds(GpGraphics* graphics, GpRectF* rect)
{
RECT wnd_rect;
GpStatus stat=Ok;
rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
}
- if (graphics->hdc)
+ return stat;
+}
+
+static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
+{
+ GpStatus stat = get_graphics_device_bounds(graphics, rect);
+
+ if (stat == Ok && graphics->hdc)
{
- POINT points[2];
+ GpPointF points[4], min_point, max_point;
+ int i;
+
+ points[0].X = points[2].X = rect->X;
+ points[0].Y = points[1].Y = rect->Y;
+ points[1].X = points[3].X = rect->X + rect->Width;
+ points[2].Y = points[3].Y = rect->Y + rect->Height;
- points[0].x = rect->X;
- points[0].y = rect->Y;
- points[1].x = rect->X + rect->Width;
- points[1].y = rect->Y + rect->Height;
+ gdip_transform_points(graphics, CoordinateSpaceDevice, WineCoordinateSpaceGdiDevice, points, 4);
- DPtoLP(graphics->hdc, points, sizeof(points)/sizeof(points[0]));
+ min_point = max_point = points[0];
- rect->X = min(points[0].x, points[1].x);
- rect->Y = min(points[0].y, points[1].y);
- rect->Width = abs(points[1].x - points[0].x);
- rect->Height = abs(points[1].y - points[0].y);
+ for (i=1; i<4; i++)
+ {
+ if (points[i].X < min_point.X) min_point.X = points[i].X;
+ if (points[i].Y < min_point.Y) min_point.Y = points[i].Y;
+ if (points[i].X > max_point.X) max_point.X = points[i].X;
+ if (points[i].Y > max_point.Y) max_point.Y = points[i].Y;
+ }
+
+ rect->X = min_point.X;
+ rect->Y = min_point.Y;
+ rect->Width = max_point.X - min_point.X;
+ rect->Height = max_point.Y - min_point.Y;
}
return stat;
GpRectF rectf;
GpRegion* tmp;
+ /* Ignore graphics image bounds for metafiles */
+ if (graphics->image && graphics->image_type == ImageTypeMetafile)
+ return GdipCombineRegionRegion(rgn, graphics->clip, CombineModeReplace);
+
if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
return stat;
TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]),
debugstr_pointf(&points[2]));
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ return METAFILE_DrawImagePointsRect((GpMetafile*)graphics->image,
+ image, points, count, srcx, srcy, srcwidth, srcheight,
+ srcUnit, imageAttributes, callback, callbackData);
+ }
+
memcpy(ptf, points, 3 * sizeof(GpPointF));
/* Ensure source width/height is positive */
ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
if (!srcwidth || !srcheight || (ptf[3].X == ptf[0].X && ptf[3].Y == ptf[0].Y))
return Ok;
- transform_and_round_points(graphics, pti, ptf, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
+ round_points(pti, ptf, 4);
TRACE("%s %s %s %s\n", wine_dbgstr_point(&pti[0]), wine_dbgstr_point(&pti[1]),
wine_dbgstr_point(&pti[2]), wine_dbgstr_point(&pti[3]));
if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
}
- stat = get_graphics_bounds(graphics, &graphics_bounds);
+ stat = get_graphics_device_bounds(graphics, &graphics_bounds);
if (stat != Ok) return stat;
if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
dst_stride = src_stride;
}
+ gdi_transform_acquire(graphics);
+
stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride,
lockeddata.PixelFormat);
+ gdi_transform_release(graphics);
+
heap_free(src_data);
heap_free(dst_dyn_data);
DeleteObject(hrgn);
}
+ gdi_transform_acquire(graphics);
+
if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
{
gdi_alpha_blend(graphics, pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY);
}
+ gdi_transform_release(graphics);
+
RestoreDC(graphics->hdc, save_state);
if (temp_hdc)
if (hrgn)
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ gdi_transform_acquire(graphics);
+
retval = draw_poly(graphics, pen, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, TRUE);
+ gdi_transform_release(graphics);
+
end:
restore_dc(graphics, save_state);
DeleteObject(hrgn);
if (stat == Ok)
{
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, transform);
if (stat == Ok)
if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y);
}
- stat = get_graphics_bounds(graphics, &gp_bound_rect);
+ stat = get_graphics_device_bounds(graphics, &gp_bound_rect);
}
if (stat == Ok)
end_pointi.X = floorf(end_point.X);
end_pointi.Y = floorf(end_point.Y);
+ if(start_pointi.X == end_pointi.X && start_pointi.Y == end_pointi.Y)
+ continue;
+
/* draw line segment */
if (abs(start_pointi.Y - end_pointi.Y) > abs(start_pointi.X - end_pointi.X))
{
/* draw output image */
if (stat == Ok)
{
+ gdi_transform_acquire(graphics);
+
stat = alpha_blend_pixels(graphics, output_area.left, output_area.top,
(BYTE*)output_bits, output_width, output_height, output_width * 4,
PixelFormat32bppARGB);
+
+ gdi_transform_release(graphics);
}
heap_free(brush_bits);
GpStatus stat;
GpPath *wide_path;
GpMatrix *transform=NULL;
+ REAL flatness=1.0;
/* Check if the final pen thickness in pixels is too thin. */
if (pen->unit == UnitPixel)
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, transform);
}
+ else
+ {
+ /* Set flatness based on the final coordinate space */
+ GpMatrix t;
+
+ stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ CoordinateSpaceWorld, &t);
+
+ if (stat != Ok)
+ return stat;
+
+ flatness = 1.0/sqrt(fmax(
+ t.matrix[0] * t.matrix[0] + t.matrix[1] * t.matrix[1],
+ t.matrix[2] * t.matrix[2] + t.matrix[3] * t.matrix[3]));
+ }
if (stat == Ok)
- stat = GdipWidenPath(wide_path, pen, transform, 1.0);
+ stat = GdipWidenPath(wide_path, pen, transform, flatness);
if (pen->unit == UnitPixel)
{
if (path->pathdata.Count == 0)
return Ok;
- if (!graphics->hdc || !brush_can_fill_path(pen->brush, FALSE))
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ retval = METAFILE_DrawPath((GpMetafile*)graphics->image, pen, path);
+ else if (!graphics->hdc || graphics->alpha_hdc || !brush_can_fill_path(pen->brush, FALSE))
retval = SOFTWARE_GdipDrawPath(graphics, pen, path);
else
retval = GDI32_GdipDrawPath(graphics, pen, path);
if (hrgn)
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ gdi_transform_acquire(graphics);
+
BeginPath(graphics->hdc);
retval = draw_poly(graphics, NULL, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, FALSE);
- if(retval != Ok)
- goto end;
-
- EndPath(graphics->hdc);
- brush_fill_path(graphics, brush);
+ if(retval == Ok)
+ {
+ EndPath(graphics->hdc);
+ brush_fill_path(graphics, brush);
+ }
- retval = Ok;
+ gdi_transform_release(graphics);
end:
RestoreDC(graphics->hdc, save_state);
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ return METAFILE_FillPath((GpMetafile*)graphics->image, brush, path);
+
if (!graphics->image && !graphics->alpha_hdc)
stat = GDI32_GdipFillPath(graphics, brush, path);
for(i = 0; i < count; i++){
rectsF[i].X = (REAL)rects[i].X;
rectsF[i].Y = (REAL)rects[i].Y;
- rectsF[i].X = (REAL)rects[i].Width;
+ rectsF[i].Width = (REAL)rects[i].Width;
rectsF[i].Height = (REAL)rects[i].Height;
}
if (!brush_can_fill_pixels(brush))
return NotImplemented;
- stat = get_graphics_bounds(graphics, &graphics_bounds);
+ stat = gdi_transform_acquire(graphics);
+
+ if (stat == Ok)
+ stat = get_graphics_device_bounds(graphics, &graphics_bounds);
if (stat == Ok)
stat = GdipCloneRegion(region, &temp_region);
if (stat == Ok)
{
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, &world_to_device);
if (stat == Ok)
if (stat == Ok && GetRgnBox(hregion, &bound_rect) == NULLREGION)
{
DeleteObject(hregion);
+ gdi_transform_release(graphics);
return Ok;
}
DeleteObject(hregion);
}
+ gdi_transform_release(graphics);
+
return stat;
}
if(graphics->busy)
return ObjectBusy;
+ if(graphics->compmode == mode)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetCompositingMode, mode);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->compmode = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->compqual == quality)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetCompositingQuality, quality);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->compqual = quality;
return Ok;
if (mode == InterpolationModeHighQuality)
mode = InterpolationModeHighQualityBicubic;
+ if (mode == graphics->interpolation)
+ return Ok;
+
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetInterpolationMode, mode);
+ if (stat != Ok)
+ return stat;
+ }
+
graphics->interpolation = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->pixeloffset == mode)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetPixelOffsetMode, mode);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->pixeloffset = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->smoothing == mode)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile) {
+ GpStatus stat;
+ BOOL antialias = (mode != SmoothingModeDefault &&
+ mode != SmoothingModeNone && mode != SmoothingModeHighSpeed);
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetAntiAliasMode, (mode << 1) + antialias);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->smoothing = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->texthint == hint)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile) {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetTextRenderingHint, hint);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->texthint = hint;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ status = METAFILE_SetClipRegion((GpMetafile*)graphics->image, region, mode);
+ if (status != Ok)
+ return status;
+ }
+
status = GdipCloneRegion(region, &clip);
if (status == Ok)
{
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);
+ SetWindowOrgEx(graphics->hdc, 0, 0, NULL);
+ SetViewportOrgEx(graphics->hdc, 0, 0, NULL);
+ }
+ graphics->gdi_transform_acquire_count++;
+ return Ok;
+}
+
+GpStatus gdi_transform_release(GpGraphics *graphics)
+{
+ if (graphics->gdi_transform_acquire_count <= 0)
+ {
+ ERR("called without matching gdi_transform_acquire");
+ return GenericError;
+ }
+ if (graphics->gdi_transform_acquire_count == 1 && graphics->hdc)
+ {
+ RestoreDC(graphics->hdc, graphics->gdi_transform_save);
+ }
+ graphics->gdi_transform_acquire_count--;
+ return Ok;
+}
+
GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix)
{
scale_y *= graphics->scale;
}
- /* transform from src_space to CoordinateSpacePage */
- switch (src_space)
+ if (dst_space < src_space)
{
- case CoordinateSpaceWorld:
- GdipMultiplyMatrix(matrix, &graphics->worldtrans, MatrixOrderAppend);
- break;
- case CoordinateSpacePage:
- break;
- case CoordinateSpaceDevice:
- GdipScaleMatrix(matrix, 1.0/scale_x, 1.0/scale_y, MatrixOrderAppend);
- break;
- }
-
- /* transform from CoordinateSpacePage to dst_space */
- switch (dst_space)
- {
- case CoordinateSpaceWorld:
+ /* transform towards world space */
+ switch ((int)src_space)
+ {
+ case WineCoordinateSpaceGdiDevice:
+ {
+ GpMatrix gdixform;
+ get_gdi_transform(graphics, &gdixform);
+ stat = GdipInvertMatrix(&gdixform);
+ if (stat != Ok)
+ break;
+ GdipMultiplyMatrix(matrix, &gdixform, MatrixOrderAppend);
+ if (dst_space == CoordinateSpaceDevice)
+ break;
+ /* else fall-through */
+ }
+ case CoordinateSpaceDevice:
+ GdipScaleMatrix(matrix, 1.0/scale_x, 1.0/scale_y, MatrixOrderAppend);
+ if (dst_space == CoordinateSpacePage)
+ break;
+ /* else fall-through */
+ case CoordinateSpacePage:
{
GpMatrix inverted_transform = graphics->worldtrans;
stat = GdipInvertMatrix(&inverted_transform);
GdipMultiplyMatrix(matrix, &inverted_transform, MatrixOrderAppend);
break;
}
- case CoordinateSpacePage:
- break;
- case CoordinateSpaceDevice:
- GdipScaleMatrix(matrix, scale_x, scale_y, MatrixOrderAppend);
- break;
+ }
+ }
+ else
+ {
+ /* transform towards device space */
+ switch ((int)src_space)
+ {
+ case CoordinateSpaceWorld:
+ GdipMultiplyMatrix(matrix, &graphics->worldtrans, MatrixOrderAppend);
+ if (dst_space == CoordinateSpacePage)
+ break;
+ /* else fall-through */
+ case CoordinateSpacePage:
+ GdipScaleMatrix(matrix, scale_x, scale_y, MatrixOrderAppend);
+ if (dst_space == CoordinateSpaceDevice)
+ break;
+ /* else fall-through */
+ case CoordinateSpaceDevice:
+ {
+ GpMatrix gdixform;
+ get_gdi_transform(graphics, &gdixform);
+ GdipMultiplyMatrix(matrix, &gdixform, MatrixOrderAppend);
+ break;
+ }
+ }
}
}
return stat;
}
-GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
- GpCoordinateSpace src_space, GpPointF *points, INT count)
+GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space,
+ GpCoordinateSpace src_space, GpPointF *points, INT count)
{
GpMatrix matrix;
GpStatus stat;
- if(!graphics || !points || count <= 0)
+ stat = get_graphics_transform(graphics, dst_space, src_space, &matrix);
+ if (stat != Ok) return stat;
+
+ return GdipTransformMatrixPoints(&matrix, points, count);
+}
+
+GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
+ GpCoordinateSpace src_space, GpPointF *points, INT count)
+{
+ if(!graphics || !points || count <= 0 ||
+ dst_space < 0 || dst_space > CoordinateSpaceDevice ||
+ src_space < 0 || src_space > CoordinateSpaceDevice)
return InvalidParameter;
if(graphics->busy)
if (src_space == dst_space) return Ok;
- stat = get_graphics_transform(graphics, dst_space, src_space, &matrix);
- if (stat != Ok) return stat;
-
- return GdipTransformMatrixPoints(&matrix, points, count);
+ return gdip_transform_points(graphics, dst_space, src_space, points, count);
}
GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
return NotImplemented;
}
+
+GpStatus WINGDIPAPI GdipGraphicsSetAbort(GpGraphics *graphics, GdiplusAbort *pabort)
+{
+ TRACE("(%p, %p)\n", graphics, pabort);
+
+ if (!graphics)
+ return InvalidParameter;
+
+ if (pabort)
+ FIXME("Abort callback is not supported.\n");
+
+ return Ok;
+}
return TRUE;
}
+/*******************************************************************************
+ * GdipAddPathArc [GDIPLUS.1]
+ *
+ * Add an elliptical arc to the given path.
+ *
+ * PARAMS
+ * path [I/O] Path that the arc is appended to
+ * x1 [I] X coordinate of the boundary box
+ * y1 [I] Y coordinate of the boundary box
+ * x2 [I] Width of the boundary box
+ * y2 [I] Height of the boundary box
+ * startAngle [I] Starting angle of the arc, clockwise
+ * sweepAngle [I] Angle of the arc, clockwise
+ *
+ * RETURNS
+ * InvalidParameter If the given path is invalid
+ * OutOfMemory If memory allocation fails, i.e. the path cannot be lengthened
+ * Ok If everything works out as expected
+ *
+ * NOTES
+ * This functions takes the newfigure value of the given path into account,
+ * i.e. the arc is connected to the end of the given path if it was set to
+ * FALSE, otherwise the arc's first point gets the PathPointTypeStart value.
+ * In both cases, the value of newfigure of the given path is FALSE
+ * afterwards.
+ */
GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
REAL y2, REAL startAngle, REAL sweepAngle)
{
return Ok;
}
+/*******************************************************************************
+ * GdipAddPathArcI [GDUPLUS.2]
+ *
+ * See GdipAddPathArc
+ */
GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
INT y2, REAL startAngle, REAL sweepAngle)
{
return stat;
}
+/*************************************************************************
+ * GdipAddPathLine [GDIPLUS.21]
+ *
+ * Add two points to the given path.
+ *
+ * PARAMS
+ * path [I/O] Path that the line is appended to
+ * x1 [I] X coordinate of the first point of the line
+ * y1 [I] Y coordinate of the first point of the line
+ * x2 [I] X coordinate of the second point of the line
+ * y2 [I] Y coordinate of the second point of the line
+ *
+ * RETURNS
+ * InvalidParameter If the first parameter is not a valid path
+ * OutOfMemory If the path cannot be lengthened, i.e. memory allocation fails
+ * Ok If everything works out as expected
+ *
+ * NOTES
+ * This functions takes the newfigure value of the given path into account,
+ * i.e. the two new points are connected to the end of the given path if it
+ * was set to FALSE, otherwise the first point is given the PathPointTypeStart
+ * value. In both cases, the value of newfigure of the given path is FALSE
+ * afterwards.
+ */
GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
{
INT old_count;
return Ok;
}
+/*************************************************************************
+ * GdipAddPathLineI [GDIPLUS.21]
+ *
+ * See GdipAddPathLine
+ */
GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
{
TRACE("(%p, %d, %d, %d, %d)\n", path, x1, y1, x2, y2);
return InvalidParameter;
}
+/*************************************************************************
+ * GdipClonePath [GDIPLUS.53]
+ *
+ * Duplicate the given path in memory.
+ *
+ * PARAMS
+ * path [I] The path to be duplicated
+ * clone [O] Pointer to the new path
+ *
+ * RETURNS
+ * InvalidParameter If the input path is invalid
+ * OutOfMemory If allocation of needed memory fails
+ * Ok If everything works out as expected
+ */
GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
{
TRACE("(%p, %p)\n", path, clone);
}
break;
}
+ case LineCapTriangle:
+ {
+ REAL segment_dy = nextpoint->Y-endpoint->Y;
+ REAL segment_dx = nextpoint->X-endpoint->X;
+ REAL segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
+ REAL distance = pen->width/2.0;
+ REAL dx, dy;
+
+ dx = distance * segment_dx / segment_length;
+ dy = distance * segment_dy / segment_length;
+
+ if (add_first_points) {
+ add_bevel_point(endpoint, nextpoint, pen, 1, last_point);
+
+ *last_point = add_path_list_node(*last_point, endpoint->X - dx,
+ endpoint->Y - dy, PathPointTypeLine);
+ }
+ if (add_last_point)
+ add_bevel_point(endpoint, nextpoint, pen, 0, last_point);
+ break;
+ }
}
}
REAL dash_pos=0.0;
int dash_index=0;
const REAL *dash_pattern;
+ REAL *dash_pattern_scaled;
int dash_count;
GpPointF *tmp_points;
REAL segment_dy;
break;
}
+ dash_pattern_scaled = heap_alloc(dash_count * sizeof(REAL));
+ if (!dash_pattern_scaled) return;
+
+ for (i = 0; i < dash_count; i++)
+ dash_pattern_scaled[i] = pen->width * dash_pattern[i];
+
tmp_points = heap_alloc_zero((end - start + 2) * sizeof(GpPoint));
- if (!tmp_points) return; /* FIXME */
+ if (!tmp_points) {
+ heap_free(dash_pattern_scaled);
+ return; /* FIXME */
+ }
if (!closed)
draw_start_cap = 1;
}
}
- if (dash_pattern[dash_index] - dash_pos > segment_length - segment_pos)
+ if (dash_pattern_scaled[dash_index] - dash_pos > segment_length - segment_pos)
{
/* advance to next segment */
if ((dash_index % 2) == 0)
else
{
/* advance to next dash in pattern */
- segment_pos += dash_pattern[dash_index] - dash_pos;
+ segment_pos += dash_pattern_scaled[dash_index] - dash_pos;
dash_pos = 0.0;
if (++dash_index == dash_count)
dash_index = 0;
if (dash_index % 2 == 0 && num_tmp_points != 0)
{
/* last dash overflows last segment */
- tmp_points[num_tmp_points] = path->pathdata.Points[end];
- widen_open_figure(tmp_points, pen, 0, num_tmp_points,
+ widen_open_figure(tmp_points, pen, 0, num_tmp_points-1,
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
}
+ heap_free(dash_pattern_scaled);
heap_free(tmp_points);
}
{
last_point = points;
- if (pen->endcap > LineCapRound)
+ if (pen->endcap > LineCapTriangle)
FIXME("unimplemented end cap %x\n", pen->endcap);
- if (pen->startcap > LineCapRound)
+ if (pen->startcap > LineCapTriangle)
FIXME("unimplemented start cap %x\n", pen->startcap);
if (pen->dashcap != DashCapFlat)
FIXME("stub: %p, %p, %.2f\n", path, matrix, flatness);
return NotImplemented;
}
+
+#define FLAGS_INTPATH 0x4000
+
+struct path_header
+{
+ DWORD version;
+ DWORD count;
+ DWORD flags;
+};
+
+/* Test to see if the path could be stored as an array of shorts */
+static BOOL is_integer_path(const GpPath *path)
+{
+ int i;
+
+ if (!path->pathdata.Count) return FALSE;
+
+ for (i = 0; i < path->pathdata.Count; i++)
+ {
+ short x, y;
+ x = gdip_round(path->pathdata.Points[i].X);
+ y = gdip_round(path->pathdata.Points[i].Y);
+ if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+DWORD write_path_data(GpPath *path, void *data)
+{
+ struct path_header *header = data;
+ BOOL integer_path = is_integer_path(path);
+ DWORD i, size;
+ BYTE *types;
+
+ size = sizeof(struct path_header) + path->pathdata.Count;
+ if (integer_path)
+ size += sizeof(short[2]) * path->pathdata.Count;
+ else
+ size += sizeof(float[2]) * path->pathdata.Count;
+ size = (size + 3) & ~3;
+
+ if (!data) return size;
+
+ header->version = VERSION_MAGIC2;
+ header->count = path->pathdata.Count;
+ header->flags = integer_path ? FLAGS_INTPATH : 0;
+
+ if (integer_path)
+ {
+ short *points = (short*)(header + 1);
+ for (i = 0; i < path->pathdata.Count; i++)
+ {
+ points[2*i] = path->pathdata.Points[i].X;
+ points[2*i + 1] = path->pathdata.Points[i].Y;
+ }
+ types = (BYTE*)(points + 2*i);
+ }
+ else
+ {
+ float *points = (float*)(header + 1);
+ for (i = 0; i < path->pathdata.Count; i++)
+ {
+ points[2*i] = path->pathdata.Points[i].X;
+ points[2*i + 1] = path->pathdata.Points[i].Y;
+ }
+ types = (BYTE*)(points + 2*i);
+ }
+
+ for (i=0; i<path->pathdata.Count; i++)
+ types[i] = path->pathdata.Types[i];
+ memset(types + i, 0, ((path->pathdata.Count + 3) & ~3) - path->pathdata.Count);
+ return size;
+}
result->unit = metafile->unit;
result->metafile_type = metafile->metafile_type;
result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
+ list_init(&result->containers);
if (!result->hemf)
{
}
typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
- GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
+ GDIPCONST EncoderParameters* params);
typedef GpStatus (*decode_image_func)(IStream *stream, GpImage **image);
}
static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
- GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+ GDIPCONST EncoderParameters* params)
{
return encode_image_wic(image, stream, &GUID_ContainerFormatBmp, params);
}
static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
- GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+ GDIPCONST EncoderParameters* params)
{
return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params);
}
-static GpStatus encode_image_png(GpImage *image, IStream* stream,
- GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+GpStatus encode_image_png(GpImage *image, IStream* stream,
+ GDIPCONST EncoderParameters* params)
{
return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params);
}
static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
- GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+ GDIPCONST EncoderParameters* params)
{
return encode_image_wic(image, stream, &GUID_ContainerFormatJpeg, params);
}
static GpStatus encode_image_gif(GpImage *image, IStream* stream,
- GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+ GDIPCONST EncoderParameters* params)
{
return encode_image_wic(image, stream, &GUID_ContainerFormatGif, params);
}
if (encode_image == NULL)
return UnknownImageFormat;
- stat = encode_image(image, stream, clsid, params);
+ stat = encode_image(image, stream, params);
return stat;
}
if(!invertible)
return InvalidParameter;
+ /* optimize inverting simple scaling and translation matrices */
+ if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
+ {
+ matrix->matrix[4] = -matrix->matrix[4] / matrix->matrix[0];
+ matrix->matrix[5] = -matrix->matrix[5] / matrix->matrix[3];
+ matrix->matrix[0] = 1 / matrix->matrix[0];
+ matrix->matrix[3] = 1 / matrix->matrix[3];
+
+ return Ok;
+ }
+
det = matrix_det(matrix);
copy = *matrix;
if(!matrix || !result)
return InvalidParameter;
- *result = (fabs(matrix_det(matrix)) >= 1e-5);
+ if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
+ *result = matrix->matrix[0] != 0 && matrix->matrix[3] != 0;
+ else
+ *result = (fabs(matrix_det(matrix)) >= 1e-5);
return Ok;
}
#include "gdiplus_private.h"
+#include <assert.h>
+#include <ole2.h>
+
+typedef struct EmfPlusARGB
+{
+ BYTE Blue;
+ BYTE Green;
+ BYTE Red;
+ BYTE Alpha;
+} EmfPlusARGB;
+
typedef struct EmfPlusRecordHeader
{
WORD Type;
GpRegion *clip;
} container;
+enum PenDataFlags
+{
+ PenDataTransform = 0x0001,
+ PenDataStartCap = 0x0002,
+ PenDataEndCap = 0x0004,
+ PenDataJoin = 0x0008,
+ PenDataMiterLimit = 0x0010,
+ PenDataLineStyle = 0x0020,
+ PenDataDashedLineCap = 0x0040,
+ PenDataDashedLineOffset = 0x0080,
+ PenDataDashedLine = 0x0100,
+ PenDataNonCenter = 0x0200,
+ PenDataCompoundLine = 0x0400,
+ PenDataCustomStartCap = 0x0800,
+ PenDataCustomEndCap = 0x1000
+};
+
+typedef struct EmfPlusTransformMatrix
+{
+ REAL TransformMatrix[6];
+} EmfPlusTransformMatrix;
+
+enum LineStyle
+{
+ LineStyleSolid,
+ LineStyleDash,
+ LineStyleDot,
+ LineStyleDashDot,
+ LineStyleDashDotDot,
+ LineStyleCustom
+};
+
+typedef struct EmfPlusPenData
+{
+ DWORD PenDataFlags;
+ DWORD PenUnit;
+ REAL PenWidth;
+ BYTE OptionalData[1];
+} EmfPlusPenData;
+
+typedef struct EmfPlusSolidBrushData
+{
+ EmfPlusARGB SolidColor;
+} EmfPlusSolidBrushData;
+
+typedef struct EmfPlusBrush
+{
+ DWORD Version;
+ DWORD Type;
+ union {
+ EmfPlusSolidBrushData solid;
+ } BrushData;
+} EmfPlusBrush;
+
+typedef struct EmfPlusPen
+{
+ DWORD Version;
+ DWORD Type;
+ /* EmfPlusPenData */
+ /* EmfPlusBrush */
+ BYTE data[1];
+} EmfPlusPen;
+
+typedef struct EmfPlusPath
+{
+ DWORD Version;
+ DWORD PathPointCount;
+ DWORD PathPointFlags;
+ /* PathPoints[] */
+ /* PathPointTypes[] */
+ /* AlignmentPadding */
+ BYTE data[1];
+} EmfPlusPath;
+
+typedef struct EmfPlusRegion
+{
+ DWORD Version;
+ DWORD RegionNodeCount;
+ BYTE RegionNode[1];
+} EmfPlusRegion;
+
+typedef enum
+{
+ BitmapDataTypePixel,
+ BitmapDataTypeCompressed,
+} BitmapDataType;
+
+typedef struct EmfPlusBitmap
+{
+ DWORD Width;
+ DWORD Height;
+ DWORD Stride;
+ DWORD PixelFormat;
+ DWORD Type;
+ BYTE BitmapData[1];
+} EmfPlusBitmap;
+
+typedef struct EmfPlusMetafile
+{
+ DWORD Type;
+ DWORD MetafileDataSize;
+ BYTE MetafileData[1];
+} EmfPlusMetafile;
+
+typedef enum ImageDataType
+{
+ ImageDataTypeUnknown,
+ ImageDataTypeBitmap,
+ ImageDataTypeMetafile,
+} ImageDataType;
+
+typedef struct EmfPlusImage
+{
+ DWORD Version;
+ ImageDataType Type;
+ union
+ {
+ EmfPlusBitmap bitmap;
+ EmfPlusMetafile metafile;
+ } ImageData;
+} EmfPlusImage;
+
+typedef struct EmfPlusImageAttributes
+{
+ DWORD Version;
+ DWORD Reserved1;
+ DWORD WrapMode;
+ EmfPlusARGB ClampColor;
+ DWORD ObjectClamp;
+ DWORD Reserved2;
+} EmfPlusImageAttributes;
+
+typedef enum ObjectType
+{
+ ObjectTypeInvalid,
+ ObjectTypeBrush,
+ ObjectTypePen,
+ ObjectTypePath,
+ ObjectTypeRegion,
+ ObjectTypeImage,
+ ObjectTypeFont,
+ ObjectTypeStringFormat,
+ ObjectTypeImageAttributes,
+ ObjectTypeCustomLineCap,
+} ObjectType;
+
+typedef struct EmfPlusObject
+{
+ EmfPlusRecordHeader Header;
+ union
+ {
+ EmfPlusBrush brush;
+ EmfPlusPen pen;
+ EmfPlusPath path;
+ EmfPlusRegion region;
+ EmfPlusImage image;
+ EmfPlusImageAttributes image_attributes;
+ } ObjectData;
+} EmfPlusObject;
+
+typedef struct EmfPlusRectF
+{
+ float X;
+ float Y;
+ float Width;
+ float Height;
+} EmfPlusRectF;
+
+typedef struct EmfPlusPointF
+{
+ float X;
+ float Y;
+} EmfPlusPointF;
+
+typedef struct EmfPlusDrawImagePoints
+{
+ EmfPlusRecordHeader Header;
+ DWORD ImageAttributesID;
+ DWORD SrcUnit;
+ EmfPlusRectF SrcRect;
+ DWORD count;
+ union
+ {
+ /*EmfPlusPointR pointR;
+ EmfPlusPoint point;*/
+ EmfPlusPointF pointF;
+ } PointData[3];
+} EmfPlusDrawImagePoints;
+
+typedef struct EmfPlusDrawPath
+{
+ EmfPlusRecordHeader Header;
+ DWORD PenId;
+} EmfPlusDrawPath;
+
+typedef struct EmfPlusFillPath
+{
+ EmfPlusRecordHeader Header;
+ union
+ {
+ DWORD BrushId;
+ EmfPlusARGB Color;
+ } data;
+} EmfPlusFillPath;
+
+static DWORD METAFILE_AddObjectId(GpMetafile *metafile)
+{
+ return (metafile->next_object_id++) % 64;
+}
+
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
{
DWORD size_needed;
return Ok;
}
+static void METAFILE_RemoveLastRecord(GpMetafile *metafile, EmfPlusRecordHeader *record)
+{
+ assert(metafile->comment_data + metafile->comment_data_length == (BYTE*)record + record->Size);
+ metafile->comment_data_length -= record->Size;
+}
+
static void METAFILE_WriteRecords(GpMetafile *metafile)
{
if (metafile->comment_data_length > 4)
else
header->Header.Flags = 0;
- header->Version = 0xDBC01002;
+ header->Version = VERSION_MAGIC2;
if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
header->EmfPlusFlags = 1;
return Ok;
}
+static GpStatus METAFILE_AddRegionObject(GpMetafile *metafile, GpRegion *region, DWORD *id)
+{
+ EmfPlusObject *object_record;
+ DWORD size;
+ GpStatus stat;
+
+ *id = -1;
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ size = write_region_data(region, NULL);
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData.region) + size, (void**)&object_record);
+ if (stat != Ok) return stat;
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | ObjectTypeRegion << 8;
+ write_region_data(region, &object_record->ObjectData.region);
+ return Ok;
+}
+
+GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode)
+{
+ EmfPlusRecordHeader *record;
+ DWORD region_id;
+ GpStatus stat;
+
+ if (metafile->metafile_type == MetafileTypeEmf)
+ {
+ FIXME("stub!\n");
+ return NotImplemented;
+ }
+
+ stat = METAFILE_AddRegionObject(metafile, region, ®ion_id);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
+ if (stat != Ok) return stat;
+
+ record->Type = EmfPlusRecordTypeSetClipRegion;
+ record->Flags = region_id | mode << 8;
+
+ METAFILE_WriteRecords(metafile);
+ return Ok;
+}
+
GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
/* regular EMF record */
if (metafile->playback_dc)
{
- ENHMETARECORD *record;
-
switch (recordType)
{
case EMR_SETMAPMODE:
return Ok;
}
default:
- break;
- }
+ {
+ ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
- record = heap_alloc_zero(dataSize + 8);
+ if (record)
+ {
+ record->iType = recordType;
+ record->nSize = dataSize + 8;
+ memcpy(record->dParm, data, dataSize);
- 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");
- PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
- record, metafile->handle_count);
+ heap_free(record);
+ }
+ else
+ return OutOfMemory;
- heap_free(record);
+ break;
+ }
}
- else
- return OutOfMemory;
}
}
else
else
{
memset(header, 0, sizeof(*header));
- header->Version = 0xdbc01002;
+ header->Version = VERSION_MAGIC2;
}
header->Type = metafile->metafile_type;
GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
{
- HMETAFILE hmf = GetMetaFileW(file);
+ HMETAFILE hmf;
+ HENHMETAFILE emf;
TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
- if(!hmf) return InvalidParameter;
+ hmf = GetMetaFileW(file);
+ if(hmf)
+ return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
+
+ emf = GetEnhMetaFileW(file);
+ if(emf)
+ return GdipCreateMetafileFromEmf(emf, TRUE, metafile);
- return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
+ return GenericError;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
return NotImplemented;
}
+
+static GpStatus METAFILE_CreateCompressedImageStream(GpImage *image, IStream **stream, DWORD *size)
+{
+ LARGE_INTEGER zero;
+ STATSTG statstg;
+ GpStatus stat;
+ HRESULT hr;
+
+ *size = 0;
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ stat = encode_image_png(image, *stream, NULL);
+ if (stat != Ok)
+ {
+ IStream_Release(*stream);
+ return stat;
+ }
+
+ hr = IStream_Stat(*stream, &statstg, 1);
+ if (FAILED(hr))
+ {
+ IStream_Release(*stream);
+ return hresult_to_status(hr);
+ }
+ *size = statstg.cbSize.u.LowPart;
+
+ zero.QuadPart = 0;
+ hr = IStream_Seek(*stream, zero, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr))
+ {
+ IStream_Release(*stream);
+ return hresult_to_status(hr);
+ }
+
+ return Ok;
+}
+
+static GpStatus METAFILE_FillEmfPlusBitmap(EmfPlusBitmap *record, IStream *stream, DWORD size)
+{
+ HRESULT hr;
+
+ record->Width = 0;
+ record->Height = 0;
+ record->Stride = 0;
+ record->PixelFormat = 0;
+ record->Type = BitmapDataTypeCompressed;
+
+ hr = IStream_Read(stream, record->BitmapData, size, NULL);
+ if (FAILED(hr)) return hresult_to_status(hr);
+ return Ok;
+}
+
+static GpStatus METAFILE_AddImageObject(GpMetafile *metafile, GpImage *image, DWORD *id)
+{
+ EmfPlusObject *object_record;
+ GpStatus stat;
+ DWORD size;
+
+ *id = -1;
+
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ if (image->type == ImageTypeBitmap)
+ {
+ IStream *stream;
+ DWORD aligned_size;
+
+ stat = METAFILE_CreateCompressedImageStream(image, &stream, &size);
+ if (stat != Ok) return stat;
+ aligned_size = (size + 3) & ~3;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.bitmap.BitmapData[aligned_size]),
+ (void**)&object_record);
+ if (stat != Ok)
+ {
+ IStream_Release(stream);
+ return stat;
+ }
+ memset(object_record->ObjectData.image.ImageData.bitmap.BitmapData + size, 0, aligned_size - size);
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | ObjectTypeImage << 8;
+ object_record->ObjectData.image.Version = VERSION_MAGIC2;
+ object_record->ObjectData.image.Type = ImageDataTypeBitmap;
+
+ stat = METAFILE_FillEmfPlusBitmap(&object_record->ObjectData.image.ImageData.bitmap, stream, size);
+ IStream_Release(stream);
+ if (stat != Ok) METAFILE_RemoveLastRecord(metafile, &object_record->Header);
+ return stat;
+ }
+ else if (image->type == ImageTypeMetafile)
+ {
+ HENHMETAFILE hemf = ((GpMetafile*)image)->hemf;
+ EmfPlusMetafile *metafile_record;
+
+ if (!hemf) return InvalidParameter;
+
+ size = GetEnhMetaFileBits(hemf, 0, NULL);
+ if (!size) return GenericError;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.metafile.MetafileData[size]),
+ (void**)&object_record);
+ if (stat != Ok) return stat;
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | ObjectTypeImage << 8;
+ object_record->ObjectData.image.Version = VERSION_MAGIC2;
+ object_record->ObjectData.image.Type = ImageDataTypeMetafile;
+ metafile_record = &object_record->ObjectData.image.ImageData.metafile;
+ metafile_record->Type = ((GpMetafile*)image)->metafile_type;
+ metafile_record->MetafileDataSize = size;
+ if (GetEnhMetaFileBits(hemf, size, metafile_record->MetafileData) != size)
+ {
+ METAFILE_RemoveLastRecord(metafile, &object_record->Header);
+ return GenericError;
+ }
+ return Ok;
+ }
+ else
+ {
+ FIXME("not supported image type (%d)\n", image->type);
+ return NotImplemented;
+ }
+}
+
+static GpStatus METAFILE_AddImageAttributesObject(GpMetafile *metafile, const GpImageAttributes *attrs, DWORD *id)
+{
+ EmfPlusObject *object_record;
+ EmfPlusImageAttributes *attrs_record;
+ GpStatus stat;
+
+ *id = -1;
+
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ if (!attrs)
+ return Ok;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData.image_attributes) + sizeof(EmfPlusImageAttributes),
+ (void**)&object_record);
+ if (stat != Ok) return stat;
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | (ObjectTypeImageAttributes << 8);
+ attrs_record = &object_record->ObjectData.image_attributes;
+ 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->ObjectClamp = attrs->clamp;
+ attrs_record->Reserved2 = 0;
+ return Ok;
+}
+
+GpStatus METAFILE_DrawImagePointsRect(GpMetafile *metafile, GpImage *image,
+ GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
+ REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
+ DrawImageAbort callback, VOID *callbackData)
+{
+ EmfPlusDrawImagePoints *draw_image_record;
+ DWORD image_id, attributes_id;
+ GpStatus stat;
+
+ if (count != 3) return InvalidParameter;
+
+ if (metafile->metafile_type == MetafileTypeEmf)
+ {
+ FIXME("MetafileTypeEmf metafiles not supported\n");
+ return NotImplemented;
+ }
+ else
+ FIXME("semi-stub\n");
+
+ if (!imageAttributes)
+ {
+ stat = METAFILE_AddImageObject(metafile, image, &image_id);
+ }
+ else if (image->type == ImageTypeBitmap)
+ {
+ INT width = ((GpBitmap*)image)->width;
+ INT height = ((GpBitmap*)image)->height;
+ GpGraphics *graphics;
+ GpBitmap *bitmap;
+
+ stat = GdipCreateBitmapFromScan0(width, height,
+ 0, PixelFormat32bppARGB, NULL, &bitmap);
+ if (stat != Ok) return stat;
+
+ stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
+ if (stat != Ok)
+ {
+ GdipDisposeImage((GpImage*)bitmap);
+ return stat;
+ }
+
+ stat = GdipDrawImageRectRectI(graphics, image, 0, 0, width, height,
+ 0, 0, width, height, UnitPixel, imageAttributes, NULL, NULL);
+ GdipDeleteGraphics(graphics);
+ if (stat != Ok)
+ {
+ GdipDisposeImage((GpImage*)bitmap);
+ return stat;
+ }
+
+ stat = METAFILE_AddImageObject(metafile, (GpImage*)bitmap, &image_id);
+ GdipDisposeImage((GpImage*)bitmap);
+ }
+ else
+ {
+ FIXME("imageAttributes not supported (image type %d)\n", image->type);
+ return NotImplemented;
+ }
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AddImageAttributesObject(metafile, imageAttributes, &attributes_id);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawImagePoints), (void**)&draw_image_record);
+ if (stat != Ok) return stat;
+ draw_image_record->Header.Type = EmfPlusRecordTypeDrawImagePoints;
+ draw_image_record->Header.Flags = image_id;
+ draw_image_record->ImageAttributesID = attributes_id;
+ draw_image_record->SrcUnit = UnitPixel;
+ draw_image_record->SrcRect.X = units_to_pixels(srcx, srcUnit, metafile->image.xres);
+ draw_image_record->SrcRect.Y = units_to_pixels(srcy, srcUnit, metafile->image.yres);
+ 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;
+ METAFILE_WriteRecords(metafile);
+ return Ok;
+}
+
+GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val)
+{
+ EmfPlusRecordHeader *record;
+ GpStatus stat;
+
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
+ if (stat != Ok) return stat;
+
+ record->Type = prop;
+ record->Flags = val;
+
+ METAFILE_WriteRecords(metafile);
+ return Ok;
+}
+
+static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD *id)
+{
+ EmfPlusObject *object_record;
+ GpStatus stat;
+ DWORD size;
+
+ *id = -1;
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ size = write_path_data(path, NULL);
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData.path) + size,
+ (void**)&object_record);
+ if (stat != Ok) return stat;
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | ObjectTypePath << 8;
+ write_path_data(path, &object_record->ObjectData.path);
+ 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;
+ EmfPlusObject *object_record;
+ EmfPlusPenData *pen_data;
+ GpStatus stat;
+ BOOL result;
+
+ *id = -1;
+ if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+ return Ok;
+
+ data_flags = 0;
+ pen_data_size = FIELD_OFFSET(EmfPlusPenData, OptionalData);
+
+ GdipIsMatrixIdentity(&pen->transform, &result);
+ if (!result)
+ {
+ data_flags |= PenDataTransform;
+ pen_data_size += sizeof(EmfPlusTransformMatrix);
+ }
+ if (pen->startcap != LineCapFlat)
+ {
+ data_flags |= PenDataStartCap;
+ pen_data_size += sizeof(DWORD);
+ }
+ if (pen->endcap != LineCapFlat)
+ {
+ data_flags |= PenDataEndCap;
+ pen_data_size += sizeof(DWORD);
+ }
+ if (pen->join != LineJoinMiter)
+ {
+ data_flags |= PenDataJoin;
+ pen_data_size += sizeof(DWORD);
+ }
+ if (pen->miterlimit != 10.0)
+ {
+ data_flags |= PenDataMiterLimit;
+ pen_data_size += sizeof(REAL);
+ }
+ if (pen->style != GP_DEFAULT_PENSTYLE)
+ {
+ data_flags |= PenDataLineStyle;
+ pen_data_size += sizeof(DWORD);
+ }
+ if (pen->dashcap != DashCapFlat)
+ {
+ data_flags |= PenDataDashedLineCap;
+ pen_data_size += sizeof(DWORD);
+ }
+ data_flags |= PenDataDashedLineOffset;
+ pen_data_size += sizeof(REAL);
+ if (pen->numdashes)
+ {
+ data_flags |= PenDataDashedLine;
+ pen_data_size += sizeof(DWORD) + pen->numdashes*sizeof(REAL);
+ }
+ if (pen->align != PenAlignmentCenter)
+ {
+ data_flags |= PenDataNonCenter;
+ pen_data_size += sizeof(DWORD);
+ }
+ /* TODO: Add support for PenDataCompoundLine */
+ if (pen->customstart)
+ {
+ FIXME("ignoring custom start cup\n");
+ }
+ if (pen->customend)
+ {
+ FIXME("ignoring custom end cup\n");
+ }
+
+ stat = METAFILE_PrepareBrushData(pen->brush, &brush_size);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ FIELD_OFFSET(EmfPlusObject, ObjectData.pen.data) + pen_data_size + brush_size,
+ (void**)&object_record);
+ if (stat != Ok) return stat;
+
+ *id = METAFILE_AddObjectId(metafile);
+ object_record->Header.Type = EmfPlusRecordTypeObject;
+ object_record->Header.Flags = *id | ObjectTypePen << 8;
+ object_record->ObjectData.pen.Version = VERSION_MAGIC2;
+ object_record->ObjectData.pen.Type = 0;
+
+ pen_data = (EmfPlusPenData*)object_record->ObjectData.pen.data;
+ pen_data->PenDataFlags = data_flags;
+ pen_data->PenUnit = pen->unit;
+ pen_data->PenWidth = pen->width;
+
+ i = 0;
+ if (data_flags & PenDataTransform)
+ {
+ EmfPlusTransformMatrix *m = (EmfPlusTransformMatrix*)(pen_data->OptionalData + i);
+ memcpy(m, &pen->transform, sizeof(*m));
+ i += sizeof(EmfPlusTransformMatrix);
+ }
+ if (data_flags & PenDataStartCap)
+ {
+ *(DWORD*)(pen_data->OptionalData + i) = pen->startcap;
+ i += sizeof(DWORD);
+ }
+ if (data_flags & PenDataEndCap)
+ {
+ *(DWORD*)(pen_data->OptionalData + i) = pen->endcap;
+ i += sizeof(DWORD);
+ }
+ if (data_flags & PenDataJoin)
+ {
+ *(DWORD*)(pen_data->OptionalData + i) = pen->join;
+ i += sizeof(DWORD);
+ }
+ if (data_flags & PenDataMiterLimit)
+ {
+ *(REAL*)(pen_data->OptionalData + i) = pen->miterlimit;
+ i += sizeof(REAL);
+ }
+ if (data_flags & PenDataLineStyle)
+ {
+ switch (pen->style & PS_STYLE_MASK)
+ {
+ case PS_SOLID: *(DWORD*)(pen_data->OptionalData + i) = LineStyleSolid; break;
+ case PS_DASH: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDash; break;
+ case PS_DOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDot; break;
+ case PS_DASHDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDot; break;
+ case PS_DASHDOTDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDotDot; break;
+ default: *(DWORD*)(pen_data->OptionalData + i) = LineStyleCustom; break;
+ }
+ i += sizeof(DWORD);
+ }
+ if (data_flags & PenDataDashedLineCap)
+ {
+ *(DWORD*)(pen_data->OptionalData + i) = pen->dashcap;
+ i += sizeof(DWORD);
+ }
+ if (data_flags & PenDataDashedLineOffset)
+ {
+ *(REAL*)(pen_data->OptionalData + i) = pen->offset;
+ i += sizeof(REAL);
+ }
+ if (data_flags & PenDataDashedLine)
+ {
+ int j;
+
+ *(DWORD*)(pen_data->OptionalData + i) = pen->numdashes;
+ i += sizeof(DWORD);
+
+ for (j=0; j<pen->numdashes; j++)
+ {
+ *(REAL*)(pen_data->OptionalData + i) = pen->dashes[j];
+ i += sizeof(REAL);
+ }
+ }
+ if (data_flags & PenDataNonCenter)
+ {
+ *(REAL*)(pen_data->OptionalData + i) = pen->align;
+ i += sizeof(DWORD);
+ }
+
+ METAFILE_FillBrushData(pen->brush,
+ (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size));
+ return Ok;
+}
+
+GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path)
+{
+ EmfPlusDrawPath *draw_path_record;
+ DWORD path_id;
+ DWORD pen_id;
+ GpStatus stat;
+
+ if (metafile->metafile_type == MetafileTypeEmf)
+ {
+ FIXME("stub!\n");
+ return NotImplemented;
+ }
+
+ stat = METAFILE_AddPenObject(metafile, pen, &pen_id);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AddPathObject(metafile, path, &path_id);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawPath), (void**)&draw_path_record);
+ if (stat != Ok) return stat;
+ draw_path_record->Header.Type = EmfPlusRecordTypeDrawPath;
+ draw_path_record->Header.Flags = path_id;
+ draw_path_record->PenId = pen_id;
+
+ METAFILE_WriteRecords(metafile);
+ 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;
+ DWORD brush_id = -1, path_id;
+ BOOL inline_color;
+ GpStatus stat;
+
+ if (metafile->metafile_type == MetafileTypeEmf)
+ {
+ FIXME("stub!\n");
+ return NotImplemented;
+ }
+
+ inline_color = brush->bt == BrushTypeSolidColor;
+ if (!inline_color)
+ {
+ stat = METAFILE_AddBrushObject(metafile, brush, &brush_id);
+ if (stat != Ok) return stat;
+ }
+
+ stat = METAFILE_AddPathObject(metafile, path, &path_id);
+ if (stat != Ok) return stat;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ sizeof(EmfPlusFillPath), (void**)&fill_path_record);
+ if (stat != Ok) return stat;
+ fill_path_record->Header.Type = EmfPlusRecordTypeFillPath;
+ 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;
+ }
+ else
+ {
+ fill_path_record->Header.Flags = path_id;
+ fill_path_record->data.BrushId = brush_id;
+ }
+
+ METAFILE_WriteRecords(metafile);
+ return Ok;
+}
*
*/
-#define FLAGS_NOFLAGS 0x0
#define FLAGS_INTPATH 0x4000
struct memory_buffer
struct region_header
{
- DWORD size;
- DWORD checksum;
DWORD magic;
DWORD num_children;
};
+struct region_data_header
+{
+ DWORD size;
+ DWORD checksum;
+ struct region_header header;
+};
+
struct path_header
{
DWORD size;
DWORD flags;
};
-/* Header size as far as header->size is concerned. This doesn't include
- * header->size or header->checksum
- */
-static const INT sizeheader_size = sizeof(DWORD) * 2;
-
typedef struct packed_point
{
short X;
short Y;
} packed_point;
-/* Test to see if the path could be stored as an array of shorts */
-static BOOL is_integer_path(const GpPath *path)
-{
- int i;
-
- if (!path->pathdata.Count) return FALSE;
-
- for (i = 0; i < path->pathdata.Count; i++)
- {
- short x, y;
- x = gdip_round(path->pathdata.Points[i].X);
- y = gdip_round(path->pathdata.Points[i].Y);
- if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
- return FALSE;
- }
- return TRUE;
-}
-
-/* Everything is measured in DWORDS; round up if there's a remainder */
-static inline INT get_pathtypes_size(const GpPath* path)
-{
- INT needed = path->pathdata.Count / sizeof(DWORD);
-
- if (path->pathdata.Count % sizeof(DWORD) > 0)
- needed++;
-
- return needed * sizeof(DWORD);
-}
-
static inline INT get_element_size(const region_element* element)
{
INT needed = sizeof(DWORD); /* DWORD for the type */
return needed + sizeof(GpRect);
case RegionDataPath:
{
- const GpPath *path = element->elementdata.path;
- DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
- /* 3 for headers, once again size doesn't count itself */
- needed += sizeof(DWORD) * 3;
- if (flags & FLAGS_INTPATH)
- needed += 2 * sizeof(SHORT) * path->pathdata.Count;
- else
- needed += 2 * sizeof(FLOAT) * path->pathdata.Count;
-
- needed += get_pathtypes_size(path);
- needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
+ needed += write_path_data(element->elementdata.path, NULL);
+ needed += sizeof(DWORD); /* Extra DWORD for path size */
return needed;
}
case RegionDataEmptyRect:
(*offset)++;
}
-static inline void write_packed_point(DWORD* location, INT* offset,
- const GpPointF* write)
-{
- packed_point *point = (packed_point *)(location + *offset);
- point->X = gdip_round(write->X);
- point->Y = gdip_round(write->Y);
- (*offset)++;
-}
-
-static inline void write_path_types(DWORD* location, INT* offset,
- const GpPath* path)
-{
- INT rounded_size = get_pathtypes_size(path);
-
- memcpy(location + *offset, path->pathdata.Types, path->pathdata.Count);
-
- /* The unwritten parts of the DWORD (if any) must be cleared */
- if (rounded_size - path->pathdata.Count)
- ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
- path->pathdata.Count, rounded_size - path->pathdata.Count);
- *offset += rounded_size / sizeof(DWORD);
-}
-
static void write_element(const region_element* element, DWORD *buffer,
INT* filled)
{
break;
case RegionDataPath:
{
- INT i;
- const GpPath* path = element->elementdata.path;
- struct path_header *pathheader;
-
- pathheader = (struct path_header *)(buffer + *filled);
-
- pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
- /* 3 for headers, once again size doesn't count itself */
- pathheader->size = sizeof(DWORD) * 3;
- if (pathheader->flags & FLAGS_INTPATH)
- pathheader->size += 2 * sizeof(SHORT) * path->pathdata.Count;
- else
- pathheader->size += 2 * sizeof(FLOAT) * path->pathdata.Count;
- pathheader->size += get_pathtypes_size(path);
- pathheader->magic = VERSION_MAGIC;
- pathheader->count = path->pathdata.Count;
-
- *filled += 4;
-
- switch (pathheader->flags & FLAGS_INTPATH)
- {
- case FLAGS_NOFLAGS:
- for (i = 0; i < path->pathdata.Count; i++)
- {
- write_float(buffer, filled, path->pathdata.Points[i].X);
- write_float(buffer, filled, path->pathdata.Points[i].Y);
- }
- break;
- case FLAGS_INTPATH:
- for (i = 0; i < path->pathdata.Count; i++)
- {
- write_packed_point(buffer, filled,
- &path->pathdata.Points[i]);
- }
- break;
- }
- write_path_types(buffer, filled, path);
+ DWORD size = write_path_data(element->elementdata.path, buffer + *filled + 1);
+ write_dword(buffer, filled, size);
+ *filled += size / sizeof(DWORD);
break;
}
case RegionDataEmptyRect:
}
}
+DWORD write_region_data(const GpRegion *region, void *data)
+{
+ struct region_header *header = data;
+ INT filled = 0;
+ DWORD size;
+
+ size = sizeof(struct region_header) + get_element_size(®ion->node);
+ if (!data) return size;
+
+ header->magic = VERSION_MAGIC2;
+ header->num_children = region->num_children;
+ filled += 2;
+ /* With few exceptions, everything written is DWORD aligned,
+ * so use that as our base */
+ write_element(®ion->node, (DWORD*)data, &filled);
+ return size;
+}
+
/*****************************************************************************
* GdipGetRegionData [GDIPLUS.@]
*
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
UINT *needed)
{
- struct region_header *region_header;
- INT filled = 0;
+ struct region_data_header *region_data_header;
UINT required;
- GpStatus status;
TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
if (!region || !buffer || !size)
return InvalidParameter;
- status = GdipGetRegionDataSize(region, &required);
- if (status != Ok) return status;
+ required = FIELD_OFFSET(struct region_data_header, header) + write_region_data(region, NULL);
if (size < required)
{
if (needed) *needed = size;
return InsufficientBuffer;
}
- region_header = (struct region_header *)buffer;
- region_header->size = sizeheader_size + get_element_size(®ion->node);
- region_header->checksum = 0;
- region_header->magic = VERSION_MAGIC;
- region_header->num_children = region->num_children;
- filled += 4;
- /* With few exceptions, everything written is DWORD aligned,
- * so use that as our base */
- write_element(®ion->node, (DWORD*)buffer, &filled);
+ region_data_header = (struct region_data_header *)buffer;
+ region_data_header->size = write_region_data(region, ®ion_data_header->header);
+ region_data_header->checksum = 0;
if (needed)
- *needed = filled * sizeof(DWORD);
+ *needed = required;
return Ok;
}
ERR("failed to read path header\n");
return InvalidParameter;
}
- if (path_header->magic != VERSION_MAGIC)
+ if (!VALID_MAGIC(path_header->magic))
{
ERR("invalid path header magic %#x\n", path_header->magic);
return InvalidParameter;
*/
GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
{
- const struct region_header *region_header;
+ const struct region_data_header *region_data_header;
struct memory_buffer mbuf;
GpStatus status;
INT count;
init_memory_buffer(&mbuf, data, size);
- region_header = buffer_read(&mbuf, sizeof(*region_header));
- if (!region_header || (region_header->magic != VERSION_MAGIC &&
- region_header->magic != VERSION_MAGIC2))
+ region_data_header = buffer_read(&mbuf, sizeof(*region_data_header));
+ if (!region_data_header || !VALID_MAGIC(region_data_header->header.magic))
return InvalidParameter;
status = GdipCreateRegion(region);
return InvalidParameter;
/* header.size doesn't count header.size and header.checksum */
- *needed = sizeof(DWORD) * 2 + sizeheader_size + get_element_size(®ion->node);
+ *needed = FIELD_OFFSET(struct region_data_header, header) + write_region_data(region, NULL);
return Ok;
}
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
: WINDING));
+ gdi_transform_acquire(graphics);
+
stat = trace_path(graphics, path);
if (stat == Ok)
{
stat = *hrgn ? Ok : OutOfMemory;
}
+ gdi_transform_release(graphics);
+
RestoreDC(graphics->hdc, save_state);
if (new_hdc)
{
reactos/dll/win32/faultrep # Synced to WineStaging-2.9
reactos/dll/win32/fontsub # Synced to WineStaging-2.9
reactos/dll/win32/fusion # Synced to WineStaging-2.16
-reactos/dll/win32/gdiplus # Synced to WineStaging-2.9
+reactos/dll/win32/gdiplus # Synced to WineStaging-2.16
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