mirror of
https://github.com/reactos/reactos.git
synced 2025-04-20 12:29:56 +00:00
[GDIPLUS] Sync with Wine Staging 2.16. CORE-13762
6bf1b63 gdiplus: Account for gdi32 transform in SOFTWARE_GdipDrawThinPath. e127101 gdiplus: Send paths to gdi32 in device coordinates. 93e8507 gdiplus: Account for gdi32 transform in GdipDrawImage. be95252 gdiplus: Use SOFTWARE_GdipDrawPath with alpha hdc's. 0914f62 gdiplus: Account for gdi transform in brush_fill_pixels. 399fd55 gdiplus: Account for gdi transform in SOFTWARE_GdipFillRegion. 016dc76 gdiplus: Transform clipping region to gdi device coordinates. cfa4f08 gdiplus: Replace DPtoLP with an internal coordinate space constant. 5c12ced gdiplus: Check for invalid coordinate space in GdipTransformPoints. 8c593bd gdiplus: Set correct color space flags for grayscale images. 7860d11 gdiplus: Don't call PlayEnhMetaFileRecord for records handled by gdiplus. 5870431 gdiplus: Force conversion of 8 bpp grayscale PNG images to 32 bpp BGRA. 42e5d27 gdiplus: Use defined constants for wrap modes. 79ebd3f gdiplus: Fix copy-paste typo. a4ab858 gdiplus: GdipCreateMetafileFromWmfFile will also load EMFs. aac33da gdiplus: Implement transform matrix for line gradient brushes. 14bb8df gdiplus: Support GdipSetClipRegion in metafiles. 4a02870 gdiplus: Add write_region_data helper and use it in GdipGetRegionData. 595959c gdiplus: Add more accurate algorithm for inverting scaling and translation matrices in GdipInvertMatrix. 1744277 gdiplus: Implement stub for GdipGraphicsSetAbort. 331a7af gdiplus: Fix a possible floating point exception in path gradients. 400cfb0 gdiplus: Avoid division by zero in SOFTWARE_GdipDrawThinPath. 2176348 gdiplus: Return success saving path to metafile. 70afb4e gdiplus: Fix saving pen dashed line cap style to metafile. a172cc6 gdiplus: Free dash_pattern_scaled (Coverity). 58eb74c gdiplus: Use write_path_data helper in GdipGetRegionData. a892b68 gdiplus: Add write_path_data helper to create EMF+ path object. 5545332 gdiplus: Store newer gdi+ version in created GdipRegions. cfe2b3f gdiplus: Don't require specific gdi+ versions in metafile structures. a8b5fdd gdiplus: Use VERSION_MAGIC2 constant in metafiles functions. 8498aa3 gdiplus: Add support for creating image object containing metafile. 9f22041 gdiplus: Fix leak in widen_dashed_figure. f9b881e gdiplus: Fix GdipGetVisibleClipBounds behavior on metafiles. de37ced gdiplus: Add partial support for GdipFillPath on metafiles. e79c4ca gdiplus: Add partial support for GdipDrawPath on metafiles. 7d6896e gdiplus: Add helper for saving pens to metafile. e502a8d gdiplus: Add helper for saving path objects in metafile. 8608bf5 gdiplus: Add DrawPath stub for metafiles. 29968cf gdiplus: Support GdipSetInterpolationMode in metafiles. f248374 gdiplus: Support GdipSetCompositingQuality in metafiles. 1cecd47 gdiplus: Support GdipSetCompositingMode in metafiles. 910975a gdiplus: Support GdipSetSmoothingMode in metafiles. f716029 gdiplus: Support GdipSetPixelOffsetMode in metafiles. 683315d gdiplus: Support GdipSetTextRenderingHint in metafiles. 689268d gdiplus: Add support for ImageAttributes when drawing image to metafile. ac231b1 gdiplus: Add function for managing metafile objects id. e1e4dd2 gdiplus: Add partial support for GdipDrawImagePointsRect on metafile. 1a75f76 gdiplus: Remove unused clsid parameter from encode_image_func helpers. 01c9fb9 gdiplus: Remove a duplicate word in a comment. 6ec3cd9 gdiplus: Set flatness more appropriately in GdipDrawPath. 7e1522c gdiplus: Scale widened dashes to the pen width. c95877d gdiplus: Write API documentation for GdipAddPathArc and GdipAddPathArcI. f1123f3 gdiplus: Write API for GdipClonePath. f96e319 gdiplus: Write API for GdipAddPathLine and GdipAddPathLineI. 260cbd0 gdiplus: Implement triangular line caps in widened paths. a4b7fe6 gdiplus: Initialize containers list in GdipCloneImage. svn path=/trunk/; revision=75872
This commit is contained in:
parent
2a10a08909
commit
c6f32e4a5f
10 changed files with 1654 additions and 332 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2007 Google (Evan Stade)
|
* Copyright (C) 2007 Google (Evan Stade)
|
||||||
|
* Copyright (C) 2003-2004,2007 Novell, Inc. http://www.novell.com (Ravindra (rkumar@novell.com))
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -162,6 +163,8 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
|
||||||
return OutOfMemory;
|
return OutOfMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dest->transform = src->transform;
|
||||||
|
|
||||||
memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
|
memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
|
||||||
memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
|
memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
|
||||||
|
|
||||||
|
@ -272,6 +275,41 @@ GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, AR
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void linegradient_init_transform(GpLineGradient *line)
|
||||||
|
{
|
||||||
|
float trans_x = line->rect.X + (line->rect.Width / 2.f);
|
||||||
|
float trans_y = line->rect.Y + (line->rect.Height / 2.f);
|
||||||
|
float dx = line->endpoint.X - line->startpoint.X;
|
||||||
|
float dy = line->endpoint.Y - line->startpoint.Y;
|
||||||
|
float t_cos, t_sin, w_ratio, h_ratio;
|
||||||
|
float h;
|
||||||
|
GpMatrix rot;
|
||||||
|
|
||||||
|
h = sqrtf(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
t_cos = dx / h;
|
||||||
|
t_sin = dy / h;
|
||||||
|
|
||||||
|
w_ratio = (fabs(t_cos) * line->rect.Width + fabs(t_sin) * line->rect.Height) / line->rect.Width;
|
||||||
|
h_ratio = (fabs(t_sin) * line->rect.Width + fabs(t_cos) * line->rect.Height) / line->rect.Height;
|
||||||
|
|
||||||
|
GdipSetMatrixElements(&line->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
GdipSetMatrixElements(&rot, t_cos, t_sin, -1.f * t_sin, t_cos, 0, 0);
|
||||||
|
|
||||||
|
/* center about the origin */
|
||||||
|
GdipTranslateMatrix(&line->transform, -trans_x, -trans_y, MatrixOrderAppend);
|
||||||
|
|
||||||
|
/* scale to normalize gradient along gradient line (?) */
|
||||||
|
GdipScaleMatrix(&line->transform, w_ratio, h_ratio, MatrixOrderAppend);
|
||||||
|
|
||||||
|
/* rotate so the gradient is horizontal */
|
||||||
|
GdipMultiplyMatrix(&line->transform, &rot, MatrixOrderAppend);
|
||||||
|
|
||||||
|
/* restore original offset in new coords */
|
||||||
|
GdipTranslateMatrix(&line->transform, trans_x, trans_y, MatrixOrderAppend);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* GdipCreateLineBrush [GDIPLUS.@]
|
* GdipCreateLineBrush [GDIPLUS.@]
|
||||||
*/
|
*/
|
||||||
|
@ -338,6 +376,8 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
|
||||||
(*line)->pblendpos = NULL;
|
(*line)->pblendpos = NULL;
|
||||||
(*line)->pblendcount = 0;
|
(*line)->pblendcount = 0;
|
||||||
|
|
||||||
|
linegradient_init_transform(*line);
|
||||||
|
|
||||||
TRACE("<-- %p\n", *line);
|
TRACE("<-- %p\n", *line);
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -370,6 +410,7 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
|
||||||
{
|
{
|
||||||
GpPointF start, end;
|
GpPointF start, end;
|
||||||
GpStatus stat;
|
GpStatus stat;
|
||||||
|
float far_x, far_y;
|
||||||
|
|
||||||
TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
|
TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
|
||||||
wrap, line);
|
wrap, line);
|
||||||
|
@ -377,31 +418,34 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
|
||||||
if(!line || !rect)
|
if(!line || !rect)
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
|
far_x = rect->X + rect->Width;
|
||||||
|
far_y = rect->Y + rect->Height;
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case LinearGradientModeHorizontal:
|
case LinearGradientModeHorizontal:
|
||||||
start.X = rect->X;
|
start.X = min(rect->X, far_x);
|
||||||
start.Y = rect->Y;
|
start.Y = rect->Y;
|
||||||
end.X = rect->X + rect->Width;
|
end.X = max(rect->X, far_x);
|
||||||
end.Y = rect->Y;
|
end.Y = rect->Y;
|
||||||
break;
|
break;
|
||||||
case LinearGradientModeVertical:
|
case LinearGradientModeVertical:
|
||||||
start.X = rect->X;
|
start.X = rect->X;
|
||||||
start.Y = rect->Y;
|
start.Y = min(rect->Y, far_y);
|
||||||
end.X = rect->X;
|
end.X = rect->X;
|
||||||
end.Y = rect->Y + rect->Height;
|
end.Y = max(rect->Y, far_y);
|
||||||
break;
|
break;
|
||||||
case LinearGradientModeForwardDiagonal:
|
case LinearGradientModeForwardDiagonal:
|
||||||
start.X = rect->X;
|
start.X = min(rect->X, far_x);
|
||||||
start.Y = rect->Y;
|
start.Y = min(rect->Y, far_y);
|
||||||
end.X = rect->X + rect->Width;
|
end.X = max(rect->X, far_x);
|
||||||
end.Y = rect->Y + rect->Height;
|
end.Y = max(rect->Y, far_y);
|
||||||
break;
|
break;
|
||||||
case LinearGradientModeBackwardDiagonal:
|
case LinearGradientModeBackwardDiagonal:
|
||||||
start.X = rect->X + rect->Width;
|
start.X = max(rect->X, far_x);
|
||||||
start.Y = rect->Y;
|
start.Y = min(rect->Y, far_y);
|
||||||
end.X = rect->X;
|
end.X = min(rect->X, far_x);
|
||||||
end.Y = rect->Y + rect->Height;
|
end.Y = max(rect->Y, far_y);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
@ -510,6 +554,8 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect
|
||||||
(*line)->startpoint.X = rect->X + exofs;
|
(*line)->startpoint.X = rect->X + exofs;
|
||||||
(*line)->startpoint.Y = rect->Y + eyofs;
|
(*line)->startpoint.Y = rect->Y + eyofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linegradient_init_transform(*line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stat;
|
return stat;
|
||||||
|
@ -2018,78 +2064,73 @@ GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush,
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
|
GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
|
||||||
{
|
{
|
||||||
static int calls;
|
|
||||||
|
|
||||||
TRACE("(%p)\n", brush);
|
TRACE("(%p)\n", brush);
|
||||||
|
|
||||||
if(!(calls++))
|
if(!brush)
|
||||||
FIXME("not implemented\n");
|
return InvalidParameter;
|
||||||
|
|
||||||
return NotImplemented;
|
return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
|
GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
|
||||||
GDIPCONST GpMatrix *matrix)
|
GDIPCONST GpMatrix *matrix)
|
||||||
{
|
{
|
||||||
static int calls;
|
|
||||||
|
|
||||||
TRACE("(%p,%p)\n", brush, matrix);
|
TRACE("(%p,%p)\n", brush, matrix);
|
||||||
|
|
||||||
if(!(calls++))
|
if(!brush || !matrix)
|
||||||
FIXME("not implemented\n");
|
return InvalidParameter;
|
||||||
|
|
||||||
return NotImplemented;
|
brush->transform = *matrix;
|
||||||
|
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix)
|
GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix)
|
||||||
{
|
{
|
||||||
static int calls;
|
|
||||||
|
|
||||||
TRACE("(%p,%p)\n", brush, matrix);
|
TRACE("(%p,%p)\n", brush, matrix);
|
||||||
|
|
||||||
if(!(calls++))
|
if(!brush || !matrix)
|
||||||
FIXME("not implemented\n");
|
return InvalidParameter;
|
||||||
|
|
||||||
return NotImplemented;
|
*matrix = brush->transform;
|
||||||
|
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
|
GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
|
||||||
GpMatrixOrder order)
|
GpMatrixOrder order)
|
||||||
{
|
{
|
||||||
static int calls;
|
|
||||||
|
|
||||||
TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order);
|
TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order);
|
||||||
|
|
||||||
if(!(calls++))
|
if(!brush)
|
||||||
FIXME("not implemented\n");
|
return InvalidParameter;
|
||||||
|
|
||||||
return NotImplemented;
|
return GdipScaleMatrix(&brush->transform, sx, sy, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush,
|
GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush,
|
||||||
GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
|
GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
|
||||||
{
|
{
|
||||||
static int calls;
|
|
||||||
|
|
||||||
TRACE("(%p,%p,%u)\n", brush, matrix, order);
|
TRACE("(%p,%p,%u)\n", brush, matrix, order);
|
||||||
|
|
||||||
if(!(calls++))
|
if(!brush)
|
||||||
FIXME("not implemented\n");
|
return InvalidParameter;
|
||||||
|
|
||||||
return NotImplemented;
|
if(!matrix)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
return GdipMultiplyMatrix(&brush->transform, matrix, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
|
GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient *brush,
|
||||||
REAL dx, REAL dy, GpMatrixOrder order)
|
REAL dx, REAL dy, GpMatrixOrder order)
|
||||||
{
|
{
|
||||||
static int calls;
|
|
||||||
|
|
||||||
TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order);
|
TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order);
|
||||||
|
|
||||||
if(!(calls++))
|
if(!brush)
|
||||||
FIXME("not implemented\n");
|
return InvalidParameter;
|
||||||
|
|
||||||
return Ok;
|
return GdipTranslateMatrix(&brush->transform, dx, dy, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
|
@ -622,7 +622,7 @@
|
||||||
622 stdcall GdipBitmapGetHistogramSize(long ptr)
|
622 stdcall GdipBitmapGetHistogramSize(long ptr)
|
||||||
623 stdcall GdipBitmapConvertFormat(ptr long long long ptr float)
|
623 stdcall GdipBitmapConvertFormat(ptr long long long ptr float)
|
||||||
624 stdcall GdipImageSetAbort(ptr ptr)
|
624 stdcall GdipImageSetAbort(ptr ptr)
|
||||||
625 stub GdipGraphicsSetAbort
|
625 stdcall GdipGraphicsSetAbort(ptr ptr)
|
||||||
626 stub GdipDrawImageFX
|
626 stub GdipDrawImageFX
|
||||||
627 stdcall GdipConvertToEmfPlus(ptr ptr ptr long ptr ptr)
|
627 stdcall GdipConvertToEmfPlus(ptr ptr ptr long ptr ptr)
|
||||||
628 stdcall GdipConvertToEmfPlusToFile(ptr ptr ptr ptr long ptr ptr)
|
628 stdcall GdipConvertToEmfPlusToFile(ptr ptr ptr ptr long ptr ptr)
|
||||||
|
|
|
@ -49,6 +49,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
|
||||||
|
|
||||||
#define VERSION_MAGIC 0xdbc01001
|
#define VERSION_MAGIC 0xdbc01001
|
||||||
#define VERSION_MAGIC2 0xdbc01002
|
#define VERSION_MAGIC2 0xdbc01002
|
||||||
|
#define VALID_MAGIC(x) (((x) & 0xfffff000) == 0xdbc01000)
|
||||||
#define TENSION_CONST (0.3)
|
#define TENSION_CONST (0.3)
|
||||||
|
|
||||||
#define GIF_DISPOSE_UNSPECIFIED 0
|
#define GIF_DISPOSE_UNSPECIFIED 0
|
||||||
|
@ -86,10 +87,17 @@ 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 pixels_to_units(REAL pixels, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
|
||||||
extern REAL units_scale(GpUnit from, GpUnit to, REAL dpi) DECLSPEC_HIDDEN;
|
extern REAL units_scale(GpUnit from, GpUnit to, REAL dpi) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
#define WineCoordinateSpaceGdiDevice ((GpCoordinateSpace)4)
|
||||||
|
|
||||||
|
extern GpStatus gdi_transform_acquire(GpGraphics *graphics);
|
||||||
|
extern GpStatus gdi_transform_release(GpGraphics *graphics);
|
||||||
extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
||||||
GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
|
GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
||||||
|
GpCoordinateSpace src_space, GpPointF *points, INT count) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
|
extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus encode_image_png(GpImage *image, IStream* stream, GDIPCONST EncoderParameters* params) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
|
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
|
||||||
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
|
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
|
||||||
|
@ -99,6 +107,7 @@ extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
|
||||||
GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
|
GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
|
||||||
extern GpStatus METAFILE_SetClipRect(GpMetafile* metafile,
|
extern GpStatus METAFILE_SetClipRect(GpMetafile* metafile,
|
||||||
REAL x, REAL y, REAL width, REAL height, CombineMode mode) DECLSPEC_HIDDEN;
|
REAL x, REAL y, REAL width, REAL height, CombineMode mode) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode) DECLSPEC_HIDDEN;
|
||||||
extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
|
extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
|
||||||
extern GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform) 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_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) DECLSPEC_HIDDEN;
|
||||||
|
@ -113,6 +122,13 @@ extern GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex) DE
|
||||||
extern GpStatus METAFILE_SaveGraphics(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_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
|
||||||
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
|
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile, GpImage *image,
|
||||||
|
GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
|
||||||
|
REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
|
||||||
|
DrawImageAbort callback, VOID *callbackData) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path) DECLSPEC_HIDDEN;
|
||||||
|
extern GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
|
extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
|
||||||
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
|
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
|
||||||
|
@ -123,6 +139,9 @@ extern void free_installed_fonts(void) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern BOOL lengthen_path(GpPath *path, INT len) DECLSPEC_HIDDEN;
|
extern BOOL lengthen_path(GpPath *path, INT len) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
extern DWORD write_region_data(const GpRegion *region, void *data) DECLSPEC_HIDDEN;
|
||||||
|
extern DWORD write_path_data(GpPath *path, void *data) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern GpStatus trace_path(GpGraphics *graphics, GpPath *path) DECLSPEC_HIDDEN;
|
extern GpStatus trace_path(GpGraphics *graphics, GpPath *path) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
typedef struct region_element region_element;
|
typedef struct region_element region_element;
|
||||||
|
@ -249,6 +268,8 @@ struct GpGraphics{
|
||||||
struct list containers;
|
struct list containers;
|
||||||
GraphicsContainer contid; /* last-issued container ID */
|
GraphicsContainer contid; /* last-issued container ID */
|
||||||
INT origin_x, origin_y;
|
INT origin_x, origin_y;
|
||||||
|
INT gdi_transform_acquire_count, gdi_transform_save;
|
||||||
|
GpMatrix gdi_transform;
|
||||||
/* For giving the caller an HDC when we technically can't: */
|
/* For giving the caller an HDC when we technically can't: */
|
||||||
HBITMAP temp_hbitmap;
|
HBITMAP temp_hbitmap;
|
||||||
int temp_hbitmap_width;
|
int temp_hbitmap_width;
|
||||||
|
@ -307,6 +328,7 @@ struct GpLineGradient{
|
||||||
ARGB* pblendcolor; /* preset blend colors */
|
ARGB* pblendcolor; /* preset blend colors */
|
||||||
REAL* pblendpos; /* preset blend positions */
|
REAL* pblendpos; /* preset blend positions */
|
||||||
INT pblendcount;
|
INT pblendcount;
|
||||||
|
GpMatrix transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GpTexture{
|
struct GpTexture{
|
||||||
|
@ -373,6 +395,7 @@ struct GpMetafile{
|
||||||
IStream *record_stream;
|
IStream *record_stream;
|
||||||
BOOL auto_frame; /* If true, determine the frame automatically */
|
BOOL auto_frame; /* If true, determine the frame automatically */
|
||||||
GpPointF auto_frame_min, auto_frame_max;
|
GpPointF auto_frame_min, auto_frame_max;
|
||||||
|
DWORD next_object_id;
|
||||||
|
|
||||||
/* playback */
|
/* playback */
|
||||||
GpGraphics *playback_graphics;
|
GpGraphics *playback_graphics;
|
||||||
|
|
|
@ -38,6 +38,10 @@ static volatile LONG g_priv_contid = GDIP_CONTID_STEP;
|
||||||
#define GDIP_GET_NEW_CONTID_FOR(pGpGraphics) \
|
#define GDIP_GET_NEW_CONTID_FOR(pGpGraphics) \
|
||||||
(UINT)(InterlockedExchangeAdd(&g_priv_contid,GDIP_CONTID_STEP))
|
(UINT)(InterlockedExchangeAdd(&g_priv_contid,GDIP_CONTID_STEP))
|
||||||
|
|
||||||
|
|
||||||
|
/* ReactOS FIXME: Inspect */
|
||||||
|
#define fmax max
|
||||||
|
|
||||||
/* looks-right constants */
|
/* looks-right constants */
|
||||||
#define ANCHOR_WIDTH (2.0)
|
#define ANCHOR_WIDTH (2.0)
|
||||||
#define MAX_ITERS (50)
|
#define MAX_ITERS (50)
|
||||||
|
@ -245,6 +249,14 @@ static INT prepare_dc(GpGraphics *graphics, GpPen *pen)
|
||||||
|
|
||||||
width *= units_to_pixels(pen->width, pen->unit == UnitWorld ? graphics->unit : pen->unit, graphics->xres);
|
width *= units_to_pixels(pen->width, pen->unit == UnitWorld ? graphics->unit : pen->unit, graphics->xres);
|
||||||
width *= graphics->scale;
|
width *= graphics->scale;
|
||||||
|
|
||||||
|
pt[0].X = 0.0;
|
||||||
|
pt[0].Y = 0.0;
|
||||||
|
pt[1].X = 1.0;
|
||||||
|
pt[1].Y = 1.0;
|
||||||
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, pt, 2);
|
||||||
|
width *= sqrt((pt[1].X - pt[0].X) * (pt[1].X - pt[0].X) +
|
||||||
|
(pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pen->dash == DashStyleCustom){
|
if(pen->dash == DashStyleCustom){
|
||||||
|
@ -280,43 +292,23 @@ static void restore_dc(GpGraphics *graphics, INT state)
|
||||||
RestoreDC(graphics->hdc, state);
|
RestoreDC(graphics->hdc, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This helper applies all the changes that the points listed in ptf need in
|
static void round_points(POINT *pti, GpPointF *ptf, INT count)
|
||||||
* order to be drawn on the device context. In the end, this should include at
|
|
||||||
* least:
|
|
||||||
* -scaling by page unit
|
|
||||||
* -applying world transformation
|
|
||||||
* -converting from float to int
|
|
||||||
* Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx,
|
|
||||||
* SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using
|
|
||||||
* gdi to draw, and these functions would irreparably mess with line widths.
|
|
||||||
*/
|
|
||||||
static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
|
|
||||||
GpPointF *ptf, INT count)
|
|
||||||
{
|
{
|
||||||
REAL scale_x, scale_y;
|
|
||||||
GpMatrix matrix;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
scale_x = units_to_pixels(1.0, graphics->unit, graphics->xres);
|
|
||||||
scale_y = units_to_pixels(1.0, graphics->unit, graphics->yres);
|
|
||||||
|
|
||||||
/* apply page scale */
|
|
||||||
if(graphics->unit != UnitDisplay)
|
|
||||||
{
|
|
||||||
scale_x *= graphics->scale;
|
|
||||||
scale_y *= graphics->scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
matrix = graphics->worldtrans;
|
|
||||||
GdipScaleMatrix(&matrix, scale_x, scale_y, MatrixOrderAppend);
|
|
||||||
GdipTransformMatrixPoints(&matrix, ptf, count);
|
|
||||||
|
|
||||||
for(i = 0; i < count; i++){
|
for(i = 0; i < count; i++){
|
||||||
pti[i].x = gdip_round(ptf[i].X);
|
pti[i].x = gdip_round(ptf[i].X);
|
||||||
pti[i].y = gdip_round(ptf[i].Y);
|
pti[i].y = gdip_round(ptf[i].Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
|
||||||
|
GpPointF *ptf, INT count)
|
||||||
|
{
|
||||||
|
gdip_transform_points(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, ptf, count);
|
||||||
|
round_points(pti, ptf, count);
|
||||||
|
}
|
||||||
|
|
||||||
static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_width, INT dst_height,
|
static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_width, INT dst_height,
|
||||||
HDC hdc, INT src_x, INT src_y, INT src_width, INT src_height)
|
HDC hdc, INT src_x, INT src_y, INT src_width, INT src_height)
|
||||||
{
|
{
|
||||||
|
@ -344,8 +336,26 @@ static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_
|
||||||
|
|
||||||
static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
|
static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
|
||||||
{
|
{
|
||||||
/* clipping region is in device coords */
|
GpRegion *rgn;
|
||||||
return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
|
GpMatrix transform;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, &transform);
|
||||||
|
|
||||||
|
if (stat == Ok)
|
||||||
|
stat = GdipCloneRegion(graphics->clip, &rgn);
|
||||||
|
|
||||||
|
if (stat == Ok)
|
||||||
|
{
|
||||||
|
stat = GdipTransformRegion(rgn, &transform);
|
||||||
|
|
||||||
|
if (stat == Ok)
|
||||||
|
stat = GdipGetRegionHRgn(rgn, NULL, hrgn);
|
||||||
|
|
||||||
|
GdipDeleteRegion(rgn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw ARGB data to the given graphics object */
|
/* Draw ARGB data to the given graphics object */
|
||||||
|
@ -555,6 +565,7 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
|
||||||
REAL blendfac;
|
REAL blendfac;
|
||||||
|
|
||||||
/* clamp to between 0.0 and 1.0, using the wrap mode */
|
/* clamp to between 0.0 and 1.0, using the wrap mode */
|
||||||
|
position = (position - brush->rect.X) / brush->rect.Width;
|
||||||
if (brush->wrap == WrapModeTile)
|
if (brush->wrap == WrapModeTile)
|
||||||
{
|
{
|
||||||
position = fmodf(position, 1.0f);
|
position = fmodf(position, 1.0f);
|
||||||
|
@ -905,9 +916,8 @@ static ARGB sample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT wi
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
y = height*2 + y % (height * 2);
|
y = height*2 + y % (height * 2);
|
||||||
|
|
||||||
if ((attributes->wrap & 1) == 1)
|
if (attributes->wrap & WrapModeTileFlipX)
|
||||||
{
|
{
|
||||||
/* Flip X */
|
|
||||||
if ((x / width) % 2 == 0)
|
if ((x / width) % 2 == 0)
|
||||||
x = x % width;
|
x = x % width;
|
||||||
else
|
else
|
||||||
|
@ -916,9 +926,8 @@ static ARGB sample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT wi
|
||||||
else
|
else
|
||||||
x = x % width;
|
x = x % width;
|
||||||
|
|
||||||
if ((attributes->wrap & 2) == 2)
|
if (attributes->wrap & WrapModeTileFlipY)
|
||||||
{
|
{
|
||||||
/* Flip Y */
|
|
||||||
if ((y / height) % 2 == 0)
|
if ((y / height) % 2 == 0)
|
||||||
y = y % height;
|
y = y % height;
|
||||||
else
|
else
|
||||||
|
@ -1220,10 +1229,8 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
||||||
case BrushTypeLinearGradient:
|
case BrushTypeLinearGradient:
|
||||||
{
|
{
|
||||||
GpLineGradient *fill = (GpLineGradient*)brush;
|
GpLineGradient *fill = (GpLineGradient*)brush;
|
||||||
GpPointF draw_points[3], line_points[3];
|
GpPointF draw_points[3];
|
||||||
GpStatus stat;
|
GpStatus stat;
|
||||||
static const GpRectF box_1 = { 0.0, 0.0, 1.0, 1.0 };
|
|
||||||
GpMatrix *world_to_gradient; /* FIXME: Store this in the brush? */
|
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
draw_points[0].X = fill_area->X;
|
draw_points[0].X = fill_area->X;
|
||||||
|
@ -1236,27 +1243,16 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
||||||
/* Transform the points to a co-ordinate space where X is the point's
|
/* Transform the points to a co-ordinate space where X is the point's
|
||||||
* position in the gradient, 0.0 being the start point and 1.0 the
|
* position in the gradient, 0.0 being the start point and 1.0 the
|
||||||
* end point. */
|
* end point. */
|
||||||
stat = GdipTransformPoints(graphics, CoordinateSpaceWorld,
|
stat = gdip_transform_points(graphics, CoordinateSpaceWorld,
|
||||||
CoordinateSpaceDevice, draw_points, 3);
|
WineCoordinateSpaceGdiDevice, draw_points, 3);
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
line_points[0] = fill->startpoint;
|
GpMatrix world_to_gradient = fill->transform;
|
||||||
line_points[1] = fill->endpoint;
|
|
||||||
line_points[2].X = fill->startpoint.X + (fill->startpoint.Y - fill->endpoint.Y);
|
|
||||||
line_points[2].Y = fill->startpoint.Y + (fill->endpoint.X - fill->startpoint.X);
|
|
||||||
|
|
||||||
stat = GdipCreateMatrix3(&box_1, line_points, &world_to_gradient);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat == Ok)
|
|
||||||
{
|
|
||||||
stat = GdipInvertMatrix(world_to_gradient);
|
|
||||||
|
|
||||||
|
stat = GdipInvertMatrix(&world_to_gradient);
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
stat = GdipTransformMatrixPoints(world_to_gradient, draw_points, 3);
|
stat = GdipTransformMatrixPoints(&world_to_gradient, draw_points, 3);
|
||||||
|
|
||||||
GdipDeleteMatrix(world_to_gradient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
|
@ -1308,8 +1304,8 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
||||||
draw_points[2].Y = fill_area->Y+1;
|
draw_points[2].Y = fill_area->Y+1;
|
||||||
|
|
||||||
/* Transform the points to the co-ordinate space of the bitmap. */
|
/* Transform the points to the co-ordinate space of the bitmap. */
|
||||||
stat = GdipTransformPoints(graphics, CoordinateSpaceWorld,
|
stat = gdip_transform_points(graphics, CoordinateSpaceWorld,
|
||||||
CoordinateSpaceDevice, draw_points, 3);
|
WineCoordinateSpaceGdiDevice, draw_points, 3);
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
|
@ -1439,7 +1435,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
||||||
if (stat != Ok)
|
if (stat != Ok)
|
||||||
return stat;
|
return stat;
|
||||||
|
|
||||||
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
|
stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
|
||||||
CoordinateSpaceWorld, &world_to_device);
|
CoordinateSpaceWorld, &world_to_device);
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
|
@ -1575,8 +1571,17 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
||||||
REAL blend_amount, pdy, pdx;
|
REAL blend_amount, pdy, pdx;
|
||||||
pdy = yf - center_point.Y;
|
pdy = yf - center_point.Y;
|
||||||
pdx = xf - center_point.X;
|
pdx = xf - center_point.X;
|
||||||
blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy );
|
|
||||||
outer_color = blend_colors(start_color, end_color, blend_amount);
|
if (fabs(pdx) <= 0.001 && fabs(pdy) <= 0.001)
|
||||||
|
{
|
||||||
|
/* Too close to center point, don't try to calculate outer color */
|
||||||
|
outer_color = start_color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy );
|
||||||
|
outer_color = blend_colors(start_color, end_color, blend_amount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
distance = (end_point.Y - start_point.Y) * (start_point.X - xf) +
|
distance = (end_point.Y - start_point.Y) * (start_point.X - xf) +
|
||||||
|
@ -1662,7 +1667,10 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
|
||||||
ptf[3].X = x2 - dbig;
|
ptf[3].X = x2 - dbig;
|
||||||
ptf[2].X = x2 + dsmall;
|
ptf[2].X = x2 + dsmall;
|
||||||
|
|
||||||
transform_and_round_points(graphics, pt, ptf, 4);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
|
||||||
|
|
||||||
|
round_points(pt, ptf, 3);
|
||||||
|
|
||||||
Polygon(graphics->hdc, pt, 4);
|
Polygon(graphics->hdc, pt, 4);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1684,7 +1692,10 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
|
||||||
ptf[2].X = x2;
|
ptf[2].X = x2;
|
||||||
ptf[2].Y = y2;
|
ptf[2].Y = y2;
|
||||||
|
|
||||||
transform_and_round_points(graphics, pt, ptf, 3);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
|
||||||
|
|
||||||
|
round_points(pt, ptf, 3);
|
||||||
|
|
||||||
Polygon(graphics->hdc, pt, 3);
|
Polygon(graphics->hdc, pt, 3);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1696,7 +1707,10 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
|
||||||
ptf[1].X = x2 + dx;
|
ptf[1].X = x2 + dx;
|
||||||
ptf[1].Y = y2 + dy;
|
ptf[1].Y = y2 + dy;
|
||||||
|
|
||||||
transform_and_round_points(graphics, pt, ptf, 2);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
|
||||||
|
|
||||||
|
round_points(pt, ptf, 3);
|
||||||
|
|
||||||
Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
|
Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1716,7 +1730,10 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
|
||||||
ptf[2].X = x2 + dx;
|
ptf[2].X = x2 + dx;
|
||||||
ptf[2].Y = y2 + dy;
|
ptf[2].Y = y2 + dy;
|
||||||
|
|
||||||
transform_and_round_points(graphics, pt, ptf, 3);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
|
||||||
|
|
||||||
|
round_points(pt, ptf, 3);
|
||||||
|
|
||||||
Polygon(graphics->hdc, pt, 3);
|
Polygon(graphics->hdc, pt, 3);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1736,7 +1753,10 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
|
||||||
ptf[3].X = x2 + dx;
|
ptf[3].X = x2 + dx;
|
||||||
ptf[3].Y = y2 + dy;
|
ptf[3].Y = y2 + dy;
|
||||||
|
|
||||||
transform_and_round_points(graphics, pt, ptf, 4);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
|
||||||
|
|
||||||
|
round_points(pt, ptf, 3);
|
||||||
|
|
||||||
Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
|
Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
|
||||||
pt[2].y, pt[3].x, pt[3].y);
|
pt[2].y, pt[3].x, pt[3].y);
|
||||||
|
|
||||||
|
@ -1762,7 +1782,9 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s
|
||||||
GdipTranslateMatrix(&matrix, x2, y2, MatrixOrderAppend);
|
GdipTranslateMatrix(&matrix, x2, y2, MatrixOrderAppend);
|
||||||
GdipTransformMatrixPoints(&matrix, custptf, count);
|
GdipTransformMatrixPoints(&matrix, custptf, count);
|
||||||
|
|
||||||
transform_and_round_points(graphics, custpt, custptf, count);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
|
||||||
|
|
||||||
|
round_points(pt, ptf, 3);
|
||||||
|
|
||||||
for(i = 0; i < count; i++)
|
for(i = 0; i < count; i++)
|
||||||
tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
|
tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
|
||||||
|
@ -1985,7 +2007,9 @@ static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transform_and_round_points(graphics, pti, ptcopy, count);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptcopy, count);
|
||||||
|
|
||||||
|
round_points(pti, ptcopy, count);
|
||||||
|
|
||||||
for(i = 0; i < count; i++){
|
for(i = 0; i < count; i++){
|
||||||
tp[i] = convert_path_point_type(types[i]);
|
tp[i] = convert_path_point_type(types[i]);
|
||||||
|
@ -2108,7 +2132,7 @@ static GpStatus restore_container(GpGraphics* graphics,
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
|
static GpStatus get_graphics_device_bounds(GpGraphics* graphics, GpRectF* rect)
|
||||||
{
|
{
|
||||||
RECT wnd_rect;
|
RECT wnd_rect;
|
||||||
GpStatus stat=Ok;
|
GpStatus stat=Ok;
|
||||||
|
@ -2152,21 +2176,39 @@ static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
|
||||||
rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
|
rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graphics->hdc)
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
|
||||||
|
{
|
||||||
|
GpStatus stat = get_graphics_device_bounds(graphics, rect);
|
||||||
|
|
||||||
|
if (stat == Ok && graphics->hdc)
|
||||||
{
|
{
|
||||||
POINT points[2];
|
GpPointF points[4], min_point, max_point;
|
||||||
|
int i;
|
||||||
|
|
||||||
points[0].x = rect->X;
|
points[0].X = points[2].X = rect->X;
|
||||||
points[0].y = rect->Y;
|
points[0].Y = points[1].Y = rect->Y;
|
||||||
points[1].x = rect->X + rect->Width;
|
points[1].X = points[3].X = rect->X + rect->Width;
|
||||||
points[1].y = rect->Y + rect->Height;
|
points[2].Y = points[3].Y = rect->Y + rect->Height;
|
||||||
|
|
||||||
DPtoLP(graphics->hdc, points, sizeof(points)/sizeof(points[0]));
|
gdip_transform_points(graphics, CoordinateSpaceDevice, WineCoordinateSpaceGdiDevice, points, 4);
|
||||||
|
|
||||||
rect->X = min(points[0].x, points[1].x);
|
min_point = max_point = points[0];
|
||||||
rect->Y = min(points[0].y, points[1].y);
|
|
||||||
rect->Width = abs(points[1].x - points[0].x);
|
for (i=1; i<4; i++)
|
||||||
rect->Height = abs(points[1].y - points[0].y);
|
{
|
||||||
|
if (points[i].X < min_point.X) min_point.X = points[i].X;
|
||||||
|
if (points[i].Y < min_point.Y) min_point.Y = points[i].Y;
|
||||||
|
if (points[i].X > max_point.X) max_point.X = points[i].X;
|
||||||
|
if (points[i].Y > max_point.Y) max_point.Y = points[i].Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect->X = min_point.X;
|
||||||
|
rect->Y = min_point.Y;
|
||||||
|
rect->Width = max_point.X - min_point.X;
|
||||||
|
rect->Height = max_point.Y - min_point.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stat;
|
return stat;
|
||||||
|
@ -2180,6 +2222,10 @@ static GpStatus get_visible_clip_region(GpGraphics *graphics, GpRegion *rgn)
|
||||||
GpRectF rectf;
|
GpRectF rectf;
|
||||||
GpRegion* tmp;
|
GpRegion* tmp;
|
||||||
|
|
||||||
|
/* Ignore graphics image bounds for metafiles */
|
||||||
|
if (graphics->image && graphics->image_type == ImageTypeMetafile)
|
||||||
|
return GdipCombineRegionRegion(rgn, graphics->clip, CombineModeReplace);
|
||||||
|
|
||||||
if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
|
if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
|
||||||
return stat;
|
return stat;
|
||||||
|
|
||||||
|
@ -2954,6 +3000,13 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||||
TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]),
|
TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]),
|
||||||
debugstr_pointf(&points[2]));
|
debugstr_pointf(&points[2]));
|
||||||
|
|
||||||
|
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
return METAFILE_DrawImagePointsRect((GpMetafile*)graphics->image,
|
||||||
|
image, points, count, srcx, srcy, srcwidth, srcheight,
|
||||||
|
srcUnit, imageAttributes, callback, callbackData);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(ptf, points, 3 * sizeof(GpPointF));
|
memcpy(ptf, points, 3 * sizeof(GpPointF));
|
||||||
|
|
||||||
/* Ensure source width/height is positive */
|
/* Ensure source width/height is positive */
|
||||||
|
@ -2983,7 +3036,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||||
ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
|
ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
|
||||||
if (!srcwidth || !srcheight || (ptf[3].X == ptf[0].X && ptf[3].Y == ptf[0].Y))
|
if (!srcwidth || !srcheight || (ptf[3].X == ptf[0].X && ptf[3].Y == ptf[0].Y))
|
||||||
return Ok;
|
return Ok;
|
||||||
transform_and_round_points(graphics, pti, ptf, 4);
|
gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
|
||||||
|
round_points(pti, ptf, 4);
|
||||||
|
|
||||||
TRACE("%s %s %s %s\n", wine_dbgstr_point(&pti[0]), wine_dbgstr_point(&pti[1]),
|
TRACE("%s %s %s %s\n", wine_dbgstr_point(&pti[0]), wine_dbgstr_point(&pti[1]),
|
||||||
wine_dbgstr_point(&pti[2]), wine_dbgstr_point(&pti[3]));
|
wine_dbgstr_point(&pti[2]), wine_dbgstr_point(&pti[3]));
|
||||||
|
@ -3045,7 +3099,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||||
if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
|
if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
|
||||||
}
|
}
|
||||||
|
|
||||||
stat = get_graphics_bounds(graphics, &graphics_bounds);
|
stat = get_graphics_device_bounds(graphics, &graphics_bounds);
|
||||||
if (stat != Ok) return stat;
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
|
if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
|
||||||
|
@ -3183,10 +3237,14 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||||
dst_stride = src_stride;
|
dst_stride = src_stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
|
stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
|
||||||
dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride,
|
dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride,
|
||||||
lockeddata.PixelFormat);
|
lockeddata.PixelFormat);
|
||||||
|
|
||||||
|
gdi_transform_release(graphics);
|
||||||
|
|
||||||
heap_free(src_data);
|
heap_free(src_data);
|
||||||
|
|
||||||
heap_free(dst_dyn_data);
|
heap_free(dst_dyn_data);
|
||||||
|
@ -3270,6 +3328,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||||
DeleteObject(hrgn);
|
DeleteObject(hrgn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
|
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,
|
gdi_alpha_blend(graphics, pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
|
||||||
|
@ -3281,6 +3341,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||||
hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY);
|
hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdi_transform_release(graphics);
|
||||||
|
|
||||||
RestoreDC(graphics->hdc, save_state);
|
RestoreDC(graphics->hdc, save_state);
|
||||||
|
|
||||||
if (temp_hdc)
|
if (temp_hdc)
|
||||||
|
@ -3506,9 +3568,13 @@ static GpStatus GDI32_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *pat
|
||||||
if (hrgn)
|
if (hrgn)
|
||||||
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
|
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
|
||||||
|
|
||||||
|
gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
retval = draw_poly(graphics, pen, path->pathdata.Points,
|
retval = draw_poly(graphics, pen, path->pathdata.Points,
|
||||||
path->pathdata.Types, path->pathdata.Count, TRUE);
|
path->pathdata.Types, path->pathdata.Count, TRUE);
|
||||||
|
|
||||||
|
gdi_transform_release(graphics);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
restore_dc(graphics, save_state);
|
restore_dc(graphics, save_state);
|
||||||
DeleteObject(hrgn);
|
DeleteObject(hrgn);
|
||||||
|
@ -3541,7 +3607,7 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
|
stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
|
||||||
CoordinateSpaceWorld, transform);
|
CoordinateSpaceWorld, transform);
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
|
@ -3570,7 +3636,7 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa
|
||||||
if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y);
|
if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
stat = get_graphics_bounds(graphics, &gp_bound_rect);
|
stat = get_graphics_device_bounds(graphics, &gp_bound_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
|
@ -3708,6 +3774,9 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa
|
||||||
end_pointi.X = floorf(end_point.X);
|
end_pointi.X = floorf(end_point.X);
|
||||||
end_pointi.Y = floorf(end_point.Y);
|
end_pointi.Y = floorf(end_point.Y);
|
||||||
|
|
||||||
|
if(start_pointi.X == end_pointi.X && start_pointi.Y == end_pointi.Y)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* draw line segment */
|
/* draw line segment */
|
||||||
if (abs(start_pointi.Y - end_pointi.Y) > abs(start_pointi.X - end_pointi.X))
|
if (abs(start_pointi.Y - end_pointi.Y) > abs(start_pointi.X - end_pointi.X))
|
||||||
{
|
{
|
||||||
|
@ -3799,9 +3868,13 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa
|
||||||
/* draw output image */
|
/* draw output image */
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
|
gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
stat = alpha_blend_pixels(graphics, output_area.left, output_area.top,
|
stat = alpha_blend_pixels(graphics, output_area.left, output_area.top,
|
||||||
(BYTE*)output_bits, output_width, output_height, output_width * 4,
|
(BYTE*)output_bits, output_width, output_height, output_width * 4,
|
||||||
PixelFormat32bppARGB);
|
PixelFormat32bppARGB);
|
||||||
|
|
||||||
|
gdi_transform_release(graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_free(brush_bits);
|
heap_free(brush_bits);
|
||||||
|
@ -3819,6 +3892,7 @@ static GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *
|
||||||
GpStatus stat;
|
GpStatus stat;
|
||||||
GpPath *wide_path;
|
GpPath *wide_path;
|
||||||
GpMatrix *transform=NULL;
|
GpMatrix *transform=NULL;
|
||||||
|
REAL flatness=1.0;
|
||||||
|
|
||||||
/* Check if the final pen thickness in pixels is too thin. */
|
/* Check if the final pen thickness in pixels is too thin. */
|
||||||
if (pen->unit == UnitPixel)
|
if (pen->unit == UnitPixel)
|
||||||
|
@ -3860,9 +3934,24 @@ static GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *
|
||||||
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
|
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
|
||||||
CoordinateSpaceWorld, transform);
|
CoordinateSpaceWorld, transform);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set flatness based on the final coordinate space */
|
||||||
|
GpMatrix t;
|
||||||
|
|
||||||
|
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
|
||||||
|
CoordinateSpaceWorld, &t);
|
||||||
|
|
||||||
|
if (stat != Ok)
|
||||||
|
return stat;
|
||||||
|
|
||||||
|
flatness = 1.0/sqrt(fmax(
|
||||||
|
t.matrix[0] * t.matrix[0] + t.matrix[1] * t.matrix[1],
|
||||||
|
t.matrix[2] * t.matrix[2] + t.matrix[3] * t.matrix[3]));
|
||||||
|
}
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
stat = GdipWidenPath(wide_path, pen, transform, 1.0);
|
stat = GdipWidenPath(wide_path, pen, transform, flatness);
|
||||||
|
|
||||||
if (pen->unit == UnitPixel)
|
if (pen->unit == UnitPixel)
|
||||||
{
|
{
|
||||||
|
@ -3900,7 +3989,9 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
|
||||||
if (path->pathdata.Count == 0)
|
if (path->pathdata.Count == 0)
|
||||||
return Ok;
|
return Ok;
|
||||||
|
|
||||||
if (!graphics->hdc || !brush_can_fill_path(pen->brush, FALSE))
|
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
retval = METAFILE_DrawPath((GpMetafile*)graphics->image, pen, path);
|
||||||
|
else if (!graphics->hdc || graphics->alpha_hdc || !brush_can_fill_path(pen->brush, FALSE))
|
||||||
retval = SOFTWARE_GdipDrawPath(graphics, pen, path);
|
retval = SOFTWARE_GdipDrawPath(graphics, pen, path);
|
||||||
else
|
else
|
||||||
retval = GDI32_GdipDrawPath(graphics, pen, path);
|
retval = GDI32_GdipDrawPath(graphics, pen, path);
|
||||||
|
@ -4166,17 +4257,19 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
|
||||||
if (hrgn)
|
if (hrgn)
|
||||||
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
|
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
|
||||||
|
|
||||||
|
gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
BeginPath(graphics->hdc);
|
BeginPath(graphics->hdc);
|
||||||
retval = draw_poly(graphics, NULL, path->pathdata.Points,
|
retval = draw_poly(graphics, NULL, path->pathdata.Points,
|
||||||
path->pathdata.Types, path->pathdata.Count, FALSE);
|
path->pathdata.Types, path->pathdata.Count, FALSE);
|
||||||
|
|
||||||
if(retval != Ok)
|
if(retval == Ok)
|
||||||
goto end;
|
{
|
||||||
|
EndPath(graphics->hdc);
|
||||||
|
brush_fill_path(graphics, brush);
|
||||||
|
}
|
||||||
|
|
||||||
EndPath(graphics->hdc);
|
gdi_transform_release(graphics);
|
||||||
brush_fill_path(graphics, brush);
|
|
||||||
|
|
||||||
retval = Ok;
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
RestoreDC(graphics->hdc, save_state);
|
RestoreDC(graphics->hdc, save_state);
|
||||||
|
@ -4219,6 +4312,9 @@ GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *p
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
return METAFILE_FillPath((GpMetafile*)graphics->image, brush, path);
|
||||||
|
|
||||||
if (!graphics->image && !graphics->alpha_hdc)
|
if (!graphics->image && !graphics->alpha_hdc)
|
||||||
stat = GDI32_GdipFillPath(graphics, brush, path);
|
stat = GDI32_GdipFillPath(graphics, brush, path);
|
||||||
|
|
||||||
|
@ -4425,7 +4521,7 @@ GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics *graphics, GpBrush *brush, GD
|
||||||
for(i = 0; i < count; i++){
|
for(i = 0; i < count; i++){
|
||||||
rectsF[i].X = (REAL)rects[i].X;
|
rectsF[i].X = (REAL)rects[i].X;
|
||||||
rectsF[i].Y = (REAL)rects[i].Y;
|
rectsF[i].Y = (REAL)rects[i].Y;
|
||||||
rectsF[i].X = (REAL)rects[i].Width;
|
rectsF[i].Width = (REAL)rects[i].Width;
|
||||||
rectsF[i].Height = (REAL)rects[i].Height;
|
rectsF[i].Height = (REAL)rects[i].Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4502,14 +4598,17 @@ static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
|
||||||
if (!brush_can_fill_pixels(brush))
|
if (!brush_can_fill_pixels(brush))
|
||||||
return NotImplemented;
|
return NotImplemented;
|
||||||
|
|
||||||
stat = get_graphics_bounds(graphics, &graphics_bounds);
|
stat = gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
|
if (stat == Ok)
|
||||||
|
stat = get_graphics_device_bounds(graphics, &graphics_bounds);
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
stat = GdipCloneRegion(region, &temp_region);
|
stat = GdipCloneRegion(region, &temp_region);
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
|
stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
|
||||||
CoordinateSpaceWorld, &world_to_device);
|
CoordinateSpaceWorld, &world_to_device);
|
||||||
|
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
|
@ -4527,6 +4626,7 @@ static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
|
||||||
if (stat == Ok && GetRgnBox(hregion, &bound_rect) == NULLREGION)
|
if (stat == Ok && GetRgnBox(hregion, &bound_rect) == NULLREGION)
|
||||||
{
|
{
|
||||||
DeleteObject(hregion);
|
DeleteObject(hregion);
|
||||||
|
gdi_transform_release(graphics);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4558,6 +4658,8 @@ static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
|
||||||
DeleteObject(hregion);
|
DeleteObject(hregion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdi_transform_release(graphics);
|
||||||
|
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5889,6 +5991,19 @@ GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics,
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if(graphics->compmode == mode)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if(graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
|
||||||
|
EmfPlusRecordTypeSetCompositingMode, mode);
|
||||||
|
if(stat != Ok)
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
graphics->compmode = mode;
|
graphics->compmode = mode;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -5905,6 +6020,19 @@ GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics,
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if(graphics->compqual == quality)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if(graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
|
||||||
|
EmfPlusRecordTypeSetCompositingQuality, quality);
|
||||||
|
if(stat != Ok)
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
graphics->compqual = quality;
|
graphics->compqual = quality;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -5927,6 +6055,19 @@ GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
|
||||||
if (mode == InterpolationModeHighQuality)
|
if (mode == InterpolationModeHighQuality)
|
||||||
mode = InterpolationModeHighQualityBicubic;
|
mode = InterpolationModeHighQualityBicubic;
|
||||||
|
|
||||||
|
if (mode == graphics->interpolation)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
|
||||||
|
EmfPlusRecordTypeSetInterpolationMode, mode);
|
||||||
|
if (stat != Ok)
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
graphics->interpolation = mode;
|
graphics->interpolation = mode;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -5994,6 +6135,19 @@ GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if(graphics->pixeloffset == mode)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if(graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
|
||||||
|
EmfPlusRecordTypeSetPixelOffsetMode, mode);
|
||||||
|
if(stat != Ok)
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
graphics->pixeloffset = mode;
|
graphics->pixeloffset = mode;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -6040,6 +6194,20 @@ GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mod
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if(graphics->smoothing == mode)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if(graphics->image && graphics->image->type == ImageTypeMetafile) {
|
||||||
|
GpStatus stat;
|
||||||
|
BOOL antialias = (mode != SmoothingModeDefault &&
|
||||||
|
mode != SmoothingModeNone && mode != SmoothingModeHighSpeed);
|
||||||
|
|
||||||
|
stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
|
||||||
|
EmfPlusRecordTypeSetAntiAliasMode, (mode << 1) + antialias);
|
||||||
|
if(stat != Ok)
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
graphics->smoothing = mode;
|
graphics->smoothing = mode;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -6068,6 +6236,18 @@ GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics,
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if(graphics->texthint == hint)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if(graphics->image && graphics->image->type == ImageTypeMetafile) {
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
|
||||||
|
EmfPlusRecordTypeSetTextRenderingHint, hint);
|
||||||
|
if(stat != Ok)
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
graphics->texthint = hint;
|
graphics->texthint = hint;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
|
@ -6251,6 +6431,13 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
return ObjectBusy;
|
return ObjectBusy;
|
||||||
|
|
||||||
|
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
status = METAFILE_SetClipRegion((GpMetafile*)graphics->image, region, mode);
|
||||||
|
if (status != Ok)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
status = GdipCloneRegion(region, &clip);
|
status = GdipCloneRegion(region, &clip);
|
||||||
if (status == Ok)
|
if (status == Ok)
|
||||||
{
|
{
|
||||||
|
@ -6536,6 +6723,56 @@ GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_gdi_transform(GpGraphics *graphics, GpMatrix *matrix)
|
||||||
|
{
|
||||||
|
XFORM xform;
|
||||||
|
|
||||||
|
if (graphics->hdc == NULL)
|
||||||
|
{
|
||||||
|
GdipSetMatrixElements(matrix, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graphics->gdi_transform_acquire_count)
|
||||||
|
{
|
||||||
|
*matrix = graphics->gdi_transform;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetTransform(graphics->hdc, 0x204, &xform);
|
||||||
|
GdipSetMatrixElements(matrix, xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus gdi_transform_acquire(GpGraphics *graphics)
|
||||||
|
{
|
||||||
|
if (graphics->gdi_transform_acquire_count == 0 && graphics->hdc)
|
||||||
|
{
|
||||||
|
get_gdi_transform(graphics, &graphics->gdi_transform);
|
||||||
|
graphics->gdi_transform_save = SaveDC(graphics->hdc);
|
||||||
|
SetGraphicsMode(graphics->hdc, GM_COMPATIBLE);
|
||||||
|
SetMapMode(graphics->hdc, MM_TEXT);
|
||||||
|
SetWindowOrgEx(graphics->hdc, 0, 0, NULL);
|
||||||
|
SetViewportOrgEx(graphics->hdc, 0, 0, NULL);
|
||||||
|
}
|
||||||
|
graphics->gdi_transform_acquire_count++;
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus gdi_transform_release(GpGraphics *graphics)
|
||||||
|
{
|
||||||
|
if (graphics->gdi_transform_acquire_count <= 0)
|
||||||
|
{
|
||||||
|
ERR("called without matching gdi_transform_acquire");
|
||||||
|
return GenericError;
|
||||||
|
}
|
||||||
|
if (graphics->gdi_transform_acquire_count == 1 && graphics->hdc)
|
||||||
|
{
|
||||||
|
RestoreDC(graphics->hdc, graphics->gdi_transform_save);
|
||||||
|
}
|
||||||
|
graphics->gdi_transform_acquire_count--;
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
||||||
GpCoordinateSpace src_space, GpMatrix *matrix)
|
GpCoordinateSpace src_space, GpMatrix *matrix)
|
||||||
{
|
{
|
||||||
|
@ -6555,23 +6792,29 @@ GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_spac
|
||||||
scale_y *= graphics->scale;
|
scale_y *= graphics->scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* transform from src_space to CoordinateSpacePage */
|
if (dst_space < src_space)
|
||||||
switch (src_space)
|
|
||||||
{
|
{
|
||||||
case CoordinateSpaceWorld:
|
/* transform towards world space */
|
||||||
GdipMultiplyMatrix(matrix, &graphics->worldtrans, MatrixOrderAppend);
|
switch ((int)src_space)
|
||||||
break;
|
{
|
||||||
case CoordinateSpacePage:
|
case WineCoordinateSpaceGdiDevice:
|
||||||
break;
|
{
|
||||||
case CoordinateSpaceDevice:
|
GpMatrix gdixform;
|
||||||
GdipScaleMatrix(matrix, 1.0/scale_x, 1.0/scale_y, MatrixOrderAppend);
|
get_gdi_transform(graphics, &gdixform);
|
||||||
break;
|
stat = GdipInvertMatrix(&gdixform);
|
||||||
}
|
if (stat != Ok)
|
||||||
|
break;
|
||||||
/* transform from CoordinateSpacePage to dst_space */
|
GdipMultiplyMatrix(matrix, &gdixform, MatrixOrderAppend);
|
||||||
switch (dst_space)
|
if (dst_space == CoordinateSpaceDevice)
|
||||||
{
|
break;
|
||||||
case CoordinateSpaceWorld:
|
/* else fall-through */
|
||||||
|
}
|
||||||
|
case CoordinateSpaceDevice:
|
||||||
|
GdipScaleMatrix(matrix, 1.0/scale_x, 1.0/scale_y, MatrixOrderAppend);
|
||||||
|
if (dst_space == CoordinateSpacePage)
|
||||||
|
break;
|
||||||
|
/* else fall-through */
|
||||||
|
case CoordinateSpacePage:
|
||||||
{
|
{
|
||||||
GpMatrix inverted_transform = graphics->worldtrans;
|
GpMatrix inverted_transform = graphics->worldtrans;
|
||||||
stat = GdipInvertMatrix(&inverted_transform);
|
stat = GdipInvertMatrix(&inverted_transform);
|
||||||
|
@ -6579,23 +6822,54 @@ GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_spac
|
||||||
GdipMultiplyMatrix(matrix, &inverted_transform, MatrixOrderAppend);
|
GdipMultiplyMatrix(matrix, &inverted_transform, MatrixOrderAppend);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CoordinateSpacePage:
|
}
|
||||||
break;
|
}
|
||||||
case CoordinateSpaceDevice:
|
else
|
||||||
GdipScaleMatrix(matrix, scale_x, scale_y, MatrixOrderAppend);
|
{
|
||||||
break;
|
/* transform towards device space */
|
||||||
|
switch ((int)src_space)
|
||||||
|
{
|
||||||
|
case CoordinateSpaceWorld:
|
||||||
|
GdipMultiplyMatrix(matrix, &graphics->worldtrans, MatrixOrderAppend);
|
||||||
|
if (dst_space == CoordinateSpacePage)
|
||||||
|
break;
|
||||||
|
/* else fall-through */
|
||||||
|
case CoordinateSpacePage:
|
||||||
|
GdipScaleMatrix(matrix, scale_x, scale_y, MatrixOrderAppend);
|
||||||
|
if (dst_space == CoordinateSpaceDevice)
|
||||||
|
break;
|
||||||
|
/* else fall-through */
|
||||||
|
case CoordinateSpaceDevice:
|
||||||
|
{
|
||||||
|
GpMatrix gdixform;
|
||||||
|
get_gdi_transform(graphics, &gdixform);
|
||||||
|
GdipMultiplyMatrix(matrix, &gdixform, MatrixOrderAppend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
||||||
GpCoordinateSpace src_space, GpPointF *points, INT count)
|
GpCoordinateSpace src_space, GpPointF *points, INT count)
|
||||||
{
|
{
|
||||||
GpMatrix matrix;
|
GpMatrix matrix;
|
||||||
GpStatus stat;
|
GpStatus stat;
|
||||||
|
|
||||||
if(!graphics || !points || count <= 0)
|
stat = get_graphics_transform(graphics, dst_space, src_space, &matrix);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
return GdipTransformMatrixPoints(&matrix, points, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
||||||
|
GpCoordinateSpace src_space, GpPointF *points, INT count)
|
||||||
|
{
|
||||||
|
if(!graphics || !points || count <= 0 ||
|
||||||
|
dst_space < 0 || dst_space > CoordinateSpaceDevice ||
|
||||||
|
src_space < 0 || src_space > CoordinateSpaceDevice)
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
if(graphics->busy)
|
if(graphics->busy)
|
||||||
|
@ -6605,10 +6879,7 @@ GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace
|
||||||
|
|
||||||
if (src_space == dst_space) return Ok;
|
if (src_space == dst_space) return Ok;
|
||||||
|
|
||||||
stat = get_graphics_transform(graphics, dst_space, src_space, &matrix);
|
return gdip_transform_points(graphics, dst_space, src_space, points, count);
|
||||||
if (stat != Ok) return stat;
|
|
||||||
|
|
||||||
return GdipTransformMatrixPoints(&matrix, points, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
|
||||||
|
@ -7129,3 +7400,16 @@ GpStatus WINGDIPAPI GdipResetPageTransform(GpGraphics *graphics)
|
||||||
|
|
||||||
return NotImplemented;
|
return NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GpStatus WINGDIPAPI GdipGraphicsSetAbort(GpGraphics *graphics, GdiplusAbort *pabort)
|
||||||
|
{
|
||||||
|
TRACE("(%p, %p)\n", graphics, pabort);
|
||||||
|
|
||||||
|
if (!graphics)
|
||||||
|
return InvalidParameter;
|
||||||
|
|
||||||
|
if (pabort)
|
||||||
|
FIXME("Abort callback is not supported.\n");
|
||||||
|
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
|
@ -152,6 +152,32 @@ static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, R
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* GdipAddPathArc [GDIPLUS.1]
|
||||||
|
*
|
||||||
|
* Add an elliptical arc to the given path.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* path [I/O] Path that the arc is appended to
|
||||||
|
* x1 [I] X coordinate of the boundary box
|
||||||
|
* y1 [I] Y coordinate of the boundary box
|
||||||
|
* x2 [I] Width of the boundary box
|
||||||
|
* y2 [I] Height of the boundary box
|
||||||
|
* startAngle [I] Starting angle of the arc, clockwise
|
||||||
|
* sweepAngle [I] Angle of the arc, clockwise
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* InvalidParameter If the given path is invalid
|
||||||
|
* OutOfMemory If memory allocation fails, i.e. the path cannot be lengthened
|
||||||
|
* Ok If everything works out as expected
|
||||||
|
*
|
||||||
|
* NOTES
|
||||||
|
* This functions takes the newfigure value of the given path into account,
|
||||||
|
* i.e. the arc is connected to the end of the given path if it was set to
|
||||||
|
* FALSE, otherwise the arc's first point gets the PathPointTypeStart value.
|
||||||
|
* In both cases, the value of newfigure of the given path is FALSE
|
||||||
|
* afterwards.
|
||||||
|
*/
|
||||||
GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
|
GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
|
||||||
REAL y2, REAL startAngle, REAL sweepAngle)
|
REAL y2, REAL startAngle, REAL sweepAngle)
|
||||||
{
|
{
|
||||||
|
@ -186,6 +212,11 @@ GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* GdipAddPathArcI [GDUPLUS.2]
|
||||||
|
*
|
||||||
|
* See GdipAddPathArc
|
||||||
|
*/
|
||||||
GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
|
GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
|
||||||
INT y2, REAL startAngle, REAL sweepAngle)
|
INT y2, REAL startAngle, REAL sweepAngle)
|
||||||
{
|
{
|
||||||
|
@ -632,6 +663,30 @@ GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath *path, GDIPCONST GpPoint *points, I
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* GdipAddPathLine [GDIPLUS.21]
|
||||||
|
*
|
||||||
|
* Add two points to the given path.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* path [I/O] Path that the line is appended to
|
||||||
|
* x1 [I] X coordinate of the first point of the line
|
||||||
|
* y1 [I] Y coordinate of the first point of the line
|
||||||
|
* x2 [I] X coordinate of the second point of the line
|
||||||
|
* y2 [I] Y coordinate of the second point of the line
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* InvalidParameter If the first parameter is not a valid path
|
||||||
|
* OutOfMemory If the path cannot be lengthened, i.e. memory allocation fails
|
||||||
|
* Ok If everything works out as expected
|
||||||
|
*
|
||||||
|
* NOTES
|
||||||
|
* This functions takes the newfigure value of the given path into account,
|
||||||
|
* i.e. the two new points are connected to the end of the given path if it
|
||||||
|
* was set to FALSE, otherwise the first point is given the PathPointTypeStart
|
||||||
|
* value. In both cases, the value of newfigure of the given path is FALSE
|
||||||
|
* afterwards.
|
||||||
|
*/
|
||||||
GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
|
GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
|
||||||
{
|
{
|
||||||
INT old_count;
|
INT old_count;
|
||||||
|
@ -661,6 +716,11 @@ GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REA
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* GdipAddPathLineI [GDIPLUS.21]
|
||||||
|
*
|
||||||
|
* See GdipAddPathLine
|
||||||
|
*/
|
||||||
GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
|
GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
|
||||||
{
|
{
|
||||||
TRACE("(%p, %d, %d, %d, %d)\n", path, x1, y1, x2, y2);
|
TRACE("(%p, %d, %d, %d, %d)\n", path, x1, y1, x2, y2);
|
||||||
|
@ -1044,6 +1104,20 @@ GpStatus WINGDIPAPI GdipAddPathStringI(GpPath* path, GDIPCONST WCHAR* string, IN
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* GdipClonePath [GDIPLUS.53]
|
||||||
|
*
|
||||||
|
* Duplicate the given path in memory.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* path [I] The path to be duplicated
|
||||||
|
* clone [O] Pointer to the new path
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* InvalidParameter If the input path is invalid
|
||||||
|
* OutOfMemory If allocation of needed memory fails
|
||||||
|
* Ok If everything works out as expected
|
||||||
|
*/
|
||||||
GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
|
GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
|
||||||
{
|
{
|
||||||
TRACE("(%p, %p)\n", path, clone);
|
TRACE("(%p, %p)\n", path, clone);
|
||||||
|
@ -1869,6 +1943,27 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LineCapTriangle:
|
||||||
|
{
|
||||||
|
REAL segment_dy = nextpoint->Y-endpoint->Y;
|
||||||
|
REAL segment_dx = nextpoint->X-endpoint->X;
|
||||||
|
REAL segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
|
||||||
|
REAL distance = pen->width/2.0;
|
||||||
|
REAL dx, dy;
|
||||||
|
|
||||||
|
dx = distance * segment_dx / segment_length;
|
||||||
|
dy = distance * segment_dy / segment_length;
|
||||||
|
|
||||||
|
if (add_first_points) {
|
||||||
|
add_bevel_point(endpoint, nextpoint, pen, 1, last_point);
|
||||||
|
|
||||||
|
*last_point = add_path_list_node(*last_point, endpoint->X - dx,
|
||||||
|
endpoint->Y - dy, PathPointTypeLine);
|
||||||
|
}
|
||||||
|
if (add_last_point)
|
||||||
|
add_bevel_point(endpoint, nextpoint, pen, 0, last_point);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1954,6 +2049,7 @@ static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
|
||||||
REAL dash_pos=0.0;
|
REAL dash_pos=0.0;
|
||||||
int dash_index=0;
|
int dash_index=0;
|
||||||
const REAL *dash_pattern;
|
const REAL *dash_pattern;
|
||||||
|
REAL *dash_pattern_scaled;
|
||||||
int dash_count;
|
int dash_count;
|
||||||
GpPointF *tmp_points;
|
GpPointF *tmp_points;
|
||||||
REAL segment_dy;
|
REAL segment_dy;
|
||||||
|
@ -1992,8 +2088,17 @@ static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dash_pattern_scaled = heap_alloc(dash_count * sizeof(REAL));
|
||||||
|
if (!dash_pattern_scaled) return;
|
||||||
|
|
||||||
|
for (i = 0; i < dash_count; i++)
|
||||||
|
dash_pattern_scaled[i] = pen->width * dash_pattern[i];
|
||||||
|
|
||||||
tmp_points = heap_alloc_zero((end - start + 2) * sizeof(GpPoint));
|
tmp_points = heap_alloc_zero((end - start + 2) * sizeof(GpPoint));
|
||||||
if (!tmp_points) return; /* FIXME */
|
if (!tmp_points) {
|
||||||
|
heap_free(dash_pattern_scaled);
|
||||||
|
return; /* FIXME */
|
||||||
|
}
|
||||||
|
|
||||||
if (!closed)
|
if (!closed)
|
||||||
draw_start_cap = 1;
|
draw_start_cap = 1;
|
||||||
|
@ -2040,7 +2145,7 @@ static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dash_pattern[dash_index] - dash_pos > segment_length - segment_pos)
|
if (dash_pattern_scaled[dash_index] - dash_pos > segment_length - segment_pos)
|
||||||
{
|
{
|
||||||
/* advance to next segment */
|
/* advance to next segment */
|
||||||
if ((dash_index % 2) == 0)
|
if ((dash_index % 2) == 0)
|
||||||
|
@ -2054,7 +2159,7 @@ static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* advance to next dash in pattern */
|
/* advance to next dash in pattern */
|
||||||
segment_pos += dash_pattern[dash_index] - dash_pos;
|
segment_pos += dash_pattern_scaled[dash_index] - dash_pos;
|
||||||
dash_pos = 0.0;
|
dash_pos = 0.0;
|
||||||
if (++dash_index == dash_count)
|
if (++dash_index == dash_count)
|
||||||
dash_index = 0;
|
dash_index = 0;
|
||||||
|
@ -2066,12 +2171,12 @@ static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
|
||||||
if (dash_index % 2 == 0 && num_tmp_points != 0)
|
if (dash_index % 2 == 0 && num_tmp_points != 0)
|
||||||
{
|
{
|
||||||
/* last dash overflows last segment */
|
/* last dash overflows last segment */
|
||||||
tmp_points[num_tmp_points] = path->pathdata.Points[end];
|
widen_open_figure(tmp_points, pen, 0, num_tmp_points-1,
|
||||||
widen_open_figure(tmp_points, pen, 0, num_tmp_points,
|
|
||||||
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
|
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
|
||||||
closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
|
closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
heap_free(dash_pattern_scaled);
|
||||||
heap_free(tmp_points);
|
heap_free(tmp_points);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2104,10 +2209,10 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
|
||||||
{
|
{
|
||||||
last_point = points;
|
last_point = points;
|
||||||
|
|
||||||
if (pen->endcap > LineCapRound)
|
if (pen->endcap > LineCapTriangle)
|
||||||
FIXME("unimplemented end cap %x\n", pen->endcap);
|
FIXME("unimplemented end cap %x\n", pen->endcap);
|
||||||
|
|
||||||
if (pen->startcap > LineCapRound)
|
if (pen->startcap > LineCapTriangle)
|
||||||
FIXME("unimplemented start cap %x\n", pen->startcap);
|
FIXME("unimplemented start cap %x\n", pen->startcap);
|
||||||
|
|
||||||
if (pen->dashcap != DashCapFlat)
|
if (pen->dashcap != DashCapFlat)
|
||||||
|
@ -2338,3 +2443,77 @@ GpStatus WINGDIPAPI GdipWindingModeOutline(GpPath *path, GpMatrix *matrix, REAL
|
||||||
FIXME("stub: %p, %p, %.2f\n", path, matrix, flatness);
|
FIXME("stub: %p, %p, %.2f\n", path, matrix, flatness);
|
||||||
return NotImplemented;
|
return NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FLAGS_INTPATH 0x4000
|
||||||
|
|
||||||
|
struct path_header
|
||||||
|
{
|
||||||
|
DWORD version;
|
||||||
|
DWORD count;
|
||||||
|
DWORD flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Test to see if the path could be stored as an array of shorts */
|
||||||
|
static BOOL is_integer_path(const GpPath *path)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!path->pathdata.Count) return FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < path->pathdata.Count; i++)
|
||||||
|
{
|
||||||
|
short x, y;
|
||||||
|
x = gdip_round(path->pathdata.Points[i].X);
|
||||||
|
y = gdip_round(path->pathdata.Points[i].Y);
|
||||||
|
if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD write_path_data(GpPath *path, void *data)
|
||||||
|
{
|
||||||
|
struct path_header *header = data;
|
||||||
|
BOOL integer_path = is_integer_path(path);
|
||||||
|
DWORD i, size;
|
||||||
|
BYTE *types;
|
||||||
|
|
||||||
|
size = sizeof(struct path_header) + path->pathdata.Count;
|
||||||
|
if (integer_path)
|
||||||
|
size += sizeof(short[2]) * path->pathdata.Count;
|
||||||
|
else
|
||||||
|
size += sizeof(float[2]) * path->pathdata.Count;
|
||||||
|
size = (size + 3) & ~3;
|
||||||
|
|
||||||
|
if (!data) return size;
|
||||||
|
|
||||||
|
header->version = VERSION_MAGIC2;
|
||||||
|
header->count = path->pathdata.Count;
|
||||||
|
header->flags = integer_path ? FLAGS_INTPATH : 0;
|
||||||
|
|
||||||
|
if (integer_path)
|
||||||
|
{
|
||||||
|
short *points = (short*)(header + 1);
|
||||||
|
for (i = 0; i < path->pathdata.Count; i++)
|
||||||
|
{
|
||||||
|
points[2*i] = path->pathdata.Points[i].X;
|
||||||
|
points[2*i + 1] = path->pathdata.Points[i].Y;
|
||||||
|
}
|
||||||
|
types = (BYTE*)(points + 2*i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float *points = (float*)(header + 1);
|
||||||
|
for (i = 0; i < path->pathdata.Count; i++)
|
||||||
|
{
|
||||||
|
points[2*i] = path->pathdata.Points[i].X;
|
||||||
|
points[2*i + 1] = path->pathdata.Points[i].Y;
|
||||||
|
}
|
||||||
|
types = (BYTE*)(points + 2*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<path->pathdata.Count; i++)
|
||||||
|
types[i] = path->pathdata.Types[i];
|
||||||
|
memset(types + i, 0, ((path->pathdata.Count + 3) & ~3) - path->pathdata.Count);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
|
@ -1322,6 +1322,7 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
|
||||||
result->unit = metafile->unit;
|
result->unit = metafile->unit;
|
||||||
result->metafile_type = metafile->metafile_type;
|
result->metafile_type = metafile->metafile_type;
|
||||||
result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
|
result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
|
||||||
|
list_init(&result->containers);
|
||||||
|
|
||||||
if (!result->hemf)
|
if (!result->hemf)
|
||||||
{
|
{
|
||||||
|
@ -4165,7 +4166,7 @@ static GpStatus decode_image_emf(IStream *stream, GpImage **image)
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
|
typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
|
||||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
|
GDIPCONST EncoderParameters* params);
|
||||||
|
|
||||||
typedef GpStatus (*decode_image_func)(IStream *stream, GpImage **image);
|
typedef GpStatus (*decode_image_func)(IStream *stream, GpImage **image);
|
||||||
|
|
||||||
|
@ -4541,31 +4542,31 @@ static GpStatus encode_image_wic(GpImage *image, IStream* stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
|
static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
|
||||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
|
GDIPCONST EncoderParameters* params)
|
||||||
{
|
{
|
||||||
return encode_image_wic(image, stream, &GUID_ContainerFormatBmp, params);
|
return encode_image_wic(image, stream, &GUID_ContainerFormatBmp, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
|
static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
|
||||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
|
GDIPCONST EncoderParameters* params)
|
||||||
{
|
{
|
||||||
return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params);
|
return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GpStatus encode_image_png(GpImage *image, IStream* stream,
|
GpStatus encode_image_png(GpImage *image, IStream* stream,
|
||||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
|
GDIPCONST EncoderParameters* params)
|
||||||
{
|
{
|
||||||
return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params);
|
return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
|
static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
|
||||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
|
GDIPCONST EncoderParameters* params)
|
||||||
{
|
{
|
||||||
return encode_image_wic(image, stream, &GUID_ContainerFormatJpeg, params);
|
return encode_image_wic(image, stream, &GUID_ContainerFormatJpeg, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GpStatus encode_image_gif(GpImage *image, IStream* stream,
|
static GpStatus encode_image_gif(GpImage *image, IStream* stream,
|
||||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
|
GDIPCONST EncoderParameters* params)
|
||||||
{
|
{
|
||||||
return encode_image_wic(image, stream, &GUID_ContainerFormatGif, params);
|
return encode_image_wic(image, stream, &GUID_ContainerFormatGif, params);
|
||||||
}
|
}
|
||||||
|
@ -4595,7 +4596,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
|
||||||
if (encode_image == NULL)
|
if (encode_image == NULL)
|
||||||
return UnknownImageFormat;
|
return UnknownImageFormat;
|
||||||
|
|
||||||
stat = encode_image(image, stream, clsid, params);
|
stat = encode_image(image, stream, params);
|
||||||
|
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,6 +184,17 @@ GpStatus WINGDIPAPI GdipInvertMatrix(GpMatrix *matrix)
|
||||||
if(!invertible)
|
if(!invertible)
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
|
/* optimize inverting simple scaling and translation matrices */
|
||||||
|
if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
|
||||||
|
{
|
||||||
|
matrix->matrix[4] = -matrix->matrix[4] / matrix->matrix[0];
|
||||||
|
matrix->matrix[5] = -matrix->matrix[5] / matrix->matrix[3];
|
||||||
|
matrix->matrix[0] = 1 / matrix->matrix[0];
|
||||||
|
matrix->matrix[3] = 1 / matrix->matrix[3];
|
||||||
|
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
det = matrix_det(matrix);
|
det = matrix_det(matrix);
|
||||||
|
|
||||||
copy = *matrix;
|
copy = *matrix;
|
||||||
|
@ -205,7 +216,10 @@ GpStatus WINGDIPAPI GdipIsMatrixInvertible(GDIPCONST GpMatrix *matrix, BOOL *res
|
||||||
if(!matrix || !result)
|
if(!matrix || !result)
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
*result = (fabs(matrix_det(matrix)) >= 1e-5);
|
if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
|
||||||
|
*result = matrix->matrix[0] != 0 && matrix->matrix[3] != 0;
|
||||||
|
else
|
||||||
|
*result = (fabs(matrix_det(matrix)) >= 1e-5);
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,17 @@
|
||||||
|
|
||||||
#include "gdiplus_private.h"
|
#include "gdiplus_private.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ole2.h>
|
||||||
|
|
||||||
|
typedef struct EmfPlusARGB
|
||||||
|
{
|
||||||
|
BYTE Blue;
|
||||||
|
BYTE Green;
|
||||||
|
BYTE Red;
|
||||||
|
BYTE Alpha;
|
||||||
|
} EmfPlusARGB;
|
||||||
|
|
||||||
typedef struct EmfPlusRecordHeader
|
typedef struct EmfPlusRecordHeader
|
||||||
{
|
{
|
||||||
WORD Type;
|
WORD Type;
|
||||||
|
@ -132,6 +143,216 @@ typedef struct container
|
||||||
GpRegion *clip;
|
GpRegion *clip;
|
||||||
} container;
|
} container;
|
||||||
|
|
||||||
|
enum PenDataFlags
|
||||||
|
{
|
||||||
|
PenDataTransform = 0x0001,
|
||||||
|
PenDataStartCap = 0x0002,
|
||||||
|
PenDataEndCap = 0x0004,
|
||||||
|
PenDataJoin = 0x0008,
|
||||||
|
PenDataMiterLimit = 0x0010,
|
||||||
|
PenDataLineStyle = 0x0020,
|
||||||
|
PenDataDashedLineCap = 0x0040,
|
||||||
|
PenDataDashedLineOffset = 0x0080,
|
||||||
|
PenDataDashedLine = 0x0100,
|
||||||
|
PenDataNonCenter = 0x0200,
|
||||||
|
PenDataCompoundLine = 0x0400,
|
||||||
|
PenDataCustomStartCap = 0x0800,
|
||||||
|
PenDataCustomEndCap = 0x1000
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct EmfPlusTransformMatrix
|
||||||
|
{
|
||||||
|
REAL TransformMatrix[6];
|
||||||
|
} EmfPlusTransformMatrix;
|
||||||
|
|
||||||
|
enum LineStyle
|
||||||
|
{
|
||||||
|
LineStyleSolid,
|
||||||
|
LineStyleDash,
|
||||||
|
LineStyleDot,
|
||||||
|
LineStyleDashDot,
|
||||||
|
LineStyleDashDotDot,
|
||||||
|
LineStyleCustom
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct EmfPlusPenData
|
||||||
|
{
|
||||||
|
DWORD PenDataFlags;
|
||||||
|
DWORD PenUnit;
|
||||||
|
REAL PenWidth;
|
||||||
|
BYTE OptionalData[1];
|
||||||
|
} EmfPlusPenData;
|
||||||
|
|
||||||
|
typedef struct EmfPlusSolidBrushData
|
||||||
|
{
|
||||||
|
EmfPlusARGB SolidColor;
|
||||||
|
} EmfPlusSolidBrushData;
|
||||||
|
|
||||||
|
typedef struct EmfPlusBrush
|
||||||
|
{
|
||||||
|
DWORD Version;
|
||||||
|
DWORD Type;
|
||||||
|
union {
|
||||||
|
EmfPlusSolidBrushData solid;
|
||||||
|
} BrushData;
|
||||||
|
} EmfPlusBrush;
|
||||||
|
|
||||||
|
typedef struct EmfPlusPen
|
||||||
|
{
|
||||||
|
DWORD Version;
|
||||||
|
DWORD Type;
|
||||||
|
/* EmfPlusPenData */
|
||||||
|
/* EmfPlusBrush */
|
||||||
|
BYTE data[1];
|
||||||
|
} EmfPlusPen;
|
||||||
|
|
||||||
|
typedef struct EmfPlusPath
|
||||||
|
{
|
||||||
|
DWORD Version;
|
||||||
|
DWORD PathPointCount;
|
||||||
|
DWORD PathPointFlags;
|
||||||
|
/* PathPoints[] */
|
||||||
|
/* PathPointTypes[] */
|
||||||
|
/* AlignmentPadding */
|
||||||
|
BYTE data[1];
|
||||||
|
} EmfPlusPath;
|
||||||
|
|
||||||
|
typedef struct EmfPlusRegion
|
||||||
|
{
|
||||||
|
DWORD Version;
|
||||||
|
DWORD RegionNodeCount;
|
||||||
|
BYTE RegionNode[1];
|
||||||
|
} EmfPlusRegion;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BitmapDataTypePixel,
|
||||||
|
BitmapDataTypeCompressed,
|
||||||
|
} BitmapDataType;
|
||||||
|
|
||||||
|
typedef struct EmfPlusBitmap
|
||||||
|
{
|
||||||
|
DWORD Width;
|
||||||
|
DWORD Height;
|
||||||
|
DWORD Stride;
|
||||||
|
DWORD PixelFormat;
|
||||||
|
DWORD Type;
|
||||||
|
BYTE BitmapData[1];
|
||||||
|
} EmfPlusBitmap;
|
||||||
|
|
||||||
|
typedef struct EmfPlusMetafile
|
||||||
|
{
|
||||||
|
DWORD Type;
|
||||||
|
DWORD MetafileDataSize;
|
||||||
|
BYTE MetafileData[1];
|
||||||
|
} EmfPlusMetafile;
|
||||||
|
|
||||||
|
typedef enum ImageDataType
|
||||||
|
{
|
||||||
|
ImageDataTypeUnknown,
|
||||||
|
ImageDataTypeBitmap,
|
||||||
|
ImageDataTypeMetafile,
|
||||||
|
} ImageDataType;
|
||||||
|
|
||||||
|
typedef struct EmfPlusImage
|
||||||
|
{
|
||||||
|
DWORD Version;
|
||||||
|
ImageDataType Type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
EmfPlusBitmap bitmap;
|
||||||
|
EmfPlusMetafile metafile;
|
||||||
|
} ImageData;
|
||||||
|
} EmfPlusImage;
|
||||||
|
|
||||||
|
typedef struct EmfPlusImageAttributes
|
||||||
|
{
|
||||||
|
DWORD Version;
|
||||||
|
DWORD Reserved1;
|
||||||
|
DWORD WrapMode;
|
||||||
|
EmfPlusARGB ClampColor;
|
||||||
|
DWORD ObjectClamp;
|
||||||
|
DWORD Reserved2;
|
||||||
|
} EmfPlusImageAttributes;
|
||||||
|
|
||||||
|
typedef enum ObjectType
|
||||||
|
{
|
||||||
|
ObjectTypeInvalid,
|
||||||
|
ObjectTypeBrush,
|
||||||
|
ObjectTypePen,
|
||||||
|
ObjectTypePath,
|
||||||
|
ObjectTypeRegion,
|
||||||
|
ObjectTypeImage,
|
||||||
|
ObjectTypeFont,
|
||||||
|
ObjectTypeStringFormat,
|
||||||
|
ObjectTypeImageAttributes,
|
||||||
|
ObjectTypeCustomLineCap,
|
||||||
|
} ObjectType;
|
||||||
|
|
||||||
|
typedef struct EmfPlusObject
|
||||||
|
{
|
||||||
|
EmfPlusRecordHeader Header;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
EmfPlusBrush brush;
|
||||||
|
EmfPlusPen pen;
|
||||||
|
EmfPlusPath path;
|
||||||
|
EmfPlusRegion region;
|
||||||
|
EmfPlusImage image;
|
||||||
|
EmfPlusImageAttributes image_attributes;
|
||||||
|
} ObjectData;
|
||||||
|
} EmfPlusObject;
|
||||||
|
|
||||||
|
typedef struct EmfPlusRectF
|
||||||
|
{
|
||||||
|
float X;
|
||||||
|
float Y;
|
||||||
|
float Width;
|
||||||
|
float Height;
|
||||||
|
} EmfPlusRectF;
|
||||||
|
|
||||||
|
typedef struct EmfPlusPointF
|
||||||
|
{
|
||||||
|
float X;
|
||||||
|
float Y;
|
||||||
|
} EmfPlusPointF;
|
||||||
|
|
||||||
|
typedef struct EmfPlusDrawImagePoints
|
||||||
|
{
|
||||||
|
EmfPlusRecordHeader Header;
|
||||||
|
DWORD ImageAttributesID;
|
||||||
|
DWORD SrcUnit;
|
||||||
|
EmfPlusRectF SrcRect;
|
||||||
|
DWORD count;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
/*EmfPlusPointR pointR;
|
||||||
|
EmfPlusPoint point;*/
|
||||||
|
EmfPlusPointF pointF;
|
||||||
|
} PointData[3];
|
||||||
|
} EmfPlusDrawImagePoints;
|
||||||
|
|
||||||
|
typedef struct EmfPlusDrawPath
|
||||||
|
{
|
||||||
|
EmfPlusRecordHeader Header;
|
||||||
|
DWORD PenId;
|
||||||
|
} EmfPlusDrawPath;
|
||||||
|
|
||||||
|
typedef struct EmfPlusFillPath
|
||||||
|
{
|
||||||
|
EmfPlusRecordHeader Header;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
DWORD BrushId;
|
||||||
|
EmfPlusARGB Color;
|
||||||
|
} data;
|
||||||
|
} EmfPlusFillPath;
|
||||||
|
|
||||||
|
static DWORD METAFILE_AddObjectId(GpMetafile *metafile)
|
||||||
|
{
|
||||||
|
return (metafile->next_object_id++) % 64;
|
||||||
|
}
|
||||||
|
|
||||||
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
|
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
|
||||||
{
|
{
|
||||||
DWORD size_needed;
|
DWORD size_needed;
|
||||||
|
@ -178,6 +399,12 @@ static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void *
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void METAFILE_RemoveLastRecord(GpMetafile *metafile, EmfPlusRecordHeader *record)
|
||||||
|
{
|
||||||
|
assert(metafile->comment_data + metafile->comment_data_length == (BYTE*)record + record->Size);
|
||||||
|
metafile->comment_data_length -= record->Size;
|
||||||
|
}
|
||||||
|
|
||||||
static void METAFILE_WriteRecords(GpMetafile *metafile)
|
static void METAFILE_WriteRecords(GpMetafile *metafile)
|
||||||
{
|
{
|
||||||
if (metafile->comment_data_length > 4)
|
if (metafile->comment_data_length > 4)
|
||||||
|
@ -206,7 +433,7 @@ static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
|
||||||
else
|
else
|
||||||
header->Header.Flags = 0;
|
header->Header.Flags = 0;
|
||||||
|
|
||||||
header->Version = 0xDBC01002;
|
header->Version = VERSION_MAGIC2;
|
||||||
|
|
||||||
if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
|
if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
|
||||||
header->EmfPlusFlags = 1;
|
header->EmfPlusFlags = 1;
|
||||||
|
@ -606,6 +833,53 @@ GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width,
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_AddRegionObject(GpMetafile *metafile, GpRegion *region, DWORD *id)
|
||||||
|
{
|
||||||
|
EmfPlusObject *object_record;
|
||||||
|
DWORD size;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
*id = -1;
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
size = write_region_data(region, NULL);
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData.region) + size, (void**)&object_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | ObjectTypeRegion << 8;
|
||||||
|
write_region_data(region, &object_record->ObjectData.region);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode)
|
||||||
|
{
|
||||||
|
EmfPlusRecordHeader *record;
|
||||||
|
DWORD region_id;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
if (metafile->metafile_type == MetafileTypeEmf)
|
||||||
|
{
|
||||||
|
FIXME("stub!\n");
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = METAFILE_AddRegionObject(metafile, region, ®ion_id);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
record->Type = EmfPlusRecordTypeSetClipRegion;
|
||||||
|
record->Flags = region_id | mode << 8;
|
||||||
|
|
||||||
|
METAFILE_WriteRecords(metafile);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
|
GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
|
||||||
{
|
{
|
||||||
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
|
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
|
||||||
|
@ -1127,8 +1401,6 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
|
||||||
/* regular EMF record */
|
/* regular EMF record */
|
||||||
if (metafile->playback_dc)
|
if (metafile->playback_dc)
|
||||||
{
|
{
|
||||||
ENHMETARECORD *record;
|
|
||||||
|
|
||||||
switch (recordType)
|
switch (recordType)
|
||||||
{
|
{
|
||||||
case EMR_SETMAPMODE:
|
case EMR_SETMAPMODE:
|
||||||
|
@ -1173,24 +1445,27 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
|
ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
|
||||||
|
|
||||||
|
if (record)
|
||||||
|
{
|
||||||
|
record->iType = recordType;
|
||||||
|
record->nSize = dataSize + 8;
|
||||||
|
memcpy(record->dParm, data, dataSize);
|
||||||
|
|
||||||
|
if(PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
|
||||||
|
record, metafile->handle_count) == 0)
|
||||||
|
ERR("PlayEnhMetaFileRecord failed\n");
|
||||||
|
|
||||||
|
heap_free(record);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return OutOfMemory;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
record = heap_alloc_zero(dataSize + 8);
|
|
||||||
|
|
||||||
if (record)
|
|
||||||
{
|
|
||||||
record->iType = recordType;
|
|
||||||
record->nSize = dataSize + 8;
|
|
||||||
memcpy(record->dParm, data, dataSize);
|
|
||||||
|
|
||||||
PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
|
|
||||||
record, metafile->handle_count);
|
|
||||||
|
|
||||||
heap_free(record);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return OutOfMemory;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1816,7 +2091,7 @@ GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memset(header, 0, sizeof(*header));
|
memset(header, 0, sizeof(*header));
|
||||||
header->Version = 0xdbc01002;
|
header->Version = VERSION_MAGIC2;
|
||||||
}
|
}
|
||||||
|
|
||||||
header->Type = metafile->metafile_type;
|
header->Type = metafile->metafile_type;
|
||||||
|
@ -2065,13 +2340,20 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
|
||||||
GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
|
GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
|
||||||
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
|
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
|
||||||
{
|
{
|
||||||
HMETAFILE hmf = GetMetaFileW(file);
|
HMETAFILE hmf;
|
||||||
|
HENHMETAFILE emf;
|
||||||
|
|
||||||
TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
|
TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
|
||||||
|
|
||||||
if(!hmf) return InvalidParameter;
|
hmf = GetMetaFileW(file);
|
||||||
|
if(hmf)
|
||||||
|
return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
|
||||||
|
|
||||||
return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
|
emf = GetEnhMetaFileW(file);
|
||||||
|
if(emf)
|
||||||
|
return GdipCreateMetafileFromEmf(emf, TRUE, metafile);
|
||||||
|
|
||||||
|
return GenericError;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
|
GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
|
||||||
|
@ -2185,3 +2467,585 @@ GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
|
||||||
FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
|
FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
|
||||||
return NotImplemented;
|
return NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_CreateCompressedImageStream(GpImage *image, IStream **stream, DWORD *size)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER zero;
|
||||||
|
STATSTG statstg;
|
||||||
|
GpStatus stat;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
|
||||||
|
if (FAILED(hr)) return hresult_to_status(hr);
|
||||||
|
|
||||||
|
stat = encode_image_png(image, *stream, NULL);
|
||||||
|
if (stat != Ok)
|
||||||
|
{
|
||||||
|
IStream_Release(*stream);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IStream_Stat(*stream, &statstg, 1);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
IStream_Release(*stream);
|
||||||
|
return hresult_to_status(hr);
|
||||||
|
}
|
||||||
|
*size = statstg.cbSize.u.LowPart;
|
||||||
|
|
||||||
|
zero.QuadPart = 0;
|
||||||
|
hr = IStream_Seek(*stream, zero, STREAM_SEEK_SET, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
IStream_Release(*stream);
|
||||||
|
return hresult_to_status(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_FillEmfPlusBitmap(EmfPlusBitmap *record, IStream *stream, DWORD size)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
record->Width = 0;
|
||||||
|
record->Height = 0;
|
||||||
|
record->Stride = 0;
|
||||||
|
record->PixelFormat = 0;
|
||||||
|
record->Type = BitmapDataTypeCompressed;
|
||||||
|
|
||||||
|
hr = IStream_Read(stream, record->BitmapData, size, NULL);
|
||||||
|
if (FAILED(hr)) return hresult_to_status(hr);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_AddImageObject(GpMetafile *metafile, GpImage *image, DWORD *id)
|
||||||
|
{
|
||||||
|
EmfPlusObject *object_record;
|
||||||
|
GpStatus stat;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
*id = -1;
|
||||||
|
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if (image->type == ImageTypeBitmap)
|
||||||
|
{
|
||||||
|
IStream *stream;
|
||||||
|
DWORD aligned_size;
|
||||||
|
|
||||||
|
stat = METAFILE_CreateCompressedImageStream(image, &stream, &size);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
aligned_size = (size + 3) & ~3;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.bitmap.BitmapData[aligned_size]),
|
||||||
|
(void**)&object_record);
|
||||||
|
if (stat != Ok)
|
||||||
|
{
|
||||||
|
IStream_Release(stream);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
memset(object_record->ObjectData.image.ImageData.bitmap.BitmapData + size, 0, aligned_size - size);
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | ObjectTypeImage << 8;
|
||||||
|
object_record->ObjectData.image.Version = VERSION_MAGIC2;
|
||||||
|
object_record->ObjectData.image.Type = ImageDataTypeBitmap;
|
||||||
|
|
||||||
|
stat = METAFILE_FillEmfPlusBitmap(&object_record->ObjectData.image.ImageData.bitmap, stream, size);
|
||||||
|
IStream_Release(stream);
|
||||||
|
if (stat != Ok) METAFILE_RemoveLastRecord(metafile, &object_record->Header);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
else if (image->type == ImageTypeMetafile)
|
||||||
|
{
|
||||||
|
HENHMETAFILE hemf = ((GpMetafile*)image)->hemf;
|
||||||
|
EmfPlusMetafile *metafile_record;
|
||||||
|
|
||||||
|
if (!hemf) return InvalidParameter;
|
||||||
|
|
||||||
|
size = GetEnhMetaFileBits(hemf, 0, NULL);
|
||||||
|
if (!size) return GenericError;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.metafile.MetafileData[size]),
|
||||||
|
(void**)&object_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | ObjectTypeImage << 8;
|
||||||
|
object_record->ObjectData.image.Version = VERSION_MAGIC2;
|
||||||
|
object_record->ObjectData.image.Type = ImageDataTypeMetafile;
|
||||||
|
metafile_record = &object_record->ObjectData.image.ImageData.metafile;
|
||||||
|
metafile_record->Type = ((GpMetafile*)image)->metafile_type;
|
||||||
|
metafile_record->MetafileDataSize = size;
|
||||||
|
if (GetEnhMetaFileBits(hemf, size, metafile_record->MetafileData) != size)
|
||||||
|
{
|
||||||
|
METAFILE_RemoveLastRecord(metafile, &object_record->Header);
|
||||||
|
return GenericError;
|
||||||
|
}
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FIXME("not supported image type (%d)\n", image->type);
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_AddImageAttributesObject(GpMetafile *metafile, const GpImageAttributes *attrs, DWORD *id)
|
||||||
|
{
|
||||||
|
EmfPlusObject *object_record;
|
||||||
|
EmfPlusImageAttributes *attrs_record;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
*id = -1;
|
||||||
|
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
if (!attrs)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData.image_attributes) + sizeof(EmfPlusImageAttributes),
|
||||||
|
(void**)&object_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | (ObjectTypeImageAttributes << 8);
|
||||||
|
attrs_record = &object_record->ObjectData.image_attributes;
|
||||||
|
attrs_record->Version = VERSION_MAGIC2;
|
||||||
|
attrs_record->Reserved1 = 0;
|
||||||
|
attrs_record->WrapMode = attrs->wrap;
|
||||||
|
attrs_record->ClampColor.Blue = attrs->outside_color & 0xff;
|
||||||
|
attrs_record->ClampColor.Green = (attrs->outside_color >> 8) & 0xff;
|
||||||
|
attrs_record->ClampColor.Red = (attrs->outside_color >> 16) & 0xff;
|
||||||
|
attrs_record->ClampColor.Alpha = attrs->outside_color >> 24;
|
||||||
|
attrs_record->ObjectClamp = attrs->clamp;
|
||||||
|
attrs_record->Reserved2 = 0;
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus METAFILE_DrawImagePointsRect(GpMetafile *metafile, GpImage *image,
|
||||||
|
GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
|
||||||
|
REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
|
||||||
|
DrawImageAbort callback, VOID *callbackData)
|
||||||
|
{
|
||||||
|
EmfPlusDrawImagePoints *draw_image_record;
|
||||||
|
DWORD image_id, attributes_id;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
if (count != 3) return InvalidParameter;
|
||||||
|
|
||||||
|
if (metafile->metafile_type == MetafileTypeEmf)
|
||||||
|
{
|
||||||
|
FIXME("MetafileTypeEmf metafiles not supported\n");
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FIXME("semi-stub\n");
|
||||||
|
|
||||||
|
if (!imageAttributes)
|
||||||
|
{
|
||||||
|
stat = METAFILE_AddImageObject(metafile, image, &image_id);
|
||||||
|
}
|
||||||
|
else if (image->type == ImageTypeBitmap)
|
||||||
|
{
|
||||||
|
INT width = ((GpBitmap*)image)->width;
|
||||||
|
INT height = ((GpBitmap*)image)->height;
|
||||||
|
GpGraphics *graphics;
|
||||||
|
GpBitmap *bitmap;
|
||||||
|
|
||||||
|
stat = GdipCreateBitmapFromScan0(width, height,
|
||||||
|
0, PixelFormat32bppARGB, NULL, &bitmap);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
|
||||||
|
if (stat != Ok)
|
||||||
|
{
|
||||||
|
GdipDisposeImage((GpImage*)bitmap);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = GdipDrawImageRectRectI(graphics, image, 0, 0, width, height,
|
||||||
|
0, 0, width, height, UnitPixel, imageAttributes, NULL, NULL);
|
||||||
|
GdipDeleteGraphics(graphics);
|
||||||
|
if (stat != Ok)
|
||||||
|
{
|
||||||
|
GdipDisposeImage((GpImage*)bitmap);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = METAFILE_AddImageObject(metafile, (GpImage*)bitmap, &image_id);
|
||||||
|
GdipDisposeImage((GpImage*)bitmap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FIXME("imageAttributes not supported (image type %d)\n", image->type);
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddImageAttributesObject(metafile, imageAttributes, &attributes_id);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawImagePoints), (void**)&draw_image_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
draw_image_record->Header.Type = EmfPlusRecordTypeDrawImagePoints;
|
||||||
|
draw_image_record->Header.Flags = image_id;
|
||||||
|
draw_image_record->ImageAttributesID = attributes_id;
|
||||||
|
draw_image_record->SrcUnit = UnitPixel;
|
||||||
|
draw_image_record->SrcRect.X = units_to_pixels(srcx, srcUnit, metafile->image.xres);
|
||||||
|
draw_image_record->SrcRect.Y = units_to_pixels(srcy, srcUnit, metafile->image.yres);
|
||||||
|
draw_image_record->SrcRect.Width = units_to_pixels(srcwidth, srcUnit, metafile->image.xres);
|
||||||
|
draw_image_record->SrcRect.Height = units_to_pixels(srcheight, srcUnit, metafile->image.yres);
|
||||||
|
draw_image_record->count = 3;
|
||||||
|
draw_image_record->PointData[0].pointF.X = points[0].X;
|
||||||
|
draw_image_record->PointData[0].pointF.Y = points[0].Y;
|
||||||
|
draw_image_record->PointData[1].pointF.X = points[1].X;
|
||||||
|
draw_image_record->PointData[1].pointF.Y = points[1].Y;
|
||||||
|
draw_image_record->PointData[2].pointF.X = points[2].X;
|
||||||
|
draw_image_record->PointData[2].pointF.Y = points[2].Y;
|
||||||
|
METAFILE_WriteRecords(metafile);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val)
|
||||||
|
{
|
||||||
|
EmfPlusRecordHeader *record;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
record->Type = prop;
|
||||||
|
record->Flags = val;
|
||||||
|
|
||||||
|
METAFILE_WriteRecords(metafile);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD *id)
|
||||||
|
{
|
||||||
|
EmfPlusObject *object_record;
|
||||||
|
GpStatus stat;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
*id = -1;
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
size = write_path_data(path, NULL);
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData.path) + size,
|
||||||
|
(void**)&object_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | ObjectTypePath << 8;
|
||||||
|
write_path_data(path, &object_record->ObjectData.path);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_PrepareBrushData(GpBrush *brush, DWORD *size)
|
||||||
|
{
|
||||||
|
if (brush->bt == BrushTypeSolidColor)
|
||||||
|
{
|
||||||
|
*size = FIELD_OFFSET(EmfPlusBrush, BrushData.solid) + sizeof(EmfPlusSolidBrushData);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIXME("unsupported brush type: %d\n", brush->bt);
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void METAFILE_FillBrushData(GpBrush *brush, EmfPlusBrush *data)
|
||||||
|
{
|
||||||
|
if (brush->bt == BrushTypeSolidColor)
|
||||||
|
{
|
||||||
|
GpSolidFill *solid = (GpSolidFill*)brush;
|
||||||
|
|
||||||
|
data->Version = VERSION_MAGIC2;
|
||||||
|
data->Type = solid->brush.bt;
|
||||||
|
data->BrushData.solid.SolidColor.Blue = solid->color & 0xff;
|
||||||
|
data->BrushData.solid.SolidColor.Green = (solid->color >> 8) & 0xff;
|
||||||
|
data->BrushData.solid.SolidColor.Red = (solid->color >> 16) & 0xff;
|
||||||
|
data->BrushData.solid.SolidColor.Alpha = solid->color >> 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id)
|
||||||
|
{
|
||||||
|
DWORD i, data_flags, pen_data_size, brush_size;
|
||||||
|
EmfPlusObject *object_record;
|
||||||
|
EmfPlusPenData *pen_data;
|
||||||
|
GpStatus stat;
|
||||||
|
BOOL result;
|
||||||
|
|
||||||
|
*id = -1;
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
data_flags = 0;
|
||||||
|
pen_data_size = FIELD_OFFSET(EmfPlusPenData, OptionalData);
|
||||||
|
|
||||||
|
GdipIsMatrixIdentity(&pen->transform, &result);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataTransform;
|
||||||
|
pen_data_size += sizeof(EmfPlusTransformMatrix);
|
||||||
|
}
|
||||||
|
if (pen->startcap != LineCapFlat)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataStartCap;
|
||||||
|
pen_data_size += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (pen->endcap != LineCapFlat)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataEndCap;
|
||||||
|
pen_data_size += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (pen->join != LineJoinMiter)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataJoin;
|
||||||
|
pen_data_size += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (pen->miterlimit != 10.0)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataMiterLimit;
|
||||||
|
pen_data_size += sizeof(REAL);
|
||||||
|
}
|
||||||
|
if (pen->style != GP_DEFAULT_PENSTYLE)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataLineStyle;
|
||||||
|
pen_data_size += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (pen->dashcap != DashCapFlat)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataDashedLineCap;
|
||||||
|
pen_data_size += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
data_flags |= PenDataDashedLineOffset;
|
||||||
|
pen_data_size += sizeof(REAL);
|
||||||
|
if (pen->numdashes)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataDashedLine;
|
||||||
|
pen_data_size += sizeof(DWORD) + pen->numdashes*sizeof(REAL);
|
||||||
|
}
|
||||||
|
if (pen->align != PenAlignmentCenter)
|
||||||
|
{
|
||||||
|
data_flags |= PenDataNonCenter;
|
||||||
|
pen_data_size += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
/* TODO: Add support for PenDataCompoundLine */
|
||||||
|
if (pen->customstart)
|
||||||
|
{
|
||||||
|
FIXME("ignoring custom start cup\n");
|
||||||
|
}
|
||||||
|
if (pen->customend)
|
||||||
|
{
|
||||||
|
FIXME("ignoring custom end cup\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = METAFILE_PrepareBrushData(pen->brush, &brush_size);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData.pen.data) + pen_data_size + brush_size,
|
||||||
|
(void**)&object_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | ObjectTypePen << 8;
|
||||||
|
object_record->ObjectData.pen.Version = VERSION_MAGIC2;
|
||||||
|
object_record->ObjectData.pen.Type = 0;
|
||||||
|
|
||||||
|
pen_data = (EmfPlusPenData*)object_record->ObjectData.pen.data;
|
||||||
|
pen_data->PenDataFlags = data_flags;
|
||||||
|
pen_data->PenUnit = pen->unit;
|
||||||
|
pen_data->PenWidth = pen->width;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (data_flags & PenDataTransform)
|
||||||
|
{
|
||||||
|
EmfPlusTransformMatrix *m = (EmfPlusTransformMatrix*)(pen_data->OptionalData + i);
|
||||||
|
memcpy(m, &pen->transform, sizeof(*m));
|
||||||
|
i += sizeof(EmfPlusTransformMatrix);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataStartCap)
|
||||||
|
{
|
||||||
|
*(DWORD*)(pen_data->OptionalData + i) = pen->startcap;
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataEndCap)
|
||||||
|
{
|
||||||
|
*(DWORD*)(pen_data->OptionalData + i) = pen->endcap;
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataJoin)
|
||||||
|
{
|
||||||
|
*(DWORD*)(pen_data->OptionalData + i) = pen->join;
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataMiterLimit)
|
||||||
|
{
|
||||||
|
*(REAL*)(pen_data->OptionalData + i) = pen->miterlimit;
|
||||||
|
i += sizeof(REAL);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataLineStyle)
|
||||||
|
{
|
||||||
|
switch (pen->style & PS_STYLE_MASK)
|
||||||
|
{
|
||||||
|
case PS_SOLID: *(DWORD*)(pen_data->OptionalData + i) = LineStyleSolid; break;
|
||||||
|
case PS_DASH: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDash; break;
|
||||||
|
case PS_DOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDot; break;
|
||||||
|
case PS_DASHDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDot; break;
|
||||||
|
case PS_DASHDOTDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDotDot; break;
|
||||||
|
default: *(DWORD*)(pen_data->OptionalData + i) = LineStyleCustom; break;
|
||||||
|
}
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataDashedLineCap)
|
||||||
|
{
|
||||||
|
*(DWORD*)(pen_data->OptionalData + i) = pen->dashcap;
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataDashedLineOffset)
|
||||||
|
{
|
||||||
|
*(REAL*)(pen_data->OptionalData + i) = pen->offset;
|
||||||
|
i += sizeof(REAL);
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataDashedLine)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
*(DWORD*)(pen_data->OptionalData + i) = pen->numdashes;
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
|
||||||
|
for (j=0; j<pen->numdashes; j++)
|
||||||
|
{
|
||||||
|
*(REAL*)(pen_data->OptionalData + i) = pen->dashes[j];
|
||||||
|
i += sizeof(REAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data_flags & PenDataNonCenter)
|
||||||
|
{
|
||||||
|
*(REAL*)(pen_data->OptionalData + i) = pen->align;
|
||||||
|
i += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
METAFILE_FillBrushData(pen->brush,
|
||||||
|
(EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size));
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path)
|
||||||
|
{
|
||||||
|
EmfPlusDrawPath *draw_path_record;
|
||||||
|
DWORD path_id;
|
||||||
|
DWORD pen_id;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
if (metafile->metafile_type == MetafileTypeEmf)
|
||||||
|
{
|
||||||
|
FIXME("stub!\n");
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = METAFILE_AddPenObject(metafile, pen, &pen_id);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AddPathObject(metafile, path, &path_id);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawPath), (void**)&draw_path_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
draw_path_record->Header.Type = EmfPlusRecordTypeDrawPath;
|
||||||
|
draw_path_record->Header.Flags = path_id;
|
||||||
|
draw_path_record->PenId = pen_id;
|
||||||
|
|
||||||
|
METAFILE_WriteRecords(metafile);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GpBrush *brush, DWORD *id)
|
||||||
|
{
|
||||||
|
EmfPlusObject *object_record;
|
||||||
|
GpStatus stat;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
*id = -1;
|
||||||
|
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||||
|
return Ok;
|
||||||
|
|
||||||
|
stat = METAFILE_PrepareBrushData(brush, &size);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
FIELD_OFFSET(EmfPlusObject, ObjectData) + size, (void**)&object_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
*id = METAFILE_AddObjectId(metafile);
|
||||||
|
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||||
|
object_record->Header.Flags = *id | ObjectTypeBrush << 8;
|
||||||
|
METAFILE_FillBrushData(brush, &object_record->ObjectData.brush);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path)
|
||||||
|
{
|
||||||
|
EmfPlusFillPath *fill_path_record;
|
||||||
|
DWORD brush_id = -1, path_id;
|
||||||
|
BOOL inline_color;
|
||||||
|
GpStatus stat;
|
||||||
|
|
||||||
|
if (metafile->metafile_type == MetafileTypeEmf)
|
||||||
|
{
|
||||||
|
FIXME("stub!\n");
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_color = brush->bt == BrushTypeSolidColor;
|
||||||
|
if (!inline_color)
|
||||||
|
{
|
||||||
|
stat = METAFILE_AddBrushObject(metafile, brush, &brush_id);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = METAFILE_AddPathObject(metafile, path, &path_id);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
|
||||||
|
stat = METAFILE_AllocateRecord(metafile,
|
||||||
|
sizeof(EmfPlusFillPath), (void**)&fill_path_record);
|
||||||
|
if (stat != Ok) return stat;
|
||||||
|
fill_path_record->Header.Type = EmfPlusRecordTypeFillPath;
|
||||||
|
if (inline_color)
|
||||||
|
{
|
||||||
|
fill_path_record->Header.Flags = 0x8000 | path_id;
|
||||||
|
fill_path_record->data.Color.Blue = ((GpSolidFill*)brush)->color & 0xff;
|
||||||
|
fill_path_record->data.Color.Green = (((GpSolidFill*)brush)->color >> 8) & 0xff;
|
||||||
|
fill_path_record->data.Color.Red = (((GpSolidFill*)brush)->color >> 16) & 0xff;
|
||||||
|
fill_path_record->data.Color.Alpha = ((GpSolidFill*)brush)->color >> 24;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fill_path_record->Header.Flags = path_id;
|
||||||
|
fill_path_record->data.BrushId = brush_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
METAFILE_WriteRecords(metafile);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FLAGS_NOFLAGS 0x0
|
|
||||||
#define FLAGS_INTPATH 0x4000
|
#define FLAGS_INTPATH 0x4000
|
||||||
|
|
||||||
struct memory_buffer
|
struct memory_buffer
|
||||||
|
@ -73,12 +72,17 @@ struct memory_buffer
|
||||||
|
|
||||||
struct region_header
|
struct region_header
|
||||||
{
|
{
|
||||||
DWORD size;
|
|
||||||
DWORD checksum;
|
|
||||||
DWORD magic;
|
DWORD magic;
|
||||||
DWORD num_children;
|
DWORD num_children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct region_data_header
|
||||||
|
{
|
||||||
|
DWORD size;
|
||||||
|
DWORD checksum;
|
||||||
|
struct region_header header;
|
||||||
|
};
|
||||||
|
|
||||||
struct path_header
|
struct path_header
|
||||||
{
|
{
|
||||||
DWORD size;
|
DWORD size;
|
||||||
|
@ -87,46 +91,12 @@ struct path_header
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Header size as far as header->size is concerned. This doesn't include
|
|
||||||
* header->size or header->checksum
|
|
||||||
*/
|
|
||||||
static const INT sizeheader_size = sizeof(DWORD) * 2;
|
|
||||||
|
|
||||||
typedef struct packed_point
|
typedef struct packed_point
|
||||||
{
|
{
|
||||||
short X;
|
short X;
|
||||||
short Y;
|
short Y;
|
||||||
} packed_point;
|
} packed_point;
|
||||||
|
|
||||||
/* Test to see if the path could be stored as an array of shorts */
|
|
||||||
static BOOL is_integer_path(const GpPath *path)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!path->pathdata.Count) return FALSE;
|
|
||||||
|
|
||||||
for (i = 0; i < path->pathdata.Count; i++)
|
|
||||||
{
|
|
||||||
short x, y;
|
|
||||||
x = gdip_round(path->pathdata.Points[i].X);
|
|
||||||
y = gdip_round(path->pathdata.Points[i].Y);
|
|
||||||
if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Everything is measured in DWORDS; round up if there's a remainder */
|
|
||||||
static inline INT get_pathtypes_size(const GpPath* path)
|
|
||||||
{
|
|
||||||
INT needed = path->pathdata.Count / sizeof(DWORD);
|
|
||||||
|
|
||||||
if (path->pathdata.Count % sizeof(DWORD) > 0)
|
|
||||||
needed++;
|
|
||||||
|
|
||||||
return needed * sizeof(DWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline INT get_element_size(const region_element* element)
|
static inline INT get_element_size(const region_element* element)
|
||||||
{
|
{
|
||||||
INT needed = sizeof(DWORD); /* DWORD for the type */
|
INT needed = sizeof(DWORD); /* DWORD for the type */
|
||||||
|
@ -136,17 +106,8 @@ static inline INT get_element_size(const region_element* element)
|
||||||
return needed + sizeof(GpRect);
|
return needed + sizeof(GpRect);
|
||||||
case RegionDataPath:
|
case RegionDataPath:
|
||||||
{
|
{
|
||||||
const GpPath *path = element->elementdata.path;
|
needed += write_path_data(element->elementdata.path, NULL);
|
||||||
DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
|
needed += sizeof(DWORD); /* Extra DWORD for path size */
|
||||||
/* 3 for headers, once again size doesn't count itself */
|
|
||||||
needed += sizeof(DWORD) * 3;
|
|
||||||
if (flags & FLAGS_INTPATH)
|
|
||||||
needed += 2 * sizeof(SHORT) * path->pathdata.Count;
|
|
||||||
else
|
|
||||||
needed += 2 * sizeof(FLOAT) * path->pathdata.Count;
|
|
||||||
|
|
||||||
needed += get_pathtypes_size(path);
|
|
||||||
needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
|
|
||||||
return needed;
|
return needed;
|
||||||
}
|
}
|
||||||
case RegionDataEmptyRect:
|
case RegionDataEmptyRect:
|
||||||
|
@ -692,29 +653,6 @@ static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
|
||||||
(*offset)++;
|
(*offset)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write_packed_point(DWORD* location, INT* offset,
|
|
||||||
const GpPointF* write)
|
|
||||||
{
|
|
||||||
packed_point *point = (packed_point *)(location + *offset);
|
|
||||||
point->X = gdip_round(write->X);
|
|
||||||
point->Y = gdip_round(write->Y);
|
|
||||||
(*offset)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write_path_types(DWORD* location, INT* offset,
|
|
||||||
const GpPath* path)
|
|
||||||
{
|
|
||||||
INT rounded_size = get_pathtypes_size(path);
|
|
||||||
|
|
||||||
memcpy(location + *offset, path->pathdata.Types, path->pathdata.Count);
|
|
||||||
|
|
||||||
/* The unwritten parts of the DWORD (if any) must be cleared */
|
|
||||||
if (rounded_size - path->pathdata.Count)
|
|
||||||
ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
|
|
||||||
path->pathdata.Count, rounded_size - path->pathdata.Count);
|
|
||||||
*offset += rounded_size / sizeof(DWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_element(const region_element* element, DWORD *buffer,
|
static void write_element(const region_element* element, DWORD *buffer,
|
||||||
INT* filled)
|
INT* filled)
|
||||||
{
|
{
|
||||||
|
@ -738,43 +676,9 @@ static void write_element(const region_element* element, DWORD *buffer,
|
||||||
break;
|
break;
|
||||||
case RegionDataPath:
|
case RegionDataPath:
|
||||||
{
|
{
|
||||||
INT i;
|
DWORD size = write_path_data(element->elementdata.path, buffer + *filled + 1);
|
||||||
const GpPath* path = element->elementdata.path;
|
write_dword(buffer, filled, size);
|
||||||
struct path_header *pathheader;
|
*filled += size / sizeof(DWORD);
|
||||||
|
|
||||||
pathheader = (struct path_header *)(buffer + *filled);
|
|
||||||
|
|
||||||
pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
|
|
||||||
/* 3 for headers, once again size doesn't count itself */
|
|
||||||
pathheader->size = sizeof(DWORD) * 3;
|
|
||||||
if (pathheader->flags & FLAGS_INTPATH)
|
|
||||||
pathheader->size += 2 * sizeof(SHORT) * path->pathdata.Count;
|
|
||||||
else
|
|
||||||
pathheader->size += 2 * sizeof(FLOAT) * path->pathdata.Count;
|
|
||||||
pathheader->size += get_pathtypes_size(path);
|
|
||||||
pathheader->magic = VERSION_MAGIC;
|
|
||||||
pathheader->count = path->pathdata.Count;
|
|
||||||
|
|
||||||
*filled += 4;
|
|
||||||
|
|
||||||
switch (pathheader->flags & FLAGS_INTPATH)
|
|
||||||
{
|
|
||||||
case FLAGS_NOFLAGS:
|
|
||||||
for (i = 0; i < path->pathdata.Count; i++)
|
|
||||||
{
|
|
||||||
write_float(buffer, filled, path->pathdata.Points[i].X);
|
|
||||||
write_float(buffer, filled, path->pathdata.Points[i].Y);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FLAGS_INTPATH:
|
|
||||||
for (i = 0; i < path->pathdata.Count; i++)
|
|
||||||
{
|
|
||||||
write_packed_point(buffer, filled,
|
|
||||||
&path->pathdata.Points[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write_path_types(buffer, filled, path);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RegionDataEmptyRect:
|
case RegionDataEmptyRect:
|
||||||
|
@ -783,6 +687,24 @@ static void write_element(const region_element* element, DWORD *buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD write_region_data(const GpRegion *region, void *data)
|
||||||
|
{
|
||||||
|
struct region_header *header = data;
|
||||||
|
INT filled = 0;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
size = sizeof(struct region_header) + get_element_size(®ion->node);
|
||||||
|
if (!data) return size;
|
||||||
|
|
||||||
|
header->magic = VERSION_MAGIC2;
|
||||||
|
header->num_children = region->num_children;
|
||||||
|
filled += 2;
|
||||||
|
/* With few exceptions, everything written is DWORD aligned,
|
||||||
|
* so use that as our base */
|
||||||
|
write_element(®ion->node, (DWORD*)data, &filled);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* GdipGetRegionData [GDIPLUS.@]
|
* GdipGetRegionData [GDIPLUS.@]
|
||||||
*
|
*
|
||||||
|
@ -819,36 +741,27 @@ static void write_element(const region_element* element, DWORD *buffer,
|
||||||
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
|
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
|
||||||
UINT *needed)
|
UINT *needed)
|
||||||
{
|
{
|
||||||
struct region_header *region_header;
|
struct region_data_header *region_data_header;
|
||||||
INT filled = 0;
|
|
||||||
UINT required;
|
UINT required;
|
||||||
GpStatus status;
|
|
||||||
|
|
||||||
TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
|
TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
|
||||||
|
|
||||||
if (!region || !buffer || !size)
|
if (!region || !buffer || !size)
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
status = GdipGetRegionDataSize(region, &required);
|
required = FIELD_OFFSET(struct region_data_header, header) + write_region_data(region, NULL);
|
||||||
if (status != Ok) return status;
|
|
||||||
if (size < required)
|
if (size < required)
|
||||||
{
|
{
|
||||||
if (needed) *needed = size;
|
if (needed) *needed = size;
|
||||||
return InsufficientBuffer;
|
return InsufficientBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
region_header = (struct region_header *)buffer;
|
region_data_header = (struct region_data_header *)buffer;
|
||||||
region_header->size = sizeheader_size + get_element_size(®ion->node);
|
region_data_header->size = write_region_data(region, ®ion_data_header->header);
|
||||||
region_header->checksum = 0;
|
region_data_header->checksum = 0;
|
||||||
region_header->magic = VERSION_MAGIC;
|
|
||||||
region_header->num_children = region->num_children;
|
|
||||||
filled += 4;
|
|
||||||
/* With few exceptions, everything written is DWORD aligned,
|
|
||||||
* so use that as our base */
|
|
||||||
write_element(®ion->node, (DWORD*)buffer, &filled);
|
|
||||||
|
|
||||||
if (needed)
|
if (needed)
|
||||||
*needed = filled * sizeof(DWORD);
|
*needed = required;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
@ -949,7 +862,7 @@ static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, regio
|
||||||
ERR("failed to read path header\n");
|
ERR("failed to read path header\n");
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
}
|
}
|
||||||
if (path_header->magic != VERSION_MAGIC)
|
if (!VALID_MAGIC(path_header->magic))
|
||||||
{
|
{
|
||||||
ERR("invalid path header magic %#x\n", path_header->magic);
|
ERR("invalid path header magic %#x\n", path_header->magic);
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
@ -1044,7 +957,7 @@ static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, regio
|
||||||
*/
|
*/
|
||||||
GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
|
GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
|
||||||
{
|
{
|
||||||
const struct region_header *region_header;
|
const struct region_data_header *region_data_header;
|
||||||
struct memory_buffer mbuf;
|
struct memory_buffer mbuf;
|
||||||
GpStatus status;
|
GpStatus status;
|
||||||
INT count;
|
INT count;
|
||||||
|
@ -1056,9 +969,8 @@ GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRe
|
||||||
|
|
||||||
init_memory_buffer(&mbuf, data, size);
|
init_memory_buffer(&mbuf, data, size);
|
||||||
|
|
||||||
region_header = buffer_read(&mbuf, sizeof(*region_header));
|
region_data_header = buffer_read(&mbuf, sizeof(*region_data_header));
|
||||||
if (!region_header || (region_header->magic != VERSION_MAGIC &&
|
if (!region_data_header || !VALID_MAGIC(region_data_header->header.magic))
|
||||||
region_header->magic != VERSION_MAGIC2))
|
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
status = GdipCreateRegion(region);
|
status = GdipCreateRegion(region);
|
||||||
|
@ -1090,7 +1002,7 @@ GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
|
||||||
return InvalidParameter;
|
return InvalidParameter;
|
||||||
|
|
||||||
/* header.size doesn't count header.size and header.checksum */
|
/* header.size doesn't count header.size and header.checksum */
|
||||||
*needed = sizeof(DWORD) * 2 + sizeheader_size + get_element_size(®ion->node);
|
*needed = FIELD_OFFSET(struct region_data_header, header) + write_region_data(region, NULL);
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
@ -1135,6 +1047,8 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
|
||||||
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
|
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
|
||||||
: WINDING));
|
: WINDING));
|
||||||
|
|
||||||
|
gdi_transform_acquire(graphics);
|
||||||
|
|
||||||
stat = trace_path(graphics, path);
|
stat = trace_path(graphics, path);
|
||||||
if (stat == Ok)
|
if (stat == Ok)
|
||||||
{
|
{
|
||||||
|
@ -1142,6 +1056,8 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
|
||||||
stat = *hrgn ? Ok : OutOfMemory;
|
stat = *hrgn ? Ok : OutOfMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdi_transform_release(graphics);
|
||||||
|
|
||||||
RestoreDC(graphics->hdc, save_state);
|
RestoreDC(graphics->hdc, save_state);
|
||||||
if (new_hdc)
|
if (new_hdc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,7 +68,7 @@ reactos/dll/win32/dciman32 # Synced to WineStaging-2.9
|
||||||
reactos/dll/win32/faultrep # Synced to WineStaging-2.9
|
reactos/dll/win32/faultrep # Synced to WineStaging-2.9
|
||||||
reactos/dll/win32/fontsub # Synced to WineStaging-2.9
|
reactos/dll/win32/fontsub # Synced to WineStaging-2.9
|
||||||
reactos/dll/win32/fusion # Synced to WineStaging-2.16
|
reactos/dll/win32/fusion # Synced to WineStaging-2.16
|
||||||
reactos/dll/win32/gdiplus # Synced to WineStaging-2.9
|
reactos/dll/win32/gdiplus # Synced to WineStaging-2.16
|
||||||
reactos/dll/win32/hhctrl.ocx # Synced to WineStaging-2.9
|
reactos/dll/win32/hhctrl.ocx # Synced to WineStaging-2.9
|
||||||
reactos/dll/win32/hlink # Synced to WineStaging-2.9
|
reactos/dll/win32/hlink # Synced to WineStaging-2.9
|
||||||
reactos/dll/win32/hnetcfg # Synced to WineStaging-2.9
|
reactos/dll/win32/hnetcfg # Synced to WineStaging-2.9
|
||||||
|
|
Loading…
Reference in a new issue