[GDIPLUS] Sync with Wine Staging 1.9.23. CORE-12409

svn path=/trunk/; revision=73270
This commit is contained in:
Amine Khaldi 2016-11-17 22:35:44 +00:00
parent 3e8eeb6c2e
commit 3c5dbe9f1f
10 changed files with 1716 additions and 174 deletions

View file

@ -441,26 +441,43 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect
{
GpStatus stat;
LinearGradientMode mode;
REAL width, height, exofs, eyofs;
REAL exofs, eyofs;
REAL sin_angle, cos_angle, sin_cos_angle;
TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
wrap, line);
sin_angle = sinf(deg2rad(angle));
cos_angle = cosf(deg2rad(angle));
sin_cos_angle = sin_angle * cos_angle;
if (!rect || !rect->Width || !rect->Height)
return InvalidParameter;
angle = fmodf(angle, 360);
if (angle < 0)
angle += 360;
if (isAngleScalable)
{
width = height = 1.0;
float add_angle = 0;
while(angle >= 90) {
angle -= 180;
add_angle += M_PI;
}
if (angle != 90 && angle != -90)
angle = atan((rect->Width / rect->Height) * tan(deg2rad(angle)));
else
angle = deg2rad(angle);
angle += add_angle;
}
else
{
width = rect->Width;
height = rect->Height;
angle = deg2rad(angle);
}
sin_angle = sinf(angle);
cos_angle = cosf(angle);
sin_cos_angle = sin_angle * cos_angle;
if (sin_cos_angle >= 0)
mode = LinearGradientModeForwardDiagonal;
else
@ -472,19 +489,13 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect
{
if (sin_cos_angle >= 0)
{
exofs = width * sin_cos_angle + height * cos_angle * cos_angle;
eyofs = width * sin_angle * sin_angle + height * sin_cos_angle;
exofs = rect->Height * sin_cos_angle + rect->Width * cos_angle * cos_angle;
eyofs = rect->Height * sin_angle * sin_angle + rect->Width * sin_cos_angle;
}
else
{
exofs = width * sin_angle * sin_angle + height * sin_cos_angle;
eyofs = -width * sin_cos_angle + height * sin_angle * sin_angle;
}
if (isAngleScalable)
{
exofs = exofs * rect->Width;
eyofs = eyofs * rect->Height;
exofs = rect->Width * sin_angle * sin_angle + rect->Height * sin_cos_angle;
eyofs = -rect->Width * sin_cos_angle + rect->Height * sin_angle * sin_angle;
}
if (sin_angle >= 0)

View file

@ -615,11 +615,11 @@
615 stub GdipGetEffectParameterSize
616 stub GdipGetEffectParameters
617 stdcall GdipSetEffectParameters(ptr ptr long)
618 stub GdipInitializePalette
618 stdcall 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 stub GdipBitmapGetHistogram
622 stub GdipBitmapGetHistogramSize
621 stdcall GdipBitmapGetHistogram(ptr long long ptr ptr ptr ptr)
622 stdcall GdipBitmapGetHistogramSize(long ptr)
623 stdcall GdipBitmapConvertFormat(ptr long long long ptr float)
624 stdcall GdipImageSetAbort(ptr ptr)
625 stub GdipGraphicsSetAbort

View file

@ -89,6 +89,9 @@ extern REAL units_to_pixels(REAL units, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
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;
extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
@ -97,9 +100,21 @@ extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDE
extern GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SetClipRect(GpMetafile* metafile,
REAL x, REAL y, REAL width, REAL height, 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_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* matrix, MatrixOrder order) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_BeginContainer(GpMetafile* metafile, GDIPCONST GpRectF *dstrect,
GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex) 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 void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
@ -367,10 +382,13 @@ struct GpMetafile{
GpRectF src_rect;
HANDLETABLE *handle_table;
int handle_count;
XFORM gdiworldtransform;
GpMatrix *world_transform;
GpUnit page_unit;
REAL page_scale;
GpRegion *base_clip; /* clip region in device space for all metafile output */
GpRegion *clip; /* clip region within the metafile */
struct list containers;
};
struct GpBitmap{

View file

@ -47,9 +47,6 @@ static GpStatus draw_driver_string(GpGraphics *graphics, GDIPCONST UINT16 *text,
GDIPCONST GpBrush *brush, GDIPCONST PointF *positions,
INT flags, GDIPCONST GpMatrix *matrix);
static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix);
/* Converts from gdiplus path point type to gdi path point type. */
static BYTE convert_path_point_type(BYTE type)
{
@ -1920,9 +1917,15 @@ GpStatus trace_path(GpGraphics *graphics, GpPath *path)
return result;
}
typedef enum GraphicsContainerType {
BEGIN_CONTAINER,
SAVE_GRAPHICS
} GraphicsContainerType;
typedef struct _GraphicsContainerItem {
struct list entry;
GraphicsContainer contid;
GraphicsContainerType type;
SmoothingMode smoothing;
CompositingQuality compqual;
@ -1939,7 +1942,7 @@ typedef struct _GraphicsContainerItem {
} GraphicsContainerItem;
static GpStatus init_container(GraphicsContainerItem** container,
GDIPCONST GpGraphics* graphics){
GDIPCONST GpGraphics* graphics, GraphicsContainerType type){
GpStatus sts;
*container = heap_alloc_zero(sizeof(GraphicsContainerItem));
@ -1947,6 +1950,7 @@ static GpStatus init_container(GraphicsContainerItem** container,
return OutOfMemory;
(*container)->contid = graphics->contid + 1;
(*container)->type = type;
(*container)->smoothing = graphics->smoothing;
(*container)->compqual = graphics->compqual;
@ -3075,6 +3079,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
HDC hdc;
BOOL temp_hdc = FALSE, temp_bitmap = FALSE;
HBITMAP hbitmap, old_hbm=NULL;
HRGN hrgn;
INT save_state;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
bitmap->format == PixelFormat24bppRGB ||
@ -3135,6 +3141,16 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
old_hbm = SelectObject(hdc, hbitmap);
}
save_state = SaveDC(graphics->hdc);
stat = get_clip_hrgn(graphics, &hrgn);
if (stat == Ok && hrgn)
{
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
DeleteObject(hrgn);
}
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,
@ -3146,6 +3162,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY);
}
RestoreDC(graphics->hdc, save_state);
if (temp_hdc)
{
SelectObject(hdc, old_hbm);
@ -3284,6 +3302,12 @@ GpStatus WINGDIPAPI GdipDrawLine(GpGraphics *graphics, GpPen *pen, REAL x1,
TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2);
if (!pen)
return InvalidParameter;
if (pen->unit == UnitPixel && pen->width <= 0.0)
return Ok;
pt[0].X = x1;
pt[0].Y = y1;
pt[1].X = x2;
@ -3347,26 +3371,12 @@ GpStatus WINGDIPAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, GDIPCONST
return retval;
}
GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
GpStatus GDI32_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
INT save_state;
GpStatus retval;
HRGN hrgn=NULL;
TRACE("(%p, %p, %p)\n", graphics, pen, path);
if(!pen || !graphics)
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
if (!graphics->hdc)
{
FIXME("graphics object has no HDC\n");
return Ok;
}
save_state = prepare_dc(graphics, pen);
retval = get_clip_hrgn(graphics, &hrgn);
@ -3387,6 +3397,398 @@ end:
return retval;
}
GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
GpStatus stat;
GpPath* flat_path;
GpMatrix* transform;
GpRectF gp_bound_rect;
GpRect gp_output_area;
RECT output_area;
INT output_height, output_width;
DWORD *output_bits, *brush_bits=NULL;
int i;
static const BYTE static_dash_pattern[] = {1,1,1,0,1,0,1,0};
const BYTE *dash_pattern;
INT dash_pattern_size;
BYTE *dyn_dash_pattern = NULL;
stat = GdipClonePath(path, &flat_path);
if (stat != Ok)
return stat;
stat = GdipCreateMatrix(&transform);
if (stat == Ok)
{
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, transform);
if (stat == Ok)
stat = GdipFlattenPath(flat_path, transform, 1.0);
GdipDeleteMatrix(transform);
}
/* estimate the output size in pixels, can be larger than necessary */
if (stat == Ok)
{
output_area.left = floorf(flat_path->pathdata.Points[0].X);
output_area.right = ceilf(flat_path->pathdata.Points[0].X);
output_area.top = floorf(flat_path->pathdata.Points[0].Y);
output_area.bottom = ceilf(flat_path->pathdata.Points[0].Y);
for (i=1; i<flat_path->pathdata.Count; i++)
{
REAL x, y;
x = flat_path->pathdata.Points[i].X;
y = flat_path->pathdata.Points[i].Y;
if (floorf(x) < output_area.left) output_area.left = floorf(x);
if (floorf(y) < output_area.top) output_area.top = floorf(y);
if (ceilf(x) > output_area.right) output_area.right = ceilf(x);
if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y);
}
stat = get_graphics_bounds(graphics, &gp_bound_rect);
}
if (stat == Ok)
{
output_area.left = max(output_area.left, floorf(gp_bound_rect.X));
output_area.top = max(output_area.top, floorf(gp_bound_rect.Y));
output_area.right = min(output_area.right, ceilf(gp_bound_rect.X + gp_bound_rect.Width));
output_area.bottom = min(output_area.bottom, ceilf(gp_bound_rect.Y + gp_bound_rect.Height));
output_width = output_area.right - output_area.left + 1;
output_height = output_area.bottom - output_area.top + 1;
if (output_width <= 0 || output_height <= 0)
{
GdipDeletePath(flat_path);
return Ok;
}
gp_output_area.X = output_area.left;
gp_output_area.Y = output_area.top;
gp_output_area.Width = output_width;
gp_output_area.Height = output_height;
output_bits = heap_alloc_zero(output_width * output_height * sizeof(DWORD));
if (!output_bits)
stat = OutOfMemory;
}
if (stat == Ok)
{
if (pen->brush->bt != BrushTypeSolidColor)
{
/* allocate and draw brush output */
brush_bits = heap_alloc_zero(output_width * output_height * sizeof(DWORD));
if (brush_bits)
{
stat = brush_fill_pixels(graphics, pen->brush, brush_bits,
&gp_output_area, output_width);
}
else
stat = OutOfMemory;
}
if (stat == Ok)
{
/* convert dash pattern to bool array */
switch (pen->dash)
{
case DashStyleCustom:
{
dash_pattern_size = 0;
for (i=0; i < pen->numdashes; i++)
dash_pattern_size += gdip_round(pen->dashes[i]);
if (dash_pattern_size != 0)
{
dash_pattern = dyn_dash_pattern = heap_alloc(dash_pattern_size);
if (dyn_dash_pattern)
{
int j=0;
for (i=0; i < pen->numdashes; i++)
{
int k;
for (k=0; k < gdip_round(pen->dashes[i]); k++)
dyn_dash_pattern[j++] = (i&1)^1;
}
}
else
stat = OutOfMemory;
break;
}
/* else fall through */
}
case DashStyleSolid:
default:
dash_pattern = static_dash_pattern;
dash_pattern_size = 1;
break;
case DashStyleDash:
dash_pattern = static_dash_pattern;
dash_pattern_size = 4;
break;
case DashStyleDot:
dash_pattern = &static_dash_pattern[4];
dash_pattern_size = 2;
break;
case DashStyleDashDot:
dash_pattern = static_dash_pattern;
dash_pattern_size = 6;
break;
case DashStyleDashDotDot:
dash_pattern = static_dash_pattern;
dash_pattern_size = 8;
break;
}
}
if (stat == Ok)
{
/* trace path */
GpPointF subpath_start = flat_path->pathdata.Points[0];
INT prev_x = INT_MAX, prev_y = INT_MAX;
int dash_pos = dash_pattern_size - 1;
for (i=0; i < flat_path->pathdata.Count; i++)
{
BYTE type, type2;
GpPointF start_point, end_point;
GpPoint start_pointi, end_pointi;
type = flat_path->pathdata.Types[i];
if (i+1 < flat_path->pathdata.Count)
type2 = flat_path->pathdata.Types[i+1];
else
type2 = PathPointTypeStart;
start_point = flat_path->pathdata.Points[i];
if ((type & PathPointTypePathTypeMask) == PathPointTypeStart)
subpath_start = start_point;
if ((type & PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
end_point = subpath_start;
else if ((type2 & PathPointTypePathTypeMask) == PathPointTypeStart)
continue;
else
end_point = flat_path->pathdata.Points[i+1];
start_pointi.X = floorf(start_point.X);
start_pointi.Y = floorf(start_point.Y);
end_pointi.X = floorf(end_point.X);
end_pointi.Y = floorf(end_point.Y);
/* draw line segment */
if (abs(start_pointi.Y - end_pointi.Y) > abs(start_pointi.X - end_pointi.X))
{
INT x, y, start_y, end_y, step;
if (start_pointi.Y < end_pointi.Y)
{
step = 1;
start_y = ceilf(start_point.Y) - output_area.top;
end_y = end_pointi.Y - output_area.top;
}
else
{
step = -1;
start_y = start_point.Y - output_area.top;
end_y = ceilf(end_point.Y) - output_area.top;
}
for (y=start_y; y != (end_y+step); y+=step)
{
x = gdip_round( start_point.X +
(end_point.X - start_point.X) * (y + output_area.top - start_point.Y) / (end_point.Y - start_point.Y) )
- output_area.left;
if (x == prev_x && y == prev_y)
continue;
prev_x = x;
prev_y = y;
dash_pos = (dash_pos + 1 == dash_pattern_size) ? 0 : dash_pos + 1;
if (!dash_pattern[dash_pos])
continue;
if (x < 0 || x >= output_width || y < 0 || y >= output_height)
continue;
if (brush_bits)
output_bits[x + y*output_width] = brush_bits[x + y*output_width];
else
output_bits[x + y*output_width] = ((GpSolidFill*)pen->brush)->color;
}
}
else
{
INT x, y, start_x, end_x, step;
if (start_pointi.X < end_pointi.X)
{
step = 1;
start_x = ceilf(start_point.X) - output_area.left;
end_x = end_pointi.X - output_area.left;
}
else
{
step = -1;
start_x = start_point.X - output_area.left;
end_x = ceilf(end_point.X) - output_area.left;
}
for (x=start_x; x != (end_x+step); x+=step)
{
y = gdip_round( start_point.Y +
(end_point.Y - start_point.Y) * (x + output_area.left - start_point.X) / (end_point.X - start_point.X) )
- output_area.top;
if (x == prev_x && y == prev_y)
continue;
prev_x = x;
prev_y = y;
dash_pos = (dash_pos + 1 == dash_pattern_size) ? 0 : dash_pos + 1;
if (!dash_pattern[dash_pos])
continue;
if (x < 0 || x >= output_width || y < 0 || y >= output_height)
continue;
if (brush_bits)
output_bits[x + y*output_width] = brush_bits[x + y*output_width];
else
output_bits[x + y*output_width] = ((GpSolidFill*)pen->brush)->color;
}
}
}
}
/* draw output image */
if (stat == Ok)
{
stat = alpha_blend_pixels(graphics, output_area.left, output_area.top,
(BYTE*)output_bits, output_width, output_height, output_width * 4,
PixelFormat32bppARGB);
}
heap_free(brush_bits);
heap_free(dyn_dash_pattern);
heap_free(output_bits);
}
GdipDeletePath(flat_path);
return stat;
}
GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
GpStatus stat;
GpPath *wide_path;
GpMatrix *transform=NULL;
/* Check if the final pen thickness in pixels is too thin. */
if (pen->unit == UnitPixel)
{
if (pen->width < 1.415)
return SOFTWARE_GdipDrawThinPath(graphics, pen, path);
}
else
{
GpPointF points[3] = {{0,0}, {1,0}, {0,1}};
points[1].X = pen->width;
points[2].Y = pen->width;
stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, points, 3);
if (stat != Ok)
return stat;
if (((points[1].X-points[0].X)*(points[1].X-points[0].X) +
(points[1].Y-points[0].Y)*(points[1].Y-points[0].Y) < 2.0001) &&
((points[2].X-points[0].X)*(points[2].X-points[0].X) +
(points[2].Y-points[0].Y)*(points[2].Y-points[0].Y) < 2.0001))
return SOFTWARE_GdipDrawThinPath(graphics, pen, path);
}
stat = GdipClonePath(path, &wide_path);
if (stat != Ok)
return stat;
if (pen->unit == UnitPixel)
{
/* We have to transform this to device coordinates to get the widths right. */
stat = GdipCreateMatrix(&transform);
if (stat == Ok)
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, transform);
}
if (stat == Ok)
stat = GdipWidenPath(wide_path, pen, transform, 1.0);
if (pen->unit == UnitPixel)
{
/* Transform the path back to world coordinates */
if (stat == Ok)
stat = GdipInvertMatrix(transform);
if (stat == Ok)
stat = GdipTransformPath(wide_path, transform);
}
/* Actually draw the path */
if (stat == Ok)
stat = GdipFillPath(graphics, pen->brush, wide_path);
GdipDeleteMatrix(transform);
GdipDeletePath(wide_path);
return stat;
}
GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
GpStatus retval;
TRACE("(%p, %p, %p)\n", graphics, pen, path);
if(!pen || !graphics)
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
if (path->pathdata.Count == 0)
return Ok;
if (!graphics->hdc)
retval = SOFTWARE_GdipDrawPath(graphics, pen, path);
else
retval = GDI32_GdipDrawPath(graphics, pen, path);
return retval;
}
GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
{
@ -3934,6 +4336,23 @@ static GpStatus GDI32_GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
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_AND);
DeleteObject(hrgn);
}
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
{
BeginPath(graphics->hdc);
@ -3945,7 +4364,6 @@ static GpStatus GDI32_GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
RestoreDC(graphics->hdc, save_state);
DeleteObject(hrgn);
return Ok;
}
@ -5128,14 +5546,11 @@ GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
return GdipSetMatrixElements(&graphics->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
}
GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
{
return GdipEndContainer(graphics, state);
}
GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
GpMatrixOrder order)
{
GpStatus stat;
TRACE("(%p, %.2f, %d)\n", graphics, angle, order);
if(!graphics)
@ -5144,45 +5559,119 @@ GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
if(graphics->busy)
return ObjectBusy;
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
stat = METAFILE_RotateWorldTransform((GpMetafile*)graphics->image, angle, order);
if (stat != Ok)
return stat;
}
return GdipRotateMatrix(&graphics->worldtrans, angle, order);
}
GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
{
return GdipBeginContainer2(graphics, state);
}
GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
GraphicsContainer *state)
static GpStatus begin_container(GpGraphics *graphics,
GraphicsContainerType type, GraphicsContainer *state)
{
GraphicsContainerItem *container;
GpStatus sts;
TRACE("(%p, %p)\n", graphics, state);
if(!graphics || !state)
return InvalidParameter;
sts = init_container(&container, graphics);
sts = init_container(&container, graphics, type);
if(sts != Ok)
return sts;
list_add_head(&graphics->containers, &container->entry);
*state = graphics->contid = container->contid;
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
if (type == BEGIN_CONTAINER)
METAFILE_BeginContainerNoParams((GpMetafile*)graphics->image, container->contid);
else
METAFILE_SaveGraphics((GpMetafile*)graphics->image, container->contid);
}
return Ok;
}
GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
{
TRACE("(%p, %p)\n", graphics, state);
return begin_container(graphics, SAVE_GRAPHICS, state);
}
GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
GraphicsContainer *state)
{
TRACE("(%p, %p)\n", graphics, state);
return begin_container(graphics, BEGIN_CONTAINER, state);
}
GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state)
{
FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
return NotImplemented;
GraphicsContainerItem *container;
GpMatrix transform;
GpStatus stat;
GpRectF scaled_srcrect;
REAL scale_x, scale_y;
TRACE("(%p, %s, %s, %d, %p)\n", graphics, debugstr_rectf(dstrect), debugstr_rectf(srcrect), unit, state);
if(!graphics || !dstrect || !srcrect || unit < UnitPixel || unit > UnitMillimeter || !state)
return InvalidParameter;
stat = init_container(&container, graphics, BEGIN_CONTAINER);
if(stat != Ok)
return stat;
list_add_head(&graphics->containers, &container->entry);
*state = graphics->contid = container->contid;
scale_x = units_to_pixels(1.0, unit, graphics->xres);
scale_y = units_to_pixels(1.0, unit, graphics->yres);
scaled_srcrect.X = scale_x * srcrect->X;
scaled_srcrect.Y = scale_y * srcrect->Y;
scaled_srcrect.Width = scale_x * srcrect->Width;
scaled_srcrect.Height = scale_y * srcrect->Height;
transform.matrix[0] = dstrect->Width / scaled_srcrect.Width;
transform.matrix[1] = 0.0;
transform.matrix[2] = 0.0;
transform.matrix[3] = dstrect->Height / scaled_srcrect.Height;
transform.matrix[4] = dstrect->X - scaled_srcrect.X;
transform.matrix[5] = dstrect->Y - scaled_srcrect.Y;
GdipMultiplyMatrix(&graphics->worldtrans, &transform, MatrixOrderPrepend);
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
METAFILE_BeginContainer((GpMetafile*)graphics->image, dstrect, srcrect, unit, container->contid);
}
return Ok;
}
GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics *graphics, GDIPCONST GpRect *dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state)
{
FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
return NotImplemented;
GpRectF dstrectf, srcrectf;
TRACE("(%p, %p, %p, %d, %p)\n", graphics, dstrect, srcrect, unit, state);
if (!dstrect || !srcrect)
return InvalidParameter;
dstrectf.X = dstrect->X;
dstrectf.Y = dstrect->Y;
dstrectf.Width = dstrect->Width;
dstrectf.Height = dstrect->Height;
srcrectf.X = srcrect->X;
srcrectf.Y = srcrect->Y;
srcrectf.Width = srcrect->Width;
srcrectf.Height = srcrect->Height;
return GdipBeginContainer(graphics, &dstrectf, &srcrectf, unit, state);
}
GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data)
@ -5191,18 +5680,17 @@ GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST B
return NotImplemented;
}
GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
static GpStatus end_container(GpGraphics *graphics, GraphicsContainerType type,
GraphicsContainer state)
{
GpStatus sts;
GraphicsContainerItem *container, *container2;
TRACE("(%p, %x)\n", graphics, state);
if(!graphics)
return InvalidParameter;
LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
if(container->contid == state)
if(container->contid == state && container->type == type)
break;
}
@ -5225,9 +5713,28 @@ GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer sta
list_remove(&container->entry);
delete_container(container);
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
if (type == BEGIN_CONTAINER)
METAFILE_EndContainer((GpMetafile*)graphics->image, state);
else
METAFILE_RestoreGraphics((GpMetafile*)graphics->image, state);
}
return Ok;
}
GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
{
TRACE("(%p, %x)\n", graphics, state);
return end_container(graphics, BEGIN_CONTAINER, state);
}
GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
{
TRACE("(%p, %x)\n", graphics, state);
return end_container(graphics, SAVE_GRAPHICS, state);
}
GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,
REAL sy, GpMatrixOrder order)
{
@ -5459,6 +5966,8 @@ GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics,
GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
{
GpStatus stat;
TRACE("(%p, %p)\n", graphics, matrix);
if(!graphics || !matrix)
@ -5471,6 +5980,13 @@ GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix
matrix->matrix[0], matrix->matrix[1], matrix->matrix[2],
matrix->matrix[3], matrix->matrix[4], matrix->matrix[5]);
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
stat = METAFILE_SetWorldTransform((GpMetafile*)graphics->image, matrix);
if (stat != Ok)
return stat;
}
graphics->worldtrans = *matrix;
return Ok;
@ -5479,6 +5995,8 @@ GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix
GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
REAL dy, GpMatrixOrder order)
{
GpStatus stat;
TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order);
if(!graphics)
@ -5487,6 +6005,13 @@ GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
if(graphics->busy)
return ObjectBusy;
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
stat = METAFILE_TranslateWorldTransform((GpMetafile*)graphics->image, dx, dy, order);
if (stat != Ok)
return stat;
}
return GdipTranslateMatrix(&graphics->worldtrans, dx, dy, order);
}
@ -5562,6 +6087,13 @@ GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
if(graphics->busy)
return ObjectBusy;
if (graphics->image && graphics->image->type == ImageTypeMetafile)
{
status = METAFILE_SetClipRect((GpMetafile*)graphics->image, x, y, width, height, mode);
if (status != Ok)
return status;
}
rect.X = x;
rect.Y = y;
rect.Width = width;
@ -5628,8 +6160,8 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points,
INT count)
{
INT save_state;
POINT *pti;
GpStatus status;
GpPath* path;
TRACE("(%p, %p, %d)\n", graphics, points, count);
@ -5639,24 +6171,16 @@ GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST Gp
if(graphics->busy)
return ObjectBusy;
if (!graphics->hdc)
{
FIXME("graphics object has no HDC\n");
return Ok;
}
status = GdipCreatePath(FillModeAlternate, &path);
if (status != Ok) return status;
pti = heap_alloc_zero(sizeof(POINT) * count);
status = GdipAddPathPolygon(path, points, count);
if (status == Ok)
status = GdipDrawPath(graphics, pen, path);
save_state = prepare_dc(graphics, pen);
SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
GdipDeletePath(path);
transform_and_round_points(graphics, pti, (GpPointF*)points, count);
Polygon(graphics->hdc, pti, count);
restore_dc(graphics, save_state);
heap_free(pti);
return Ok;
return status;
}
GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint *points,
@ -5724,6 +6248,13 @@ GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST G
if(graphics->busy)
return ObjectBusy;
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
ret = METAFILE_MultiplyWorldTransform((GpMetafile*)graphics->image, matrix, order);
if (ret != Ok)
return ret;
}
m = graphics->worldtrans;
ret = GdipMultiplyMatrix(&m, matrix, order);
@ -5896,7 +6427,7 @@ GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
return Ok;
}
static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix)
{
GpStatus stat = Ok;
@ -6176,6 +6707,8 @@ static GpStatus GDI32_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT1
GpPointF pt;
HFONT hfont;
UINT eto_flags=0;
GpStatus status;
HRGN hrgn;
if (flags & unsupported_flags)
FIXME("Ignoring flags %x\n", flags & unsupported_flags);
@ -6187,6 +6720,14 @@ static GpStatus GDI32_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT1
SetBkMode(graphics->hdc, TRANSPARENT);
SetTextColor(graphics->hdc, get_gdi_brush_color(brush));
status = get_clip_hrgn(graphics, &hrgn);
if (status == Ok && hrgn)
{
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
DeleteObject(hrgn);
}
pt = positions[0];
GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &pt, 1);

