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 GpStatus WINGDIPAPI
GdipCloneRegion(GpRegion
*region
, GpRegion
**clone
)
147 FIXME("(%p %p): stub\n", region
, clone
);
150 return NotImplemented
;
153 GpStatus WINGDIPAPI
GdipCombineRegionPath(GpRegion
*region
, GpPath
*path
, CombineMode mode
)
155 FIXME("(%p %p %d): stub\n", region
, path
, mode
);
156 return NotImplemented
;
159 GpStatus WINGDIPAPI
GdipCombineRegionRect(GpRegion
*region
, GDIPCONST GpRectF
*rect
,
162 FIXME("(%p %p %d): stub\n", region
, rect
, mode
);
163 return NotImplemented
;
166 GpStatus WINGDIPAPI
GdipCombineRegionRectI(GpRegion
*region
, GDIPCONST GpRect
*rect
,
169 FIXME("(%p %p %d): stub\n", region
, rect
, mode
);
170 return NotImplemented
;
173 GpStatus WINGDIPAPI
GdipCombineRegionRegion(GpRegion
*region1
, GpRegion
*region2
,
176 FIXME("(%p %p %d): stub\n", region1
, region2
, mode
);
177 return NotImplemented
;
180 GpStatus WINGDIPAPI
GdipCreateRegion(GpRegion
**region
)
183 return InvalidParameter
;
185 TRACE("%p\n", region
);
187 *region
= GdipAlloc(sizeof(GpRegion
));
191 return init_region(*region
, RegionDataInfiniteRect
);
194 GpStatus WINGDIPAPI
GdipCreateRegionPath(GpPath
*path
, GpRegion
**region
)
196 FIXME("(%p, %p): stub\n", path
, region
);
199 return NotImplemented
;
202 GpStatus WINGDIPAPI
GdipCreateRegionRect(GDIPCONST GpRectF
*rect
, GpRegion
**region
)
204 FIXME("(%p, %p): stub\n", rect
, region
);
207 return NotImplemented
;
210 GpStatus WINGDIPAPI
GdipCreateRegionRectI(GDIPCONST GpRect
*rect
, GpRegion
**region
)
212 FIXME("(%p, %p): stub\n", rect
, region
);
215 return NotImplemented
;
218 GpStatus WINGDIPAPI
GdipCreateRegionRgnData(GDIPCONST BYTE
*data
, INT size
, GpRegion
**region
)
220 FIXME("(%p, %d, %p): stub\n", data
, size
, region
);
223 return NotImplemented
;
226 GpStatus WINGDIPAPI
GdipCreateRegionHrgn(HRGN hrgn
, GpRegion
**region
)
228 FIXME("(%p, %p): stub\n", hrgn
, region
);
231 return NotImplemented
;
234 GpStatus WINGDIPAPI
GdipDeleteRegion(GpRegion
*region
)
236 TRACE("%p\n", region
);
239 return InvalidParameter
;
241 delete_element(®ion
->node
);
247 GpStatus WINGDIPAPI
GdipGetRegionBounds(GpRegion
*region
, GpGraphics
*graphics
, GpRectF
*rect
)
249 FIXME("(%p, %p, %p): stub\n", region
, graphics
, rect
);
251 return NotImplemented
;
254 GpStatus WINGDIPAPI
GdipGetRegionBoundsI(GpRegion
*region
, GpGraphics
*graphics
, GpRect
*rect
)
256 FIXME("(%p, %p, %p): stub\n", region
, graphics
, rect
);
258 return NotImplemented
;
261 GpStatus WINGDIPAPI
GdipGetRegionData(GpRegion
*region
, BYTE
*buffer
, UINT size
, UINT
*needed
)
263 FIXME("(%p, %p, %d, %p): stub\n", region
, buffer
, size
, needed
);
265 return NotImplemented
;
268 GpStatus WINGDIPAPI
GdipGetRegionDataSize(GpRegion
*region
, UINT
*needed
)
270 if (!(region
&& needed
))
271 return InvalidParameter
;
273 TRACE("%p, %p\n", region
, needed
);
275 /* header.size doesn't count header.size and header.checksum */
276 *needed
= region
->header
.size
+ sizeof(DWORD
) * 2;
281 GpStatus WINGDIPAPI
GdipGetRegionHRgn(GpRegion
*region
, GpGraphics
*graphics
, HRGN
*hrgn
)
283 FIXME("(%p, %p, %p): stub\n", region
, graphics
, hrgn
);
286 return NotImplemented
;
289 GpStatus WINGDIPAPI
GdipIsEmptyRegion(GpRegion
*region
, GpGraphics
*graphics
, BOOL
*res
)
291 FIXME("(%p, %p, %p): stub\n", region
, graphics
, res
);
293 return NotImplemented
;
296 GpStatus WINGDIPAPI
GdipIsEqualRegion(GpRegion
*region
, GpRegion
*region2
, GpGraphics
*graphics
,
299 FIXME("(%p, %p, %p, %p): stub\n", region
, region2
, graphics
, res
);
301 return NotImplemented
;
304 GpStatus WINGDIPAPI
GdipIsInfiniteRegion(GpRegion
*region
, GpGraphics
*graphics
, BOOL
*res
)
306 FIXME("(%p, %p, %p): stub\n", region
, graphics
, res
);
308 return NotImplemented
;
311 GpStatus WINGDIPAPI
GdipSetEmpty(GpRegion
*region
)
315 TRACE("%p\n", region
);
318 return InvalidParameter
;
320 delete_element(®ion
->node
);
321 stat
= init_region(region
, RegionDataEmptyRect
);
326 GpStatus WINGDIPAPI
GdipSetInfinite(GpRegion
*region
)
331 return InvalidParameter
;
335 delete_element(®ion
->node
);
336 stat
= init_region(region
, RegionDataInfiniteRect
);
341 GpStatus WINGDIPAPI
GdipTransformRegion(GpRegion
*region
, GpMatrix
*matrix
)
343 FIXME("(%p, %p): stub\n", region
, matrix
);
345 return NotImplemented
;
348 GpStatus WINGDIPAPI
GdipTranslateRegion(GpRegion
*region
, REAL dx
, REAL dy
)
350 FIXME("(%p, %f, %f): stub\n", region
, dx
, dy
);
352 return NotImplemented
;
355 GpStatus WINGDIPAPI
GdipTranslateRegionI(GpRegion
*region
, INT dx
, INT dy
)
357 FIXME("(%p, %d, %d): stub\n", region
, dx
, dy
);
359 return NotImplemented
;