[GDIPLUS] Sync with Wine Staging 1.7.47. CORE-9924

svn path=/trunk/; revision=68437
This commit is contained in:
Amine Khaldi 2015-07-19 13:31:15 +00:00
parent 1174b60215
commit 373482cc7d
10 changed files with 877 additions and 436 deletions

View file

@ -450,7 +450,7 @@ GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, LOGFONTW
matrix = graphics->worldtrans;
if (font->unit == UnitPixel)
if (font->unit == UnitPixel || font->unit == UnitWorld)
{
height = units_to_pixels(font->emSize, graphics->unit, graphics->yres);
if (graphics->unit != UnitDisplay)

View file

@ -20,3 +20,6 @@
/* @makedep: gdiplus.manifest */
WINE_MANIFEST 24 gdiplus.manifest
/* @makedep: gdiplus11.manifest */
WINE_MANIFEST11 24 gdiplus11.manifest

View file

@ -610,7 +610,7 @@
610 stdcall GdipFindFirstImageItem(ptr ptr)
611 stub GdipFindNextImageItem
612 stdcall GdipGetImageItemData(ptr ptr)
613 stub GdipCreateEffect
613 stdcall -stub GdipCreateEffect(ptr ptr)
614 stdcall GdipDeleteEffect(ptr)
615 stub GdipGetEffectParameterSize
616 stub GdipGetEffectParameters
@ -621,7 +621,7 @@
621 stub GdipBitmapGetHistogram
622 stub GdipBitmapGetHistogramSize
623 stub GdipBitmapConvertFormat
624 stub GdipImageSetAbort
624 stdcall GdipImageSetAbort(ptr ptr)
625 stub GdipGraphicsSetAbort
626 stub GdipDrawImageFX
627 stdcall GdipConvertToEmfPlus(ptr ptr ptr long ptr ptr)

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="Microsoft.Windows.GdiPlus" version="1.1.7601.23038" processorArchitecture="" publicKeyToken="6595b64144ccf1df"/>
<file name="gdiplus.dll"/>
</assembly>

View file

@ -47,9 +47,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
#define MAX_DASHLEN (16) /* this is a limitation of gdi */
#define INCH_HIMETRIC (2540)
#define VERSION_MAGIC 0xdbc01001
#define VERSION_MAGIC 0xdbc01001
#define VERSION_MAGIC2 0xdbc01002
#define TENSION_CONST (0.3)
#define GIF_DISPOSE_UNSPECIFIED 0
#define GIF_DISPOSE_DO_NOT_DISPOSE 1
#define GIF_DISPOSE_RESTORE_TO_BKGND 2
#define GIF_DISPOSE_RESTORE_TO_PREV 3
COLORREF ARGB2COLORREF(ARGB color) DECLSPEC_HIDDEN;
HBITMAP ARGB2BMP(ARGB color) DECLSPEC_HIDDEN;
extern INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2,
@ -124,6 +130,26 @@ static inline ARGB color_over(ARGB bg, ARGB fg)
return (a<<24)|(r<<16)|(g<<8)|b;
}
/* fg is premult, bg and return value are not */
static inline ARGB color_over_fgpremult(ARGB bg, ARGB fg)
{
BYTE b, g, r, a;
BYTE bg_alpha, fg_alpha;
fg_alpha = (fg>>24)&0xff;
if (fg_alpha == 0) return bg;
bg_alpha = (((bg>>24)&0xff) * (0xff-fg_alpha)) / 0xff;
a = bg_alpha + fg_alpha;
b = ((bg&0xff)*bg_alpha + (fg&0xff)*0xff)/a;
g = (((bg>>8)&0xff)*bg_alpha + ((fg>>8)&0xff)*0xff)/a;
r = (((bg>>16)&0xff)*bg_alpha + ((fg>>16)&0xff)*0xff)/a;
return (a<<24)|(r<<16)|(g<<8)|b;
}
extern const char *debugstr_rectf(const RectF* rc) DECLSPEC_HIDDEN;
extern const char *debugstr_pointf(const PointF* pt) DECLSPEC_HIDDEN;
@ -278,7 +304,7 @@ struct GpAdustableArrowCap{
struct GpImage{
IPicture *picture;
IStream *stream; /* source stream */
IWICBitmapDecoder *decoder;
ImageType type;
GUID format;
UINT flags;

View file

@ -247,6 +247,7 @@ static INT prepare_dc(GpGraphics *graphics, GpPen *pen)
(pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
width *= units_to_pixels(pen->width, pen->unit == UnitWorld ? graphics->unit : pen->unit, graphics->xres);
width *= graphics->scale;
}
if(pen->dash == DashStyleCustom){
@ -349,21 +350,28 @@ static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
}
/* Draw non-premultiplied ARGB data to the given graphics object */
/* Draw ARGB data to the given graphics object */
static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
const BYTE *src, INT src_width, INT src_height, INT src_stride)
const BYTE *src, INT src_width, INT src_height, INT src_stride, const PixelFormat fmt)
{
GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
INT x, y;
for (x=0; x<src_width; x++)
for (y=0; y<src_height; y++)
{
for (y=0; y<src_height; y++)
for (x=0; x<src_width; x++)
{
ARGB dst_color, src_color;
GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
src_color = ((ARGB*)(src + src_stride * y))[x];
GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
if (!(src_color & 0xff000000))
continue;
GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
if (fmt & PixelFormatPAlpha)
GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over_fgpremult(dst_color, src_color));
else
GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
}
}
@ -371,7 +379,7 @@ static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_
}
static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
const BYTE *src, INT src_width, INT src_height, INT src_stride)
const BYTE *src, INT src_width, INT src_height, INT src_stride, PixelFormat fmt)
{
HDC hdc;
HBITMAP hbitmap;
@ -395,7 +403,8 @@ static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_
hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
(void**)&temp_bits, NULL, 0);
if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE)
if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE ||
fmt & PixelFormatPAlpha)
memcpy(temp_bits, src, src_width * src_height * 4);
else
convert_32bppARGB_to_32bppPARGB(src_width, src_height, temp_bits,
@ -411,7 +420,7 @@ static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_
}
static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst_y,
const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion)
const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion, PixelFormat fmt)
{
GpStatus stat=Ok;
@ -461,7 +470,7 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst
stat = alpha_blend_bmp_pixels(graphics, rects[i].left, rects[i].top,
&src[(rects[i].left - dst_x) * 4 + (rects[i].top - dst_y) * src_stride],
rects[i].right - rects[i].left, rects[i].bottom - rects[i].top,
src_stride);
src_stride, fmt);
}
GdipFree(rgndata);
@ -494,7 +503,7 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst
ExtSelectClipRgn(graphics->hdc, hregion, RGN_AND);
stat = alpha_blend_hdc_pixels(graphics, dst_x, dst_y, src, src_width,
src_height, src_stride);
src_height, src_stride, fmt);
RestoreDC(graphics->hdc, save);
@ -505,27 +514,29 @@ static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst
}
static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
const BYTE *src, INT src_width, INT src_height, INT src_stride)
const BYTE *src, INT src_width, INT src_height, INT src_stride, PixelFormat fmt)
{
return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL);
return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL, fmt);
}
static ARGB blend_colors(ARGB start, ARGB end, REAL position)
{
ARGB result=0;
ARGB i;
INT a1, a2, a3;
INT start_a, end_a, final_a;
INT pos;
a1 = (start >> 24) & 0xff;
a2 = (end >> 24) & 0xff;
pos = gdip_round(position * 0xff);
a3 = (int)(a1*(1.0f - position)+a2*(position));
start_a = ((start >> 24) & 0xff) * (pos ^ 0xff);
end_a = ((end >> 24) & 0xff) * pos;
result |= a3 << 24;
final_a = start_a + end_a;
for (i=0xff; i<=0xff0000; i = i << 8)
result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
return result;
if (final_a < 0xff) return 0;
return (final_a / 0xff) << 24 |
((((start >> 16) & 0xff) * start_a + (((end >> 16) & 0xff) * end_a)) / final_a) << 16 |
((((start >> 8) & 0xff) * start_a + (((end >> 8) & 0xff) * end_a)) / final_a) << 8 |
(((start & 0xff) * start_a + ((end & 0xff) * end_a)) / final_a);
}
static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
@ -645,8 +656,9 @@ static BOOL color_is_gray(ARGB color)
return (r == g) && (g == b);
}
static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
UINT width, UINT height, INT stride, ColorAdjustType type)
/* returns preferred pixel format for the applied attributes */
static PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
UINT width, UINT height, INT stride, ColorAdjustType type, PixelFormat fmt)
{
UINT x, y;
INT i;
@ -658,6 +670,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
BYTE min_blue, min_green, min_red;
BYTE max_blue, max_green, max_red;
if (!data || fmt != PixelFormat32bppARGB)
return PixelFormat32bppARGB;
if (attributes->colorkeys[type].enabled)
key = &attributes->colorkeys[type];
else
@ -691,6 +706,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
{
const struct color_remap_table *table;
if (!data || fmt != PixelFormat32bppARGB)
return PixelFormat32bppARGB;
if (attributes->colorremaptables[type].enabled)
table = &attributes->colorremaptables[type];
else
@ -720,6 +738,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
int gray_matrix[5][5];
BOOL identity;
if (!data || fmt != PixelFormat32bppARGB)
return PixelFormat32bppARGB;
if (attributes->colormatrices[type].enabled)
colormatrices = &attributes->colormatrices[type];
else
@ -758,6 +779,9 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
{
REAL gamma;
if (!data || fmt != PixelFormat32bppARGB)
return PixelFormat32bppARGB;
if (attributes->gamma_enabled[type])
gamma = attributes->gamma[type];
else
@ -782,6 +806,8 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
*src_color = (*src_color & 0xff000000) | (red << 16) | (green << 8) | blue;
}
}
return fmt;
}
/* Given a bitmap and its source rectangle, find the smallest rectangle in the
@ -1226,7 +1252,7 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
if (stat == Ok)
apply_image_attributes(fill->imageattributes, fill->bitmap_bits,
bitmap->width, bitmap->height,
src_stride, ColorAdjustTypeBitmap);
src_stride, ColorAdjustTypeBitmap, lockeddata.PixelFormat);
if (stat != Ok)
{
@ -2115,7 +2141,7 @@ static void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font,
HFONT unscaled_font;
TEXTMETRICW textmet;
if (font->unit == UnitPixel)
if (font->unit == UnitPixel || font->unit == UnitWorld)
font_height = font->emSize;
else
{
@ -2138,8 +2164,8 @@ static void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font,
GpMatrix xform = *matrix;
GdipTransformMatrixPoints(&xform, pt, 3);
}
if (graphics)
GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+
(pt[1].X-pt[0].X)*(pt[1].X-pt[0].X));
@ -2979,15 +3005,18 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
return OutOfMemory;
src_stride = sizeof(ARGB) * src_area.Width;
/* Read the bits we need from the source bitmap into an ARGB buffer. */
/* Read the bits we need from the source bitmap into a compatible buffer. */
lockeddata.Width = src_area.Width;
lockeddata.Height = src_area.Height;
lockeddata.Stride = src_stride;
lockeddata.PixelFormat = PixelFormat32bppARGB;
lockeddata.Scan0 = src_data;
if (!do_resampling && bitmap->format == PixelFormat32bppPARGB)
lockeddata.PixelFormat = apply_image_attributes(imageAttributes, NULL, 0, 0, 0, ColorAdjustTypeBitmap, bitmap->format);
else
lockeddata.PixelFormat = PixelFormat32bppARGB;
stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf,
PixelFormat32bppARGB, &lockeddata);
lockeddata.PixelFormat, &lockeddata);
if (stat == Ok)
stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
@ -3000,7 +3029,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
apply_image_attributes(imageAttributes, src_data,
src_area.Width, src_area.Height,
src_stride, ColorAdjustTypeBitmap);
src_stride, ColorAdjustTypeBitmap, lockeddata.PixelFormat);
if (do_resampling)
{
@ -3048,7 +3077,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
}
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);
GdipFree(src_data);
@ -3998,7 +4028,8 @@ static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
if (stat == Ok)
stat = alpha_blend_pixels_hrgn(graphics, gp_bound_rect.X,
gp_bound_rect.Y, (BYTE*)pixel_data, gp_bound_rect.Width,
gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion);
gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion,
PixelFormat32bppARGB);
GdipFree(pixel_data);
}
@ -4730,6 +4761,9 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
scaled_rect.Width = layoutRect->Width * args.rel_width;
scaled_rect.Height = layoutRect->Height * args.rel_height;
if (scaled_rect.Width >= 1 << 23) scaled_rect.Width = 1 << 23;
if (scaled_rect.Height >= 1 << 23) scaled_rect.Height = 1 << 23;
get_font_hfont(graphics, font, stringFormat, &gdifont, NULL);
oldfont = SelectObject(hdc, gdifont);
@ -5705,7 +5739,7 @@ GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc)
{
stat = METAFILE_GetDC((GpMetafile*)graphics->image, hdc);
}
else if (!graphics->hdc || graphics->alpha_hdc ||
else if (!graphics->hdc ||
(graphics->image && graphics->image->type == ImageTypeBitmap && ((GpBitmap*)graphics->image)->format & PixelFormatAlpha))
{
/* Create a fake HDC and fill it with a constant color. */
@ -5797,7 +5831,7 @@ GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc)
/* Write the changed pixels to the real target. */
alpha_blend_pixels(graphics, 0, 0, graphics->temp_bits,
graphics->temp_hbitmap_width, graphics->temp_hbitmap_height,
graphics->temp_hbitmap_width * 4);
graphics->temp_hbitmap_width * 4, PixelFormat32bppARGB);
/* Clean up. */
DeleteDC(graphics->temp_hdc);
@ -6352,7 +6386,7 @@ static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UI
/* draw the result */
stat = alpha_blend_pixels(graphics, min_x, min_y, pixel_data, pixel_area.Width,
pixel_area.Height, pixel_data_stride);
pixel_area.Height, pixel_data_stride, PixelFormat32bppARGB);
GdipFree(pixel_data);

