2 * Copyright (C) 2008 Google (Lei Zhang)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "gdiplus_private.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
33 /**********************************************************
35 * Data returned by GdipGetRegionData looks something like this:
37 * struct region_data_header
39 * DWORD size; size in bytes of the data - 8.
40 * DWORD magic1; probably a checksum.
41 * DWORD magic2; always seems to be 0xdbc01001 - version?
42 * DWORD num_ops; number of combining ops * 2
45 * Then follows a sequence of combining ops and region elements.
47 * A region element is either a RECTF or some path data.
49 * Combining ops are just stored as their CombineMode value.
51 * Each RECTF is preceded by the DWORD 0x10000000. An empty rect is
52 * stored as 0x10000002 (with no following RECTF) and an infinite rect
53 * is stored as 0x10000003 (again with no following RECTF).
55 * Path data is preceded by the DWORD 0x10000001. Then follows a
56 * DWORD size and then size bytes of data.
58 * The combining ops are stored in the reverse order to the region
59 * elements and in the reverse order to which the region was
62 * When two or more complex regions (ie those with more than one
63 * element) are combined, the combining op for the two regions comes
64 * first, then the combining ops for the region elements in region 1,
65 * followed by the region elements for region 1, then follows the
66 * combining ops for region 2 and finally region 2's region elements.
67 * Presumably you're supposed to use the 0x1000000x header to find the
68 * end of the op list (the count of the elements in each region is not
71 * When a simple region (1 element) is combined, it's treated as if a
72 * single rect/path is being combined.
76 typedef enum RegionType
78 RegionDataRect
= 0x10000000,
79 RegionDataPath
= 0x10000001,
80 RegionDataEmptyRect
= 0x10000002,
81 RegionDataInfiniteRect
= 0x10000003,
84 /* Header size as far as header->size is concerned. This doesn't include
85 * header->size or header->checksum
87 static const INT sizeheader_size
= sizeof(DWORD
) * 2;
89 static inline INT
get_element_size(const region_element
* element
)
91 INT needed
= sizeof(DWORD
); /* DWORD for the type */
95 return needed
+ sizeof(GpRect
);
97 needed
+= element
->elementdata
.pathdata
.pathheader
.size
;
98 needed
+= sizeof(DWORD
); /* Extra DWORD for pathheader.size */
100 case RegionDataEmptyRect
:
101 case RegionDataInfiniteRect
:
104 needed
+= get_element_size(element
->elementdata
.combine
.left
);
105 needed
+= get_element_size(element
->elementdata
.combine
.right
);
112 /* Does not check parameters, caller must do that */
113 static inline GpStatus
init_region(GpRegion
* region
, const RegionType type
)
115 region
->node
.type
= type
;
116 region
->header
.checksum
= 0xdeadbeef;
117 region
->header
.magic
= VERSION_MAGIC
;
118 region
->header
.num_children
= 0;
119 region
->header
.size
= sizeheader_size
+ get_element_size(®ion
->node
);
124 static inline void delete_element(region_element
* element
)
126 switch(element
->type
)
131 GdipDeletePath(element
->elementdata
.pathdata
.path
);
133 case RegionDataEmptyRect
:
134 case RegionDataInfiniteRect
:
137 delete_element(element
->elementdata
.combine
.left
);
138 delete_element(element
->elementdata
.combine
.right
);
139 GdipFree(element
->elementdata
.combine
.left
);
140 GdipFree(element
->elementdata
.combine
.right
);
145 /*****************************************************************************
146 * GdipCloneRegion [GDIPLUS.@]
148 GpStatus WINGDIPAPI
GdipCloneRegion(GpRegion
*region
, GpRegion
**clone
)
150 FIXME("(%p %p): stub\n", region
, clone
);
153 return NotImplemented
;
156 GpStatus WINGDIPAPI
GdipCombineRegionPath(GpRegion
*region
, GpPath
*path
, CombineMode mode
)
158 FIXME("(%p %p %d): stub\n", region
, path
, mode
);
159 return NotImplemented
;
162 GpStatus WINGDIPAPI
GdipCombineRegionRect(GpRegion
*region
, GDIPCONST GpRectF
*rect
,
165 FIXME("(%p %p %d): stub\n", region
, rect
, mode
);
166 return NotImplemented
;
169 GpStatus WINGDIPAPI
GdipCombineRegionRectI(GpRegion
*region
, GDIPCONST GpRect
*rect
,
172 FIXME("(%p %p %d): stub\n", region
, rect
, mode
);
173 return NotImplemented
;
176 GpStatus WINGDIPAPI
GdipCombineRegionRegion(GpRegion
*region1
, GpRegion
*region2
,
179 FIXME("(%p %p %d): stub\n", region1
, region2
, mode
);
180 return NotImplemented
;
183 GpStatus WINGDIPAPI
GdipCreateRegion(GpRegion
**region
)
186 return InvalidParameter
;
188 TRACE("%p\n", region
);
190 *region
= GdipAlloc(sizeof(GpRegion
));
194 return init_region(*region
, RegionDataInfiniteRect
);
197 GpStatus WINGDIPAPI
GdipCreateRegionPath(GpPath
*path
, GpRegion
**region
)
199 FIXME("(%p, %p): stub\n", path
, region
);
202 return NotImplemented
;
205 GpStatus WINGDIPAPI
GdipCreateRegionRect(GDIPCONST GpRectF
*rect
, GpRegion
**region
)
207 FIXME("(%p, %p): stub\n", rect
, region
);
210 return NotImplemented
;
213 GpStatus WINGDIPAPI
GdipCreateRegionRectI(GDIPCONST GpRect
*rect
, GpRegion
**region
)
215 FIXME("(%p, %p): stub\n", rect
, region
);
218 return NotImplemented
;
221 GpStatus WINGDIPAPI
GdipCreateRegionRgnData(GDIPCONST BYTE
*data
, INT size
, GpRegion
**region
)
223 FIXME("(%p, %d, %p): stub\n", data
, size
, region
);
226 return NotImplemented
;
229 GpStatus WINGDIPAPI
GdipCreateRegionHrgn(HRGN hrgn
, GpRegion
**region
)
231 FIXME("(%p, %p): stub\n", hrgn
, region
);
234 return NotImplemented
;
237 GpStatus WINGDIPAPI
GdipDeleteRegion(GpRegion
*region
)
239 TRACE("%p\n", region
);
242 return InvalidParameter
;
244 delete_element(®ion
->node
);
250 GpStatus WINGDIPAPI
GdipGetRegionBounds(GpRegion
*region
, GpGraphics
*graphics
, GpRectF
*rect
)
252 FIXME("(%p, %p, %p): stub\n", region
, graphics
, rect
);
254 return NotImplemented
;
257 GpStatus WINGDIPAPI
GdipGetRegionBoundsI(GpRegion
*region
, GpGraphics
*graphics
, GpRect
*rect
)
259 FIXME("(%p, %p, %p): stub\n", region
, graphics
, rect
);
261 return NotImplemented
;
264 GpStatus WINGDIPAPI
GdipGetRegionData(GpRegion
*region
, BYTE
*buffer
, UINT size
, UINT
*needed
)
266 FIXME("(%p, %p, %d, %p): stub\n", region
, buffer
, size
, needed
);
268 return NotImplemented
;
271 GpStatus WINGDIPAPI
GdipGetRegionDataSize(GpRegion
*region
, UINT
*needed
)
273 if (!(region
&& needed
))
274 return InvalidParameter
;
276 TRACE("%p, %p\n", region
, needed
);
278 /* header.size doesn't count header.size and header.checksum */
279 *needed
= region
->header
.size
+ sizeof(DWORD
) * 2;
284 /*****************************************************************************
285 * GdipGetRegionHRgn [GDIPLUS.@]
287 GpStatus WINGDIPAPI
GdipGetRegionHRgn(GpRegion
*region
, GpGraphics
*graphics
, HRGN
*hrgn
)
289 FIXME("(%p, %p, %p): stub\n", region
, graphics
, hrgn
);
292 return NotImplemented
;
295 GpStatus WINGDIPAPI
GdipIsEmptyRegion(GpRegion
*region
, GpGraphics
*graphics
, BOOL
*res
)
297 FIXME("(%p, %p, %p): stub\n", region
, graphics
, res
);
299 return NotImplemented
;
302 GpStatus WINGDIPAPI
GdipIsEqualRegion(GpRegion
*region
, GpRegion
*region2
, GpGraphics
*graphics
,
305 FIXME("(%p, %p, %p, %p): stub\n", region
, region2
, graphics
, res
);
307 return NotImplemented
;
310 GpStatus WINGDIPAPI
GdipIsInfiniteRegion(GpRegion
*region
, GpGraphics
*graphics
, BOOL
*res
)
312 FIXME("(%p, %p, %p): stub\n", region
, graphics
, res
);
314 return NotImplemented
;
317 GpStatus WINGDIPAPI
GdipSetEmpty(GpRegion
*region
)
321 TRACE("%p\n", region
);
324 return InvalidParameter
;
326 delete_element(®ion
->node
);
327 stat
= init_region(region
, RegionDataEmptyRect
);
332 GpStatus WINGDIPAPI
GdipSetInfinite(GpRegion
*region
)
337 return InvalidParameter
;
339 TRACE("%p\n", region
);
341 delete_element(®ion
->node
);
342 stat
= init_region(region
, RegionDataInfiniteRect
);
347 GpStatus WINGDIPAPI
GdipTransformRegion(GpRegion
*region
, GpMatrix
*matrix
)
349 FIXME("(%p, %p): stub\n", region
, matrix
);
351 return NotImplemented
;
354 GpStatus WINGDIPAPI
GdipTranslateRegion(GpRegion
*region
, REAL dx
, REAL dy
)
356 FIXME("(%p, %f, %f): stub\n", region
, dx
, dy
);
358 return NotImplemented
;
361 GpStatus WINGDIPAPI
GdipTranslateRegionI(GpRegion
*region
, INT dx
, INT dy
)
363 FIXME("(%p, %d, %d): stub\n", region
, dx
, dy
);
365 return NotImplemented
;