ReactOS 0.4.17-dev-218-g5635d24
region.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2008 Google (Lei Zhang)
3 * Copyright (C) 2013 Dmitry Timoshkov
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20#include <assert.h>
21#include <stdarg.h>
22
23#include "windef.h"
24#include "winbase.h"
25#include "wingdi.h"
26
27#include "objbase.h"
28
29#include "gdiplus.h"
30#include "gdiplus_private.h"
31#include "wine/debug.h"
32
34
35/**********************************************************
36 *
37 * Data returned by GdipGetRegionData looks something like this:
38 *
39 * struct region_data_header
40 * {
41 * DWORD size; size in bytes of the data - 8.
42 * DWORD magic1; probably a checksum.
43 * DWORD magic2; always seems to be 0xdbc01001 - version?
44 * DWORD num_ops; number of combining ops * 2
45 * };
46 *
47 * Then follows a sequence of combining ops and region elements.
48 *
49 * A region element is either a RECTF or some path data.
50 *
51 * Combining ops are just stored as their CombineMode value.
52 *
53 * Each RECTF is preceded by the DWORD 0x10000000. An empty rect is
54 * stored as 0x10000002 (with no following RECTF) and an infinite rect
55 * is stored as 0x10000003 (again with no following RECTF).
56 *
57 * Path data is preceded by the DWORD 0x10000001. Then follows a
58 * DWORD size and then size bytes of data.
59 *
60 * The combining ops are stored in the reverse order to the region
61 * elements and in the reverse order to which the region was
62 * constructed.
63 *
64 * When two or more complex regions (ie those with more than one
65 * element) are combined, the combining op for the two regions comes
66 * first, then the combining ops for the region elements in region 1,
67 * followed by the region elements for region 1, then follows the
68 * combining ops for region 2 and finally region 2's region elements.
69 * Presumably you're supposed to use the 0x1000000x header to find the
70 * end of the op list (the count of the elements in each region is not
71 * stored).
72 *
73 * When a simple region (1 element) is combined, it's treated as if a
74 * single rect/path is being combined.
75 *
76 */
77
78#define FLAGS_INTPATH 0x4000
79
81{
84};
85
87{
91};
92
93struct path_header
94{
99};
100
101typedef struct packed_point
102{
103 short X;
104 short Y;
106
108 REAL *min_x, REAL *min_y, REAL *max_x, REAL *max_y, BOOL *empty, BOOL *infinite);
109
111{
112 INT needed = sizeof(DWORD); /* DWORD for the type */
113 switch(element->type)
114 {
115 case RegionDataRect:
116 return needed + sizeof(GpRect);
117 case RegionDataPath:
118 {
119 needed += write_path_data(element->elementdata.path, NULL);
120 needed += sizeof(DWORD); /* Extra DWORD for path size */
121 return needed;
122 }
125 return needed;
126 default:
127 needed += get_element_size(element->elementdata.combine.left);
128 needed += get_element_size(element->elementdata.combine.right);
129 return needed;
130 }
131
132 return 0;
133}
134
135/* Does not check parameters, caller must do that */
136static inline GpStatus init_region(GpRegion* region, const RegionType type)
137{
138 region->node.type = type;
139 region->num_children = 0;
140
141 return Ok;
142}
143
145 region_element** element2)
146{
148
149 /* root node is allocated with GpRegion */
150 if(!*element2){
151 *element2 = calloc(1, sizeof(region_element));
152 if (!*element2)
153 return OutOfMemory;
154 }
155
156 (*element2)->type = element->type;
157
158 switch (element->type)
159 {
160 case RegionDataRect:
161 (*element2)->elementdata.rect = element->elementdata.rect;
162 return Ok;
165 return Ok;
166 case RegionDataPath:
167 stat = GdipClonePath(element->elementdata.path, &(*element2)->elementdata.path);
168 if (stat == Ok) return Ok;
169 break;
170 default:
171 (*element2)->elementdata.combine.left = NULL;
172 (*element2)->elementdata.combine.right = NULL;
173
174 stat = clone_element(element->elementdata.combine.left,
175 &(*element2)->elementdata.combine.left);
176 if (stat == Ok)
177 {
178 stat = clone_element(element->elementdata.combine.right,
179 &(*element2)->elementdata.combine.right);
180 if (stat == Ok) return Ok;
181 }
182 break;
183 }
184
185 delete_element(*element2);
186 *element2 = NULL;
187 return stat;
188}
189
190/* Common code for CombineRegion*
191 * All the caller has to do is get its format into an element
192 */
193static inline void fuse_region(GpRegion* region, region_element* left,
195{
196 region->node.type = mode;
197 region->node.elementdata.combine.left = left;
198 region->node.elementdata.combine.right = right;
199 region->num_children += 2;
200}
201
202/*****************************************************************************
203 * GdipCloneRegion [GDIPLUS.@]
204 *
205 * Creates a deep copy of the region
206 *
207 * PARAMS
208 * region [I] source region
209 * clone [O] resulting clone
210 *
211 * RETURNS
212 * SUCCESS: Ok
213 * FAILURE: InvalidParameter or OutOfMemory
214 */
216{
218
219 TRACE("%p %p\n", region, clone);
220
221 if (!(region && clone))
222 return InvalidParameter;
223
224 *clone = calloc(1, sizeof(GpRegion));
225 if (!*clone)
226 return OutOfMemory;
227 element = &(*clone)->node;
228
229 (*clone)->num_children = region->num_children;
230 return clone_element(&region->node, &element);
231}
232
233/*****************************************************************************
234 * GdipCombineRegionPath [GDIPLUS.@]
235 */
237{
238 GpRegion *path_region;
241
242 TRACE("%p %p %d\n", region, path, mode);
243
244 if (!(region && path))
245 return InvalidParameter;
246
247 stat = GdipCreateRegionPath(path, &path_region);
248 if (stat != Ok)
249 return stat;
250
251 /* simply replace region data */
253 delete_element(&region->node);
254 memcpy(region, path_region, sizeof(GpRegion));
255 free(path_region);
256 return Ok;
257 }
258
259 left = malloc(sizeof(region_element));
260 if (left)
261 {
262 *left = region->node;
263 stat = clone_element(&path_region->node, &right);
264 if (stat == Ok)
265 {
266 fuse_region(region, left, right, mode);
267 GdipDeleteRegion(path_region);
268 return Ok;
269 }
270 }
271 else
273
274 free(left);
275 GdipDeleteRegion(path_region);
276 return stat;
277}
278
279/*****************************************************************************
280 * GdipCombineRegionRect [GDIPLUS.@]
281 */
284{
285 GpRegion *rect_region;
288
289 TRACE("%p %s %d\n", region, debugstr_rectf(rect), mode);
290
291 if (!(region && rect))
292 return InvalidParameter;
293
294 stat = GdipCreateRegionRect(rect, &rect_region);
295 if (stat != Ok)
296 return stat;
297
298 /* simply replace region data */
300 delete_element(&region->node);
301 memcpy(region, rect_region, sizeof(GpRegion));
302 free(rect_region);
303 return Ok;
304 }
305
306 left = malloc(sizeof(region_element));
307 if (left)
308 {
309 memcpy(left, &region->node, sizeof(region_element));
310 stat = clone_element(&rect_region->node, &right);
311 if (stat == Ok)
312 {
313 fuse_region(region, left, right, mode);
314 GdipDeleteRegion(rect_region);
315 return Ok;
316 }
317 }
318 else
320
321 free(left);
322 GdipDeleteRegion(rect_region);
323 return stat;
324}
325
326/*****************************************************************************
327 * GdipCombineRegionRectI [GDIPLUS.@]
328 */
331{
332 GpRectF rectf;
333
334 TRACE("%p %p %d\n", region, rect, mode);
335
336 if (!rect)
337 return InvalidParameter;
338
339 set_rect(&rectf, rect->X, rect->Y, rect->Width, rect->Height);
340 return GdipCombineRegionRect(region, &rectf, mode);
341}
342
343/*****************************************************************************
344 * GdipCombineRegionRegion [GDIPLUS.@]
345 */
347 GpRegion *region2, CombineMode mode)
348{
351 GpRegion *reg2copy;
352
353 TRACE("%p %p %d\n", region1, region2, mode);
354
355 if(!(region1 && region2))
356 return InvalidParameter;
357
358 /* simply replace region data */
360 stat = GdipCloneRegion(region2, &reg2copy);
361 if(stat != Ok) return stat;
362
363 delete_element(&region1->node);
364 memcpy(region1, reg2copy, sizeof(GpRegion));
365 free(reg2copy);
366 return Ok;
367 }
368
369 left = malloc(sizeof(region_element));
370 if (!left)
371 return OutOfMemory;
372
373 *left = region1->node;
374 stat = clone_element(&region2->node, &right);
375 if (stat != Ok)
376 {
377 free(left);
378 return OutOfMemory;
379 }
380
381 fuse_region(region1, left, right, mode);
382 region1->num_children += region2->num_children;
383
384 return Ok;
385}
386
387/*****************************************************************************
388 * GdipCreateRegion [GDIPLUS.@]
389 */
391{
392 TRACE("%p\n", region);
393
394 if(!region)
395 return InvalidParameter;
396
397 *region = calloc(1, sizeof(GpRegion));
398 if(!*region)
399 return OutOfMemory;
400
401 TRACE("=> %p\n", *region);
402
403 return init_region(*region, RegionDataInfiniteRect);
404}
405
406/*****************************************************************************
407 * GdipCreateRegionPath [GDIPLUS.@]
408 *
409 * Creates a GpRegion from a GpPath
410 *
411 * PARAMS
412 * path [I] path to base the region on
413 * region [O] pointer to the newly allocated region
414 *
415 * RETURNS
416 * SUCCESS: Ok
417 * FAILURE: InvalidParameter
418 *
419 * NOTES
420 * If a path has no floating point points, its points will be stored as shorts
421 * (INTPATH)
422 *
423 * If a path is empty, it is considered to be an INTPATH
424 */
426{
429
430 TRACE("%p, %p\n", path, region);
431
432 if (!(path && region))
433 return InvalidParameter;
434
435 *region = calloc(1, sizeof(GpRegion));
436 if(!*region)
437 return OutOfMemory;
438 stat = init_region(*region, RegionDataPath);
439 if (stat != Ok)
440 {
441 GdipDeleteRegion(*region);
442 return stat;
443 }
444 element = &(*region)->node;
445
446 stat = GdipClonePath(path, &element->elementdata.path);
447 if (stat != Ok)
448 {
449 GdipDeleteRegion(*region);
450 return stat;
451 }
452
453 return Ok;
454}
455
456/*****************************************************************************
457 * GdipCreateRegionRect [GDIPLUS.@]
458 */
460 GpRegion **region)
461{
463
464 TRACE("%s, %p\n", debugstr_rectf(rect), region);
465
466 if (!(rect && region))
467 return InvalidParameter;
468
469 *region = calloc(1, sizeof(GpRegion));
470 stat = init_region(*region, RegionDataRect);
471 if(stat != Ok)
472 {
473 GdipDeleteRegion(*region);
474 return stat;
475 }
476
477 (*region)->node.elementdata.rect.X = rect->X;
478 (*region)->node.elementdata.rect.Y = rect->Y;
479 (*region)->node.elementdata.rect.Width = rect->Width;
480 (*region)->node.elementdata.rect.Height = rect->Height;
481
482 return Ok;
483}
484
485/*****************************************************************************
486 * GdipCreateRegionRectI [GDIPLUS.@]
487 */
489 GpRegion **region)
490{
491 GpRectF rectf;
492
493 TRACE("%p, %p\n", rect, region);
494
495 set_rect(&rectf, rect->X, rect->Y, rect->Width, rect->Height);
496 return GdipCreateRegionRect(&rectf, region);
497}
498
499/******************************************************************************
500 * GdipCreateRegionHrgn [GDIPLUS.@]
501 */
503{
504 DWORD size;
506 LPRECT rect;
508 GpPath* path;
510 DWORD i;
511
512 TRACE("(%p, %p)\n", hrgn, region);
513
514 if(!region || !(size = GetRegionData(hrgn, 0, NULL)))
515 return InvalidParameter;
516
517 buf = malloc(size);
518 if(!buf)
519 return OutOfMemory;
520
521 if(!GetRegionData(hrgn, size, buf)){
522 free(buf);
523 return GenericError;
524 }
525
526 if(buf->rdh.nCount == 0){
527 if((stat = GdipCreateRegion(&local)) != Ok){
528 free(buf);
529 return stat;
530 }
531 if((stat = GdipSetEmpty(local)) != Ok){
532 free(buf);
534 return stat;
535 }
536 *region = local;
537 free(buf);
538 return Ok;
539 }
540
542 free(buf);
543 return stat;
544 }
545
546 rect = (LPRECT)buf->Buffer;
547 for(i = 0; i < buf->rdh.nCount; i++){
549 (REAL)(rect->right - rect->left), (REAL)(rect->bottom - rect->top))) != Ok){
550 free(buf);
552 return stat;
553 }
554 rect++;
555 }
556
557 stat = GdipCreateRegionPath(path, region);
558
559 free(buf);
561 return stat;
562}
563
564/*****************************************************************************
565 * GdipDeleteRegion [GDIPLUS.@]
566 */
568{
569 TRACE("%p\n", region);
570
571 if (!region)
572 return InvalidParameter;
573
574 delete_element(&region->node);
575 free(region);
576
577 return Ok;
578}
579
580/*****************************************************************************
581 * GdipGetRegionBounds [GDIPLUS.@]
582 */
584{
585 REAL min_x, min_y, max_x, max_y;
586 BOOL empty, infinite;
587
588 TRACE("(%p, %p, %p)\n", region, graphics, rect);
589
590 if(!region || !graphics || !rect)
591 return InvalidParameter;
592
593 /* Contrary to MSDN, native ignores the graphics transform. */
594 get_region_bounding_box(&region->node, &min_x, &min_y, &max_x, &max_y, &empty, &infinite);
595
596 /* infinite */
597 if(infinite){
598 rect->X = rect->Y = -(REAL)(1 << 22);
599 rect->Width = rect->Height = (REAL)(1 << 23);
600 TRACE("%p => infinite\n", region);
601 return Ok;
602 }
603
604 if(empty){
605 rect->X = rect->Y = rect->Width = rect->Height = 0.0;
606 TRACE("%p => empty\n", region);
607 return Ok;
608 }
609
610 rect->X = min_x;
611 rect->Y = min_y;
612 rect->Width = max_x - min_x;
613 rect->Height = max_y - min_y;
614 TRACE("%p => %s\n", region, debugstr_rectf(rect));
615
616 return Ok;
617}
618
619/*****************************************************************************
620 * GdipGetRegionBoundsI [GDIPLUS.@]
621 */
623{
624 GpRectF rectf;
626
627 TRACE("(%p, %p, %p)\n", region, graphics, rect);
628
629 if(!rect)
630 return InvalidParameter;
631
632 status = GdipGetRegionBounds(region, graphics, &rectf);
633 if(status == Ok){
634 rect->X = gdip_round(rectf.X);
635 rect->Y = gdip_round(rectf.Y);
636 rect->Width = gdip_round(rectf.Width);
637 rect->Height = gdip_round(rectf.Height);
638 }
639
640 return status;
641}
642
643static inline void write_dword(DWORD* location, INT* offset, const DWORD write)
644{
646 (*offset)++;
647}
648
649static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
650{
651 ((FLOAT*)location)[*offset] = write;
652 (*offset)++;
653}
654
656 INT* filled)
657{
658 write_dword(buffer, filled, element->type);
659 switch (element->type)
660 {
663 case CombineModeUnion:
664 case CombineModeXor:
667 write_element(element->elementdata.combine.left, buffer, filled);
668 write_element(element->elementdata.combine.right, buffer, filled);
669 break;
670 case RegionDataRect:
671 write_float(buffer, filled, element->elementdata.rect.X);
672 write_float(buffer, filled, element->elementdata.rect.Y);
673 write_float(buffer, filled, element->elementdata.rect.Width);
674 write_float(buffer, filled, element->elementdata.rect.Height);
675 break;
676 case RegionDataPath:
677 {
678 DWORD size = write_path_data(element->elementdata.path, buffer + *filled + 1);
679 write_dword(buffer, filled, size);
680 *filled += size / sizeof(DWORD);
681 break;
682 }
685 break;
686 }
687}
688
690{
691 struct region_header *header = data;
692 INT filled = 0;
693 DWORD size;
694
695 size = sizeof(struct region_header) + get_element_size(&region->node);
696 if (!data) return size;
697
698 header->magic = VERSION_MAGIC2;
699 header->num_children = region->num_children;
700 filled += 2;
701 /* With few exceptions, everything written is DWORD aligned,
702 * so use that as our base */
703 write_element(&region->node, (DWORD*)data, &filled);
704 return size;
705}
706
707/*****************************************************************************
708 * GdipGetRegionData [GDIPLUS.@]
709 *
710 * Returns the header, followed by combining ops and region elements.
711 *
712 * PARAMS
713 * region [I] region to retrieve from
714 * buffer [O] buffer to hold the resulting data
715 * size [I] size of the buffer
716 * needed [O] (optional) how much data was written
717 *
718 * RETURNS
719 * SUCCESS: Ok
720 * FAILURE: InvalidParameter
721 *
722 * NOTES
723 * The header contains the size, a checksum, a version string, and the number
724 * of children. The size does not count itself or the checksum.
725 * Version is always something like 0xdbc01001 or 0xdbc01002
726 *
727 * An element is a RECT, or PATH; Combining ops are stored as their
728 * CombineMode value. Special regions (infinite, empty) emit just their
729 * op-code; GpRectFs emit their code followed by their points; GpPaths emit
730 * their code followed by a second header for the path followed by the actual
731 * path data. Followed by the flags for each point. The pathheader contains
732 * the size of the data to follow, a version number again, followed by a count
733 * of how many points, and any special flags which may apply. 0x4000 means it's
734 * a path of shorts instead of FLOAT.
735 *
736 * Combining Ops are stored in reverse order from when they were constructed;
737 * the output is a tree where the left side combining area is always taken
738 * first.
739 */
741 UINT *needed)
742{
744 UINT required;
745
746 TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
747
748 if (!region || !buffer || !size)
749 return InvalidParameter;
750
751 required = FIELD_OFFSET(struct region_data_header, header) + write_region_data(region, NULL);
752 if (size < required)
753 {
754 if (needed) *needed = size;
755 return InsufficientBuffer;
756 }
757
761
762 if (needed)
763 *needed = required;
764
765 return Ok;
766}
767
769{
771 const DWORD *type;
772
773 type = buffer_read(mbuf, sizeof(*type));
774 if (!type) return Ok;
775
776 TRACE("type %#lx\n", *type);
777
778 node->type = *type;
779
780 switch (node->type)
781 {
784 case CombineModeUnion:
785 case CombineModeXor:
788 {
790
791 left = calloc(1, sizeof(region_element));
792 if (!left) return OutOfMemory;
793 right = calloc(1, sizeof(region_element));
794 if (!right)
795 {
796 free(left);
797 return OutOfMemory;
798 }
799
800 status = read_element(mbuf, region, left, count);
801 if (status == Ok)
802 {
803 status = read_element(mbuf, region, right, count);
804 if (status == Ok)
805 {
806 node->elementdata.combine.left = left;
807 node->elementdata.combine.right = right;
808 region->num_children += 2;
809 return Ok;
810 }
811 }
812
813 free(left);
814 free(right);
815 return status;
816 }
817
818 case RegionDataRect:
819 {
820 const GpRectF *rc;
821
822 rc = buffer_read(mbuf, sizeof(*rc));
823 if (!rc)
824 {
825 ERR("failed to read rect data\n");
826 return InvalidParameter;
827 }
828
829 node->elementdata.rect = *rc;
830 *count += 1;
831 return Ok;
832 }
833
834 case RegionDataPath:
835 {
836 GpPath *path;
837 const struct path_header *path_header;
838 const BYTE *types;
839
840 path_header = buffer_read(mbuf, sizeof(*path_header));
841 if (!path_header)
842 {
843 ERR("failed to read path header\n");
844 return InvalidParameter;
845 }
847 {
848 ERR("invalid path header magic %#lx\n", path_header->magic);
849 return InvalidParameter;
850 }
851
852 /* Windows always fails to create an empty path in a region */
853 if (!path_header->count)
854 {
855 TRACE("refusing to create an empty path in a region\n");
856 return GenericError;
857 }
858
860 if (status) return status;
861
862 node->elementdata.path = path;
863
865 return OutOfMemory;
866
867 path->pathdata.Count = path_header->count;
868
870 FIXME("unhandled path flags %#lx\n", path_header->flags);
871
873 {
874 const packed_point *pt;
875 DWORD i;
876
877 pt = buffer_read(mbuf, sizeof(*pt) * path_header->count);
878 if (!pt)
879 {
880 ERR("failed to read packed %lu path points\n", path_header->count);
881 return InvalidParameter;
882 }
883
884 for (i = 0; i < path_header->count; i++)
885 {
886 path->pathdata.Points[i].X = (REAL)pt[i].X;
887 path->pathdata.Points[i].Y = (REAL)pt[i].Y;
888 }
889 }
890 else
891 {
892 const GpPointF *ptf;
893
894 ptf = buffer_read(mbuf, sizeof(*ptf) * path_header->count);
895 if (!ptf)
896 {
897 ERR("failed to read %lu path points\n", path_header->count);
898 return InvalidParameter;
899 }
900 memcpy(path->pathdata.Points, ptf, sizeof(*ptf) * path_header->count);
901 }
902
904 if (!types)
905 {
906 ERR("failed to read %lu path types\n", path_header->count);
907 return InvalidParameter;
908 }
909 memcpy(path->pathdata.Types, types, path_header->count);
910 if (path_header->count & 3)
911 {
912 if (!buffer_read(mbuf, 4 - (path_header->count & 3)))
913 {
914 ERR("failed to read rounding %lu bytes\n", 4 - (path_header->count & 3));
915 return InvalidParameter;
916 }
917 }
918
919 *count += 1;
920 return Ok;
921 }
922
925 *count += 1;
926 return Ok;
927
928 default:
929 FIXME("element type %#lx is not supported\n", *type);
930 break;
931 }
932
933 return InvalidParameter;
934}
935
936/*****************************************************************************
937 * GdipCreateRegionRgnData [GDIPLUS.@]
938 */
940{
942 struct memory_buffer mbuf;
944 INT count;
945
946 TRACE("(%p, %d, %p)\n", data, size, region);
947
948 if (!data || !size)
949 return InvalidParameter;
950
952
955 return InvalidParameter;
956
957 status = GdipCreateRegion(region);
958 if (status != Ok)
959 return status;
960
961 count = 0;
962 status = read_element(&mbuf, *region, &(*region)->node, &count);
963 if (status == Ok && !count)
965
966 if (status != Ok)
967 {
968 GdipDeleteRegion(*region);
969 *region = NULL;
970 }
971
972 return status;
973}
974
975/*****************************************************************************
976 * GdipGetRegionDataSize [GDIPLUS.@]
977 */
979{
980 TRACE("%p, %p\n", region, needed);
981
982 if (!(region && needed))
983 return InvalidParameter;
984
985 /* header.size doesn't count header.size and header.checksum */
986 *needed = FIELD_OFFSET(struct region_data_header, header) + write_region_data(region, NULL);
987
988 return Ok;
989}
990
992{
993 HDC new_hdc=NULL, hdc;
994 GpGraphics *new_graphics=NULL;
996 INT save_state;
997
998 if (!path->pathdata.Count) /* PathToRegion doesn't support empty paths */
999 {
1000 *hrgn = CreateRectRgn( 0, 0, 0, 0 );
1001 return *hrgn ? Ok : OutOfMemory;
1002 }
1003
1004 if (!graphics)
1005 {
1006 hdc = new_hdc = CreateCompatibleDC(0);
1007 if (!new_hdc)
1008 return OutOfMemory;
1009
1010 stat = GdipCreateFromHDC(new_hdc, &new_graphics);
1011 graphics = new_graphics;
1012 if (stat != Ok)
1013 {
1014 DeleteDC(new_hdc);
1015 return stat;
1016 }
1017 }
1018 else if (has_gdi_dc(graphics))
1019 {
1020 stat = gdi_dc_acquire(graphics, &hdc);
1021 if (stat != Ok)
1022 return stat;
1023 }
1024 else
1025 {
1026 graphics->hdc = hdc = new_hdc = CreateCompatibleDC(0);
1027 if (!new_hdc)
1028 return OutOfMemory;
1029 }
1030
1031 save_state = SaveDC(hdc);
1032 EndPath(hdc);
1033
1035
1036 gdi_transform_acquire(graphics);
1037
1038 stat = trace_path(graphics, path);
1039 if (stat == Ok)
1040 {
1041 *hrgn = PathToRegion(hdc);
1042 stat = *hrgn ? Ok : OutOfMemory;
1043 }
1044
1045 gdi_transform_release(graphics);
1046
1047 RestoreDC(hdc, save_state);
1048 if (new_hdc)
1049 {
1050 DeleteDC(new_hdc);
1051 if (new_graphics)
1052 GdipDeleteGraphics(new_graphics);
1053 else
1054 graphics->hdc = NULL;
1055 }
1056 else
1057 gdi_dc_release(graphics, hdc);
1058
1059 return stat;
1060}
1061
1063{
1064 switch (element->type)
1065 {
1067 *hrgn = NULL;
1068 return Ok;
1070 *hrgn = CreateRectRgn(0, 0, 0, 0);
1071 return *hrgn ? Ok : OutOfMemory;
1072 case RegionDataPath:
1073 return get_path_hrgn(element->elementdata.path, graphics, hrgn);
1074 case RegionDataRect:
1075 {
1076 GpPath* path;
1077 GpStatus stat;
1078 GpRectF* rc = &element->elementdata.rect;
1079
1081 if (stat != Ok)
1082 return stat;
1083 stat = GdipAddPathRectangle(path, rc->X, rc->Y, rc->Width, rc->Height);
1084
1085 if (stat == Ok)
1086 stat = get_path_hrgn(path, graphics, hrgn);
1087
1089
1090 return stat;
1091 }
1093 case CombineModeUnion:
1094 case CombineModeXor:
1095 case CombineModeExclude:
1097 {
1098 HRGN left, right;
1099 GpStatus stat;
1100 int ret;
1101
1102 stat = get_region_hrgn(element->elementdata.combine.left, graphics, &left);
1103 if (stat != Ok)
1104 {
1105 *hrgn = NULL;
1106 return stat;
1107 }
1108
1109 if (left == NULL)
1110 {
1111 /* existing region is infinite */
1112 switch (element->type)
1113 {
1115 return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
1117 left = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
1118 break;
1120 *hrgn = CreateRectRgn(0, 0, 0, 0);
1121 return *hrgn ? Ok : OutOfMemory;
1122 case CombineModeUnion:
1123 *hrgn = NULL;
1124 return Ok;
1125 }
1126 }
1127
1128 stat = get_region_hrgn(element->elementdata.combine.right, graphics, &right);
1129 if (stat != Ok)
1130 {
1132 *hrgn = NULL;
1133 return stat;
1134 }
1135
1136 if (right == NULL)
1137 {
1138 /* new region is infinite */
1139 switch (element->type)
1140 {
1142 *hrgn = left;
1143 return Ok;
1145 right = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
1146 break;
1147 case CombineModeExclude:
1149 *hrgn = CreateRectRgn(0, 0, 0, 0);
1150 return *hrgn ? Ok : OutOfMemory;
1151 case CombineModeUnion:
1153 *hrgn = NULL;
1154 return Ok;
1155 }
1156 }
1157
1158 switch (element->type)
1159 {
1162 break;
1163 case CombineModeUnion:
1165 break;
1166 case CombineModeXor:
1168 break;
1169 case CombineModeExclude:
1171 break;
1174 break;
1175 default:
1176 ret = ERROR;
1177 }
1178
1180
1181 if (ret == ERROR)
1182 {
1184 *hrgn = NULL;
1185 return GenericError;
1186 }
1187
1188 *hrgn = left;
1189 return Ok;
1190 }
1191 default:
1192 FIXME("GdipGetRegionHRgn unimplemented for region type=%lx\n", element->type);
1193 *hrgn = NULL;
1194 return NotImplemented;
1195 }
1196}
1197
1198/*****************************************************************************
1199 * GdipGetRegionHRgn [GDIPLUS.@]
1200 */
1202{
1203 TRACE("(%p, %p, %p)\n", region, graphics, hrgn);
1204
1205 if (!region || !hrgn)
1206 return InvalidParameter;
1207
1208 return get_region_hrgn(&region->node, graphics, hrgn);
1209}
1210
1212{
1214 GpRectF rect;
1215
1216 TRACE("(%p, %p, %p)\n", region, graphics, res);
1217
1218 if(!region || !graphics || !res)
1219 return InvalidParameter;
1220
1221 status = GdipGetRegionBounds(region, graphics, &rect);
1222 if (status != Ok) return status;
1223
1224 *res = rect.Width == 0.0 && rect.Height == 0.0;
1225 TRACE("=> %d\n", *res);
1226
1227 return Ok;
1228}
1229
1230/*****************************************************************************
1231 * GdipIsEqualRegion [GDIPLUS.@]
1232 */
1234 BOOL *res)
1235{
1236 HRGN hrgn1, hrgn2;
1237 GpStatus stat;
1238
1239 TRACE("(%p, %p, %p, %p)\n", region, region2, graphics, res);
1240
1241 if(!region || !region2 || !graphics || !res)
1242 return InvalidParameter;
1243
1244 stat = GdipGetRegionHRgn(region, graphics, &hrgn1);
1245 if(stat != Ok)
1246 return stat;
1247 stat = GdipGetRegionHRgn(region2, graphics, &hrgn2);
1248 if(stat != Ok){
1249 DeleteObject(hrgn1);
1250 return stat;
1251 }
1252
1253 *res = EqualRgn(hrgn1, hrgn2);
1254
1255 /* one of GpRegions is infinite */
1256 if(*res == ERROR)
1257 *res = (!hrgn1 && !hrgn2);
1258
1259 DeleteObject(hrgn1);
1261
1262 return Ok;
1263}
1264
1265/*****************************************************************************
1266 * GdipIsInfiniteRegion [GDIPLUS.@]
1267 */
1269{
1270 /* I think graphics is ignored here */
1271 TRACE("(%p, %p, %p)\n", region, graphics, res);
1272
1273 if(!region || !graphics || !res)
1274 return InvalidParameter;
1275
1276 *res = (region->node.type == RegionDataInfiniteRect);
1277
1278 return Ok;
1279}
1280
1281/*****************************************************************************
1282 * GdipIsVisibleRegionRect [GDIPLUS.@]
1283 */
1285{
1286 HRGN hrgn;
1287 GpStatus stat;
1288 RECT rect;
1289
1290 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %p, %p)\n", region, x, y, w, h, graphics, res);
1291
1292 if(!region || !res)
1293 return InvalidParameter;
1294
1295 if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
1296 return stat;
1297
1298 /* infinite */
1299 if(!hrgn){
1300 *res = TRUE;
1301 return Ok;
1302 }
1303
1304 SetRect(&rect, ceilr(x), ceilr(y), ceilr(x + w), ceilr(y + h));
1305 *res = RectInRegion(hrgn, &rect);
1306
1308
1309 return Ok;
1310}
1311
1312/*****************************************************************************
1313 * GdipIsVisibleRegionRectI [GDIPLUS.@]
1314 */
1316{
1317 TRACE("(%p, %d, %d, %d, %d, %p, %p)\n", region, x, y, w, h, graphics, res);
1318 if(!region || !res)
1319 return InvalidParameter;
1320
1321 return GdipIsVisibleRegionRect(region, (REAL)x, (REAL)y, (REAL)w, (REAL)h, graphics, res);
1322}
1323
1324/* get_region_bounding_box
1325 *
1326 * Returns a box guaranteed to enclose the entire region, but not guaranteed to be minimal.
1327 * Sets "empty" if bounding box is empty.
1328 * Sets "infinite" if everything outside bounding box is inside the region.
1329 * In the infinite case, the bounding box encloses all points not in the region. */
1331 REAL *min_x, REAL *min_y, REAL *max_x, REAL *max_y, BOOL *empty, BOOL *infinite)
1332{
1333 REAL left_min_x, left_min_y, left_max_x, left_max_y;
1334 BOOL left_empty, left_infinite;
1335 REAL right_min_x, right_min_y, right_max_x, right_max_y;
1336 BOOL right_empty, right_infinite;
1337 /* For combine modes, we convert the mode to flags as follows to simplify the logic:
1338 * 0x8 = point in combined region if it's in both
1339 * 0x4 = point in combined region if it's in left and not right
1340 * 0x2 = point in combined region if it's not in left and is in right
1341 * 0x1 = point in combined region if it's in neither region */
1342 int flags;
1343 const int combine_mode_flags[] = {
1344 0xa, /* CombineModeReplace - shouldn't be used */
1345 0x8, /* CombineModeIntersect */
1346 0xe, /* CombineModeUnion */
1347 0x6, /* CombineModeXor */
1348 0x4, /* CombineModeExclude */
1349 0x2, /* CombineModeComplement */
1350 };
1351
1352 /* handle unit elements first */
1353 switch (element->type)
1354 {
1356 *min_x = *min_y = *max_x = *max_y = 0.0;
1357 *empty = TRUE;
1358 *infinite = TRUE;
1359 return;
1361 *min_x = *min_y = *max_x = *max_y = 0.0;
1362 *empty = TRUE;
1363 *infinite = FALSE;
1364 return;
1365 case RegionDataPath:
1366 {
1367 GpPath *path = element->elementdata.path;
1368 int i;
1369
1370 if (path->pathdata.Count <= 1) {
1371 *min_x = *min_y = *max_x = *max_y = 0.0;
1372 *empty = TRUE;
1373 *infinite = FALSE;
1374 return;
1375 }
1376
1377 *min_x = *max_x = path->pathdata.Points[0].X;
1378 *min_y = *max_y = path->pathdata.Points[0].Y;
1379 *empty = FALSE;
1380 *infinite = FALSE;
1381
1382 for (i=1; i < path->pathdata.Count; i++)
1383 {
1384 if (path->pathdata.Points[i].X < *min_x)
1385 *min_x = path->pathdata.Points[i].X;
1386 else if (path->pathdata.Points[i].X > *max_x)
1387 *max_x = path->pathdata.Points[i].X;
1388 if (path->pathdata.Points[i].Y < *min_y)
1389 *min_y = path->pathdata.Points[i].Y;
1390 else if (path->pathdata.Points[i].Y > *max_y)
1391 *max_y = path->pathdata.Points[i].Y;
1392 }
1393
1394 return;
1395 }
1396 case RegionDataRect:
1397 *min_x = element->elementdata.rect.X;
1398 *min_y = element->elementdata.rect.Y;
1399 *max_x = element->elementdata.rect.X + element->elementdata.rect.Width;
1400 *max_y = element->elementdata.rect.Y + element->elementdata.rect.Height;
1401 *empty = FALSE;
1402 *infinite = FALSE;
1403 return;
1404 }
1405
1406 /* Should be only combine modes left */
1407 assert(element->type < ARRAY_SIZE(combine_mode_flags));
1408
1409 flags = combine_mode_flags[element->type];
1410
1411 get_region_bounding_box(element->elementdata.combine.left,
1412 &left_min_x, &left_min_y, &left_max_x, &left_max_y, &left_empty, &left_infinite);
1413
1414 if (left_infinite)
1415 {
1416 /* change our function so we can ignore the infinity */
1417 flags = ((flags & 0x3) << 2) | ((flags & 0xc) >> 2);
1418 }
1419
1420 if (left_empty && (flags & 0x3) == 0) {
1421 /* no points in region regardless of right region, return empty */
1422 *empty = TRUE;
1423 *infinite = FALSE;
1424 return;
1425 }
1426
1427 if (left_empty && (flags & 0x3) == 0x3) {
1428 /* all points in region regardless of right region, return infinite */
1429 *empty = TRUE;
1430 *infinite = TRUE;
1431 return;
1432 }
1433
1434 get_region_bounding_box(element->elementdata.combine.right,
1435 &right_min_x, &right_min_y, &right_max_x, &right_max_y, &right_empty, &right_infinite);
1436
1437 if (right_infinite)
1438 {
1439 /* change our function so we can ignore the infinity */
1440 flags = ((flags & 0x5) << 1) | ((flags & 0xa) >> 1);
1441 }
1442
1443 /* result is infinite if points in neither region are in the result */
1444 *infinite = (flags & 0x1);
1445
1446 if (*infinite)
1447 {
1448 /* Again, we modify our function to ignore the infinity.
1449 * The points we care about are the ones that are different from the outside of our box,
1450 * not the points inside the region, so we invert the whole thing.
1451 * From here we can assume 0x1 is not set. */
1452 flags ^= 0xf;
1453 }
1454
1455 if (left_empty)
1456 {
1457 /* We already took care of the cases where the right region doesn't matter,
1458 * so we can just use the right bounding box. */
1459 *min_x = right_min_x;
1460 *min_y = right_min_y;
1461 *max_x = right_max_x;
1462 *max_y = right_max_y;
1463 *empty = right_empty;
1464 return;
1465 }
1466
1467 if (right_empty)
1468 {
1469 /* With no points in right region, and infinities eliminated, we only care
1470 * about flag 0x4, the case where a point is in left region and not right. */
1471 if (flags & 0x4)
1472 {
1473 /* We have a copy of the left region. */
1474 *min_x = left_min_x;
1475 *min_y = left_min_y;
1476 *max_x = left_max_x;
1477 *max_y = left_max_y;
1478 *empty = left_empty;
1479 return;
1480 }
1481 /* otherwise, it's an empty (or infinite) region */
1482 *empty = TRUE;
1483 return;
1484 }
1485
1486 /* From here we know 0x1 isn't set, and we know at least one flag is set.
1487 * We can ignore flag 0x8 because we must assume that any point within the
1488 * intersection of the bounding boxes might be within the region. */
1489 switch (flags & 0x6)
1490 {
1491 case 0x0:
1492 /* intersection */
1493 *min_x = fmaxf(left_min_x, right_min_x);
1494 *min_y = fmaxf(left_min_y, right_min_y);
1495 *max_x = fminf(left_max_x, right_max_x);
1496 *max_y = fminf(left_max_y, right_max_y);
1497 *empty = *min_x > *max_x || *min_y > *max_y;
1498 return;
1499 case 0x2:
1500 /* right (or complement) */
1501 *min_x = right_min_x;
1502 *min_y = right_min_y;
1503 *max_x = right_max_x;
1504 *max_y = right_max_y;
1505 *empty = right_empty;
1506 return;
1507 case 0x4:
1508 /* left (or exclude) */
1509 *min_x = left_min_x;
1510 *min_y = left_min_y;
1511 *max_x = left_max_x;
1512 *max_y = left_max_y;
1513 *empty = left_empty;
1514 return;
1515 case 0x6:
1516 /* union (or xor) */
1517 *min_x = fminf(left_min_x, right_min_x);
1518 *min_y = fminf(left_min_y, right_min_y);
1519 *max_x = fmaxf(left_max_x, right_max_x);
1520 *max_y = fmaxf(left_max_y, right_max_y);
1521 *empty = FALSE;
1522 return;
1523 }
1524}
1525
1526/*****************************************************************************
1527 * GdipIsVisibleRegionPoint [GDIPLUS.@]
1528 */
1530{
1531 HRGN hrgn;
1532 GpStatus stat;
1533 REAL min_x, min_y, max_x, max_y;
1534 BOOL empty, infinite;
1535
1536 TRACE("(%p, %.2f, %.2f, %p, %p)\n", region, x, y, graphics, res);
1537
1538 if(!region || !res)
1539 return InvalidParameter;
1540
1541 x = gdip_round(x);
1542 y = gdip_round(y);
1543
1544 /* Check for cases where we can skip quantization. */
1545 get_region_bounding_box(&region->node, &min_x, &min_y, &max_x, &max_y, &empty, &infinite);
1546 if (empty || x < min_x || y < min_y || x > max_x || y > max_y)
1547 {
1548 *res = infinite;
1549 return Ok;
1550 }
1551
1552 if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
1553 return stat;
1554
1555 /* infinite */
1556 if(!hrgn){
1557 *res = TRUE;
1558 return Ok;
1559 }
1560
1561 *res = PtInRegion(hrgn, x, y);
1562
1564
1565 return Ok;
1566}
1567
1568/*****************************************************************************
1569 * GdipIsVisibleRegionPointI [GDIPLUS.@]
1570 */
1572{
1573 TRACE("(%p, %d, %d, %p, %p)\n", region, x, y, graphics, res);
1574
1575 return GdipIsVisibleRegionPoint(region, (REAL)x, (REAL)y, graphics, res);
1576}
1577
1578/*****************************************************************************
1579 * GdipSetEmpty [GDIPLUS.@]
1580 */
1582{
1583 GpStatus stat;
1584
1585 TRACE("%p\n", region);
1586
1587 if (!region)
1588 return InvalidParameter;
1589
1590 delete_element(&region->node);
1592
1593 return stat;
1594}
1595
1597{
1598 GpStatus stat;
1599
1600 TRACE("%p\n", region);
1601
1602 if (!region)
1603 return InvalidParameter;
1604
1605 delete_element(&region->node);
1607
1608 return stat;
1609}
1610
1611/* Transforms GpRegion elements with given matrix */
1613{
1614 GpStatus stat;
1615
1616 switch(element->type)
1617 {
1620 return Ok;
1621 case RegionDataRect:
1622 {
1623 GpRegion *new_region;
1624 GpPath *path;
1625
1626 if (matrix->matrix[1] == 0.0 && matrix->matrix[2] == 0.0)
1627 {
1628 GpPointF points[2];
1629
1630 points[0].X = element->elementdata.rect.X;
1631 points[0].Y = element->elementdata.rect.Y;
1632 points[1].X = element->elementdata.rect.X + element->elementdata.rect.Width;
1633 points[1].Y = element->elementdata.rect.Y + element->elementdata.rect.Height;
1634
1636 if (stat != Ok)
1637 return stat;
1638
1639 if (points[0].X > points[1].X)
1640 {
1641 REAL temp;
1642 temp = points[0].X;
1643 points[0].X = points[1].X;
1644 points[1].X = temp;
1645 }
1646
1647 if (points[0].Y > points[1].Y)
1648 {
1649 REAL temp;
1650 temp = points[0].Y;
1651 points[0].Y = points[1].Y;
1652 points[1].Y = temp;
1653 }
1654
1655 element->elementdata.rect.X = points[0].X;
1656 element->elementdata.rect.Y = points[0].Y;
1657 element->elementdata.rect.Width = points[1].X - points[0].X;
1658 element->elementdata.rect.Height = points[1].Y - points[0].Y;
1659 return Ok;
1660 }
1661
1662 /* We can't rotate/shear a rectangle, so convert it to a path. */
1664 if (stat == Ok)
1665 {
1667 element->elementdata.rect.X, element->elementdata.rect.Y,
1668 element->elementdata.rect.Width, element->elementdata.rect.Height);
1669
1670 if (stat == Ok)
1671 stat = GdipCreateRegionPath(path, &new_region);
1672
1674 }
1675
1676 if (stat == Ok)
1677 {
1678 /* Steal the element from the created region. */
1679 memcpy(element, &new_region->node, sizeof(region_element));
1680 free(new_region);
1681 }
1682 else
1683 return stat;
1684 }
1685 /* Fall-through to do the actual conversion. */
1686 case RegionDataPath:
1687 if (!element->elementdata.path->pathdata.Count)
1688 return Ok;
1689
1691 element->elementdata.path->pathdata.Points,
1692 element->elementdata.path->pathdata.Count);
1693 return stat;
1694 default:
1695 stat = transform_region_element(element->elementdata.combine.left, matrix);
1696 if (stat == Ok)
1697 stat = transform_region_element(element->elementdata.combine.right, matrix);
1698 return stat;
1699 }
1700}
1701
1703{
1704 TRACE("(%p, %s)\n", region, debugstr_matrix(matrix));
1705
1706 if (!region || !matrix)
1707 return InvalidParameter;
1708
1709 return transform_region_element(&region->node, matrix);
1710}
1711
1712/* Translates GpRegion elements with specified offsets */
1714{
1715 INT i;
1716
1717 switch(element->type)
1718 {
1721 return;
1722 case RegionDataRect:
1723 element->elementdata.rect.X += dx;
1724 element->elementdata.rect.Y += dy;
1725 return;
1726 case RegionDataPath:
1727 for(i = 0; i < element->elementdata.path->pathdata.Count; i++){
1728 element->elementdata.path->pathdata.Points[i].X += dx;
1729 element->elementdata.path->pathdata.Points[i].Y += dy;
1730 }
1731 return;
1732 default:
1733 translate_region_element(element->elementdata.combine.left, dx, dy);
1734 translate_region_element(element->elementdata.combine.right, dx, dy);
1735 return;
1736 }
1737}
1738
1739/*****************************************************************************
1740 * GdipTranslateRegion [GDIPLUS.@]
1741 */
1743{
1744 TRACE("(%p, %f, %f)\n", region, dx, dy);
1745
1746 if(!region)
1747 return InvalidParameter;
1748
1749 translate_region_element(&region->node, dx, dy);
1750
1751 return Ok;
1752}
1753
1754/*****************************************************************************
1755 * GdipTranslateRegionI [GDIPLUS.@]
1756 */
1758{
1759 TRACE("(%p, %d, %d)\n", region, dx, dy);
1760
1761 return GdipTranslateRegion(region, (REAL)dx, (REAL)dy);
1762}
1763
1765{
1766 GpRegion *region_copy;
1767 GpStatus stat;
1768 HRGN hrgn;
1769 DWORD data_size;
1770
1771 stat = GdipCloneRegion(region, &region_copy);
1772
1773 if (stat == Ok)
1774 {
1775 stat = GdipTransformRegion(region_copy, matrix);
1776
1777 if (stat == Ok)
1778 stat = GdipGetRegionHRgn(region_copy, NULL, &hrgn);
1779
1780 if (stat == Ok)
1781 {
1782 if (hrgn)
1783 {
1784 data_size = GetRegionData(hrgn, 0, NULL);
1785
1786 *data = malloc(data_size);
1787
1788 if (*data)
1789 GetRegionData(hrgn, data_size, *data);
1790 else
1791 stat = OutOfMemory;
1792
1794 }
1795 else
1796 {
1797 data_size = sizeof(RGNDATAHEADER) + sizeof(RECT);
1798
1799 *data = calloc(1, data_size);
1800
1801 if (*data)
1802 {
1803 (*data)->rdh.dwSize = sizeof(RGNDATAHEADER);
1804 (*data)->rdh.iType = RDH_RECTANGLES;
1805 (*data)->rdh.nCount = 1;
1806 (*data)->rdh.nRgnSize = sizeof(RECT);
1807 (*data)->rdh.rcBound.left = (*data)->rdh.rcBound.top = -0x400000;
1808 (*data)->rdh.rcBound.right = (*data)->rdh.rcBound.bottom = 0x400000;
1809
1810 memcpy((*data)->Buffer, &(*data)->rdh.rcBound, sizeof(RECT));
1811 }
1812 else
1813 stat = OutOfMemory;
1814 }
1815 }
1816
1817 GdipDeleteRegion(region_copy);
1818 }
1819
1820 return stat;
1821}
1822
1824{
1825 GpStatus stat;
1827
1828 TRACE("(%p, %p, %s)\n", region, count, debugstr_matrix(matrix));
1829
1830 if (!region || !count || !matrix)
1831 return InvalidParameter;
1832
1834
1835 if (stat == Ok)
1836 {
1837 *count = data->rdh.nCount;
1838 free(data);
1839 }
1840
1841 return stat;
1842}
1843
1845{
1846 GpStatus stat;
1847 DWORD i;
1849 RECT *rects;
1850
1851 if (!region || !count || !matrix)
1852 return InvalidParameter;
1853
1855
1856 if (stat == Ok)
1857 {
1858 *count = data->rdh.nCount;
1859 rects = (RECT*)data->Buffer;
1860
1861 if (scans)
1862 {
1863 for (i=0; i<data->rdh.nCount; i++)
1864 {
1865 scans[i].X = rects[i].left;
1866 scans[i].Y = rects[i].top;
1867 scans[i].Width = rects[i].right - rects[i].left;
1868 scans[i].Height = rects[i].bottom - rects[i].top;
1869 }
1870 }
1871
1872 free(data);
1873 }
1874
1875 return Ok;
1876}
1877
1879{
1880 GpStatus stat;
1881 DWORD i;
1883 RECT *rects;
1884
1885 if (!region || !count || !matrix)
1886 return InvalidParameter;
1887
1889
1890 if (stat == Ok)
1891 {
1892 *count = data->rdh.nCount;
1893 rects = (RECT*)data->Buffer;
1894
1895 if (scans)
1896 {
1897 for (i=0; i<data->rdh.nCount; i++)
1898 {
1899 scans[i].X = rects[i].left;
1900 scans[i].Y = rects[i].top;
1901 scans[i].Width = rects[i].right - rects[i].left;
1902 scans[i].Height = rects[i].bottom - rects[i].top;
1903 }
1904 }
1905
1906 free(data);
1907 }
1908
1909 return Ok;
1910}
static HRGN hrgn2
static HRGN hrgn
#define stat
Definition: acwin.h:100
#define write
Definition: acwin.h:98
struct _RGNDATAHEADER RGNDATAHEADER
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define WINDING
Definition: constants.h:279
#define ALTERNATE
Definition: constants.h:278
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
RECT rect
Definition: combotst.c:67
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
float REAL
Definition: types.h:41
#define Y(I)
static const WCHAR empty[1]
Definition: string.c:47
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
Definition: graphics.c:2434
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
Definition: graphics.c:2616
GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath *path, REAL x, REAL y, REAL width, REAL height)
GpStatus WINGDIPAPI GdipClonePath(GpPath *path, GpPath **clone)
GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts, INT count)
Definition: matrix.c:365
DWORD write_region_data(const GpRegion *region, void *data)
Definition: region.c:689
static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, HRGN *hrgn)
Definition: region.c:1062
GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion *region, REAL x, REAL y, REAL w, REAL h, GpGraphics *graphics, BOOL *res)
Definition: region.c:1284
#define FLAGS_INTPATH
Definition: region.c:78
GpStatus WINGDIPAPI GdipCombineRegionPath(GpRegion *region, GpPath *path, CombineMode mode)
Definition: region.c:236
static GpStatus clone_element(const region_element *element, region_element **element2)
Definition: region.c:144
static GpStatus get_region_scans_data(GpRegion *region, GpMatrix *matrix, LPRGNDATA *data)
Definition: region.c:1764
static void translate_region_element(region_element *element, REAL dx, REAL dy)
Definition: region.c:1713
static void write_element(const region_element *element, DWORD *buffer, INT *filled)
Definition: region.c:655
GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
Definition: region.c:1211
GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
Definition: region.c:1268
GpStatus WINGDIPAPI GdipSetInfinite(GpRegion *region)
Definition: region.c:1596
GpStatus WINGDIPAPI GdipSetEmpty(GpRegion *region)
Definition: region.c:1581
GpStatus WINGDIPAPI GdipTranslateRegionI(GpRegion *region, INT dx, INT dy)
Definition: region.c:1757
GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
Definition: region.c:1201
GpStatus WINGDIPAPI GdipGetRegionBoundsI(GpRegion *region, GpGraphics *graphics, GpRect *rect)
Definition: region.c:622
GpStatus WINGDIPAPI GdipTransformRegion(GpRegion *region, GpMatrix *matrix)
Definition: region.c:1702
GpStatus WINGDIPAPI GdipCreateRegionRect(GDIPCONST GpRectF *rect, GpRegion **region)
Definition: region.c:459
GpStatus WINGDIPAPI GdipIsVisibleRegionPoint(GpRegion *region, REAL x, REAL y, GpGraphics *graphics, BOOL *res)
Definition: region.c:1529
static GpStatus init_region(GpRegion *region, const RegionType type)
Definition: region.c:136
GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
Definition: region.c:939
static GpStatus transform_region_element(region_element *element, GpMatrix *matrix)
Definition: region.c:1612
GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion *region, INT x, INT y, INT w, INT h, GpGraphics *graphics, BOOL *res)
Definition: region.c:1315
static INT get_element_size(const region_element *element)
Definition: region.c:110
GpStatus WINGDIPAPI GdipTranslateRegion(GpRegion *region, REAL dx, REAL dy)
Definition: region.c:1742
GpStatus WINGDIPAPI GdipGetRegionScans(GpRegion *region, GpRectF *scans, INT *count, GpMatrix *matrix)
Definition: region.c:1878
GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *region, GpRegion *region2, GpGraphics *graphics, BOOL *res)
Definition: region.c:1233
static void write_float(DWORD *location, INT *offset, const FLOAT write)
Definition: region.c:649
GpStatus WINGDIPAPI GdipCombineRegionRectI(GpRegion *region, GDIPCONST GpRect *rect, CombineMode mode)
Definition: region.c:329
GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
Definition: region.c:390
static void fuse_region(GpRegion *region, region_element *left, region_element *right, const CombineMode mode)
Definition: region.c:193
GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
Definition: region.c:978
GpStatus WINGDIPAPI GdipCombineRegionRect(GpRegion *region, GDIPCONST GpRectF *rect, CombineMode mode)
Definition: region.c:282
GpStatus WINGDIPAPI GdipGetRegionScansCount(GpRegion *region, UINT *count, GpMatrix *matrix)
Definition: region.c:1823
GpStatus WINGDIPAPI GdipCreateRegionHrgn(HRGN hrgn, GpRegion **region)
Definition: region.c:502
GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1, GpRegion *region2, CombineMode mode)
Definition: region.c:346
static void get_region_bounding_box(struct region_element *element, REAL *min_x, REAL *min_y, REAL *max_x, REAL *max_y, BOOL *empty, BOOL *infinite)
Definition: region.c:1330
static void write_dword(DWORD *location, INT *offset, const DWORD write)
Definition: region.c:643
static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
Definition: region.c:768
GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion *region, INT x, INT y, GpGraphics *graphics, BOOL *res)
Definition: region.c:1571
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, UINT *needed)
Definition: region.c:740
GpStatus WINGDIPAPI GdipGetRegionScansI(GpRegion *region, GpRect *scans, INT *count, GpMatrix *matrix)
Definition: region.c:1844
GpStatus WINGDIPAPI GdipGetRegionBounds(GpRegion *region, GpGraphics *graphics, GpRectF *rect)
Definition: region.c:583
static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
Definition: region.c:991
GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
Definition: region.c:425
GpStatus WINGDIPAPI GdipDeleteRegion(GpRegion *region)
Definition: region.c:567
GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect, GpRegion **region)
Definition: region.c:488
GpStatus WINGDIPAPI GdipCloneRegion(GpRegion *region, GpRegion **clone)
Definition: region.c:215
#define assert(_expr)
Definition: assert.h:32
_ACRTIMP float __cdecl fmaxf(float, float)
_ACRTIMP float __cdecl fminf(float, float)
#define pt(x, y)
Definition: drawing.c:79
return ret
Definition: mutex.c:146
#define ERROR(name)
Definition: error_private.h:53
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
#define local
Definition: zutil.h:30
pKey DeleteObject()
void delete_element(region_element *element)
Definition: gdiplus.c:465
const char * debugstr_rectf(const RectF *rc)
Definition: gdiplus.c:486
BOOL lengthen_path(GpPath *path, INT len)
Definition: gdiplus.c:415
const char * debugstr_matrix(const GpMatrix *matrix)
Definition: gdiplus.c:498
static INT gdip_round(REAL x)
static void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
DWORD write_path_data(GpPath *path, void *data)
static void set_rect(GpRectF *rect, REAL x, REAL y, REAL width, REAL height)
#define VERSION_MAGIC2
void gdi_dc_release(GpGraphics *graphics, HDC hdc)
Definition: graphics.c:75
static const void * buffer_read(struct memory_buffer *mbuf, INT size)
static INT ceilr(REAL x)
GpStatus gdi_dc_acquire(GpGraphics *graphics, HDC *hdc)
Definition: graphics.c:54
GpStatus gdi_transform_acquire(GpGraphics *graphics)
Definition: graphics.c:7228
RegionType
@ RegionDataEmptyRect
@ RegionDataRect
@ RegionDataInfiniteRect
@ RegionDataPath
#define VALID_MAGIC(x)
static BOOL has_gdi_dc(GpGraphics *graphics)
GpStatus gdi_transform_release(GpGraphics *graphics)
Definition: graphics.c:7250
GpStatus trace_path(GpGraphics *graphics, GpPath *path)
Definition: graphics.c:2127
CombineMode
Definition: gdiplusenums.h:387
@ CombineModeUnion
Definition: gdiplusenums.h:390
@ CombineModeReplace
Definition: gdiplusenums.h:388
@ CombineModeComplement
Definition: gdiplusenums.h:393
@ CombineModeIntersect
Definition: gdiplusenums.h:389
@ CombineModeExclude
Definition: gdiplusenums.h:392
@ CombineModeXor
Definition: gdiplusenums.h:391
@ FillModeAlternate
Definition: gdiplusenums.h:55
#define GDIPCONST
Definition: gdiplusflat.h:24
#define WINGDIPAPI
Definition: gdiplusflat.h:22
Rect GpRect
Status
Definition: gdiplustypes.h:24
@ Ok
Definition: gdiplustypes.h:25
@ InvalidParameter
Definition: gdiplustypes.h:27
@ OutOfMemory
Definition: gdiplustypes.h:28
@ InsufficientBuffer
Definition: gdiplustypes.h:30
@ NotImplemented
Definition: gdiplustypes.h:31
@ GenericError
Definition: gdiplustypes.h:26
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint res
Definition: glext.h:9613
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLdouble GLdouble right
Definition: glext.h:10859
GLuint GLenum matrix
Definition: glext.h:9407
GLenum mode
Definition: glext.h:6217
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLint left
Definition: glext.h:7726
GLbitfield flags
Definition: glext.h:7161
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
GLsizei const GLfloat * points
Definition: glext.h:8112
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLint dy
Definition: linetemp.h:97
if(dx< 0)
Definition: linetemp.h:194
GLint dx
Definition: linetemp.h:97
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
unsigned int UINT
Definition: ndis.h:50
#define DWORD
Definition: nt_native.h:44
#define calloc
Definition: rosglue.h:14
static calc_node_t temp
Definition: rpn_ieee.c:38
#define TRACE(s)
Definition: solgame.cpp:4
region_element node
DWORD num_children
REAL X
Definition: gdiplustypes.h:643
REAL Height
Definition: gdiplustypes.h:659
REAL X
Definition: gdiplustypes.h:656
REAL Width
Definition: gdiplustypes.h:658
REAL Y
Definition: gdiplustypes.h:657
INT Width
Definition: gdiplustypes.h:666
INT Height
Definition: gdiplustypes.h:667
INT X
Definition: gdiplustypes.h:664
INT Y
Definition: gdiplustypes.h:665
short X
Definition: region.c:103
short Y
Definition: region.c:104
DWORD size
Definition: region.c:95
DWORD magic
Definition: region.c:96
struct region_header header
Definition: region.c:90
DWORD checksum
Definition: region.c:89
struct region_element::@405::@406 combine
union region_element::@405 elementdata
DWORD num_children
Definition: region.c:83
DWORD magic
Definition: region.c:82
Definition: stat.h:66
Definition: ps.c:97
LONG right
Definition: windef.h:108
LONG bottom
Definition: windef.h:109
LONG top
Definition: windef.h:107
LONG left
Definition: windef.h:106
Definition: cmds.c:130
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
float FLOAT
Definition: typedefs.h:69
int32_t INT
Definition: typedefs.h:58
Definition: dlist.c:348
#define LPRECT
Definition: precomp.h:28
#define RECT
Definition: precomp.h:26
HRGN WINAPI CreateRectRgn(_In_ int, _In_ int, _In_ int, _In_ int)
#define RGN_DIFF
Definition: wingdi.h:358
#define RDH_RECTANGLES
Definition: wingdi.h:669
BOOL WINAPI EqualRgn(_In_ HRGN, _In_ HRGN)
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
BOOL WINAPI PtInRegion(_In_ HRGN, _In_ int, _In_ int)
int WINAPI CombineRgn(_In_opt_ HRGN hrgnDest, _In_opt_ HRGN hrgnSrc1, _In_opt_ HRGN hrgnSrc2, _In_ int fnCombineMode)
#define RGN_AND
Definition: wingdi.h:356
BOOL WINAPI RestoreDC(_In_ HDC, _In_ int)
HRGN WINAPI PathToRegion(_In_ HDC)
#define RGN_XOR
Definition: wingdi.h:360
#define RGN_OR
Definition: wingdi.h:359
BOOL WINAPI RectInRegion(_In_ HRGN, _In_ LPCRECT)
DWORD WINAPI GetRegionData(_In_ HRGN hrgn, _In_ DWORD nCount, _Out_writes_bytes_to_opt_(nCount, return) LPRGNDATA lpRgnData)
BOOL WINAPI DeleteDC(_In_ HDC)
BOOL WINAPI EndPath(_In_ HDC)
int WINAPI SaveDC(_In_ HDC)
int WINAPI SetPolyFillMode(_In_ HDC, _In_ int)
Definition: dc.c:1174
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
unsigned char BYTE
Definition: xxhash.c:193