[GDIPLUS]

* Sync with Wine 1.7.17.
CORE-8080

svn path=/trunk/; revision=62888
This commit is contained in:
Amine Khaldi 2014-04-22 15:42:03 +00:00
parent cceb6b9f47
commit 86c5b8463d
11 changed files with 1075 additions and 590 deletions

View file

@ -756,8 +756,6 @@ GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
/******************************************************************************
* GdipCreateTextureIA [GDIPLUS.@]
*
* FIXME: imageattr ignored
*/
GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
@ -855,6 +853,7 @@ GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
imageattr->wrap = wrapmode;
stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture);
GdipDisposeImageAttributes(imageattr);
}
return stat;

View file

@ -1112,15 +1112,39 @@ GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontColle
/*****************************************************************************
* GdipPrivateAddFontFile [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection,
GDIPCONST WCHAR* filename)
GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection *collection, GDIPCONST WCHAR *name)
{
FIXME("stub: %p, %s\n", fontCollection, debugstr_w(filename));
HANDLE file, mapping;
LARGE_INTEGER size;
void *mem;
GpStatus status;
if (!(fontCollection && filename))
TRACE("%p, %s\n", collection, debugstr_w(name));
if (!collection || !name) return InvalidParameter;
file = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (file == INVALID_HANDLE_VALUE) return InvalidParameter;
if (!GetFileSizeEx(file, &size) || size.u.HighPart)
{
CloseHandle(file);
return InvalidParameter;
}
return NotImplemented;
mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
CloseHandle(file);
if (!mapping) return InvalidParameter;
mem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
CloseHandle(mapping);
if (!mem) return InvalidParameter;
/* GdipPrivateAddMemoryFont creates a copy of the memory block */
status = GdipPrivateAddMemoryFont(collection, mem, size.u.LowPart);
UnmapViewOfFile(mem);
return status;
}
#define TT_PLATFORM_APPLE_UNICODE 0

View file

