gdiplus: Implemented GdipReversePath with tests.
[wine/wine-kai.git] / dlls / gdiplus / region.c
blobc4007b3ff38d08a0e887589490c2fb1d91f2d483
1 /*
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
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wingdi.h"
25 #include "objbase.h"
27 #include "gdiplus.h"
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
38 * {
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
43 * };
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
60 * constructed.
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
69 * stored).
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,
82 } RegionType;
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 */
92 switch(element->type)
94 case RegionDataRect:
95 return needed + sizeof(GpRect);
96 case RegionDataPath:
97 needed += element->elementdata.pathdata.pathheader.size;
98 needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
99 return needed;
100 case RegionDataEmptyRect:
101 case RegionDataInfiniteRect:
102 return needed;
103 default:
104 needed += get_element_size(element->elementdata.combine.left);
105 needed += get_element_size(element->elementdata.combine.right);
106 return needed;
109 return 0;
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(&region->node);
121 return Ok;
124 static inline void delete_element(region_element* element)
126 switch(element->type)
128 case RegionDataRect:
129 break;
130 case RegionDataPath:
131 GdipDeletePath(element->elementdata.pathdata.path);
132 break;
133 case RegionDataEmptyRect:
134 case RegionDataInfiniteRect:
135 break;
136 default:
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);
141 break;
145 /*****************************************************************************
146 * GdipCloneRegion [GDIPLUS.@]
148 GpStatus WINGDIPAPI GdipCloneRegion(GpRegion *region, GpRegion **clone)
150 FIXME("(%p %p): stub\n", region, clone);
152 *clone = NULL;
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,
163 CombineMode mode)
165 FIXME("(%p %p %d): stub\n", region, rect, mode);
166 return NotImplemented;
169 GpStatus WINGDIPAPI GdipCombineRegionRectI(GpRegion *region, GDIPCONST GpRect *rect,
170 CombineMode mode)
172 FIXME("(%p %p %d): stub\n", region, rect, mode);
173 return NotImplemented;
176 GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1, GpRegion *region2,
177 CombineMode mode)
179 FIXME("(%p %p %d): stub\n", region1, region2, mode);
180 return NotImplemented;
183 GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
185 if(!region)
186 return InvalidParameter;
188 TRACE("%p\n", region);
190 *region = GdipAlloc(sizeof(GpRegion));
191 if(!*region)
192 return OutOfMemory;
194 return init_region(*region, RegionDataInfiniteRect);
197 GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
199 FIXME("(%p, %p): stub\n", path, region);
201 *region = NULL;
202 return NotImplemented;
205 GpStatus WINGDIPAPI GdipCreateRegionRect(GDIPCONST GpRectF *rect, GpRegion **region)
207 FIXME("(%p, %p): stub\n", rect, region);
209 *region = NULL;
210 return NotImplemented;
213 GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect, GpRegion **region)
215 FIXME("(%p, %p): stub\n", rect, region);
217 *region = NULL;
218 return NotImplemented;
221 GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
223 FIXME("(%p, %d, %p): stub\n", data, size, region);
225 *region = NULL;
226 return NotImplemented;
229 GpStatus WINGDIPAPI GdipCreateRegionHrgn(HRGN hrgn, GpRegion **region)
231 FIXME("(%p, %p): stub\n", hrgn, region);
233 *region = NULL;
234 return NotImplemented;
237 GpStatus WINGDIPAPI GdipDeleteRegion(GpRegion *region)
239 TRACE("%p\n", region);
241 if (!region)
242 return InvalidParameter;
244 delete_element(&region->node);
245 GdipFree(region);
247 return Ok;
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;
281 return Ok;
284 /*****************************************************************************
285 * GdipGetRegionHRgn [GDIPLUS.@]
287 GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
289 FIXME("(%p, %p, %p): stub\n", region, graphics, hrgn);
291 *hrgn = NULL;
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,
303 BOOL *res)
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)
319 GpStatus stat;
321 TRACE("%p\n", region);
323 if (!region)
324 return InvalidParameter;
326 delete_element(&region->node);
327 stat = init_region(region, RegionDataEmptyRect);
329 return stat;
332 GpStatus WINGDIPAPI GdipSetInfinite(GpRegion *region)
334 GpStatus stat;
336 if (!region)
337 return InvalidParameter;
339 TRACE("%p\n", region);
341 delete_element(&region->node);
342 stat = init_region(region, RegionDataInfiniteRect);
344 return stat;
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;