View file

@ -1567,17 +1567,49 @@ GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath* path, INT x, INT y,
GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPoint(GpPath* path, REAL x, REAL y,
GpPen *pen, GpGraphics *graphics, BOOL *result)
{
static int calls;
GpStatus stat;
GpPath *wide_path;
GpMatrix *transform = NULL;
TRACE("(%p,%0.2f,%0.2f,%p,%p,%p)\n", path, x, y, pen, graphics, result);
if(!path || !pen)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
stat = GdipClonePath(path, &wide_path);
return NotImplemented;
if (stat != Ok)
return stat;
if (pen->unit == UnitPixel && graphics != NULL)
{
stat = GdipCreateMatrix(&transform);
if (stat == Ok)
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, transform);
}
if (stat == Ok)
stat = GdipWidenPath(wide_path, pen, transform, 1.0);
if (pen->unit == UnitPixel && graphics != NULL)
{
if (stat == Ok)
stat = GdipInvertMatrix(transform);
if (stat == Ok)
stat = GdipTransformPath(wide_path, transform);
}
if (stat == Ok)
stat = GdipIsVisiblePathPoint(wide_path, x, y, graphics, result);
GdipDeleteMatrix(transform);
GdipDeletePath(wide_path);
return stat;
}
GpStatus WINGDIPAPI GdipIsVisiblePathPointI(GpPath* path, INT x, INT y, GpGraphics *graphics, BOOL *result)
@ -1874,7 +1906,7 @@ static void widen_closed_figure(GpPath *path, GpPen *pen, int start, int end,
int i;
path_list_node_t *prev_point;
if (end <= start+1)
if (end <= start)
return;
/* left outline */

View file

@ -26,6 +26,7 @@
HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
#define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
#define WMF_PLACEABLE_KEY 0x9ac6cdd7
static const struct
{
@ -2138,6 +2139,10 @@ GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
srcRect->Height = (REAL) ((GpBitmap*)image)->height;
*srcUnit = UnitPixel;
}
else{
WARN("GpImage with no image data\n");
return InvalidParameter;
}
TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
srcRect->Width, srcRect->Height, *srcUnit);
@ -2161,6 +2166,10 @@ GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
*height = ((GpBitmap*)image)->height;
*width = ((GpBitmap*)image)->width;
}
else{
WARN("GpImage with no image data\n");
return InvalidParameter;
}
TRACE("returning (%f, %f)\n", *height, *width);
return Ok;
@ -2215,6 +2224,11 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
*height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
else if(image->type == ImageTypeBitmap)
*height = ((GpBitmap*)image)->height;
else
{
WARN("GpImage with no image data\n");
return InvalidParameter;
}
TRACE("returning %d\n", *height);
@ -2313,6 +2327,11 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
*width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
else if(image->type == ImageTypeBitmap)
*width = ((GpBitmap*)image)->width;
else
{
WARN("GpImage with no image data\n");
return InvalidParameter;
}
TRACE("returning %d\n", *width);
@ -3981,29 +4000,25 @@ static GpStatus decode_image_tiff(IStream* stream, GpImage **image)
static GpStatus load_wmf(IStream *stream, GpMetafile **metafile)
{
GpStatus status = GenericError;
HRESULT hr;
UINT size;
LARGE_INTEGER pos;
WmfPlaceableFileHeader pfh;
BOOL is_placeable = FALSE;
LARGE_INTEGER seek;
GpStatus status;
METAHEADER mh;
HMETAFILE hmf;
HRESULT hr;
UINT size;
void *buf;
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
hr = IStream_Read(stream, &mh, sizeof(mh), &size);
if (hr != S_OK || size != sizeof(mh))
return GenericError;
if (mh.mtType == 0xcdd7 && mh.mtHeaderSize == 0x9ac6)
if (((WmfPlaceableFileHeader *)&mh)->Key == WMF_PLACEABLE_KEY)
{
is_placeable = TRUE;
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
seek.QuadPart = 0;
hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) return hresult_to_status(hr);
hr = IStream_Read(stream, &pfh, sizeof(pfh), &size);
if (hr != S_OK || size != sizeof(pfh))
@ -4012,82 +4027,112 @@ static GpStatus load_wmf(IStream *stream, GpMetafile **metafile)
hr = IStream_Read(stream, &mh, sizeof(mh), &size);
if (hr != S_OK || size != sizeof(mh))
return GenericError;
is_placeable = TRUE;
}
pos.QuadPart = is_placeable ? sizeof(pfh) : 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
seek.QuadPart = is_placeable ? sizeof(pfh) : 0;
hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) return hresult_to_status(hr);
buf = heap_alloc(mh.mtSize * 2);
if (!buf) return OutOfMemory;
hr = IStream_Read(stream, buf, mh.mtSize * 2, &size);
if (hr == S_OK && size == mh.mtSize * 2)
if (hr != S_OK || size != mh.mtSize * 2)
{
hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
if (hmf)
{
status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
if (status != Ok)
DeleteMetaFile(hmf);
}
heap_free(buf);
return GenericError;
}
hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
heap_free(buf);
if (!hmf)
return GenericError;
status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
if (status != Ok)
DeleteMetaFile(hmf);
return status;
}
static GpStatus decode_image_wmf(IStream *stream, GpImage **image)
{
GpMetafile *metafile;
GpStatus status;
TRACE("%p %p\n", stream, image);
if (!stream || !image)
return InvalidParameter;
status = load_wmf(stream, &metafile);
if (status != Ok)
{
TRACE("Could not load metafile\n");
return status;
}
*image = (GpImage *)metafile;
TRACE("<-- %p\n", *image);
return Ok;
}
static GpStatus load_emf(IStream *stream, GpMetafile **metafile)
{
GpStatus status = GenericError;
HRESULT hr;
UINT size;
LARGE_INTEGER pos;
LARGE_INTEGER seek;
ENHMETAHEADER emh;
HENHMETAFILE hemf;
GpStatus status;
HRESULT hr;
UINT size;
void *buf;
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
hr = IStream_Read(stream, &emh, sizeof(emh), &size);
if (hr != S_OK || size != sizeof(emh) || emh.dSignature != ENHMETA_SIGNATURE)
return GenericError;
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
seek.QuadPart = 0;
hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) return hresult_to_status(hr);
buf = heap_alloc(emh.nBytes);
if (!buf) return OutOfMemory;
hr = IStream_Read(stream, buf, emh.nBytes, &size);
if (hr == S_OK && size == emh.nBytes)
if (hr != S_OK || size != emh.nBytes)
{
hemf = SetEnhMetaFileBits(emh.nBytes, buf);
if (hemf)
{
status = GdipCreateMetafileFromEmf(hemf, FALSE, metafile);
if (status != Ok)
DeleteEnhMetaFile(hemf);
}
heap_free(buf);
return GenericError;
}
hemf = SetEnhMetaFileBits(emh.nBytes, buf);
heap_free(buf);
if (!hemf)
return GenericError;
status = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
if (status != Ok)
DeleteEnhMetaFile(hemf);
return status;
}
static GpStatus decode_image_metafile(IStream *stream, GpImage **image)
static GpStatus decode_image_emf(IStream *stream, GpImage **image)
{
GpMetafile *metafile;
GpStatus status;
TRACE("%p %p\n", stream, image);
if(!stream || !image)
if (!stream || !image)
return InvalidParameter;
if (load_emf(stream, &metafile) != Ok && load_wmf(stream, &metafile) != Ok)
status = load_emf(stream, &metafile);
if (status != Ok)
{
TRACE("Could not load metafile\n");
return GenericError;
return status;
}
*image = (GpImage *)metafile;
@ -4487,7 +4532,7 @@ static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
static GpStatus encode_image_gif(GpImage *image, IStream* stream,
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
{
return encode_image_wic(image, stream, &CLSID_WICGifEncoder, params);
return encode_image_wic(image, stream, &GUID_ContainerFormatGif, params);
}
/*****************************************************************************
@ -4500,7 +4545,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
encode_image_func encode_image;
int i;
TRACE("%p %p %p %p\n", image, stream, clsid, params);
TRACE("%p %p %s %p\n", image, stream, wine_dbgstr_guid(clsid), params);
if(!image || !stream)
return InvalidParameter;
@ -4748,7 +4793,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
/* SigMask */ emf_sig_mask,
},
NULL,
decode_image_metafile,
decode_image_emf,
NULL
},
{
@ -4768,7 +4813,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
/* SigMask */ wmf_sig_mask,
},
NULL,
decode_image_metafile,
decode_image_wmf,
NULL
},
{
@ -5348,8 +5393,15 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
*/
GpStatus WINGDIPAPI GdipImageSetAbort(GpImage *image, GdiplusAbort *pabort)
{
FIXME("(%p, %p): stub\n", image, pabort);
return NotImplemented;
TRACE("(%p, %p)\n", image, pabort);
if (!image)
return InvalidParameter;
if (pabort)
FIXME("Abort callback is not supported.\n");
return Ok;
}
/*****************************************************************************
@ -5361,3 +5413,248 @@ GpStatus WINGDIPAPI GdipBitmapConvertFormat(GpBitmap *bitmap, PixelFormat format
FIXME("(%p, 0x%08x, %d, %d, %p, %f): stub\n", bitmap, format, dithertype, palettetype, palette, alphathreshold);
return NotImplemented;
}
static void set_histogram_point_argb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[ color >> 24 ]++;
ch1[(color >> 16) & 0xff]++;
ch2[(color >> 8) & 0xff]++;
ch3[ color & 0xff]++;
}
static void set_histogram_point_pargb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
BYTE alpha = color >> 24;
ch0[alpha]++;
ch1[(((color >> 16) & 0xff) * alpha) / 0xff]++;
ch2[(((color >> 8) & 0xff) * alpha) / 0xff]++;
ch3[(( color & 0xff) * alpha) / 0xff]++;
}
static void set_histogram_point_rgb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[(color >> 16) & 0xff]++;
ch1[(color >> 8) & 0xff]++;
ch2[ color & 0xff]++;
}
static void set_histogram_point_gray(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[(76 * ((color >> 16) & 0xff) + 150 * ((color >> 8) & 0xff) + 29 * (color & 0xff)) / 0xff]++;
}
static void set_histogram_point_b(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[color & 0xff]++;
}
static void set_histogram_point_g(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[(color >> 8) & 0xff]++;
}
static void set_histogram_point_r(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[(color >> 16) & 0xff]++;
}
static void set_histogram_point_a(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
ch0[(color >> 24) & 0xff]++;
}
/*****************************************************************************
* GdipBitmapGetHistogram [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipBitmapGetHistogram(GpBitmap *bitmap, HistogramFormat format, UINT num_of_entries,
UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
{
static void (* const set_histogram_point[])(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) =
{
set_histogram_point_argb,
set_histogram_point_pargb,
set_histogram_point_rgb,
set_histogram_point_gray,
set_histogram_point_b,
set_histogram_point_g,
set_histogram_point_r,
set_histogram_point_a,
};
UINT width, height, x, y;
TRACE("(%p, %d, %u, %p, %p, %p, %p)\n", bitmap, format, num_of_entries,
ch0, ch1, ch2, ch3);
if (!bitmap || num_of_entries != 256)
return InvalidParameter;
/* Make sure passed channel pointers match requested format */
switch (format)
{
case HistogramFormatARGB:
case HistogramFormatPARGB:
if (!ch0 || !ch1 || !ch2 || !ch3)
return InvalidParameter;
memset(ch0, 0, num_of_entries * sizeof(UINT));
memset(ch1, 0, num_of_entries * sizeof(UINT));
memset(ch2, 0, num_of_entries * sizeof(UINT));
memset(ch3, 0, num_of_entries * sizeof(UINT));
break;
case HistogramFormatRGB:
if (!ch0 || !ch1 || !ch2 || ch3)
return InvalidParameter;
memset(ch0, 0, num_of_entries * sizeof(UINT));
memset(ch1, 0, num_of_entries * sizeof(UINT));
memset(ch2, 0, num_of_entries * sizeof(UINT));
break;
case HistogramFormatGray:
case HistogramFormatB:
case HistogramFormatG:
case HistogramFormatR:
case HistogramFormatA:
if (!ch0 || ch1 || ch2 || ch3)
return InvalidParameter;
memset(ch0, 0, num_of_entries * sizeof(UINT));
break;
default:
WARN("Invalid histogram format requested, %d\n", format);
return InvalidParameter;
}
GdipGetImageWidth(&bitmap->image, &width);
GdipGetImageHeight(&bitmap->image, &height);
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
ARGB color;
GdipBitmapGetPixel(bitmap, x, y, &color);
set_histogram_point[format](color, ch0, ch1, ch2, ch3);
}
return Ok;
}
/*****************************************************************************
* GdipBitmapGetHistogramSize [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipBitmapGetHistogramSize(HistogramFormat format, UINT *num_of_entries)
{
TRACE("(%d, %p)\n", format, num_of_entries);
if (!num_of_entries)
return InvalidParameter;
*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;
}

View file

@ -21,18 +21,52 @@
GpStatus WINGDIPAPI GdipCloneImageAttributes(GDIPCONST GpImageAttributes *imageattr,
GpImageAttributes **cloneImageattr)
{
GpStatus stat;
GpStatus stat = Ok;
struct color_remap_table remap_tables[ColorAdjustTypeCount] = {{0}};
int i;
TRACE("(%p, %p)\n", imageattr, cloneImageattr);
if(!imageattr || !cloneImageattr)
return InvalidParameter;
stat = GdipCreateImageAttributes(cloneImageattr);
for (i=0; i<ColorAdjustTypeCount; i++)
{
if (imageattr->colorremaptables[i].enabled)
{
remap_tables[i].enabled = TRUE;
remap_tables[i].mapsize = imageattr->colorremaptables[i].mapsize;
remap_tables[i].colormap = heap_alloc(sizeof(ColorMap) * remap_tables[i].mapsize);
if (remap_tables[i].colormap)
{
memcpy(remap_tables[i].colormap, imageattr->colorremaptables[i].colormap,
sizeof(ColorMap) * remap_tables[i].mapsize);
}
else
{
stat = OutOfMemory;
break;
}
}
}
if (stat == Ok)
stat = GdipCreateImageAttributes(cloneImageattr);
if (stat == Ok)
{
**cloneImageattr = *imageattr;
memcpy((*cloneImageattr)->colorremaptables, remap_tables, sizeof(remap_tables));
}
if (stat != Ok)
{
for (i=0; i<ColorAdjustTypeCount; i++)
heap_free(remap_tables[i].colormap);
}
return stat;
}

View file

@ -484,23 +484,17 @@ GpStatus WINGDIPAPI GdipIsMatrixEqual(GDIPCONST GpMatrix *matrix, GDIPCONST GpMa
GpStatus WINGDIPAPI GdipIsMatrixIdentity(GDIPCONST GpMatrix *matrix, BOOL *result)
{
GpMatrix *e;
GpStatus ret;
BOOL isIdentity;
static const GpMatrix identity =
{
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0 }
};
TRACE("(%p, %p)\n", matrix, result);
if(!matrix || !result)
return InvalidParameter;
ret = GdipCreateMatrix(&e);
if(ret != Ok) return ret;
ret = GdipIsMatrixEqual(matrix, e, &isIdentity);
if(ret == Ok)
*result = isIdentity;
heap_free(e);
return ret;
return GdipIsMatrixEqual(matrix, &identity, result);
}

View file

@ -48,6 +48,12 @@ typedef struct EmfPlusFillRects
DWORD Count;
} EmfPlusFillRects;
typedef struct EmfPlusSetClipRect
{
EmfPlusRecordHeader Header;
GpRectF ClipRect;
} EmfPlusSetClipRect;
typedef struct EmfPlusSetPageTransform
{
EmfPlusRecordHeader Header;
@ -62,6 +68,12 @@ typedef struct EmfPlusRect
SHORT Height;
} EmfPlusRect;
typedef struct EmfPlusSetWorldTransform
{
EmfPlusRecordHeader Header;
REAL MatrixData[6];
} EmfPlusSetWorldTransform;
typedef struct EmfPlusScaleWorldTransform
{
EmfPlusRecordHeader Header;
@ -69,6 +81,57 @@ typedef struct EmfPlusScaleWorldTransform
REAL Sy;
} EmfPlusScaleWorldTransform;
typedef struct EmfPlusMultiplyWorldTransform
{
EmfPlusRecordHeader Header;
REAL MatrixData[6];
} EmfPlusMultiplyWorldTransform;
typedef struct EmfPlusRotateWorldTransform
{
EmfPlusRecordHeader Header;
REAL Angle;
} EmfPlusRotateWorldTransform;
typedef struct EmfPlusTranslateWorldTransform
{
EmfPlusRecordHeader Header;
REAL dx;
REAL dy;
} EmfPlusTranslateWorldTransform;
typedef struct EmfPlusBeginContainer
{
EmfPlusRecordHeader Header;
GpRectF DestRect;
GpRectF SrcRect;
DWORD StackIndex;
} EmfPlusBeginContainer;
typedef struct EmfPlusContainerRecord
{
EmfPlusRecordHeader Header;
DWORD StackIndex;
} EmfPlusContainerRecord;
enum container_type
{
BEGIN_CONTAINER,
SAVE_GRAPHICS
};
typedef struct container
{
struct list entry;
DWORD id;
enum container_type type;
GraphicsContainer state;
GpMatrix world_transform;
GpUnit page_unit;
REAL page_scale;
GpRegion *clip;
} container;
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
{
DWORD size_needed;
@ -260,6 +323,7 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
(*metafile)->comment_data_size = 0;
(*metafile)->comment_data_length = 0;
(*metafile)->hemf = NULL;
list_init(&(*metafile)->containers);
if (!frameRect)
{
@ -516,6 +580,32 @@ GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
return Ok;
}
GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, REAL height, CombineMode mode)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusSetClipRect *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusSetClipRect),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeSetClipRect;
record->Header.Flags = (mode & 0xf) << 8;
record->ClipRect.X = x;
record->ClipRect.Y = y;
record->ClipRect.Width = width;
record->ClipRect.Height = height;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
@ -539,6 +629,29 @@ GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale
return Ok;
}
GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusSetWorldTransform *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusSetWorldTransform),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeSetWorldTransform;
record->Header.Flags = 0;
memcpy(record->MatrixData, transform->matrix, sizeof(record->MatrixData));
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
@ -553,7 +666,7 @@ GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, Ma
return stat;
record->Header.Type = EmfPlusRecordTypeScaleWorldTransform;
record->Header.Flags = (order == MatrixOrderAppend ? 4 : 0);
record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
record->Sx = sx;
record->Sy = sy;
@ -563,6 +676,76 @@ GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, Ma
return Ok;
}
GpStatus METAFILE_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* matrix, MatrixOrder order)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusMultiplyWorldTransform *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusMultiplyWorldTransform),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeMultiplyWorldTransform;
record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
memcpy(record->MatrixData, matrix->matrix, sizeof(record->MatrixData));
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusRotateWorldTransform *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusRotateWorldTransform),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeRotateWorldTransform;
record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
record->Angle = angle;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusTranslateWorldTransform *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusTranslateWorldTransform),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeTranslateWorldTransform;
record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
record->dx = dx;
record->dy = dy;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
@ -585,6 +768,122 @@ GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile)
return Ok;
}
GpStatus METAFILE_BeginContainer(GpMetafile* metafile, GDIPCONST GpRectF *dstrect,
GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusBeginContainer *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeBeginContainer;
record->Header.Flags = unit & 0xff;
record->DestRect = *dstrect;
record->SrcRect = *srcrect;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeBeginContainerNoParams;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeEndContainer;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeSave;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeRestore;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
{
if (hdc != metafile->record_dc)
@ -719,6 +1018,36 @@ GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *
return Ok;
}
static void METAFILE_GetFinalGdiTransform(const GpMetafile *metafile, XFORM *result)
{
const GpRectF *rect;
const GpPointF *pt;
/* This transforms metafile device space to output points. */
rect = &metafile->src_rect;
pt = metafile->playback_points;
result->eM11 = (pt[1].X - pt[0].X) / rect->Width;
result->eM21 = (pt[2].X - pt[0].X) / rect->Height;
result->eDx = pt[0].X - result->eM11 * rect->X - result->eM21 * rect->Y;
result->eM12 = (pt[1].Y - pt[0].Y) / rect->Width;
result->eM22 = (pt[2].Y - pt[0].Y) / rect->Height;
result->eDy = pt[0].Y - result->eM12 * rect->X - result->eM22 * rect->Y;
}
static GpStatus METAFILE_PlaybackUpdateGdiTransform(GpMetafile *metafile)
{
XFORM combined, final;
METAFILE_GetFinalGdiTransform(metafile, &final);
CombineTransform(&combined, &metafile->gdiworldtransform, &final);
SetGraphicsMode(metafile->playback_dc, GM_ADVANCED);
SetWorldTransform(metafile->playback_dc, &combined);
return Ok;
}
static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
{
GpStatus stat = Ok;
@ -727,20 +1056,10 @@ static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
if (stat == Ok)
{
/* The result of GdipGetDC always expects device co-ordinates, but the
* device co-ordinates of the source metafile do not correspond to
* device co-ordinates of the destination. Therefore, we set up the DC
* so that the metafile's bounds map to the destination points where we
* are drawing this metafile. */
SetMapMode(metafile->playback_dc, MM_ANISOTROPIC);
static const XFORM identity = {1, 0, 0, 1, 0, 0};
SetWindowOrgEx(metafile->playback_dc, metafile->bounds.X, metafile->bounds.Y, NULL);
SetWindowExtEx(metafile->playback_dc, metafile->bounds.Width, metafile->bounds.Height, NULL);
SetViewportOrgEx(metafile->playback_dc, metafile->playback_points[0].X, metafile->playback_points[0].Y, NULL);
SetViewportExtEx(metafile->playback_dc,
metafile->playback_points[1].X - metafile->playback_points[0].X,
metafile->playback_points[2].Y - metafile->playback_points[0].Y, NULL);
metafile->gdiworldtransform = identity;
METAFILE_PlaybackUpdateGdiTransform(metafile);
}
return stat;
@ -757,7 +1076,11 @@ static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile)
{
return GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
GpStatus stat;
stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
if (stat == Ok)
stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->clip, CombineModeIntersect);
return stat;
}
static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
@ -806,6 +1129,53 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
{
ENHMETARECORD *record;
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:
break;
}
record = heap_alloc_zero(dataSize + 8);
if (record)
@ -909,6 +1279,32 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
return stat;
}
case EmfPlusRecordTypeSetClipRect:
{
EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header;
CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
GpRegion *region;
GpMatrix world_to_device;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
return InvalidParameter;
stat = GdipCreateRegionRect(&record->ClipRect, &region);
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);
GdipDeleteRegion(region);
}
return METAFILE_PlaybackUpdateClip(real_metafile);
}
case EmfPlusRecordTypeSetPageTransform:
{
EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
@ -922,10 +1318,21 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeSetWorldTransform:
{
EmfPlusSetWorldTransform *record = (EmfPlusSetWorldTransform*)header;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetWorldTransform))
return InvalidParameter;
memcpy(real_metafile->world_transform->matrix, record->MatrixData, sizeof(record->MatrixData));
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeScaleWorldTransform:
{
EmfPlusScaleWorldTransform *record = (EmfPlusScaleWorldTransform*)header;
MatrixOrder order = (flags & 0x4) ? MatrixOrderAppend : MatrixOrderPrepend;
MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusScaleWorldTransform))
return InvalidParameter;
@ -934,12 +1341,200 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeMultiplyWorldTransform:
{
EmfPlusMultiplyWorldTransform *record = (EmfPlusMultiplyWorldTransform*)header;
MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
GpMatrix matrix;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusMultiplyWorldTransform))
return InvalidParameter;
memcpy(matrix.matrix, record->MatrixData, sizeof(matrix.matrix));
GdipMultiplyMatrix(real_metafile->world_transform, &matrix, order);
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeRotateWorldTransform:
{
EmfPlusRotateWorldTransform *record = (EmfPlusRotateWorldTransform*)header;
MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusRotateWorldTransform))
return InvalidParameter;
GdipRotateMatrix(real_metafile->world_transform, record->Angle, order);
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeTranslateWorldTransform:
{
EmfPlusTranslateWorldTransform *record = (EmfPlusTranslateWorldTransform*)header;
MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusTranslateWorldTransform))
return InvalidParameter;
GdipTranslateMatrix(real_metafile->world_transform, record->dx, record->dy, order);
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeResetWorldTransform:
{
GdipSetMatrixElements(real_metafile->world_transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeBeginContainer:
{
EmfPlusBeginContainer *record = (EmfPlusBeginContainer*)header;
container* cont;
GpUnit unit;
REAL scale_x, scale_y;
GpRectF scaled_srcrect;
GpMatrix transform;
cont = heap_alloc_zero(sizeof(*cont));
if (!cont)
return OutOfMemory;
stat = GdipCloneRegion(metafile->clip, &cont->clip);
if (stat != Ok)
{
heap_free(cont);
return stat;
}
stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
if (stat != Ok)
{
GdipDeleteRegion(cont->clip);
heap_free(cont);
return stat;
}
cont->id = record->StackIndex;
cont->type = BEGIN_CONTAINER;
cont->world_transform = *metafile->world_transform;
cont->page_unit = metafile->page_unit;
cont->page_scale = metafile->page_scale;
list_add_head(&real_metafile->containers, &cont->entry);
unit = record->Header.Flags & 0xff;
scale_x = units_to_pixels(1.0, unit, metafile->image.xres);
scale_y = units_to_pixels(1.0, unit, metafile->image.yres);
scaled_srcrect.X = scale_x * record->SrcRect.X;
scaled_srcrect.Y = scale_y * record->SrcRect.Y;
scaled_srcrect.Width = scale_x * record->SrcRect.Width;
scaled_srcrect.Height = scale_y * record->SrcRect.Height;
transform.matrix[0] = record->DestRect.Width / scaled_srcrect.Width;
transform.matrix[1] = 0.0;
transform.matrix[2] = 0.0;
transform.matrix[3] = record->DestRect.Height / scaled_srcrect.Height;
transform.matrix[4] = record->DestRect.X - scaled_srcrect.X;
transform.matrix[5] = record->DestRect.Y - scaled_srcrect.Y;
GdipMultiplyMatrix(real_metafile->world_transform, &transform, MatrixOrderPrepend);
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeBeginContainerNoParams:
case EmfPlusRecordTypeSave:
{
EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
container* cont;
cont = heap_alloc_zero(sizeof(*cont));
if (!cont)
return OutOfMemory;
stat = GdipCloneRegion(metafile->clip, &cont->clip);
if (stat != Ok)
{
heap_free(cont);
return stat;
}
if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
else
stat = GdipSaveGraphics(metafile->playback_graphics, &cont->state);
if (stat != Ok)
{
GdipDeleteRegion(cont->clip);
heap_free(cont);
return stat;
}
cont->id = record->StackIndex;
if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
cont->type = BEGIN_CONTAINER;
else
cont->type = SAVE_GRAPHICS;
cont->world_transform = *metafile->world_transform;
cont->page_unit = metafile->page_unit;
cont->page_scale = metafile->page_scale;
list_add_head(&real_metafile->containers, &cont->entry);
break;
}
case EmfPlusRecordTypeEndContainer:
case EmfPlusRecordTypeRestore:
{
EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
container* cont;
enum container_type type;
BOOL found=FALSE;
if (recordType == EmfPlusRecordTypeEndContainer)
type = BEGIN_CONTAINER;
else
type = SAVE_GRAPHICS;
LIST_FOR_EACH_ENTRY(cont, &real_metafile->containers, container, entry)
{
if (cont->id == record->StackIndex && cont->type == type)
{
found = TRUE;
break;
}
}
if (found)
{
container* cont2;
/* pop any newer items on the stack */
while ((cont2 = LIST_ENTRY(list_head(&real_metafile->containers), container, entry)) != cont)
{
list_remove(&cont2->entry);
GdipDeleteRegion(cont2->clip);
heap_free(cont2);
}
if (type == BEGIN_CONTAINER)
GdipEndContainer(real_metafile->playback_graphics, cont->state);
else
GdipRestoreGraphics(real_metafile->playback_graphics, cont->state);
*real_metafile->world_transform = cont->world_transform;
real_metafile->page_unit = cont->page_unit;
real_metafile->page_scale = cont->page_scale;
GdipCombineRegionRegion(real_metafile->clip, cont->clip, CombineModeReplace);
list_remove(&cont->entry);
GdipDeleteRegion(cont->clip);
heap_free(cont);
}
break;
}
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;
@ -1064,6 +1659,9 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
if (stat == Ok)
stat = GdipGetClip(graphics, real_metafile->base_clip);
if (stat == Ok)
stat = GdipCreateRegion(&real_metafile->clip);
if (stat == Ok)
stat = GdipCreatePath(FillModeAlternate, &dst_path);
@ -1118,6 +1716,17 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
GdipDeleteRegion(real_metafile->base_clip);
real_metafile->base_clip = NULL;
GdipDeleteRegion(real_metafile->clip);
real_metafile->clip = NULL;
while (list_head(&real_metafile->containers))
{
container* cont = LIST_ENTRY(list_head(&real_metafile->containers), container, entry);
list_remove(&cont->entry);
GdipDeleteRegion(cont->clip);
heap_free(cont);
}
GdipEndContainer(graphics, state);
}
@ -1199,17 +1808,22 @@ GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
if(!metafile || !header)
return InvalidParameter;
if (!metafile->hemf)
return InvalidParameter;
status = GdipGetMetafileHeaderFromEmf(metafile->hemf, header);
if (status != Ok) return status;
if (metafile->hemf)
{
status = GdipGetMetafileHeaderFromEmf(metafile->hemf, header);
if (status != Ok) return status;
}
else
{
memset(header, 0, sizeof(*header));
header->Version = 0xdbc01002;
}
header->Type = metafile->metafile_type;
header->DpiX = metafile->image.xres;
header->DpiY = metafile->image.yres;
header->Width = metafile->bounds.Width;
header->Height = metafile->bounds.Height;
header->Width = gdip_round(metafile->bounds.Width);
header->Height = gdip_round(metafile->bounds.Height);
return Ok;
}
@ -1390,6 +2004,7 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
(*metafile)->metafile_type = header.Type;
(*metafile)->hemf = hemf;
(*metafile)->preserve_hemf = !delete;
list_init(&(*metafile)->containers);
TRACE("<-- %p\n", *metafile);

View file

@ -68,7 +68,7 @@ reactos/dll/win32/dciman32 # Synced to WineStaging-1.9.11
reactos/dll/win32/faultrep # Synced to WineStaging-1.9.11
reactos/dll/win32/fontsub # Synced to WineStaging-1.9.13
reactos/dll/win32/fusion # Synced to WineStaging-1.9.23
reactos/dll/win32/gdiplus # Synced to WineStaging-1.9.16
reactos/dll/win32/gdiplus # Synced to WineStaging-1.9.23
reactos/dll/win32/hhctrl.ocx # Synced to WineStaging-1.9.16
reactos/dll/win32/hlink # Synced to WineStaging-1.9.16
reactos/dll/win32/hnetcfg # Synced to WineStaging-1.9.16