Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
a66d6645
Commit
a66d6645
authored
Jun 13, 2015
by
Dmitry Timoshkov
Committed by
Alexandre Julliard
Jun 15, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gdiplus: Implement GdipCreateRegionRgnData.
parent
01e53858
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
273 additions
and
41 deletions
+273
-41
region.c
dlls/gdiplus/region.c
+208
-41
region.c
dlls/gdiplus/tests/region.c
+65
-0
No files found.
dlls/gdiplus/region.c
View file @
a66d6645
/*
* Copyright (C) 2008 Google (Lei Zhang)
* Copyright (C) 2013 Dmitry Timoshkov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
...
...
@@ -76,6 +77,28 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
#define FLAGS_NOFLAGS 0x0
#define FLAGS_INTPATH 0x4000
struct
memory_buffer
{
const
BYTE
*
buffer
;
INT
size
,
pos
;
};
struct
region_header
{
DWORD
size
;
DWORD
checksum
;
DWORD
magic
;
DWORD
num_children
;
};
struct
path_header
{
DWORD
size
;
DWORD
magic
;
DWORD
count
;
DWORD
flags
;
};
/* Header size as far as header->size is concerned. This doesn't include
* header->size or header->checksum
*/
...
...
@@ -729,15 +752,9 @@ static void write_element(const region_element* element, DWORD *buffer,
{
INT
i
;
const
GpPath
*
path
=
element
->
elementdata
.
path
;
struct
_pathheader
{
DWORD
size
;
DWORD
magic
;
DWORD
count
;
DWORD
flags
;
}
*
pathheader
;
struct
path_header
*
pathheader
;
pathheader
=
(
struct
_path
header
*
)(
buffer
+
*
filled
);
pathheader
=
(
struct
path_
header
*
)(
buffer
+
*
filled
);
pathheader
->
flags
=
is_integer_path
(
path
)
?
FLAGS_INTPATH
:
FLAGS_NOFLAGS
;
/* 3 for headers, once again size doesn't count itself */
...
...
@@ -778,14 +795,6 @@ static void write_element(const region_element* element, DWORD *buffer,
}
}
struct
region_header
{
DWORD
size
;
DWORD
checksum
;
DWORD
magic
;
DWORD
num_children
;
};
/*****************************************************************************
* GdipGetRegionData [GDIPLUS.@]
*
...
...
@@ -856,36 +865,190 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
return
Ok
;
}
static
inline
GpStatus
read_dword
(
DWORD
**
buffer
,
INT
*
size
,
DWORD
*
ret
)
static
inline
void
init_memory_buffer
(
struct
memory_buffer
*
mbuf
,
const
BYTE
*
buffer
,
INT
size
)
{
if
(
*
size
<
sizeof
(
DWORD
))
return
GenericError
;
mbuf
->
buffer
=
buffer
;
mbuf
->
size
=
size
;
mbuf
->
pos
=
0
;
}
*
ret
=
**
buffer
;
(
*
buffer
)
++
;
(
*
size
)
-=
sizeof
(
DWORD
);
return
Ok
;
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
(
GpRegion
*
region
,
region_element
*
element
,
DWORD
**
buffer
,
INT
*
size
)
static
GpStatus
read_element
(
struct
memory_buffer
*
mbuf
,
GpRegion
*
region
,
region_element
*
node
,
INT
*
count
)
{
GpStatus
status
;
const
DWORD
*
type
;
status
=
read_dword
(
buffer
,
size
,
&
element
->
type
);
if
(
status
!=
Ok
)
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
;
}
switch
(
element
->
type
)
case
RegionDataRect
:
{
case
RegionDataInfiniteRect
:
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
:
break
;
case
RegionDataInfiniteRect
:
*
count
+=
1
;
return
Ok
;
default:
FIXME
(
"
region element type 0x%08x not supported
\n
"
,
element
->
type
);
return
NotImplemented
;
FIXME
(
"
element type %#x is not supported
\n
"
,
*
type
);
break
;
}
return
Ok
;
return
InvalidParameter
;
}
/*****************************************************************************
...
...
@@ -893,28 +1056,32 @@ static GpStatus read_element(GpRegion *region, region_element *element, DWORD **
*/
GpStatus
WINGDIPAPI
GdipCreateRegionRgnData
(
GDIPCONST
BYTE
*
data
,
INT
size
,
GpRegion
**
region
)
{
struct
region_header
*
region_header
;
DWORD
*
buffer
=
(
DWORD
*
)
data
;
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
<
sizeof
(
*
region_header
)
||
!
region
)
if
(
!
data
||
!
size
)
return
InvalidParameter
;
region_header
=
(
struct
region_header
*
)
buffer
;
if
(
region_header
->
magic
!=
VERSION_MAGIC
&&
region_header
->
magic
!=
VERSION_MAGIC2
)
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
;
/* skip header */
buffer
+=
4
;
size
-=
sizeof
(
*
region_header
);
count
=
0
;
status
=
read_element
(
&
mbuf
,
*
region
,
&
(
*
region
)
->
node
,
&
count
);
if
(
status
==
Ok
&&
!
count
)
status
=
InvalidParameter
;
status
=
read_element
(
*
region
,
&
(
*
region
)
->
node
,
&
buffer
,
&
size
);
if
(
status
!=
Ok
)
{
GdipDeleteRegion
(
*
region
);
...
...
dlls/gdiplus/tests/region.c
View file @
a66d6645
...
...
@@ -102,6 +102,56 @@ static void verify_region(HRGN hrgn, const RECT *rc)
rgn
.
data
.
rdh
.
rcBound
.
left
,
rgn
.
data
.
rdh
.
rcBound
.
top
,
rgn
.
data
.
rdh
.
rcBound
.
right
,
rgn
.
data
.
rdh
.
rcBound
.
bottom
);
}
static
void
test_region_data
(
DWORD
*
data
,
UINT
size
,
INT
line
)
{
GpStatus
status
;
GpRegion
*
region
;
DWORD
buf
[
256
];
UINT
needed
,
i
;
status
=
GdipCreateRegionRgnData
((
BYTE
*
)
data
,
size
,
&
region
);
/* Windows always fails to create an empty path in a region */
if
(
data
[
4
]
==
RGNDATA_PATH
)
{
struct
path_header
{
DWORD
size
;
DWORD
magic
;
DWORD
count
;
DWORD
flags
;
}
*
path_header
=
(
struct
path_header
*
)(
data
+
5
);
if
(
!
path_header
->
count
)
{
ok_
(
__FILE__
,
line
)(
status
==
GenericError
,
"expected GenericError, got %d
\n
"
,
status
);
return
;
}
}
ok_
(
__FILE__
,
line
)(
status
==
Ok
,
"GdipCreateRegionRgnData error %d
\n
"
,
status
);
if
(
status
!=
Ok
)
return
;
needed
=
0
;
status
=
GdipGetRegionDataSize
(
region
,
&
needed
);
ok_
(
__FILE__
,
line
)(
status
==
Ok
,
"status %d
\n
"
,
status
);
ok_
(
__FILE__
,
line
)(
needed
==
size
,
"data size mismatch: %u != %u
\n
"
,
needed
,
size
);
memset
(
buf
,
0xee
,
sizeof
(
buf
));
needed
=
0
;
status
=
GdipGetRegionData
(
region
,
(
BYTE
*
)
buf
,
sizeof
(
buf
),
&
needed
);
ok_
(
__FILE__
,
line
)(
status
==
Ok
,
"status %08x
\n
"
,
status
);
ok_
(
__FILE__
,
line
)(
needed
==
size
,
"data size mismatch: %u != %u
\n
"
,
needed
,
size
);
size
/=
sizeof
(
DWORD
);
for
(
i
=
0
;
i
<
size
-
1
;
i
++
)
{
if
(
i
==
1
)
continue
;
/* data[1] never matches */
ok_
(
__FILE__
,
line
)(
data
[
i
]
==
buf
[
i
],
"off %u: %#x != %#x
\n
"
,
i
,
data
[
i
],
buf
[
i
]);
}
/* some Windows versions fail to properly clear the aligned DWORD */
ok_
(
__FILE__
,
line
)(
data
[
size
-
1
]
==
buf
[
size
-
1
]
||
broken
(
data
[
size
-
1
]
!=
buf
[
size
-
1
]),
"off %u: %#x != %#x
\n
"
,
size
-
1
,
data
[
size
-
1
],
buf
[
size
-
1
]);
}
static
void
test_getregiondata
(
void
)
{
GpStatus
status
;
...
...
@@ -143,6 +193,7 @@ static void test_getregiondata(void)
expect_dword
(
buf
+
3
,
0
);
expect_dword
(
buf
+
4
,
RGNDATA_INFINITE_RECT
);
expect_dword
(
buf
+
6
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipSetEmpty
(
region
);
ok
(
status
==
Ok
,
"status %08x
\n
"
,
status
);
...
...
@@ -160,6 +211,7 @@ static void test_getregiondata(void)
expect_dword
(
buf
+
3
,
0
);
expect_dword
(
buf
+
4
,
RGNDATA_EMPTY_RECT
);
expect_dword
(
buf
+
6
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipSetInfinite
(
region
);
ok
(
status
==
Ok
,
"status %08x
\n
"
,
status
);
...
...
@@ -177,6 +229,7 @@ static void test_getregiondata(void)
expect_dword
(
buf
+
3
,
0
);
expect_dword
(
buf
+
4
,
RGNDATA_INFINITE_RECT
);
expect_dword
(
buf
+
6
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeleteRegion
(
region
);
ok
(
status
==
Ok
,
"status %08x
\n
"
,
status
);
...
...
@@ -205,6 +258,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
7
,
100
.
0
);
expect_float
(
buf
+
8
,
200
.
0
);
expect_dword
(
buf
+
10
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
rect
.
X
=
50
;
rect
.
Y
=
30
;
...
...
@@ -290,6 +344,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
37
,
22
.
0
);
expect_float
(
buf
+
38
,
55
.
0
);
expect_dword
(
buf
+
39
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeleteRegion
(
region2
);
ok
(
status
==
Ok
,
"status %08x
\n
"
,
status
);
...
...
@@ -331,6 +386,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
16
,
28
.
0
);
expect_dword
(
buf
+
17
,
0x81010100
);
expect_dword
(
buf
+
18
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
rect
.
X
=
50
;
rect
.
Y
=
30
;
...
...
@@ -371,6 +427,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
22
,
10
.
0
);
expect_float
(
buf
+
23
,
20
.
0
);
expect_dword
(
buf
+
24
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeleteRegion
(
region
);
ok
(
status
==
Ok
,
"status %08x
\n
"
,
status
);
...
...
@@ -403,6 +460,7 @@ static void test_getregiondata(void)
ok
(
*
(
buf
+
8
)
==
0x4000
/* before win7 */
||
*
(
buf
+
8
)
==
0
,
"expected 0x4000 or 0, got %08x
\n
"
,
*
(
buf
+
8
));
expect_dword
(
buf
+
10
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
/* Transform an empty region */
status
=
GdipCreateMatrix
(
&
matrix
);
...
...
@@ -453,6 +511,7 @@ static void test_getregiondata(void)
expect
(
6
,
point
[
3
].
Y
);
expect_dword
(
buf
+
13
,
0x81010100
);
/* 0x01010100 if we don't close the path */
expect_dword
(
buf
+
14
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipTranslateRegion
(
region
,
0
.
6
,
0
.
8
);
expect
(
Ok
,
status
);
...
...
@@ -480,6 +539,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
16
,
6
.
8
);
expect_dword
(
buf
+
17
,
0x81010100
);
/* 0x01010100 if we don't close the path */
expect_dword
(
buf
+
18
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeletePath
(
path
);
expect
(
Ok
,
status
);
...
...
@@ -522,6 +582,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
16
,
6
.
2
);
expect_dword
(
buf
+
17
,
0x01010100
);
expect_dword
(
buf
+
18
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeletePath
(
path
);
expect
(
Ok
,
status
);
...
...
@@ -584,6 +645,7 @@ static void test_getregiondata(void)
ok
(
*
(
buf
+
28
)
==
0x00000101
||
*
(
buf
+
28
)
==
0x43050101
/* Win 7 */
,
"expected 00000101 or 43050101 got %08x
\n
"
,
*
(
buf
+
28
));
expect_dword
(
buf
+
29
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeletePath
(
path
);
expect
(
Ok
,
status
);
...
...
@@ -627,6 +689,7 @@ static void test_getregiondata(void)
expect
(
23
,
point
[
3
].
Y
);
expect_dword
(
buf
+
13
,
0x81010100
);
/* 0x01010100 if we don't close the path */
expect_dword
(
buf
+
14
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeletePath
(
path
);
expect
(
Ok
,
status
);
...
...
@@ -669,6 +732,7 @@ static void test_getregiondata(void)
expect_float
(
buf
+
16
,
2300
.
0
);
expect_dword
(
buf
+
17
,
0x81010100
);
/* 0x01010100 if we don't close the path */
expect_dword
(
buf
+
18
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeletePath
(
path
);
expect
(
Ok
,
status
);
...
...
@@ -732,6 +796,7 @@ static void test_getregiondata(void)
*
(
buf
+
33
)
==
0x43030303
/* 32-bit win7 */
||
*
(
buf
+
33
)
==
0x4c030303
/* 64-bit win7 */
,
"expected 0x00030303 or 0x43030303 or 0x4c030303 got %08x
\n
"
,
*
(
buf
+
33
));
expect_dword
(
buf
+
34
,
0xeeeeeeee
);
test_region_data
(
buf
,
needed
,
__LINE__
);
status
=
GdipDeletePath
(
path
);
expect
(
Ok
,
status
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment