mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 00:45:49 +00:00
[GDIPLUS] Sync with Wine Staging 1.9.23. CORE-12409
svn path=/trunk/; revision=73270
This commit is contained in:
parent
3e8eeb6c2e
commit
3c5dbe9f1f
10 changed files with 1716 additions and 174 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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, ®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 @@ 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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue