gdiplus: Implement GdipGetRegionData.

This commit is contained in:
Adam Petaccia 2008-08-04 13:56:25 -04:00 committed by Alexandre Julliard
parent aa0df2300e
commit f52c211ac3
2 changed files with 182 additions and 20 deletions

View File

@ -81,11 +81,31 @@ typedef enum RegionType
RegionDataInfiniteRect = 0x10000003,
} RegionType;
#define FLAGS_NOFLAGS 0x0
#define FLAGS_INTPATH 0x4000
/* Header size as far as header->size is concerned. This doesn't include
* header->size or header->checksum
*/
static const INT sizeheader_size = sizeof(DWORD) * 2;
typedef struct packed_point
{
short X;
short Y;
} packed_point;
/* Everything is measured in DWORDS; round up if there's a remainder */
static inline INT get_pathtypes_size(const GpPath* path)
{
INT needed = path->pathdata.Count / sizeof(DWORD);
if (path->pathdata.Count % sizeof(DWORD) > 0)
needed++;
return needed * sizeof(DWORD);
}
static inline INT get_element_size(const region_element* element)
{
INT needed = sizeof(DWORD); /* DWORD for the type */
@ -261,11 +281,148 @@ GpStatus WINGDIPAPI GdipGetRegionBoundsI(GpRegion *region, GpGraphics *graphics,
return NotImplemented;
}
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, UINT *needed)
static inline void write_dword(DWORD* location, INT* offset, const DWORD write)
{
FIXME("(%p, %p, %d, %p): stub\n", region, buffer, size, needed);
location[*offset] = write;
(*offset)++;
}
return NotImplemented;
static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
{
((FLOAT*)location)[*offset] = write;
(*offset)++;
}
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));
(*offset)++;
}
static inline void write_path_types(DWORD* location, INT* offset,
const GpPath* 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))
ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
path->pathdata.Count,
sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD));
*offset += (get_pathtypes_size(path) / sizeof(DWORD));
}
static void write_element(const region_element* element, DWORD *buffer,
INT* filled)
{
write_dword(buffer, filled, element->type);
switch (element->type)
{
case CombineModeReplace:
case CombineModeIntersect:
case CombineModeUnion:
case CombineModeXor:
case CombineModeExclude:
case CombineModeComplement:
write_element(element->elementdata.combine.left, buffer, filled);
write_element(element->elementdata.combine.right, buffer, filled);
break;
case RegionDataRect:
write_float(buffer, filled, element->elementdata.rect.X);
write_float(buffer, filled, element->elementdata.rect.Y);
write_float(buffer, filled, element->elementdata.rect.Width);
write_float(buffer, filled, element->elementdata.rect.Height);
break;
case RegionDataPath:
{
INT i;
const GpPath* path = element->elementdata.pathdata.path;
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)
{
case FLAGS_NOFLAGS:
for (i = 0; i < path->pathdata.Count; i++)
{
write_float(buffer, filled, path->pathdata.Points[i].X);
write_float(buffer, filled, path->pathdata.Points[i].Y);
}
break;
case FLAGS_INTPATH:
for (i = 0; i < path->pathdata.Count; i++)
{
write_packed_point(buffer, filled,
&path->pathdata.Points[i]);
}
}
write_path_types(buffer, filled, path);
break;
}
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
break;
}
}
/*****************************************************************************
* GdipGetRegionData [GDIPLUS.@]
*
* Returns the header, followed by combining ops and region elements.
*
* PARAMS
* region [I] region to retrieve from
* buffer [O] buffer to hold the resulting data
* size [I] size of the buffer
* needed [O] (optional) how much data was written
*
* RETURNS
* SUCCESS: Ok
* FAILURE: InvalidParamter
*
* NOTES
* The header contains the size, a checksum, a version string, and the number
* of children. The size does not count itself or the checksum.
* Version is always something like 0xdbc01001 or 0xdbc01002
*
* An element is a RECT, or PATH; Combining ops are stored as their
* CombineMode value. Special regions (infinite, empty) emit just their
* op-code; GpRectFs emit their code followed by their points; GpPaths emit
* their code followed by a second header for the path followed by the actual
* path data. Followed by the flags for each point. The pathheader contains
* the size of the data to follow, a version number again, followed by a count
* of how many points, and any special flags which may apply. 0x4000 means its
* a path of shorts instead of FLOAT.
*
* Combining Ops are stored in reverse order from when they were constructed;
* the output is a tree where the left side combining area is always taken
* first.
*/
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
UINT *needed)
{
INT filled = 0;
if (!(region && buffer && size))
return InvalidParameter;
TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
memcpy(buffer, &region->header, sizeof(region->header));
filled += sizeof(region->header) / sizeof(DWORD);
/* With few exceptions, everything written is DWORD aligned,
* so use that as our base */
write_element(&region->node, (DWORD*)buffer, &filled);
if (needed)
*needed = filled * sizeof(DWORD);
return Ok;
}
GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)

View File

@ -71,13 +71,9 @@ static void test_getregiondata(void)
ok(status == Ok, "status %08x\n", status);
expect(20, needed);
todo_wine
{
status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
ok(status == Ok, "status %08x\n", status);
}
expect(20, needed);
todo_wine
{
expect_dword(buf, 12);
trace("buf[1] = %08x\n", buf[1]);
expect_magic((DWORD*)(buf + 2));
@ -85,26 +81,18 @@ todo_wine
expect_dword(buf + 4, RGNDATA_INFINITE_RECT);
status = GdipSetEmpty(region);
}
ok(status == Ok, "status %08x\n", status);
todo_wine
{
status = GdipGetRegionDataSize(region, &needed);
}
ok(status == Ok, "status %08x\n", status);
expect(20, needed);
status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
todo_wine
ok(status == Ok, "status %08x\n", status);
expect(20, needed);
todo_wine
{
expect_dword(buf, 12);
trace("buf[1] = %08x\n", buf[1]);
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3, 0);
expect_dword(buf + 4, RGNDATA_EMPTY_RECT);
}
status = GdipSetInfinite(region);
ok(status == Ok, "status %08x\n", status);
@ -112,17 +100,13 @@ todo_wine
ok(status == Ok, "status %08x\n", status);
expect(20, needed);
status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
todo_wine
ok(status == Ok, "status %08x\n", status);
expect(20, needed);
todo_wine
{
expect_dword(buf, 12);
trace("buf[1] = %08x\n", buf[1]);
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3, 0);
expect_dword(buf + 4, RGNDATA_INFINITE_RECT);
}
status = GdipDeleteRegion(region);
ok(status == Ok, "status %08x\n", status);
@ -143,8 +127,11 @@ todo_wine
expect(36, needed);
expect_dword(buf, 28);
trace("buf[1] = %08x\n", buf[1]);
}
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3, 0);
todo_wine
{
expect_dword(buf + 4, RGNDATA_RECT);
expect_float(buf + 5, 10.0);
expect_float(buf + 6, 20.0);
@ -195,7 +182,10 @@ todo_wine
expect(156, needed);
expect_dword(buf, 148);
trace("buf[1] = %08x\n", buf[1]);
}
expect_magic((DWORD*)(buf + 2));
todo_wine
{
expect_dword(buf + 3, 10);
expect_dword(buf + 4, CombineModeExclude);
expect_dword(buf + 5, CombineModeComplement);
@ -257,8 +247,11 @@ todo_wine
expect(72, needed);
expect_dword(buf, 64);
trace("buf[1] = %08x\n", buf[1]);
}
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3, 0);
todo_wine
{
expect_dword(buf + 4, RGNDATA_PATH);
expect_dword(buf + 5, 0x00000030);
expect_magic((DWORD*)(buf + 6));
@ -289,7 +282,10 @@ todo_wine
expect(96, needed);
expect_dword(buf, 88);
trace("buf[1] = %08x\n", buf[1]);
}
expect_magic((DWORD*)(buf + 2));
todo_wine
{
expect_dword(buf + 3, 2);
expect_dword(buf + 4, CombineModeIntersect);
expect_dword(buf + 5, RGNDATA_PATH);
@ -333,8 +329,11 @@ todo_wine
expect(36, needed);
expect_dword(buf, 28);
trace("buf[1] = %08x\n", buf[1]);
}
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3, 0);
todo_wine
{
expect_dword(buf + 4, RGNDATA_PATH);
/* Second signature for pathdata */
@ -365,9 +364,12 @@ todo_wine
expect(Ok, status);
expect(56, needed);
expect_dword(buf, 48);
}
trace("buf[1] = %08x\n", buf[1]);
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3 , 0);
todo_wine
{
expect_dword(buf + 4 , RGNDATA_PATH);
expect_dword(buf + 5, 32);
@ -399,9 +401,9 @@ todo_wine
expect(Ok, status);
status = GdipAddPathLine(path, 8.1, 1.6, 5.6, 6.2);
expect(Ok, status);
status = GdipCreateRegionPath(path, &region);
todo_wine
{
status = GdipCreateRegionPath(path, &region);
expect(Ok, status);
status = GdipGetRegionDataSize(region, &needed);
expect(Ok, status);
@ -411,8 +413,11 @@ todo_wine
expect(72, needed);
expect_dword(buf, 64);
trace("buf[1] = %08x\n", buf[1]);
}
expect_magic((DWORD*)(buf + 2));
expect_dword(buf + 3, 0);
todo_wine
{
expect_dword(buf + 4, RGNDATA_PATH);
expect_dword(buf + 5, 48);