@ -357,7 +357,7 @@ REAL units_scale(GpUnit from, GpUnit to, REAL dpi)
}
/* Calculates Bezier points from cardinal spline points. */
void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2)
{
REAL xdiff, ydiff;
@ -442,7 +442,7 @@ void delete_element(region_element* element)
case RegionDataRect:
break;
case RegionDataPath:
GdipDeletePath(element->elementdata.pathdata.path);
GdipDeletePath(element->elementdata.path);
break;
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
@ -456,13 +456,13 @@ void delete_element(region_element* element)
}
}
const char *debugstr_rectf(CONST RectF* rc)
const char *debugstr_rectf(const RectF* rc)
{
if (!rc) return "(null)";
return wine_dbg_sprintf("(%0.2f,%0.2f,%0.2f,%0.2f)", rc->X, rc->Y, rc->Width, rc->Height);
}
const char *debugstr_pointf(CONST PointF* pt)
const char *debugstr_pointf(const PointF* pt)
{
if (!pt) return "(null)";
return wine_dbg_sprintf("(%0.2f,%0.2f)", pt->X, pt->Y);

View file

@ -65,10 +65,12 @@ extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLS
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
extern MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) 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;
extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
REAL tension, REAL *x, REAL *y) DECLSPEC_HIDDEN;
@ -122,9 +124,9 @@ static inline ARGB color_over(ARGB bg, ARGB fg)
return (a<<24)|(r<<16)|(g<<8)|b;
}
extern const char *debugstr_rectf(CONST RectF* rc) DECLSPEC_HIDDEN;
extern const char *debugstr_rectf(const RectF* rc) DECLSPEC_HIDDEN;
extern const char *debugstr_pointf(CONST PointF* pt) DECLSPEC_HIDDEN;
extern const char *debugstr_pointf(const PointF* pt) DECLSPEC_HIDDEN;
extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride) DECLSPEC_HIDDEN;
@ -304,8 +306,12 @@ struct GpMetafile{
GpGraphics *playback_graphics;
HDC playback_dc;
GpPointF playback_points[3];
GpRectF src_rect;
HANDLETABLE *handle_table;
int handle_count;
GpMatrix *world_transform;
GpUnit page_unit;
REAL page_scale;
};
struct GpBitmap{
@ -412,17 +418,7 @@ struct region_element
union
{
GpRectF rect;
struct
{
GpPath* path;
struct
{
DWORD size;
DWORD magic;
DWORD count;
DWORD flags;
} pathheader;
} pathdata;
GpPath *path;
struct
{
struct region_element *left; /* the original region */
@ -432,13 +428,7 @@ struct region_element
};
struct GpRegion{
struct
{
DWORD size;
DWORD checksum;
DWORD magic;
DWORD num_children;
} header;
DWORD num_children;
region_element node;
};

View file

@ -617,7 +617,7 @@ static ARGB transform_color(ARGB color, const ColorMatrix *matrix)
return (a << 24) | (r << 16) | (g << 8) | b;
}
static int color_is_gray(ARGB color)
static BOOL color_is_gray(ARGB color)
{
unsigned char r, g, b;
@ -940,12 +940,12 @@ static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL
return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X;
}
static INT brush_can_fill_path(GpBrush *brush)
static BOOL brush_can_fill_path(GpBrush *brush)
{
switch (brush->bt)
{
case BrushTypeSolidColor:
return 1;
return TRUE;
case BrushTypeHatchFill:
{
GpHatch *hatch = (GpHatch*)brush;
@ -956,7 +956,7 @@ static INT brush_can_fill_path(GpBrush *brush)
case BrushTypeTextureFill:
/* Gdi32 isn't much help with these, so we should use brush_fill_pixels instead. */
default:
return 0;
return FALSE;
}
}
@ -1008,7 +1008,7 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
}
}
static INT brush_can_fill_pixels(GpBrush *brush)
static BOOL brush_can_fill_pixels(GpBrush *brush)
{
switch (brush->bt)
{
@ -1017,9 +1017,9 @@ static INT brush_can_fill_pixels(GpBrush *brush)
case BrushTypeLinearGradient:
case BrushTypeTextureFill:
case BrushTypePathGradient:
return 1;
return TRUE;
default:
return 0;
return FALSE;
}
}
@ -1239,7 +1239,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
INT min_y, max_y, min_x, max_x;
INT x, y;
ARGB outer_color;
static int transform_fixme_once;
static BOOL transform_fixme_once;
if (fill->focus.X != 0.0 || fill->focus.Y != 0.0)
{
@ -1276,7 +1276,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
if (!is_identity)
{
FIXME("path gradient transform not implemented\n");
transform_fixme_once = 1;
transform_fixme_once = TRUE;
}
}
@ -1310,7 +1310,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
for (i=0; i<flat_path->pathdata.Count; i++)
{
int start_center_line=0, end_center_line=0;
int seen_start=0, seen_end=0, seen_center=0;
BOOL seen_start = FALSE, seen_end = FALSE, seen_center = FALSE;
REAL center_distance;
ARGB start_color, end_color;
REAL dy, dx;
@ -1370,17 +1370,17 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
if (!seen_start && yf >= start_point.Y)
{
seen_start = 1;
seen_start = TRUE;
start_center_line ^= 1;
}
if (!seen_end && yf >= end_point.Y)
{
seen_end = 1;
seen_end = TRUE;
end_center_line ^= 1;
}
if (!seen_center && yf >= center_point.Y)
{
seen_center = 1;
seen_center = TRUE;
start_center_line ^= 1;
end_center_line ^= 1;
}
@ -2243,120 +2243,6 @@ GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
return GdipCreateFromHWND(hwnd, graphics);
}
GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
GpMetafile **metafile)
{
ENHMETAHEADER header;
MetafileType metafile_type;
TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
if(!hemf || !metafile)
return InvalidParameter;
if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
return GenericError;
metafile_type = METAFILE_GetEmfType(hemf);
if (metafile_type == MetafileTypeInvalid)
return GenericError;
*metafile = GdipAlloc(sizeof(GpMetafile));
if (!*metafile)
return OutOfMemory;
(*metafile)->image.type = ImageTypeMetafile;
(*metafile)->image.format = ImageFormatEMF;
(*metafile)->image.frame_count = 1;
(*metafile)->image.xres = (REAL)header.szlDevice.cx;
(*metafile)->image.yres = (REAL)header.szlDevice.cy;
(*metafile)->bounds.X = (REAL)header.rclBounds.left;
(*metafile)->bounds.Y = (REAL)header.rclBounds.top;
(*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
(*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
(*metafile)->unit = UnitPixel;
(*metafile)->metafile_type = metafile_type;
(*metafile)->hemf = hemf;
(*metafile)->preserve_hemf = !delete;
TRACE("<-- %p\n", *metafile);
return Ok;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
{
UINT read;
BYTE *copy;
HENHMETAFILE hemf;
GpStatus retval = Ok;
TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
if(!hwmf || !metafile || !placeable)
return InvalidParameter;
*metafile = NULL;
read = GetMetaFileBitsEx(hwmf, 0, NULL);
if(!read)
return GenericError;
copy = GdipAlloc(read);
GetMetaFileBitsEx(hwmf, read, copy);
hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
GdipFree(copy);
/* FIXME: We should store and use hwmf instead of converting to hemf */
retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
if (retval == Ok)
{
(*metafile)->image.xres = (REAL)placeable->Inch;
(*metafile)->image.yres = (REAL)placeable->Inch;
(*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
(*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
(*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
placeable->BoundingBox.Left);
(*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
placeable->BoundingBox.Top);
(*metafile)->metafile_type = MetafileTypeWmfPlaceable;
(*metafile)->image.format = ImageFormatWMF;
if (delete) DeleteMetaFile(hwmf);
}
else
DeleteEnhMetaFile(hemf);
return retval;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
{
HMETAFILE hmf = GetMetaFileW(file);
TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
if(!hmf) return InvalidParameter;
return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
}
GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
GpMetafile **metafile)
{
FIXME("(%p, %p): stub\n", file, metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
GpMetafile **metafile)
{
FIXME("(%p, %p): stub\n", stream, metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
UINT access, IStream **stream)
{
@ -2405,6 +2291,12 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
}
GdipDeleteRegion(graphics->clip);
/* Native returns ObjectBusy on the second free, instead of crashing as we'd
* do otherwise, but we can't have that in the test suite because it means
* accessing freed memory. */
graphics->busy = TRUE;
GdipFree(graphics);
return Ok;
@ -2885,9 +2777,33 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
debugstr_pointf(&points[2]));
memcpy(ptf, points, 3 * sizeof(GpPointF));
/* Ensure source width/height is positive */
if (srcwidth < 0)
{
GpPointF tmp = ptf[1];
srcx = srcx + srcwidth;
srcwidth = -srcwidth;
ptf[2].X = ptf[2].X + ptf[1].X - ptf[0].X;
ptf[2].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
ptf[1] = ptf[0];
ptf[0] = tmp;
}
if (srcheight < 0)
{
GpPointF tmp = ptf[2];
srcy = srcy + srcheight;
srcheight = -srcheight;
ptf[1].X = ptf[1].X + ptf[2].X - ptf[0].X;
ptf[1].Y = ptf[1].Y + ptf[2].Y - ptf[0].Y;
ptf[2] = ptf[0];
ptf[0] = tmp;
}
ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X;
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;
transform_and_round_points(graphics, pti, ptf, 4);
@ -2919,7 +2835,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
else if (image->type == ImageTypeBitmap)
{
GpBitmap* bitmap = (GpBitmap*)image;
int use_software=0;
BOOL use_software = FALSE;
TRACE("graphics: %.2fx%.2f dpi, fmt %#x, scale %f, image: %.2fx%.2f dpi, fmt %#x, color %08x\n",
graphics->xres, graphics->yres,
@ -2933,11 +2849,12 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
ptf[1].X - ptf[0].X != srcwidth || ptf[2].Y - ptf[0].Y != srcheight ||
srcx < 0 || srcy < 0 ||
srcx + srcwidth > bitmap->width || srcy + srcheight > bitmap->height)
use_software = 1;
use_software = TRUE;
if (use_software)
{
RECT dst_area;
GpRectF graphics_bounds;
GpRect src_area;
int i, x, y, src_stride, dst_stride;
GpMatrix dst_to_src;
@ -2963,8 +2880,18 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
}
stat = get_graphics_bounds(graphics, &graphics_bounds);
if (stat != Ok) return stat;
if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
if (graphics_bounds.Y > dst_area.top) dst_area.top = floorf(graphics_bounds.Y);
if (graphics_bounds.X + graphics_bounds.Width < dst_area.right) dst_area.right = ceilf(graphics_bounds.X + graphics_bounds.Width);
if (graphics_bounds.Y + graphics_bounds.Height < dst_area.bottom) dst_area.bottom = ceilf(graphics_bounds.Y + graphics_bounds.Height);
TRACE("dst_area: %s\n", wine_dbgstr_rect(&dst_area));
if (IsRectEmpty(&dst_area)) return Ok;
m11 = (ptf[1].X - ptf[0].X) / srcwidth;
m21 = (ptf[2].X - ptf[0].X) / srcheight;
mdx = ptf[0].X - m11 * srcx - m21 * srcy;
@ -3010,8 +2937,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
if (stat != Ok)
{
if (src_data != dst_data)
GdipFree(src_data);
GdipFree(src_data);
GdipFree(dst_data);
return stat;
}
@ -3060,7 +2986,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
else
{
HDC hdc;
int temp_hdc=0, temp_bitmap=0;
BOOL temp_hdc = FALSE, temp_bitmap = FALSE;
HBITMAP hbitmap, old_hbm=NULL;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
@ -3074,8 +3000,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
/* we can't draw a bitmap of this format directly */
hdc = CreateCompatibleDC(0);
temp_hdc = 1;
temp_bitmap = 1;
temp_hdc = TRUE;
temp_bitmap = TRUE;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = bitmap->width;
@ -3109,7 +3035,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
else
{
GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
temp_bitmap = 1;
temp_bitmap = TRUE;
}
hdc = bitmap->hdc;
@ -3338,6 +3264,7 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
INT save_state;
GpStatus retval;
HRGN hrgn=NULL;
TRACE("(%p, %p, %p)\n", graphics, pen, path);
@ -3355,10 +3282,20 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
save_state = prepare_dc(graphics, pen);
retval = get_clip_hrgn(graphics, &hrgn);
if (retval != Ok)
goto end;
if (hrgn)
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
retval = draw_poly(graphics, pen, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, TRUE);
end:
restore_dc(graphics, save_state);
DeleteObject(hrgn);
return retval;
}
@ -3603,6 +3540,7 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
{
INT save_state;
GpStatus retval;
HRGN hrgn=NULL;
if(!graphics->hdc || !brush_can_fill_path(brush))
return NotImplemented;
@ -3612,6 +3550,14 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
: WINDING));
retval = get_clip_hrgn(graphics, &hrgn);
if (retval != Ok)
goto end;
if (hrgn)
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
BeginPath(graphics->hdc);
retval = draw_poly(graphics, NULL, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, FALSE);
@ -3626,6 +3572,7 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath
end:
RestoreDC(graphics->hdc, save_state);
DeleteObject(hrgn);
return retval;
}
@ -3795,38 +3742,31 @@ GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush,
GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
REAL x, REAL y, REAL width, REAL height)
{
GpStatus stat;
GpPath *path;
GpRectF rect;
TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
if(!graphics || !brush)
return InvalidParameter;
rect.X = x;
rect.Y = y;
rect.Width = width;
rect.Height = height;
if(graphics->busy)
return ObjectBusy;
stat = GdipCreatePath(FillModeAlternate, &path);
if (stat == Ok)
{
stat = GdipAddPathRectangle(path, x, y, width, height);
if (stat == Ok)
stat = GdipFillPath(graphics, brush, path);
GdipDeletePath(path);
}
return stat;
return GdipFillRectangles(graphics, brush, &rect, 1);
}
GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
INT x, INT y, INT width, INT height)
{
GpRectF rect;
TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
return GdipFillRectangle(graphics, brush, x, y, width, height);
rect.X = (REAL)x;
rect.Y = (REAL)y;
rect.Width = (REAL)width;
rect.Height = (REAL)height;
return GdipFillRectangles(graphics, brush, &rect, 1);
}
GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects,
@ -3837,9 +3777,16 @@ GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDI
TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
if(!rects)
if(!graphics || !brush || !rects || count <= 0)
return InvalidParameter;
if (graphics->image && graphics->image->type == ImageTypeMetafile)
{
status = METAFILE_FillRectangles((GpMetafile*)graphics->image, brush, rects, count);
/* FIXME: Add gdi32 drawing. */
return status;
}
status = GdipCreatePath(FillModeAlternate, &path);
if (status != Ok) return status;
@ -4440,13 +4387,25 @@ GpStatus gdip_format_string(HDC hdc,
INT *hotkeyprefix_offsets=NULL;
INT hotkeyprefix_count=0;
INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=0;
int seen_prefix=0;
BOOL seen_prefix = FALSE;
GpStringFormat *dyn_format=NULL;
if(length == -1) length = lstrlenW(string);
stringdup = GdipAlloc((length + 1) * sizeof(WCHAR));
if(!stringdup) return OutOfMemory;
if (!format)
{
stat = GdipStringFormatGetGenericDefault(&dyn_format);
if (stat != Ok)
{
GdipFree(stringdup);
return stat;
}
format = dyn_format;
}
nwidth = rect->Width;
nheight = rect->Height;
if (ignore_empty_clip)
@ -4455,10 +4414,7 @@ GpStatus gdip_format_string(HDC hdc,
if (!nheight) nheight = INT_MAX;
}
if (format)
hkprefix = format->hkprefix;
else
hkprefix = HotkeyPrefixNone;
hkprefix = format->hkprefix;
if (hkprefix == HotkeyPrefixShow)
{
@ -4487,11 +4443,11 @@ GpStatus gdip_format_string(HDC hdc,
hotkeyprefix_offsets[hotkeyprefix_count++] = j;
else if (!seen_prefix && hkprefix != HotkeyPrefixNone && string[i] == '&')
{
seen_prefix = 1;
seen_prefix = TRUE;
continue;
}
seen_prefix = 0;
seen_prefix = FALSE;
stringdup[j] = string[i];
j++;
@ -4499,8 +4455,7 @@ GpStatus gdip_format_string(HDC hdc,
length = j;
if (format) halign = format->align;
else halign = StringAlignmentNear;
halign = format->align;
while(sum < length){
GetTextExtentExPointW(hdc, stringdup + sum, length - sum,
@ -4547,7 +4502,11 @@ GpStatus gdip_format_string(HDC hdc,
bounds.Width = size.cx;
if(height + size.cy > nheight)
{
if (format->attr & StringFormatFlagsLineLimit)
break;
bounds.Height = nheight - (height + size.cy);
}
else
bounds.Height = size.cy;
@ -4589,13 +4548,13 @@ GpStatus gdip_format_string(HDC hdc,
break;
/* Stop if this was a linewrap (but not if it was a linebreak). */
if ((lret == fitcpy) && format &&
(format->attr & (StringFormatFlagsNoWrap | StringFormatFlagsLineLimit)))
if ((lret == fitcpy) && (format->attr & StringFormatFlagsNoWrap))
break;
}
GdipFree(stringdup);
GdipFree(hotkeyprefix_offsets);
GdipDeleteStringFormat(dyn_format);
return stat;
}
@ -5239,6 +5198,8 @@ GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
{
GpStatus stat;
TRACE("(%p, %.2f)\n", graphics, scale);
if(!graphics || (scale <= 0.0))
@ -5247,6 +5208,13 @@ GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
if(graphics->busy)
return ObjectBusy;
if (graphics->image && graphics->image->type == ImageTypeMetafile)
{
stat = METAFILE_SetPageTransform((GpMetafile*)graphics->image, graphics->unit, scale);
if (stat != Ok)
return stat;
}
graphics->scale = scale;
return Ok;
@ -5254,6 +5222,8 @@ GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
{
GpStatus stat;
TRACE("(%p, %d)\n", graphics, unit);
if(!graphics)
@ -5265,6 +5235,13 @@ GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
if(unit == UnitWorld)
return InvalidParameter;
if (graphics->image && graphics->image->type == ImageTypeMetafile)
{
stat = METAFILE_SetPageTransform((GpMetafile*)graphics->image, unit, graphics->scale);
if (stat != Ok)
return stat;
}
graphics->unit = unit;
return Ok;
@ -5528,19 +5505,6 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
return status;
}
GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
UINT limitDpi)
{
static int calls;
TRACE("(%p,%u)\n", metafile, limitDpi);
if(!(calls++))
FIXME("not implemented\n");
return NotImplemented;
}
GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points,
INT count)
{
@ -6204,15 +6168,18 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
if (glyphsize > max_glyphsize)
max_glyphsize = glyphsize;
left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
if (glyphsize != 0)
{
left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
if (left < min_x) min_x = left;
if (top < min_y) min_y = top;
if (right > max_x) max_x = right;
if (bottom > max_y) max_y = bottom;
if (left < min_x) min_x = left;
if (top < min_y) min_y = top;
if (right > max_x) max_x = right;
if (bottom > max_y) max_y = bottom;
}
if (i+1 < length && (flags & DriverStringOptionsRealizedAdvance) == DriverStringOptionsRealizedAdvance)
{
@ -6221,6 +6188,10 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
}
}
if (max_glyphsize == 0)
/* Nothing to draw. */
return Ok;
glyph_mask = GdipAlloc(max_glyphsize);
text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y));
text_mask_stride = max_x - min_x;
@ -6238,11 +6209,15 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
/* Generate a mask for the text */
for (i=0; i<length; i++)
{
DWORD ret;
int left, top, stride;
GetGlyphOutlineW(hdc, text[i], ggo_flags,
ret = GetGlyphOutlineW(hdc, text[i], ggo_flags,
&glyphmetrics, max_glyphsize, glyph_mask, &identity);
if (ret == GDI_ERROR || ret == 0)
continue; /* empty glyph */
left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
stride = (glyphmetrics.gmBlackBoxX + 3) & (~3);

View file

@ -854,7 +854,7 @@ static GpStatus format_string_callback(HDC dc,
for (i = index; i < length; ++i)
{
GLYPHMETRICS gm;
TTPOLYGONHEADER *ph = NULL;
TTPOLYGONHEADER *ph = NULL, *origph;
char *start;
DWORD len, ofs = 0;
len = GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, 0, NULL, &identity);
@ -863,7 +863,7 @@ static GpStatus format_string_callback(HDC dc,
status = GenericError;
break;
}
ph = GdipAlloc(len);
origph = ph = GdipAlloc(len);
start = (char *)ph;
if (!ph || !lengthen_path(path, len / sizeof(POINTFX)))
{
@ -917,7 +917,7 @@ static GpStatus format_string_callback(HDC dc,
x += gm.gmCellIncX * args->scale;
y += gm.gmCellIncY * args->scale;
GdipFree(ph);
GdipFree(origph);
if (status != Ok)
break;
}
@ -1837,8 +1837,9 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint,
}
}
static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
path_list_node_t **last_point)
static void widen_open_figure(const GpPointF *points, GpPen *pen, int start, int end,
GpLineCap start_cap, GpCustomLineCap *start_custom, GpLineCap end_cap,
GpCustomLineCap *end_custom, path_list_node_t **last_point)
{
int i;
path_list_node_t *prev_point;
@ -1848,22 +1849,22 @@ static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
prev_point = *last_point;
widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
pen, pen->startcap, pen->customstart, FALSE, TRUE, last_point);
widen_cap(&points[start], &points[start+1],
pen, start_cap, start_custom, FALSE, TRUE, last_point);
for (i=start+1; i<end; i++)
widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i],
&path->pathdata.Points[i+1], pen, last_point);
widen_joint(&points[i-1], &points[i],
&points[i+1], pen, last_point);
widen_cap(&path->pathdata.Points[end], &path->pathdata.Points[end-1],
pen, pen->endcap, pen->customend, TRUE, TRUE, last_point);
widen_cap(&points[end], &points[end-1],
pen, end_cap, end_custom, TRUE, TRUE, last_point);
for (i=end-1; i>start; i--)
widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i],
&path->pathdata.Points[i-1], pen, last_point);
widen_joint(&points[i+1], &points[i],
&points[i-1], pen, last_point);
widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
pen, pen->startcap, pen->customstart, TRUE, FALSE, last_point);
widen_cap(&points[start], &points[start+1],
pen, start_cap, start_custom, TRUE, FALSE, last_point);
prev_point->next->type = PathPointTypeStart;
(*last_point)->type |= PathPointTypeCloseSubpath;
@ -1911,6 +1912,134 @@ static void widen_closed_figure(GpPath *path, GpPen *pen, int start, int end,
(*last_point)->type |= PathPointTypeCloseSubpath;
}
static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
int closed, path_list_node_t **last_point)
{
int i, j;
REAL dash_pos=0.0;
int dash_index=0;
const REAL *dash_pattern;
int dash_count;
GpPointF *tmp_points;
REAL segment_dy;
REAL segment_dx;
REAL segment_length;
REAL segment_pos;
int num_tmp_points=0;
int draw_start_cap=0;
static const REAL dash_dot_dot[6] = { 3.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
if (end <= start)
return;
switch (pen->dash)
{
case DashStyleDash:
default:
dash_pattern = dash_dot_dot;
dash_count = 2;
break;
case DashStyleDot:
dash_pattern = &dash_dot_dot[2];
dash_count = 2;
break;
case DashStyleDashDot:
dash_pattern = dash_dot_dot;
dash_count = 4;
break;
case DashStyleDashDotDot:
dash_pattern = dash_dot_dot;
dash_count = 6;
break;
case DashStyleCustom:
dash_pattern = pen->dashes;
dash_count = pen->numdashes;
break;
}
tmp_points = GdipAlloc((end - start + 2) * sizeof(GpPoint));
if (!tmp_points) return; /* FIXME */
if (!closed)
draw_start_cap = 1;
for (j=start; j <= end; j++)
{
if (j == start)
{
if (closed)
i = end;
else
continue;
}
else
i = j-1;
segment_dy = path->pathdata.Points[j].Y - path->pathdata.Points[i].Y;
segment_dx = path->pathdata.Points[j].X - path->pathdata.Points[i].X;
segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
segment_pos = 0.0;
while (1)
{
if (dash_pos == 0.0)
{
if ((dash_index % 2) == 0)
{
/* start dash */
num_tmp_points = 1;
tmp_points[0].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
tmp_points[0].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
}
else
{
/* end dash */
tmp_points[num_tmp_points].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
tmp_points[num_tmp_points].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
widen_open_figure(tmp_points, pen, 0, num_tmp_points,
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
LineCapFlat, NULL, last_point);
draw_start_cap = 0;
num_tmp_points = 0;
}
}
if (dash_pattern[dash_index] - dash_pos > segment_length - segment_pos)
{
/* advance to next segment */
if ((dash_index % 2) == 0)
{
tmp_points[num_tmp_points] = path->pathdata.Points[j];
num_tmp_points++;
}
dash_pos += segment_length - segment_pos;
break;
}
else
{
/* advance to next dash in pattern */
segment_pos += dash_pattern[dash_index] - dash_pos;
dash_pos = 0.0;
if (++dash_index == dash_count)
dash_index = 0;
continue;
}
}
}
if (dash_index % 2 == 0 && num_tmp_points != 0)
{
/* last dash overflows last segment */
tmp_points[num_tmp_points] = path->pathdata.Points[end];
widen_open_figure(tmp_points, pen, 0, num_tmp_points,
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
}
GdipFree(tmp_points);
}
GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
REAL flatness)
{
@ -1952,9 +2081,6 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if (pen->join == LineJoinRound)
FIXME("unimplemented line join %d\n", pen->join);
if (pen->dash != DashStyleSolid)
FIXME("unimplemented dash style %d\n", pen->dash);
if (pen->align != PenAlignmentCenter)
FIXME("unimplemented pen alignment %d\n", pen->align);
@ -1967,12 +2093,18 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
{
widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
if (pen->dash != DashStyleSolid)
widen_dashed_figure(flat_path, pen, subpath_start, i, 1, &last_point);
else
widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
}
else if (i == flat_path->pathdata.Count-1 ||
(flat_path->pathdata.Types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart)
{
widen_open_figure(flat_path, pen, subpath_start, i, &last_point);
if (pen->dash != DashStyleSolid)
widen_dashed_figure(flat_path, pen, subpath_start, i, 0, &last_point);
else
widen_open_figure(flat_path->pathdata.Points, pen, subpath_start, i, pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point);
}
}

View file

@ -1105,12 +1105,12 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
if (flags & ImageLockModeRead)
{
static int fixme=0;
static BOOL fixme = FALSE;
if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
{
FIXME("Cannot copy rows that don't start at a whole byte.\n");
fixme = 1;
fixme = TRUE;
}
stat = convert_pixels(act_rect.Width, act_rect.Height,
@ -1152,7 +1152,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
BitmapData* lockeddata)
{
GpStatus stat;
static int fixme=0;
static BOOL fixme = FALSE;
TRACE("(%p,%p)\n", bitmap, lockeddata);
@ -1182,7 +1182,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
{
FIXME("Cannot copy rows that don't start at a whole byte.\n");
fixme = 1;
fixme = TRUE;
}
stat = convert_pixels(lockeddata->Width, lockeddata->Height,
@ -1207,9 +1207,6 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
{
BitmapData lockeddata_src, lockeddata_dst;
int i;
UINT row_size;
Rect area;
GpStatus stat;
@ -1231,39 +1228,41 @@ GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
area.Width = gdip_round(width);
area.Height = gdip_round(height);
stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
&lockeddata_src);
if (stat != Ok) return stat;
stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
0, lockeddata_src.PixelFormat, NULL, dstBitmap);
stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
if (stat == Ok)
{
stat = GdipBitmapLockBits(*dstBitmap, NULL, ImageLockModeWrite,
lockeddata_src.PixelFormat, &lockeddata_dst);
stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
srcBitmap->stride,
srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
srcBitmap->format, srcBitmap->image.palette);
if (stat == Ok)
if (stat == Ok && srcBitmap->image.palette)
{
/* copy the image data */
row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
for (i=0; i<lockeddata_src.Height; i++)
memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
(BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
row_size);
ColorPalette *src_palette, *dst_palette;
GdipBitmapUnlockBits(*dstBitmap, &lockeddata_dst);
src_palette = srcBitmap->image.palette;
dst_palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count);
if (dst_palette)
{
dst_palette->Flags = src_palette->Flags;
dst_palette->Count = src_palette->Count;
memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count);
GdipFree((*dstBitmap)->image.palette);
(*dstBitmap)->image.palette = dst_palette;
}
else
stat = OutOfMemory;
}
if (stat != Ok)
GdipDisposeImage((GpImage*)*dstBitmap);
}
GdipBitmapUnlockBits(srcBitmap, &lockeddata_src);
if (stat != Ok)
{
*dstBitmap = NULL;
}
return stat;
}
@ -1318,47 +1317,10 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
}
else if (image->type == ImageTypeBitmap)
{
GpBitmap *bitmap = (GpBitmap*)image;
BitmapData lockeddata_src, lockeddata_dst;
int i;
UINT row_size;
GpBitmap *bitmap = (GpBitmap *)image;
stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
&lockeddata_src);
if (stat != Ok) return stat;
stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
if (stat == Ok)
{
stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
lockeddata_src.PixelFormat, &lockeddata_dst);
if (stat == Ok)
{
/* copy the image data */
row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
for (i=0; i<lockeddata_src.Height; i++)
memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
(BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
row_size);
GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
}
if (stat != Ok)
GdipDisposeImage(*cloneImage);
}
GdipBitmapUnlockBits(bitmap, &lockeddata_src);
if (stat != Ok)
{
*cloneImage = NULL;
}
else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
return stat;
return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
bitmap->format, bitmap, (GpBitmap **)cloneImage);
}
else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
{
@ -1557,27 +1519,6 @@ GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
return stat;
}
GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
GpMetafile* metafile, BOOL* succ, EmfType emfType,
const WCHAR* description, GpMetafile** out_metafile)
{
static int calls;
TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
debugstr_w(description), out_metafile);
if(!ref || !metafile || !out_metafile)
return InvalidParameter;
*succ = FALSE;
*out_metafile = NULL;
if(!(calls++))
FIXME("not implemented\n");
return NotImplemented;
}
GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
GpGraphics* target, GpBitmap** bitmap)
{
@ -1799,7 +1740,6 @@ static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
{
BITMAPINFO* pbmi;
HBITMAP hbitmap=NULL;
INT row_size, dib_stride;
BYTE *bits=NULL, *own_bits=NULL;
@ -1829,9 +1769,8 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
{
pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
if (!pbmi)
return OutOfMemory;
char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = width;
@ -1848,8 +1787,6 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
GdipFree(pbmi);
if (!hbitmap) return GenericError;
stride = dib_stride;
@ -2072,13 +2009,6 @@ GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
}
GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
LPBYTE pData16, INT iMapMode, INT eFlags)
{
FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
return NotImplemented;
}
/* Internal utility function: Replace the image data of dst with that of src,
* and free src. */
static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
@ -2423,76 +2353,6 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
MetafileHeader * header)
{
static int calls;
TRACE("(%p, %p)\n", metafile, header);
if(!metafile || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
MetafileHeader *header)
{
static int calls;
if(!hEmf || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
MetafileHeader *header)
{
static int calls;
TRACE("(%s,%p)\n", debugstr_w(filename), header);
if(!filename || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
MetafileHeader *header)
{
static int calls;
TRACE("(%p,%p)\n", stream, header);
if(!stream || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
{
TRACE("(%p, %p)\n", image, num);
@ -3989,6 +3849,7 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
HRESULT hr;
UINT width, height;
PixelFormat gdipformat=0;
const WICPixelFormatGUID *desired_wicformat;
WICPixelFormatGUID wicformat;
GpRect rc;
BitmapData lockeddata;
@ -4041,20 +3902,40 @@ static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
{
if (pixel_formats[i].gdip_format == bitmap->format)
{
memcpy(&wicformat, pixel_formats[i].wic_format, sizeof(GUID));
desired_wicformat = pixel_formats[i].wic_format;
gdipformat = bitmap->format;
break;
}
}
if (!gdipformat)
{
memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
desired_wicformat = &GUID_WICPixelFormat32bppBGRA;
gdipformat = PixelFormat32bppARGB;
}
memcpy(&wicformat, desired_wicformat, sizeof(GUID));
hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
}
if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat))
{
/* Encoder doesn't support this bitmap's format. */
gdipformat = 0;
for (i=0; pixel_formats[i].wic_format; i++)
{
if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format))
{
gdipformat = pixel_formats[i].gdip_format;
break;
}
}
if (!gdipformat)
{
ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat));
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
@ -4652,28 +4533,21 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi
if (retval == Ok)
{
HDC hdc;
BITMAPINFO *pbmi;
char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
INT src_height;
hdc = CreateCompatibleDC(NULL);
pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
if (pbmi)
{
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biBitCount = 0;
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biBitCount = 0;
GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
src_height = abs(pbmi->bmiHeader.biHeight);
pbmi->bmiHeader.biHeight = -src_height;
src_height = abs(pbmi->bmiHeader.biHeight);
pbmi->bmiHeader.biHeight = -src_height;
GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
GdipFree(pbmi);
}
else
retval = OutOfMemory;
GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
DeleteDC(hdc);
@ -4781,27 +4655,6 @@ GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
return Ok;
}
GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
GpMetafile **metafile)
{
FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
frameUnit, debugstr_w(desc), metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
GDIPCONST WCHAR *desc, GpMetafile **metafile)
{
FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
frameUnit, debugstr_w(desc), metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
{
TRACE("%p\n", image);
@ -4866,7 +4719,7 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
GpBitmap *new_bitmap;
GpBitmap *bitmap;
int bpp, bytesperpixel;
int rotate_90, flip_x, flip_y;
BOOL rotate_90, flip_x, flip_y;
int src_x_offset, src_y_offset;
LPBYTE src_origin;
UINT x, y, width, height;
@ -4975,16 +4828,3 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
return stat;
}
/*****************************************************************************
* GdipConvertToEmfPlusToFile [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
GpMetafile* metafile, BOOL* conversionSuccess,
const WCHAR* filename, EmfType emfType,
const WCHAR* description, GpMetafile** out_metafile)
{
FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
return NotImplemented;
}

View file

@ -35,6 +35,27 @@ typedef struct EmfPlusHeader
DWORD LogicalDpiY;
} EmfPlusHeader;
typedef struct EmfPlusFillRects
{
EmfPlusRecordHeader Header;
DWORD BrushID;
DWORD Count;
} EmfPlusFillRects;
typedef struct EmfPlusSetPageTransform
{
EmfPlusRecordHeader Header;
REAL PageScale;
} EmfPlusSetPageTransform;
typedef struct EmfPlusRect
{
SHORT X;
SHORT Y;
SHORT Width;
SHORT Height;
} EmfPlusRect;
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
{
DWORD size_needed;
@ -211,6 +232,8 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
(*metafile)->image.picture = NULL;
(*metafile)->image.flags = ImageFlagsNone;
(*metafile)->image.palette = NULL;
(*metafile)->image.xres = 72.0;
(*metafile)->image.yres = 72.0;
(*metafile)->bounds = *frameRect;
(*metafile)->unit = frameUnit;
(*metafile)->metafile_type = type;
@ -267,7 +290,11 @@ GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
if (stat == Ok)
{
*result = metafile->record_graphics;
metafile->record_graphics->xres = 96.0;
metafile->record_graphics->yres = 96.0;
}
return stat;
}
@ -294,6 +321,108 @@ GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
return Ok;
}
static BOOL is_integer_rect(const GpRectF *rect)
{
SHORT x, y, width, height;
x = rect->X;
y = rect->Y;
width = rect->Width;
height = rect->Height;
if (rect->X != (REAL)x || rect->Y != (REAL)y ||
rect->Width != (REAL)width || rect->Height != (REAL)height)
return FALSE;
return TRUE;
}
GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
GDIPCONST GpRectF* rects, INT count)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusFillRects *record;
GpStatus stat;
BOOL integer_rects = TRUE;
int i;
DWORD brushid;
int flags = 0;
if (brush->bt == BrushTypeSolidColor)
{
flags |= 0x8000;
brushid = ((GpSolidFill*)brush)->color;
}
else
{
FIXME("brush serialization not implemented\n");
return NotImplemented;
}
for (i=0; i<count; i++)
{
if (!is_integer_rect(&rects[i]))
{
integer_rects = FALSE;
break;
}
}
if (integer_rects)
flags |= 0x4000;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeFillRects;
record->Header.Flags = flags;
record->BrushID = brushid;
record->Count = count;
if (integer_rects)
{
EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
for (i=0; i<count; i++)
{
record_rects[i].X = (SHORT)rects[i].X;
record_rects[i].Y = (SHORT)rects[i].Y;
record_rects[i].Width = (SHORT)rects[i].Width;
record_rects[i].Height = (SHORT)rects[i].Height;
}
}
else
memcpy(record+1, rects, sizeof(GpRectF) * count);
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusSetPageTransform *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusSetPageTransform),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeSetPageTransform;
record->Header.Flags = unit;
record->PageScale = scale;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
{
if (hdc != metafile->record_dc)
@ -368,9 +497,40 @@ static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
}
}
static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
{
GpMatrix *real_transform;
GpStatus stat;
stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
if (stat == Ok)
{
REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
if (metafile->page_unit != UnitDisplay)
scale *= metafile->page_scale;
stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
if (stat == Ok)
stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
if (stat == Ok)
stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
GdipDeleteMatrix(real_transform);
}
return stat;
}
GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
{
GpStatus stat;
GpMetafile *real_metafile = (GpMetafile*)metafile;
TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
@ -402,6 +562,8 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
}
else
{
EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
switch(recordType)
@ -412,6 +574,85 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
case EmfPlusRecordTypeGetDC:
METAFILE_PlaybackGetDC((GpMetafile*)metafile);
break;
case EmfPlusRecordTypeFillRects:
{
EmfPlusFillRects *record = (EmfPlusFillRects*)header;
GpBrush *brush, *temp_brush=NULL;
GpRectF *rects, *temp_rects=NULL;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
return InvalidParameter;
if (flags & 0x4000)
{
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
return InvalidParameter;
}
else
{
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
return InvalidParameter;
}
if (flags & 0x8000)
{
stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
brush = temp_brush;
}
else
{
FIXME("brush deserialization not implemented\n");
return NotImplemented;
}
if (stat == Ok)
{
if (flags & 0x4000)
{
EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
int i;
rects = temp_rects = GdipAlloc(sizeof(GpRectF) * record->Count);
if (rects)
{
for (i=0; i<record->Count; i++)
{
rects[i].X = int_rects[i].X;
rects[i].Y = int_rects[i].Y;
rects[i].Width = int_rects[i].Width;
rects[i].Height = int_rects[i].Height;
}
}
else
stat = OutOfMemory;
}
else
rects = (GpRectF*)(record+1);
}
if (stat == Ok)
{
stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
}
GdipDeleteBrush(temp_brush);
GdipFree(temp_rects);
return stat;
}
case EmfPlusRecordTypeSetPageTransform:
{
EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
GpUnit unit = (GpUnit)flags;
if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
return InvalidParameter;
real_metafile->page_unit = unit;
real_metafile->page_scale = record->PageScale;
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;
@ -486,6 +727,7 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
struct enum_metafile_data data;
GpStatus stat;
GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
GraphicsContainer state;
TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
destPoints, count, srcRect, srcUnit, callback, callbackData,
@ -510,19 +752,46 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
real_metafile->playback_graphics = graphics;
real_metafile->playback_dc = NULL;
real_metafile->src_rect = *srcRect;
memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
metafile->metafile_type == MetafileTypeWmfPlaceable ||
metafile->metafile_type == MetafileTypeWmf))
stat = METAFILE_PlaybackGetDC((GpMetafile*)metafile);
if (stat == Ok)
stat = GdipBeginContainer2(graphics, &state);
if (stat == Ok)
EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
{
stat = GdipSetPageScale(graphics, 1.0);
METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
if (stat == Ok)
stat = GdipSetPageUnit(graphics, UnitPixel);
if (stat == Ok)
stat = GdipCreateMatrix(&real_metafile->world_transform);
if (stat == Ok)
{
real_metafile->page_unit = UnitDisplay;
real_metafile->page_scale = 1.0;
stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
metafile->metafile_type == MetafileTypeWmfPlaceable ||
metafile->metafile_type == MetafileTypeWmf))
stat = METAFILE_PlaybackGetDC(real_metafile);
if (stat == Ok)
EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
METAFILE_PlaybackReleaseDC(real_metafile);
GdipDeleteMatrix(real_metafile->world_transform);
real_metafile->world_transform = NULL;
GdipEndContainer(graphics, state);
}
real_metafile->playback_graphics = NULL;
@ -623,9 +892,268 @@ static int CALLBACK get_metafile_type_proc(HDC hDC, HANDLETABLE *lpHTable, const
return FALSE;
}
MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
static MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
{
MetafileType result = MetafileTypeInvalid;
EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
return result;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
MetafileHeader * header)
{
static int calls;
TRACE("(%p, %p)\n", metafile, header);
if(!metafile || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
MetafileHeader *header)
{
static int calls;
if(!hEmf || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
MetafileHeader *header)
{
static int calls;
TRACE("(%s,%p)\n", debugstr_w(filename), header);
if(!filename || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
MetafileHeader *header)
{
static int calls;
TRACE("(%p,%p)\n", stream, header);
if(!stream || !header)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
memset(header, 0, sizeof(MetafileHeader));
return Ok;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
GpMetafile **metafile)
{
ENHMETAHEADER header;
MetafileType metafile_type;
TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
if(!hemf || !metafile)
return InvalidParameter;
if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
return GenericError;
metafile_type = METAFILE_GetEmfType(hemf);
if (metafile_type == MetafileTypeInvalid)
return GenericError;
*metafile = GdipAlloc(sizeof(GpMetafile));
if (!*metafile)
return OutOfMemory;
(*metafile)->image.type = ImageTypeMetafile;
(*metafile)->image.format = ImageFormatEMF;
(*metafile)->image.frame_count = 1;
(*metafile)->image.xres = (REAL)header.szlDevice.cx;
(*metafile)->image.yres = (REAL)header.szlDevice.cy;
(*metafile)->bounds.X = (REAL)header.rclBounds.left;
(*metafile)->bounds.Y = (REAL)header.rclBounds.top;
(*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
(*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
(*metafile)->unit = UnitPixel;
(*metafile)->metafile_type = metafile_type;
(*metafile)->hemf = hemf;
(*metafile)->preserve_hemf = !delete;
TRACE("<-- %p\n", *metafile);
return Ok;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
{
UINT read;
BYTE *copy;
HENHMETAFILE hemf;
GpStatus retval = Ok;
TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
if(!hwmf || !metafile || !placeable)
return InvalidParameter;
*metafile = NULL;
read = GetMetaFileBitsEx(hwmf, 0, NULL);
if(!read)
return GenericError;
copy = GdipAlloc(read);
GetMetaFileBitsEx(hwmf, read, copy);
hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
GdipFree(copy);
/* FIXME: We should store and use hwmf instead of converting to hemf */
retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
if (retval == Ok)
{
(*metafile)->image.xres = (REAL)placeable->Inch;
(*metafile)->image.yres = (REAL)placeable->Inch;
(*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
(*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
(*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
placeable->BoundingBox.Left);
(*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
placeable->BoundingBox.Top);
(*metafile)->metafile_type = MetafileTypeWmfPlaceable;
(*metafile)->image.format = ImageFormatWMF;
if (delete) DeleteMetaFile(hwmf);
}
else
DeleteEnhMetaFile(hemf);
return retval;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
{
HMETAFILE hmf = GetMetaFileW(file);
TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
if(!hmf) return InvalidParameter;
return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
}
GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
GpMetafile **metafile)
{
FIXME("(%p, %p): stub\n", file, metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
GpMetafile **metafile)
{
FIXME("(%p, %p): stub\n", stream, metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
UINT limitDpi)
{
static int calls;
TRACE("(%p,%u)\n", metafile, limitDpi);
if(!(calls++))
FIXME("not implemented\n");
return NotImplemented;
}
GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
GpMetafile* metafile, BOOL* succ, EmfType emfType,
const WCHAR* description, GpMetafile** out_metafile)
{
static int calls;
TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
debugstr_w(description), out_metafile);
if(!ref || !metafile || !out_metafile)
return InvalidParameter;
*succ = FALSE;
*out_metafile = NULL;
if(!(calls++))
FIXME("not implemented\n");
return NotImplemented;
}
GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
LPBYTE pData16, INT iMapMode, INT eFlags)
{
FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
GpMetafile **metafile)
{
FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
frameUnit, debugstr_w(desc), metafile);
return NotImplemented;
}
GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
GDIPCONST WCHAR *desc, GpMetafile **metafile)
{
FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
frameUnit, debugstr_w(desc), metafile);
return NotImplemented;
}
/*****************************************************************************
* GdipConvertToEmfPlusToFile [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
GpMetafile* metafile, BOOL* conversionSuccess,
const WCHAR* filename, EmfType emfType,
const WCHAR* description, GpMetafile** out_metafile)
{
FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
return NotImplemented;
}

View file

@ -205,7 +205,7 @@ GpStatus WINGDIPAPI GdipPathIterNextSubpath(GpPathIterator* iterator,
if(iterator->subpath_pos == count){
*startIndex = *endIndex = *resultCount = 0;
*isClosed = 1;
*isClosed = TRUE;
return Ok;
}

View file

@ -75,6 +75,24 @@ typedef struct packed_point
short Y;
} packed_point;
/* Test to see if the path could be stored as an array of shorts */
static BOOL is_integer_path(const GpPath *path)
{
int i;
if (!path->pathdata.Count) return FALSE;
for (i = 0; i < path->pathdata.Count; i++)
{
short x, y;
x = gdip_round(path->pathdata.Points[i].X);
y = gdip_round(path->pathdata.Points[i].Y);
if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
return FALSE;
}
return TRUE;
}
/* Everything is measured in DWORDS; round up if there's a remainder */
static inline INT get_pathtypes_size(const GpPath* path)
{
@ -94,9 +112,20 @@ static inline INT get_element_size(const region_element* element)
case RegionDataRect:
return needed + sizeof(GpRect);
case RegionDataPath:
needed += element->elementdata.pathdata.pathheader.size;
needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
return needed;
{
const GpPath *path = element->elementdata.path;
DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
/* 3 for headers, once again size doesn't count itself */
needed += sizeof(DWORD) * 3;
if (flags & FLAGS_INTPATH)
needed += 2 * sizeof(SHORT) * path->pathdata.Count;
else
needed += 2 * sizeof(FLOAT) * path->pathdata.Count;
needed += get_pathtypes_size(path);
needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
return needed;
}
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
return needed;
@ -112,11 +141,8 @@ static inline INT get_element_size(const region_element* element)
/* Does not check parameters, caller must do that */
static inline GpStatus init_region(GpRegion* region, const RegionType type)
{
region->node.type = type;
region->header.checksum = 0xdeadbeef;
region->header.magic = VERSION_MAGIC;
region->header.num_children = 0;
region->header.size = sizeheader_size + get_element_size(&region->node);
region->node.type = type;
region->num_children = 0;
return Ok;
}
@ -144,9 +170,7 @@ static inline GpStatus clone_element(const region_element* element,
case RegionDataInfiniteRect:
return Ok;
case RegionDataPath:
(*element2)->elementdata.pathdata.pathheader = element->elementdata.pathdata.pathheader;
stat = GdipClonePath(element->elementdata.pathdata.path,
&(*element2)->elementdata.pathdata.path);
stat = GdipClonePath(element->elementdata.path, &(*element2)->elementdata.path);
if (stat == Ok) return Ok;
break;
default:
@ -178,9 +202,7 @@ static inline void fuse_region(GpRegion* region, region_element* left,
region->node.type = mode;
region->node.elementdata.combine.left = left;
region->node.elementdata.combine.right = right;
region->header.size = sizeheader_size + get_element_size(&region->node);
region->header.num_children += 2;
region->num_children += 2;
}
/*****************************************************************************
@ -210,7 +232,7 @@ GpStatus WINGDIPAPI GdipCloneRegion(GpRegion *region, GpRegion **clone)
return OutOfMemory;
element = &(*clone)->node;
(*clone)->header = region->header;
(*clone)->num_children = region->num_children;
return clone_element(&region->node, &element);
}
@ -367,7 +389,7 @@ GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1,
}
fuse_region(region1, left, right, mode);
region1->header.num_children += region2->header.num_children;
region1->num_children += region2->num_children;
return Ok;
}
@ -413,12 +435,7 @@ GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
{
region_element* element;
GpPoint *pointsi;
GpPointF *pointsf;
GpStatus stat;
DWORD flags = FLAGS_INTPATH;
INT count, i;
TRACE("%p, %p\n", path, region);
@ -435,77 +452,14 @@ GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
return stat;
}
element = &(*region)->node;
count = path->pathdata.Count;
/* Test to see if the path is an Integer path */
if (count)
{
pointsi = GdipAlloc(sizeof(GpPoint) * count);
pointsf = GdipAlloc(sizeof(GpPointF) * count);
if (!(pointsi && pointsf))
{
GdipFree(pointsi);
GdipFree(pointsf);
GdipDeleteRegion(*region);
return OutOfMemory;
}
stat = GdipGetPathPointsI(path, pointsi, count);
if (stat != Ok)
{
GdipDeleteRegion(*region);
return stat;
}
stat = GdipGetPathPoints(path, pointsf, count);
if (stat != Ok)
{
GdipDeleteRegion(*region);
return stat;
}
for (i = 0; i < count; i++)
{
if (!(pointsi[i].X == pointsf[i].X &&
pointsi[i].Y == pointsf[i].Y ))
{
flags = FLAGS_NOFLAGS;
break;
}
}
GdipFree(pointsi);
GdipFree(pointsf);
}
stat = GdipClonePath(path, &element->elementdata.pathdata.path);
stat = GdipClonePath(path, &element->elementdata.path);
if (stat != Ok)
{
GdipDeleteRegion(*region);
return stat;
}
/* 3 for headers, once again size doesn't count itself */
element->elementdata.pathdata.pathheader.size = ((sizeof(DWORD) * 3));
switch(flags)
{
/* Floats, sent out as floats */
case FLAGS_NOFLAGS:
element->elementdata.pathdata.pathheader.size +=
(sizeof(DWORD) * count * 2);
break;
/* INTs, sent out as packed shorts */
case FLAGS_INTPATH:
element->elementdata.pathdata.pathheader.size +=
(sizeof(DWORD) * count);
break;
default:
FIXME("Unhandled flags (%08x). Expect wrong results.\n", flags);
}
element->elementdata.pathdata.pathheader.size += get_pathtypes_size(path);
element->elementdata.pathdata.pathheader.magic = VERSION_MAGIC;
element->elementdata.pathdata.pathheader.count = count;
element->elementdata.pathdata.pathheader.flags = flags;
(*region)->header.size = sizeheader_size + get_element_size(element);
return Ok;
}
@ -727,25 +681,24 @@ static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
static inline void write_packed_point(DWORD* location, INT* offset,
const GpPointF* write)
{
packed_point point;
point.X = write->X;
point.Y = write->Y;
memcpy(location + *offset, &point, sizeof(packed_point));
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 (path->pathdata.Count % sizeof(DWORD))
if (rounded_size - path->pathdata.Count)
ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
path->pathdata.Count,
sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD));
*offset += (get_pathtypes_size(path) / 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,
@ -772,12 +725,31 @@ static void write_element(const region_element* element, DWORD *buffer,
case RegionDataPath:
{
INT i;
const GpPath* path = element->elementdata.pathdata.path;
const GpPath* path = element->elementdata.path;
struct _pathheader
{
DWORD size;
DWORD magic;
DWORD count;
DWORD flags;
} *pathheader;
memcpy(buffer + *filled, &element->elementdata.pathdata.pathheader,
sizeof(element->elementdata.pathdata.pathheader));
*filled += sizeof(element->elementdata.pathdata.pathheader) / sizeof(DWORD);
switch (element->elementdata.pathdata.pathheader.flags)
pathheader = (struct _pathheader *)(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++)
@ -792,6 +764,7 @@ static void write_element(const region_element* element, DWORD *buffer,
write_packed_point(buffer, filled,
&path->pathdata.Points[i]);
}
break;
}
write_path_types(buffer, filled, path);
break;
@ -838,15 +811,36 @@ static void write_element(const region_element* element, DWORD *buffer,
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
UINT *needed)
{
struct _region_header
{
DWORD size;
DWORD checksum;
DWORD magic;
DWORD num_children;
} *region_header;
INT filled = 0;
UINT required;
GpStatus status;
TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
if (!(region && buffer && size))
if (!region || !buffer || !size)
return InvalidParameter;
memcpy(buffer, &region->header, sizeof(region->header));
filled += sizeof(region->header) / sizeof(DWORD);
status = GdipGetRegionDataSize(region, &required);
if (status != Ok) return status;
if (size < required)
{
if (needed) *needed = size;
return InsufficientBuffer;
}
region_header = (struct _region_header *)buffer;
region_header->size = sizeheader_size + get_element_size(&region->node);
region_header->checksum = 0;
region_header->magic = VERSION_MAGIC;
region_header->num_children = region->num_children;
filled += 4;
/* With few exceptions, everything written is DWORD aligned,
* so use that as our base */
write_element(&region->node, (DWORD*)buffer, &filled);
@ -868,7 +862,7 @@ GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
return InvalidParameter;
/* header.size doesn't count header.size and header.checksum */
*needed = region->header.size + sizeof(DWORD) * 2;
*needed = sizeof(DWORD) * 2 + sizeheader_size + get_element_size(&region->node);
return Ok;
}
@ -938,7 +932,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
*hrgn = CreateRectRgn(0, 0, 0, 0);
return *hrgn ? Ok : OutOfMemory;
case RegionDataPath:
return get_path_hrgn(element->elementdata.pathdata.path, graphics, hrgn);
return get_path_hrgn(element->elementdata.path, graphics, hrgn);
case RegionDataRect:
{
GpPath* path;
@ -982,8 +976,8 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
case CombineModeIntersect:
return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
case CombineModeXor: case CombineModeExclude:
FIXME("cannot exclude from an infinite region\n");
/* fall-through */
left = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
break;
case CombineModeUnion: case CombineModeComplement:
*hrgn = NULL;
return Ok;
@ -1007,8 +1001,8 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
*hrgn = left;
return Ok;
case CombineModeXor: case CombineModeComplement:
FIXME("cannot exclude from an infinite region\n");
/* fall-through */
right = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
break;
case CombineModeUnion: case CombineModeExclude:
DeleteObject(left);
*hrgn = NULL;
@ -1291,16 +1285,19 @@ static GpStatus transform_region_element(region_element* element, GpMatrix *matr
{
/* Steal the element from the created region. */
memcpy(element, &new_region->node, sizeof(region_element));
HeapFree(GetProcessHeap(), 0, new_region);
GdipFree(new_region);
}
else
return stat;
}
/* Fall-through to do the actual conversion. */
case RegionDataPath:
if (!element->elementdata.path->pathdata.Count)
return Ok;
stat = GdipTransformMatrixPoints(matrix,
element->elementdata.pathdata.path->pathdata.Points,
element->elementdata.pathdata.path->pathdata.Count);
element->elementdata.path->pathdata.Points,
element->elementdata.path->pathdata.Count);
return stat;
default:
stat = transform_region_element(element->elementdata.combine.left, matrix);
@ -1335,9 +1332,9 @@ static void translate_region_element(region_element* element, REAL dx, REAL dy)
element->elementdata.rect.Y += dy;
return;
case RegionDataPath:
for(i = 0; i < element->elementdata.pathdata.path->pathdata.Count; i++){
element->elementdata.pathdata.path->pathdata.Points[i].X += dx;
element->elementdata.pathdata.path->pathdata.Points[i].Y += dy;
for(i = 0; i < element->elementdata.path->pathdata.Count; i++){
element->elementdata.path->pathdata.Points[i].X += dx;
element->elementdata.path->pathdata.Points[i].Y += dy;
}
return;
default:

View file

@ -74,7 +74,7 @@ reactos/dll/win32/dciman32 # Synced to Wine-1.7.1
reactos/dll/win32/dwmapi # Synced to Wine-1.7.17
reactos/dll/win32/faultrep # Synced to Wine-1.7.1
reactos/dll/win32/fusion # Synced to Wine-1.7.1
reactos/dll/win32/gdiplus # Synced to Wine-1.7.1
reactos/dll/win32/gdiplus # Synced to Wine-1.7.17
reactos/dll/win32/hhctrl.ocx # Synced to Wine-1.7.1
reactos/dll/win32/hlink # Synced to Wine-1.7.1
reactos/dll/win32/hnetcfg # Synced to Wine-1.7.1