File diff suppressed because it is too large Load diff

View file

@ -1105,10 +1105,11 @@ GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
debugstr_w(description), out_metafile);
if(!ref || !metafile || !out_metafile)
if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual)
return InvalidParameter;
*succ = FALSE;
if(succ)
*succ = FALSE;
*out_metafile = NULL;
if(!(calls++))

View file

@ -533,224 +533,6 @@ GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect,
return GdipCreateRegionRect(&rectf, region);
}
static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
{
mbuf->buffer = buffer;
mbuf->size = size;
mbuf->pos = 0;
}
static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
{
if (mbuf->size - mbuf->pos >= size)
{
const void *data = mbuf->buffer + mbuf->pos;
mbuf->pos += size;
return data;
}
return NULL;
}
static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
{
GpStatus status;
const DWORD *type;
type = buffer_read(mbuf, sizeof(DWORD));
if (!type) return Ok;
TRACE("type %#x\n", *type);
node->type = *type;
switch (node->type)
{
case CombineModeReplace:
case CombineModeIntersect:
case CombineModeUnion:
case CombineModeXor:
case CombineModeExclude:
case CombineModeComplement:
{
region_element *left, *right;
left = GdipAlloc(sizeof(region_element));
if (!left) return OutOfMemory;
right = GdipAlloc(sizeof(region_element));
if (!right)
{
GdipFree(left);
return OutOfMemory;
}
status = read_element(mbuf, region, left, count);
if (status == Ok)
{
status = read_element(mbuf, region, right, count);
if (status == Ok)
{
node->elementdata.combine.left = left;
node->elementdata.combine.right = right;
region->num_children += 2;
return Ok;
}
}
GdipFree(left);
GdipFree(right);
return status;
}
case RegionDataRect:
{
const GpRectF *rc;
rc = buffer_read(mbuf, sizeof(GpRectF));
if (!rc)
{
ERR("failed to read rect data\n");
return InvalidParameter;
}
node->elementdata.rect = *rc;
*count += 1;
return Ok;
}
case RegionDataPath:
{
GpPath *path;
const struct path_header *path_header;
const BYTE *types;
path_header = buffer_read(mbuf, sizeof(struct path_header));
if (!path_header)
{
ERR("failed to read path header\n");
return InvalidParameter;
}
if (path_header->magic != VERSION_MAGIC)
{
ERR("invalid path header magic %#x\n", path_header->magic);
return InvalidParameter;
}
/* Windows always fails to create an empty path in a region */
if (!path_header->count)
{
TRACE("refusing to create an empty path in a region\n");
return GenericError;
}
status = GdipCreatePath(FillModeAlternate, &path);
if (status) return status;
node->elementdata.path = path;
if (!lengthen_path(path, path_header->count))
return OutOfMemory;
path->pathdata.Count = path_header->count;
if (path_header->flags & ~FLAGS_INTPATH)
FIXME("unhandled path flags %#x\n", path_header->flags);
if (path_header->flags & FLAGS_INTPATH)
{
const packed_point *pt;
DWORD i;
pt = buffer_read(mbuf, sizeof(packed_point) * path_header->count);
if (!pt)
{
ERR("failed to read packed %u path points\n", path_header->count);
return InvalidParameter;
}
for (i = 0; i < path_header->count; i++)
{
path->pathdata.Points[i].X = (REAL)pt[i].X;
path->pathdata.Points[i].Y = (REAL)pt[i].Y;
}
}
else
{
const GpPointF *ptf;
ptf = buffer_read(mbuf, sizeof(GpPointF) * path_header->count);
if (!ptf)
{
ERR("failed to read %u path points\n", path_header->count);
return InvalidParameter;
}
memcpy(path->pathdata.Points, ptf, sizeof(GpPointF) * path_header->count);
}
types = buffer_read(mbuf, path_header->count);
if (!types)
{
ERR("failed to read %u path types\n", path_header->count);
return InvalidParameter;
}
memcpy(path->pathdata.Types, types, path_header->count);
if (path_header->count & 3)
{
if (!buffer_read(mbuf, 4 - (path_header->count & 3)))
{
ERR("failed to read rounding %u bytes\n", 4 - (path_header->count & 3));
return InvalidParameter;
}
}
*count += 1;
return Ok;
}
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
*count += 1;
return Ok;
default:
FIXME("element type %#x is not supported\n", *type);
break;
}
return InvalidParameter;
}
GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
{
GpStatus status;
struct memory_buffer mbuf;
const struct region_header *region_header;
INT count;
if (!data || !size) return InvalidParameter;
TRACE("%p, %d, %p\n", data, size, region);
init_memory_buffer(&mbuf, data, size);
region_header = buffer_read(&mbuf, sizeof(struct region_header));
if (!region_header || region_header->magic != VERSION_MAGIC)
return InvalidParameter;
status = GdipCreateRegion(region);
if (status != Ok) return status;
count = 0;
status = read_element(&mbuf, *region, &(*region)->node, &count);
if (status == Ok && !count)
status = InvalidParameter;
if (status != Ok)
GdipDeleteRegion(*region);
return status;
}
/******************************************************************************
* GdipCreateRegionHrgn [GDIPLUS.@]
*/
@ -1071,6 +853,232 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
return Ok;
}
static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
{
mbuf->buffer = buffer;
mbuf->size = size;
mbuf->pos = 0;
}
static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
{
if (mbuf->size - mbuf->pos >= size)
{
const void *data = mbuf->buffer + mbuf->pos;
mbuf->pos += size;
return data;
}
return NULL;
}
static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
{
GpStatus status;
const DWORD *type;
type = buffer_read(mbuf, sizeof(*type));
if (!type) return Ok;
TRACE("type %#x\n", *type);
node->type = *type;
switch (node->type)
{
case CombineModeReplace:
case CombineModeIntersect:
case CombineModeUnion:
case CombineModeXor:
case CombineModeExclude:
case CombineModeComplement:
{
region_element *left, *right;
left = GdipAlloc(sizeof(region_element));
if (!left) return OutOfMemory;
right = GdipAlloc(sizeof(region_element));
if (!right)
{
GdipFree(left);
return OutOfMemory;
}
status = read_element(mbuf, region, left, count);
if (status == Ok)
{
status = read_element(mbuf, region, right, count);
if (status == Ok)
{
node->elementdata.combine.left = left;
node->elementdata.combine.right = right;
region->num_children += 2;
return Ok;
}
}
GdipFree(left);
GdipFree(right);
return status;
}
case RegionDataRect:
{
const GpRectF *rc;
rc = buffer_read(mbuf, sizeof(*rc));
if (!rc)
{
ERR("failed to read rect data\n");
return InvalidParameter;
}
node->elementdata.rect = *rc;
*count += 1;
return Ok;
}
case RegionDataPath:
{
GpPath *path;
const struct path_header *path_header;
const BYTE *types;
path_header = buffer_read(mbuf, sizeof(*path_header));
if (!path_header)
{
ERR("failed to read path header\n");
return InvalidParameter;
}
if (path_header->magic != VERSION_MAGIC)
{
ERR("invalid path header magic %#x\n", path_header->magic);
return InvalidParameter;
}
/* Windows always fails to create an empty path in a region */
if (!path_header->count)
{
TRACE("refusing to create an empty path in a region\n");
return GenericError;
}
status = GdipCreatePath(FillModeAlternate, &path);
if (status) return status;
node->elementdata.path = path;
if (!lengthen_path(path, path_header->count))
return OutOfMemory;
path->pathdata.Count = path_header->count;
if (path_header->flags & ~FLAGS_INTPATH)
FIXME("unhandled path flags %#x\n", path_header->flags);
if (path_header->flags & FLAGS_INTPATH)
{
const packed_point *pt;
DWORD i;
pt = buffer_read(mbuf, sizeof(*pt) * path_header->count);
if (!pt)
{
ERR("failed to read packed %u path points\n", path_header->count);
return InvalidParameter;
}
for (i = 0; i < path_header->count; i++)
{
path->pathdata.Points[i].X = (REAL)pt[i].X;
path->pathdata.Points[i].Y = (REAL)pt[i].Y;
}
}
else
{
const GpPointF *ptf;
ptf = buffer_read(mbuf, sizeof(*ptf) * path_header->count);
if (!ptf)
{
ERR("failed to read %u path points\n", path_header->count);
return InvalidParameter;
}
memcpy(path->pathdata.Points, ptf, sizeof(*ptf) * path_header->count);
}
types = buffer_read(mbuf, path_header->count);
if (!types)
{
ERR("failed to read %u path types\n", path_header->count);
return InvalidParameter;
}
memcpy(path->pathdata.Types, types, path_header->count);
if (path_header->count & 3)
{
if (!buffer_read(mbuf, 4 - (path_header->count & 3)))
{
ERR("failed to read rounding %u bytes\n", 4 - (path_header->count & 3));
return InvalidParameter;
}
}
*count += 1;
return Ok;
}
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
*count += 1;
return Ok;
default:
FIXME("element type %#x is not supported\n", *type);
break;
}
return InvalidParameter;
}
/*****************************************************************************
* GdipCreateRegionRgnData [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
{
const struct region_header *region_header;
struct memory_buffer mbuf;
GpStatus status;
INT count;
TRACE("(%p, %d, %p)\n", data, size, region);
if (!data || !size)
return InvalidParameter;
init_memory_buffer(&mbuf, data, size);
region_header = buffer_read(&mbuf, sizeof(*region_header));
if (!region_header || (region_header->magic != VERSION_MAGIC &&
region_header->magic != VERSION_MAGIC2))
return InvalidParameter;
status = GdipCreateRegion(region);
if (status != Ok)
return status;
count = 0;
status = read_element(&mbuf, *region, &(*region)->node, &count);
if (status == Ok && !count)
status = InvalidParameter;
if (status != Ok)
{
GdipDeleteRegion(*region);
*region = NULL;
}
return status;
}
/*****************************************************************************
* GdipGetRegionDataSize [GDIPLUS.@]
*/
@ -1098,16 +1106,12 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
{
new_hdc = CreateCompatibleDC(0);
if (!new_hdc)
{
ERR("CreateCompatibleDC failed\n");
return OutOfMemory;
}
stat = GdipCreateFromHDC(new_hdc, &new_graphics);
graphics = new_graphics;
if (stat != Ok)
{
ERR("GdipCreateFromHDC failed: 0x%x\n", stat);
DeleteDC(new_hdc);
return stat;
}
@ -1116,10 +1120,7 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
{
graphics->hdc = new_hdc = CreateCompatibleDC(0);
if (!new_hdc)
{
ERR("CreateCompatibleDC failed\n");
return OutOfMemory;
}
}
save_state = SaveDC(graphics->hdc);
@ -1132,16 +1133,8 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
if (stat == Ok)
{
*hrgn = PathToRegion(graphics->hdc);
if (*hrgn == NULL)
{
ERR("PathToRegion failed\n");
}
stat = *hrgn ? Ok : OutOfMemory;
}
else
{
ERR("trace_path failed: 0x%x\n", stat);
}
RestoreDC(graphics->hdc, save_state);
if (new_hdc)
@ -1176,18 +1169,11 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
stat = GdipCreatePath(FillModeAlternate, &path);
if (stat != Ok)
{
ERR("GdipCreatePath failed: 0x%x\n", stat);
return stat;
}
stat = GdipAddPathRectangle(path, rc->X, rc->Y, rc->Width, rc->Height);
if (stat == Ok)
stat = get_path_hrgn(path, graphics, hrgn);
else
{
ERR("GdipAddPathRectangle failed: 0x%x\n", stat);
}
GdipDeletePath(path);
@ -1218,7 +1204,7 @@ 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:
left = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
left = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
break;
case CombineModeUnion: case CombineModeComplement:
*hrgn = NULL;
@ -1243,7 +1229,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
*hrgn = left;
return Ok;
case CombineModeXor: case CombineModeComplement:
right = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
right = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
break;
case CombineModeUnion: case CombineModeExclude:
DeleteObject(left);
@ -1297,18 +1283,12 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
*/
GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
{
GpStatus status;
TRACE("(%p, %p, %p)\n", region, graphics, hrgn);
if (!region || !hrgn)
return InvalidParameter;
status = get_region_hrgn(&region->node, graphics, hrgn);
if (status != Ok)
{
ERR("get_region_hrgn() failed. region->node.type = 0x%x\n", region->node.type);
}
return status;
return get_region_hrgn(&region->node, graphics, hrgn);
}
GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)

View file

@ -70,7 +70,7 @@ reactos/dll/win32/dwmapi # Synced to WineStaging-1.7.37
reactos/dll/win32/faultrep # Synced to WineStaging-1.7.37
reactos/dll/win32/fltlib # Synced to WineStaging-1.7.47
reactos/dll/win32/fusion # Synced to WineStaging-1.7.47
reactos/dll/win32/gdiplus # Synced to WineStaging-1.7.37
reactos/dll/win32/gdiplus # Synced to WineStaging-1.7.47
reactos/dll/win32/hhctrl.ocx # Synced to WineStaging-1.7.47
reactos/dll/win32/hlink # Synced to WineStaging-1.7.37
reactos/dll/win32/hnetcfg # Synced to WineStaging-1.7.37