gdiplus: Implement GdipGetRegionData.
This commit is contained in:
parent
aa0df2300e
commit
f52c211ac3
|
@ -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, ®ion->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(®ion->node, (DWORD*)buffer, &filled);
|
||||
|
||||
if (needed)
|
||||
*needed = filled * sizeof(DWORD);
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
|
||||
|
|
|
@ -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, ®ion);
|
||||
todo_wine
|
||||
{
|
||||
status = GdipCreateRegionPath(path, ®ion);
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue