Author: akhaldi
Date: Thu Nov 17 22:35:44 2016
New Revision: 73270
URL:
http://svn.reactos.org/svn/reactos?rev=73270&view=rev
Log:
[GDIPLUS] Sync with Wine Staging 1.9.23. CORE-12409
Modified:
trunk/reactos/dll/win32/gdiplus/brush.c
trunk/reactos/dll/win32/gdiplus/gdiplus.spec
trunk/reactos/dll/win32/gdiplus/gdiplus_private.h
trunk/reactos/dll/win32/gdiplus/graphics.c
trunk/reactos/dll/win32/gdiplus/graphicspath.c
trunk/reactos/dll/win32/gdiplus/image.c
trunk/reactos/dll/win32/gdiplus/imageattributes.c
trunk/reactos/dll/win32/gdiplus/matrix.c
trunk/reactos/dll/win32/gdiplus/metafile.c
trunk/reactos/media/doc/README.WINE
Modified: trunk/reactos/dll/win32/gdiplus/brush.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/brush.c?…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/brush.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/brush.c [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -441,25 +441,42 @@
{
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));
+ if (!rect || !rect->Width || !rect->Height)
+ return InvalidParameter;
+
+ angle = fmodf(angle, 360);
+ if (angle < 0)
+ angle += 360;
+
+ if (isAngleScalable)
+ {
+ 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
+ {
+ angle = deg2rad(angle);
+ }
+
+ sin_angle = sinf(angle);
+ cos_angle = cosf(angle);
sin_cos_angle = sin_angle * cos_angle;
-
- if (isAngleScalable)
- {
- width = height = 1.0;
- }
- else
- {
- width = rect->Width;
- height = rect->Height;
- }
if (sin_cos_angle >= 0)
mode = LinearGradientModeForwardDiagonal;
@@ -472,19 +489,13 @@
{
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)
Modified: trunk/reactos/dll/win32/gdiplus/gdiplus.spec
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/gdiplus.…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/gdiplus.spec [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/gdiplus.spec [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -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
Modified: trunk/reactos/dll/win32/gdiplus/gdiplus_private.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/gdiplus_…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/gdiplus_private.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/gdiplus_private.h [iso-8859-1] Thu Nov 17 22:35:44
2016
@@ -89,6 +89,9 @@
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_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 @@
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{
Modified: trunk/reactos/dll/win32/gdiplus/graphics.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/graphics…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/graphics.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/graphics.c [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -47,9 +47,6 @@
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 @@
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 @@
} 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 @@
return OutOfMemory;
(*container)->contid = graphics->contid + 1;
+ (*container)->type = type;
(*container)->smoothing = graphics->smoothing;
(*container)->compqual = graphics->compqual;
@@ -3075,6 +3079,8 @@
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 @@
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 @@
hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY);
}
+ RestoreDC(graphics->hdc, save_state);
+
if (temp_hdc)
{
SelectObject(hdc, old_hbm);
@@ -3284,6 +3302,12 @@
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 @@
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);
@@ -3383,6 +3393,398 @@
end:
restore_dc(graphics, save_state);
DeleteObject(hrgn);
+
+ 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;
}
@@ -3934,6 +4336,23 @@
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 @@
RestoreDC(graphics->hdc, save_state);
- DeleteObject(hrgn);
return Ok;
}
@@ -5128,14 +5546,11 @@
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 @@
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);
}
+static GpStatus begin_container(GpGraphics *graphics,
+ GraphicsContainerType type, GraphicsContainer *state)
+{
+ GraphicsContainerItem *container;
+ GpStatus sts;
+
+ if(!graphics || !state)
+ return InvalidParameter;
+
+ 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)
{
- return GdipBeginContainer2(graphics, 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)
+{
GraphicsContainerItem *container;
- GpStatus sts;
-
- TRACE("(%p, %p)\n", graphics, state);
-
- if(!graphics || !state)
- return InvalidParameter;
-
- sts = init_container(&container, graphics);
- if(sts != Ok)
- return sts;
+ 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 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;
-}
-
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 @@
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,7 +5713,26 @@
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,
@@ -5459,6 +5966,8 @@
GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
{
+ GpStatus stat;
+
TRACE("(%p, %p)\n", graphics, matrix);
if(!graphics || !matrix)
@@ -5471,6 +5980,13 @@
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 GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
REAL dy, GpMatrixOrder order)
{
+ GpStatus stat;
+
TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order);
if(!graphics)
@@ -5486,6 +6004,13 @@
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);
}
@@ -5561,6 +6086,13 @@
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;
@@ -5628,8 +6160,8 @@
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 @@
if(graphics->busy)
return ObjectBusy;
- if (!graphics->hdc)
- {
- FIXME("graphics object has no HDC\n");
- return Ok;
- }
-
- pti = heap_alloc_zero(sizeof(POINT) * count);
-
- save_state = prepare_dc(graphics, pen);
- SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
-
- transform_and_round_points(graphics, pti, (GpPointF*)points, count);
- Polygon(graphics->hdc, pti, count);
-
- restore_dc(graphics, save_state);
- heap_free(pti);
-
- return Ok;
+ status = GdipCreatePath(FillModeAlternate, &path);
+ if (status != Ok) return status;
+
+ status = GdipAddPathPolygon(path, points, count);
+ if (status == Ok)
+ status = GdipDrawPath(graphics, pen, path);
+
+ GdipDeletePath(path);
+
+ return status;
}
GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint
*points,
@@ -5723,6 +6247,13 @@
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;
@@ -5896,7 +6427,7 @@
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 @@
GpPointF pt;
HFONT hfont;
UINT eto_flags=0;
+ GpStatus status;
+ HRGN hrgn;
if (flags & unsupported_flags)
FIXME("Ignoring flags %x\n", flags & unsupported_flags);
@@ -6186,6 +6719,14 @@
save_state = SaveDC(graphics->hdc);
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);
Modified: trunk/reactos/dll/win32/gdiplus/graphicspath.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/graphics…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/graphicspath.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/graphicspath.c [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -1567,17 +1567,49 @@
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");
-
- return NotImplemented;
+ stat = GdipClonePath(path, &wide_path);
+
+ 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 @@
int i;
path_list_node_t *prev_point;
- if (end <= start+1)
+ if (end <= start)
return;
/* left outline */
Modified: trunk/reactos/dll/win32/gdiplus/image.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/image.c?…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/image.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/image.c [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -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 @@
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);
@@ -2160,6 +2165,10 @@
else if(image->type == ImageTypeBitmap){
*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);
@@ -2215,6 +2224,11 @@
*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 @@
*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 load_wmf(IStream *stream, GpMetafile **metafile)
{
- GpStatus status = GenericError;
+ WmfPlaceableFileHeader pfh;
+ BOOL is_placeable = FALSE;
+ LARGE_INTEGER seek;
+ GpStatus status;
+ METAHEADER mh;
+ HMETAFILE hmf;
HRESULT hr;
UINT size;
- LARGE_INTEGER pos;
- WmfPlaceableFileHeader pfh;
- BOOL is_placeable = FALSE;
- METAHEADER mh;
- HMETAFILE hmf;
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)
- {
- is_placeable = TRUE;
-
- pos.QuadPart = 0;
- IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+ if (((WmfPlaceableFileHeader *)&mh)->Key == WMF_PLACEABLE_KEY)
+ {
+ 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 @@
hr = IStream_Read(stream, &mh, sizeof(mh), &size);
if (hr != S_OK || size != sizeof(mh))
return GenericError;
- }
-
- pos.QuadPart = is_placeable ? sizeof(pfh) : 0;
- IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+
+ is_placeable = TRUE;
+ }
+
+ 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)
- {
- hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
- if (hmf)
- {
- status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL,
metafile);
- if (status != Ok)
- DeleteMetaFile(hmf);
- }
- }
-
+ if (hr != S_OK || size != mh.mtSize * 2)
+ {
+ 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;
+ LARGE_INTEGER seek;
+ ENHMETAHEADER emh;
+ HENHMETAFILE hemf;
+ GpStatus status;
HRESULT hr;
UINT size;
- LARGE_INTEGER pos;
- ENHMETAHEADER emh;
- HENHMETAFILE hemf;
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)
- {
- hemf = SetEnhMetaFileBits(emh.nBytes, buf);
- if (hemf)
- {
- status = GdipCreateMetafileFromEmf(hemf, FALSE, metafile);
- if (status != Ok)
- DeleteEnhMetaFile(hemf);
- }
- }
-
+ if (hr != S_OK || size != emh.nBytes)
+ {
+ 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)
- return InvalidParameter;
-
- if (load_emf(stream, &metafile) != Ok && load_wmf(stream, &metafile)
!= Ok)
+ if (!stream || !image)
+ return InvalidParameter;
+
+ 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_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 @@
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 @@
/* SigMask */ emf_sig_mask,
},
NULL,
- decode_image_metafile,
+ decode_image_emf,
NULL
},
{
@@ -4768,7 +4813,7 @@
/* SigMask */ wmf_sig_mask,
},
NULL,
- decode_image_metafile,
+ decode_image_wmf,
NULL
},
{
@@ -5348,8 +5393,15 @@
*/
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 @@
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;
+}
Modified: trunk/reactos/dll/win32/gdiplus/imageattributes.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/imageatt…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/imageattributes.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/imageattributes.c [iso-8859-1] Thu Nov 17 22:35:44
2016
@@ -21,17 +21,51 @@
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;
}
Modified: trunk/reactos/dll/win32/gdiplus/matrix.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/matrix.c…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/matrix.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/matrix.c [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -484,23 +484,17 @@
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);
+}
Modified: trunk/reactos/dll/win32/gdiplus/metafile.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/gdiplus/metafile…
==============================================================================
--- trunk/reactos/dll/win32/gdiplus/metafile.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/gdiplus/metafile.c [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -48,6 +48,12 @@
DWORD Count;
} EmfPlusFillRects;
+typedef struct EmfPlusSetClipRect
+{
+ EmfPlusRecordHeader Header;
+ GpRectF ClipRect;
+} EmfPlusSetClipRect;
+
typedef struct EmfPlusSetPageTransform
{
EmfPlusRecordHeader Header;
@@ -62,12 +68,69 @@
SHORT Height;
} EmfPlusRect;
+typedef struct EmfPlusSetWorldTransform
+{
+ EmfPlusRecordHeader Header;
+ REAL MatrixData[6];
+} EmfPlusSetWorldTransform;
+
typedef struct EmfPlusScaleWorldTransform
{
EmfPlusRecordHeader Header;
REAL Sx;
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)
{
@@ -260,6 +323,7 @@
(*metafile)->comment_data_size = 0;
(*metafile)->comment_data_length = 0;
(*metafile)->hemf = NULL;
+ list_init(&(*metafile)->containers);
if (!frameRect)
{
@@ -516,6 +580,32 @@
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 @@
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,9 +666,79 @@
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;
+
+ METAFILE_WriteRecords(metafile);
+ }
+
+ 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);
}
@@ -578,6 +761,122 @@
record->Type = EmfPlusRecordTypeResetWorldTransform;
record->Flags = 0;
+
+ METAFILE_WriteRecords(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);
}
@@ -719,6 +1018,36 @@
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 @@
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);
-
- 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);
+ static const XFORM identity = {1, 0, 0, 1, 0, 0};
+
+ metafile->gdiworldtransform = identity;
+ METAFILE_PlaybackUpdateGdiTransform(metafile);
}
return stat;
@@ -757,7 +1076,11 @@
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)
@@ -805,6 +1128,53 @@
if (metafile->playback_dc)
{
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);
@@ -909,6 +1279,32 @@
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, ®ion);
+
+ if (stat == Ok)
+ {
+ get_graphics_transform(real_metafile->playback_graphics,
+ CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
+
+ GdipTransformRegion(region, &world_to_device);
+
+ GdipCombineRegionRegion(real_metafile->clip, region, mode);
+
+ GdipDeleteRegion(region);
+ }
+
+ return METAFILE_PlaybackUpdateClip(real_metafile);
+ }
case EmfPlusRecordTypeSetPageTransform:
{
EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
@@ -922,10 +1318,21 @@
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,11 +1341,199 @@
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);
@@ -1063,6 +1658,9 @@
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 @@
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 @@
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 @@
(*metafile)->metafile_type = header.Type;
(*metafile)->hemf = hemf;
(*metafile)->preserve_hemf = !delete;
+ list_init(&(*metafile)->containers);
TRACE("<-- %p\n", *metafile);
Modified: trunk/reactos/media/doc/README.WINE
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=…
==============================================================================
--- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original)
+++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Thu Nov 17 22:35:44 2016
@@ -68,7 +68,7 @@
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