[GDI32] Remove obsolete function GdiIsHandleValid, which is just a copy of GdiValidat...
[reactos.git] / reactos / win32ss / gdi / gdi32 / objects / region.c
1 #include <precomp.h>
2
3 #define NDEBUG
4 #include <debug.h>
5
6 #define INRECT(r, x, y) \
7 ( ( ((r).right > x)) && \
8 ( ((r).left <= x)) && \
9 ( ((r).bottom > y)) && \
10 ( ((r).top <= y)) )
11
12 #define OVERLAPPING_RGN 0
13 #define INVERTED_RGN 1
14 #define SAME_RGN 2
15 #define DIFF_RGN 3
16 /*
17 From tests, there are four results based on normalized coordinates.
18 If the rects are overlapping and normalized, it's OVERLAPPING_RGN.
19 If the rects are overlapping in anyway or same in dimension and one is inverted,
20 it's INVERTED_RGN.
21 If the rects are same in dimension or NULL, it's SAME_RGN.
22 If the rects are overlapping and not normalized or displace in different areas,
23 it's DIFF_RGN.
24 */
25 INT
26 FASTCALL
27 ComplexityFromRects( PRECTL prc1, PRECTL prc2)
28 {
29 if ( prc2->left >= prc1->left )
30 {
31 if ( ( prc1->right >= prc2->right) &&
32 ( prc1->top <= prc2->top ) &&
33 ( prc1->bottom >= prc2->bottom ) )
34 return SAME_RGN;
35
36 if ( prc2->left > prc1->left )
37 {
38 if ( ( prc1->left >= prc2->right ) ||
39 ( prc1->right <= prc2->left ) ||
40 ( prc1->top >= prc2->bottom ) ||
41 ( prc1->bottom <= prc2->top ) )
42 return DIFF_RGN;
43 }
44 }
45
46 if ( ( prc2->right < prc1->right ) ||
47 ( prc2->top > prc1->top ) ||
48 ( prc2->bottom < prc1->bottom ) )
49 {
50 if ( ( prc1->left >= prc2->right ) ||
51 ( prc1->right <= prc2->left ) ||
52 ( prc1->top >= prc2->bottom ) ||
53 ( prc1->bottom <= prc2->top ) )
54 return DIFF_RGN;
55 }
56 else
57 {
58 return INVERTED_RGN;
59 }
60 return OVERLAPPING_RGN;
61 }
62
63 static
64 VOID
65 FASTCALL
66 SortRects(PRECT pRect, INT nCount)
67 {
68 INT i = 0, a = 0, b = 0, c, s;
69 RECT sRect;
70
71 if (nCount > 0)
72 {
73 i = 1; // set index point
74 c = nCount; // set inverse count
75 do
76 {
77 s = i; // set sort count
78 if ( i < nCount )
79 {
80 a = i - 1;
81 b = i;
82 do
83 {
84 if(pRect[b].top != pRect[i].bottom) break;
85 if(pRect[b].left < pRect[a].left)
86 {
87 sRect = pRect[a];
88 pRect[a] = pRect[b];
89 pRect[b] = sRect;
90 }
91 ++s;
92 ++b;
93 }
94 while ( s < nCount );
95 }
96 ++i;
97 }
98 while ( c-- != 1 );
99 }
100 }
101
102 /*
103 * I thought it was okay to have this in DeleteObject but~ Speed. (jt)
104 */
105 BOOL
106 FASTCALL
107 DeleteRegion(
108 _In_ HRGN hrgn)
109 {
110 #if 0
111 PRGN_ATTR Rgn_Attr;
112
113 if ((GdiGetHandleUserData(hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr)) &&
114 ( Rgn_Attr != NULL ))
115 {
116 PGDIBSOBJECT pgO;
117
118 pgO = GdiAllocBatchCommand(NULL, GdiBCDelRgn);
119 if (pgO)
120 {
121 pgO->hgdiobj = hrgn;
122 return TRUE;
123 }
124 }
125 #endif
126 return NtGdiDeleteObjectApp(hrgn);
127 }
128
129 INT
130 FASTCALL
131 MirrorRgnByWidth(
132 _In_ HRGN hrgn,
133 _In_ INT Width,
134 _In_ HRGN *phrgn)
135 {
136 INT cRgnDSize, Ret = 0;
137 PRGNDATA pRgnData;
138
139 cRgnDSize = NtGdiGetRegionData(hrgn, 0, NULL);
140
141 if (cRgnDSize)
142 {
143 pRgnData = LocalAlloc(LMEM_FIXED, cRgnDSize * sizeof(LONG));
144 if (pRgnData)
145 {
146 if ( GetRegionData(hrgn, cRgnDSize, pRgnData) )
147 {
148 HRGN hRgnex;
149 UINT i;
150 INT SaveL = pRgnData->rdh.rcBound.left;
151 pRgnData->rdh.rcBound.left = Width - pRgnData->rdh.rcBound.right;
152 pRgnData->rdh.rcBound.right = Width - SaveL;
153 if (pRgnData->rdh.nCount > 0)
154 {
155 PRECT pRect = (PRECT)&pRgnData->Buffer;
156 for (i = 0; i < pRgnData->rdh.nCount; i++)
157 {
158 SaveL = pRect[i].left;
159 pRect[i].left = Width - pRect[i].right;
160 pRect[i].right = Width - SaveL;
161 }
162 }
163 SortRects((PRECT)&pRgnData->Buffer, pRgnData->rdh.nCount);
164 hRgnex = ExtCreateRegion(NULL, cRgnDSize , pRgnData);
165 if (hRgnex)
166 {
167 if (phrgn) phrgn = (HRGN *)hRgnex;
168 else
169 {
170 CombineRgn(hrgn, hRgnex, 0, RGN_COPY);
171 DeleteObject(hRgnex);
172 }
173 Ret = 1;
174 }
175 }
176 LocalFree(pRgnData);
177 }
178 }
179 return Ret;
180 }
181
182 INT
183 WINAPI
184 MirrorRgnDC(
185 _In_ HDC hdc,
186 _In_ HRGN hrgn,
187 _In_ HRGN *phrn)
188 {
189 if (!GdiValidateHandle((HGDIOBJ) hdc) ||
190 (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC))
191 return 0;
192
193 return MirrorRgnByWidth(hrgn, NtGdiGetDeviceWidth(hdc), phrn);
194 }
195
196 /* FUNCTIONS *****************************************************************/
197
198 FORCEINLINE
199 ULONG
200 IntSetNullRgn(
201 _Inout_ PRGN_ATTR prgnattr)
202 {
203 prgnattr->iComplexity = NULLREGION;
204 prgnattr->AttrFlags |= ATTR_RGN_DIRTY;
205 return NULLREGION;
206 }
207
208 FORCEINLINE
209 ULONG
210 IntSetRectRgn(
211 _Inout_ PRGN_ATTR prgnattr,
212 _In_ INT xLeft,
213 _In_ INT yTop,
214 _In_ INT xRight,
215 _In_ INT yBottom)
216 {
217 ASSERT(xLeft <= xRight);
218 ASSERT(yTop <= yBottom);
219
220 if ((xLeft == xRight) || (yTop == yBottom))
221 return IntSetNullRgn(prgnattr);
222
223 prgnattr->iComplexity = SIMPLEREGION;
224 prgnattr->Rect.left = xLeft;
225 prgnattr->Rect.top = yTop;
226 prgnattr->Rect.right = xRight;
227 prgnattr->Rect.bottom = yBottom;
228 prgnattr->AttrFlags |= ATTR_RGN_DIRTY;
229 return SIMPLEREGION;
230 }
231
232 /*
233 * @implemented
234 */
235 INT
236 WINAPI
237 CombineRgn(
238 _In_ HRGN hrgnDest,
239 _In_ HRGN hrgnSrc1,
240 _In_ HRGN hrgnSrc2,
241 _In_ INT iCombineMode)
242 {
243 PRGN_ATTR prngattrDest = NULL;
244 PRGN_ATTR prngattrSrc1 = NULL;
245 PRGN_ATTR prngattrSrc2 = NULL;
246 RECT rcTemp;
247
248 /* Get the region attribute for dest and source 1 */
249 prngattrDest = GdiGetRgnAttr(hrgnDest);
250 prngattrSrc1 = GdiGetRgnAttr(hrgnSrc1);
251
252 /* If that failed or if the source 1 region is complex, go to win32k */
253 if ((prngattrDest == NULL) || (prngattrSrc1 == NULL) ||
254 (prngattrSrc1->iComplexity > SIMPLEREGION))
255 {
256 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
257 }
258
259 /* Handle RGN_COPY first, it needs only hrgnSrc1 */
260 if (iCombineMode == RGN_COPY)
261 {
262 /* Check if the source region is a NULLREGION */
263 if (prngattrSrc1->iComplexity == NULLREGION)
264 {
265 /* The dest region is a NULLREGION, too */
266 return IntSetNullRgn(prngattrDest);
267 }
268
269 /* We already know that the source region cannot be complex, so
270 create a rect region from the bounds of the source rect */
271 return IntSetRectRgn(prngattrDest,
272 prngattrSrc1->Rect.left,
273 prngattrSrc1->Rect.top,
274 prngattrSrc1->Rect.right,
275 prngattrSrc1->Rect.bottom);
276 }
277
278 /* For all other operations we need hrgnSrc2 */
279 prngattrSrc2 = GdiGetRgnAttr(hrgnSrc2);
280
281 /* If we got no attribute or the region is complex, go to win32k */
282 if ((prngattrSrc2 == NULL) || (prngattrSrc2->iComplexity > SIMPLEREGION))
283 {
284 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
285 }
286
287 /* Handle RGN_AND */
288 if (iCombineMode == RGN_AND)
289 {
290 /* Check if either of the regions is a NULLREGION */
291 if ((prngattrSrc1->iComplexity == NULLREGION) ||
292 (prngattrSrc2->iComplexity == NULLREGION))
293 {
294 /* Result is also a NULLREGION */
295 return IntSetNullRgn(prngattrDest);
296 }
297
298 /* Get the intersection of the 2 rects */
299 if (!IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
300 {
301 /* The rects do not intersect, result is a NULLREGION */
302 return IntSetNullRgn(prngattrDest);
303 }
304
305 /* Use the intersection of the rects */
306 return IntSetRectRgn(prngattrDest,
307 rcTemp.left,
308 rcTemp.top,
309 rcTemp.right,
310 rcTemp.bottom);
311 }
312
313 /* Handle RGN_DIFF */
314 if (iCombineMode == RGN_DIFF)
315 {
316 /* Check if source 1 is a NULLREGION */
317 if (prngattrSrc1->iComplexity == NULLREGION)
318 {
319 /* The result is a NULLREGION as well */
320 return IntSetNullRgn(prngattrDest);
321 }
322
323 /* Get the intersection of the 2 rects */
324 if ((prngattrSrc2->iComplexity == NULLREGION) ||
325 !IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
326 {
327 /* The rects do not intersect, dest equals source 1 */
328 return IntSetRectRgn(prngattrDest,
329 prngattrSrc1->Rect.left,
330 prngattrSrc1->Rect.top,
331 prngattrSrc1->Rect.right,
332 prngattrSrc1->Rect.bottom);
333 }
334
335 /* We need to check is whether we can subtract the rects. For that
336 we call SubtractRect, which will give us the bounding box of the
337 subtraction. The function returns FALSE if the resulting rect is
338 empty */
339 if (!SubtractRect(&rcTemp, &prngattrSrc1->Rect, &rcTemp))
340 {
341 /* The result is a NULLREGION */
342 return IntSetNullRgn(prngattrDest);
343 }
344
345 /* Now check if the result of SubtractRect matches the source 1 rect.
346 Since we already know that the rects intersect, the result can
347 only match the source 1 rect, if it could not be "cut" on either
348 side, but the overlapping was on a corner, so the new bounding box
349 equals the previous rect */
350 if (!EqualRect(&rcTemp, &prngattrSrc1->Rect))
351 {
352 /* We got a properly subtracted rect, so use it. */
353 return IntSetRectRgn(prngattrDest,
354 rcTemp.left,
355 rcTemp.top,
356 rcTemp.right,
357 rcTemp.bottom);
358 }
359
360 /* The result would be a complex region, go to win32k */
361 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
362 }
363
364 /* Handle OR and XOR */
365 if ((iCombineMode == RGN_OR) || (iCombineMode == RGN_XOR))
366 {
367 /* Check if source 1 is a NULLREGION */
368 if (prngattrSrc1->iComplexity == NULLREGION)
369 {
370 /* Check if source 2 is also a NULLREGION */
371 if (prngattrSrc2->iComplexity == NULLREGION)
372 {
373 /* Both are NULLREGIONs, result is also a NULLREGION */
374 return IntSetNullRgn(prngattrDest);
375 }
376
377 /* The result is equal to source 2 */
378 return IntSetRectRgn(prngattrDest,
379 prngattrSrc2->Rect.left,
380 prngattrSrc2->Rect.top,
381 prngattrSrc2->Rect.right,
382 prngattrSrc2->Rect.bottom );
383 }
384
385 /* Check if only source 2 is a NULLREGION */
386 if (prngattrSrc2->iComplexity == NULLREGION)
387 {
388 /* The result is equal to source 1 */
389 return IntSetRectRgn(prngattrDest,
390 prngattrSrc1->Rect.left,
391 prngattrSrc1->Rect.top,
392 prngattrSrc1->Rect.right,
393 prngattrSrc1->Rect.bottom);
394 }
395
396 /* Do the rects have the same x extent */
397 if ((prngattrSrc1->Rect.left == prngattrSrc2->Rect.left) &&
398 (prngattrSrc1->Rect.right == prngattrSrc2->Rect.right))
399 {
400 /* Do the rects also have the same y extent */
401 if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
402 (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
403 {
404 /* Rects are equal, if this is RGN_OR, the result is source 1 */
405 if (iCombineMode == RGN_OR)
406 {
407 /* The result is equal to source 1 */
408 return IntSetRectRgn(prngattrDest,
409 prngattrSrc1->Rect.left,
410 prngattrSrc1->Rect.top,
411 prngattrSrc1->Rect.right,
412 prngattrSrc1->Rect.bottom );
413 }
414 else
415 {
416 /* XORing with itself yields an empty region */
417 return IntSetNullRgn(prngattrDest);
418 }
419 }
420
421 /* Check if the rects are disjoint */
422 if ((prngattrSrc2->Rect.bottom < prngattrSrc1->Rect.top) ||
423 (prngattrSrc2->Rect.top > prngattrSrc1->Rect.bottom))
424 {
425 /* The result would be a complex region, go to win32k */
426 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
427 }
428
429 /* Check if this is OR */
430 if (iCombineMode == RGN_OR)
431 {
432 /* Use the maximum extent of both rects combined */
433 return IntSetRectRgn(prngattrDest,
434 prngattrSrc1->Rect.left,
435 min(prngattrSrc1->Rect.top, prngattrSrc2->Rect.top),
436 prngattrSrc1->Rect.right,
437 max(prngattrSrc1->Rect.bottom, prngattrSrc2->Rect.bottom));
438 }
439
440 /* Check if the rects are adjacent */
441 if (prngattrSrc2->Rect.bottom == prngattrSrc1->Rect.top)
442 {
443 /* The result is the combined rects */
444 return IntSetRectRgn(prngattrDest,
445 prngattrSrc1->Rect.left,
446 prngattrSrc2->Rect.top,
447 prngattrSrc1->Rect.right,
448 prngattrSrc1->Rect.bottom );
449 }
450 else if (prngattrSrc2->Rect.top == prngattrSrc1->Rect.bottom)
451 {
452 /* The result is the combined rects */
453 return IntSetRectRgn(prngattrDest,
454 prngattrSrc1->Rect.left,
455 prngattrSrc1->Rect.top,
456 prngattrSrc1->Rect.right,
457 prngattrSrc2->Rect.bottom );
458 }
459
460 /* When we are here, this is RGN_XOR and the rects overlap */
461 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
462 }
463
464 /* Do the rects have the same y extent */
465 if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
466 (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
467 {
468 /* Check if the rects are disjoint */
469 if ((prngattrSrc2->Rect.right < prngattrSrc1->Rect.left) ||
470 (prngattrSrc2->Rect.left > prngattrSrc1->Rect.right))
471 {
472 /* The result would be a complex region, go to win32k */
473 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
474 }
475
476 /* Check if this is OR */
477 if (iCombineMode == RGN_OR)
478 {
479 /* Use the maximum extent of both rects combined */
480 return IntSetRectRgn(prngattrDest,
481 min(prngattrSrc1->Rect.left, prngattrSrc2->Rect.left),
482 prngattrSrc1->Rect.top,
483 max(prngattrSrc1->Rect.right, prngattrSrc2->Rect.right),
484 prngattrSrc1->Rect.bottom);
485 }
486
487 /* Check if the rects are adjacent */
488 if (prngattrSrc2->Rect.right == prngattrSrc1->Rect.left)
489 {
490 /* The result is the combined rects */
491 return IntSetRectRgn(prngattrDest,
492 prngattrSrc2->Rect.left,
493 prngattrSrc1->Rect.top,
494 prngattrSrc1->Rect.right,
495 prngattrSrc1->Rect.bottom );
496 }
497 else if (prngattrSrc2->Rect.left == prngattrSrc1->Rect.right)
498 {
499 /* The result is the combined rects */
500 return IntSetRectRgn(prngattrDest,
501 prngattrSrc1->Rect.left,
502 prngattrSrc1->Rect.top,
503 prngattrSrc2->Rect.right,
504 prngattrSrc1->Rect.bottom );
505 }
506
507 /* When we are here, this is RGN_XOR and the rects overlap */
508 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
509 }
510
511 /* Last case: RGN_OR and one rect is completely within the other */
512 if (iCombineMode == RGN_OR)
513 {
514 /* Check if rect 1 can contain rect 2 */
515 if (prngattrSrc1->Rect.left <= prngattrSrc2->Rect.left)
516 {
517 /* rect 1 might be the outer one, check of that is true */
518 if ((prngattrSrc1->Rect.right >= prngattrSrc2->Rect.right) &&
519 (prngattrSrc1->Rect.top <= prngattrSrc2->Rect.top) &&
520 (prngattrSrc1->Rect.bottom >= prngattrSrc2->Rect.bottom))
521 {
522 /* Rect 1 contains rect 2, use it */
523 return IntSetRectRgn(prngattrDest,
524 prngattrSrc1->Rect.left,
525 prngattrSrc1->Rect.top,
526 prngattrSrc1->Rect.right,
527 prngattrSrc1->Rect.bottom );
528 }
529 }
530 else
531 {
532 /* rect 2 might be the outer one, check of that is true */
533 if ((prngattrSrc2->Rect.right >= prngattrSrc1->Rect.right) &&
534 (prngattrSrc2->Rect.top <= prngattrSrc1->Rect.top) &&
535 (prngattrSrc2->Rect.bottom >= prngattrSrc1->Rect.bottom))
536 {
537 /* Rect 2 contains rect 1, use it */
538 return IntSetRectRgn(prngattrDest,
539 prngattrSrc2->Rect.left,
540 prngattrSrc2->Rect.top,
541 prngattrSrc2->Rect.right,
542 prngattrSrc2->Rect.bottom );
543 }
544 }
545 }
546
547 /* We couldn't handle the operation, go to win32k */
548 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
549 }
550
551 DPRINT1("Invalid iCombineMode %d\n", iCombineMode);
552 SetLastError(ERROR_INVALID_PARAMETER);
553 return ERROR;
554 }
555
556
557 /*
558 * @implemented
559 */
560 HRGN
561 WINAPI
562 CreateEllipticRgnIndirect(
563 const RECT *prc
564 )
565 {
566 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
567 return NtGdiCreateEllipticRgn(prc->left, prc->top, prc->right, prc->bottom);
568
569 }
570
571 /*
572 * @implemented
573 */
574 HRGN
575 WINAPI
576 CreatePolygonRgn( const POINT * lppt, int cPoints, int fnPolyFillMode)
577 {
578 return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) &cPoints, 1, GdiPolyPolyRgn);
579 }
580
581 /*
582 * @implemented
583 */
584 HRGN
585 WINAPI
586 CreatePolyPolygonRgn( const POINT* lppt,
587 const INT* lpPolyCounts,
588 int nCount,
589 int fnPolyFillMode)
590 {
591 return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) lpPolyCounts, (ULONG) nCount, GdiPolyPolyRgn );
592 }
593
594 /*
595 * @implemented
596 */
597 HRGN
598 WINAPI
599 CreateRectRgn(int x1, int y1, int x2, int y2)
600 {
601 PRGN_ATTR pRgn_Attr;
602 HRGN hrgn;
603 int tmp;
604
605 /// <-
606 //// Remove when Brush/Pen/Rgn Attr is ready!
607 return NtGdiCreateRectRgn(x1,y1,x2,y2);
608 ////
609
610 /* Normalize points */
611 tmp = x1;
612 if ( x1 > x2 )
613 {
614 x1 = x2;
615 x2 = tmp;
616 }
617
618 tmp = y1;
619 if ( y1 > y2 )
620 {
621 y1 = y2;
622 y2 = tmp;
623 }
624 /* Check outside 24 bit limit for universal set. Chp 9 Areas, pg 560.*/
625 if ( x1 < -(1<<27) ||
626 y1 < -(1<<27) ||
627 x2 > (1<<27)-1 ||
628 y2 > (1<<27)-1 )
629 {
630 SetLastError(ERROR_INVALID_PARAMETER);
631 return NULL;
632 }
633
634 hrgn = hGetPEBHandle(hctRegionHandle, 0);
635
636 if (!hrgn)
637 hrgn = NtGdiCreateRectRgn(0, 0, 1, 1);
638
639 if (!hrgn)
640 return hrgn;
641
642 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
643 {
644 DPRINT1("No Attr for Region handle!!!\n");
645 DeleteRegion(hrgn);
646 return NULL;
647 }
648
649 if (( x1 == x2) || (y1 == y2))
650 {
651 pRgn_Attr->iComplexity = NULLREGION;
652 pRgn_Attr->Rect.left = pRgn_Attr->Rect.top =
653 pRgn_Attr->Rect.right = pRgn_Attr->Rect.bottom = 0;
654 }
655 else
656 {
657 pRgn_Attr->iComplexity = SIMPLEREGION;
658 pRgn_Attr->Rect.left = x1;
659 pRgn_Attr->Rect.top = y1;
660 pRgn_Attr->Rect.right = x2;
661 pRgn_Attr->Rect.bottom = y2;
662 }
663
664 pRgn_Attr->AttrFlags = (ATTR_RGN_DIRTY|ATTR_RGN_VALID);
665
666 return hrgn;
667 }
668
669 /*
670 * @implemented
671 */
672 HRGN
673 WINAPI
674 CreateRectRgnIndirect(
675 const RECT *prc
676 )
677 {
678 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
679 return CreateRectRgn(prc->left, prc->top, prc->right, prc->bottom);
680
681 }
682
683 /*
684 * @implemented
685 */
686 INT
687 WINAPI
688 ExcludeClipRect(
689 _In_ HDC hdc,
690 _In_ INT xLeft,
691 _In_ INT yTop,
692 _In_ INT xRight,
693 _In_ INT yBottom)
694 {
695 HANDLE_METADC(INT, ExcludeClipRect, ERROR, hdc, xLeft, yTop, xRight, yBottom);
696
697 return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
698 }
699
700 /*
701 * @implemented
702 */
703 HRGN
704 WINAPI
705 ExtCreateRegion(
706 CONST XFORM * lpXform,
707 DWORD nCount,
708 CONST RGNDATA * lpRgnData
709 )
710 {
711 if (lpRgnData)
712 {
713 if ((!lpXform) && (lpRgnData->rdh.nCount == 1))
714 {
715 PRECT pRect = (PRECT)&lpRgnData->Buffer[0];
716 return CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
717 }
718 return NtGdiExtCreateRegion((LPXFORM) lpXform, nCount,(LPRGNDATA) lpRgnData);
719 }
720 SetLastError(ERROR_INVALID_PARAMETER);
721 return NULL;
722 }
723
724 /*
725 * @implemented
726 */
727 INT
728 WINAPI
729 ExtSelectClipRgn(
730 _In_ HDC hdc,
731 _In_ HRGN hrgn,
732 _In_ INT iMode)
733 {
734 INT Ret;
735 HRGN NewRgn = NULL;
736
737 HANDLE_METADC(INT, ExtSelectClipRgn, 0, hdc, hrgn, iMode);
738
739 #if 0
740 if ( hrgn )
741 {
742 if ( GetLayout(hdc) & LAYOUT_RTL )
743 {
744 if ( MirrorRgnDC(hdc, hrgn, &NewRgn) )
745 {
746 if ( NewRgn ) hrgn = NewRgn;
747 }
748 }
749 }
750 #endif
751 /* Batch handles RGN_COPY only! */
752 if (iMode == RGN_COPY)
753 {
754 #if 0
755 PDC_ATTR pDc_Attr;
756 PRGN_ATTR pRgn_Attr = NULL;
757
758 /* hrgn can be NULL unless the RGN_COPY mode is specified. */
759 if (hrgn)
760 GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr);
761
762 if ( GdiGetHandleUserData((HGDIOBJ) hdc, GDI_OBJECT_TYPE_DC, (PVOID) &pDc_Attr) &&
763 pDc_Attr )
764 {
765 PGDI_TABLE_ENTRY pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hdc);
766 PTEB pTeb = NtCurrentTeb();
767
768 if ( pTeb->Win32ThreadInfo != NULL &&
769 pTeb->GdiTebBatch.HDC == hdc &&
770 !(pDc_Attr->ulDirty_ & DC_DIBSECTION) &&
771 !(pEntry->Flags & GDI_ENTRY_VALIDATE_VIS) )
772 {
773 if (!hrgn ||
774 (hrgn && pRgn_Attr && pRgn_Attr->iComplexity <= SIMPLEREGION) )
775 {
776 if ((pTeb->GdiTebBatch.Offset + sizeof(GDIBSEXTSELCLPRGN)) <= GDIBATCHBUFSIZE)
777 {
778 // FIXME: This is broken, use GdiAllocBatchCommand!
779 PGDIBSEXTSELCLPRGN pgO = (PGDIBSEXTSELCLPRGN)(&pTeb->GdiTebBatch.Buffer[0] +
780 pTeb->GdiTebBatch.Offset);
781 pgO->gbHdr.Cmd = GdiBCExtSelClipRgn;
782 pgO->gbHdr.Size = sizeof(GDIBSEXTSELCLPRGN);
783 pgO->fnMode = iMode;
784
785 if ( hrgn && pRgn_Attr )
786 {
787 Ret = pRgn_Attr->iComplexity;
788
789 if ( pDc_Attr->VisRectRegion.Rect.left >= pRgn_Attr->Rect.right ||
790 pDc_Attr->VisRectRegion.Rect.top >= pRgn_Attr->Rect.bottom ||
791 pDc_Attr->VisRectRegion.Rect.right <= pRgn_Attr->Rect.left ||
792 pDc_Attr->VisRectRegion.Rect.bottom <= pRgn_Attr->Rect.top )
793 Ret = NULLREGION;
794
795 pgO->left = pRgn_Attr->Rect.left;
796 pgO->top = pRgn_Attr->Rect.top;
797 pgO->right = pRgn_Attr->Rect.right;
798 pgO->bottom = pRgn_Attr->Rect.bottom;
799 }
800 else
801 {
802 Ret = pDc_Attr->VisRectRegion.Flags;
803 pgO->fnMode |= 0x80000000; // Set no hrgn mode.
804 }
805 pTeb->GdiTebBatch.Offset += sizeof(GDIBSEXTSELCLPRGN);
806 pTeb->GdiBatchCount++;
807 if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
808 if ( NewRgn ) DeleteObject(NewRgn);
809 return Ret;
810 }
811 }
812 }
813 }
814 #endif
815 }
816 Ret = NtGdiExtSelectClipRgn(hdc, hrgn, iMode);
817
818 if ( NewRgn ) DeleteObject(NewRgn);
819
820 return Ret;
821 }
822
823 /*
824 * @implemented
825 */
826 int
827 WINAPI
828 GetClipRgn(
829 HDC hdc,
830 HRGN hrgn
831 )
832 {
833 INT Ret;
834
835 /* Check if DC handle is valid */
836 if (!GdiGetDcAttr(hdc))
837 {
838 /* Last error code differs from what NtGdiGetRandomRgn returns */
839 SetLastError(ERROR_INVALID_PARAMETER);
840 return -1;
841 }
842
843 Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
844
845 // if (Ret)
846 // {
847 // if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL);
848 // }
849 return Ret;
850 }
851
852 /*
853 * @implemented
854 */
855 int
856 WINAPI
857 GetMetaRgn(HDC hdc,
858 HRGN hrgn)
859 {
860 return NtGdiGetRandomRgn(hdc, hrgn, METARGN);
861 }
862
863 /*
864 * @implemented
865 *
866 */
867 DWORD
868 WINAPI
869 GetRegionData(HRGN hrgn,
870 DWORD nCount,
871 LPRGNDATA lpRgnData)
872 {
873 if (!lpRgnData)
874 {
875 nCount = 0;
876 }
877
878 return NtGdiGetRegionData(hrgn,nCount,lpRgnData);
879 }
880
881 /*
882 * @implemented
883 *
884 */
885 INT
886 WINAPI
887 GetRgnBox(HRGN hrgn,
888 LPRECT prcOut)
889 {
890 PRGN_ATTR Rgn_Attr;
891
892 //if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
893 return NtGdiGetRgnBox(hrgn, prcOut);
894
895 if (Rgn_Attr->iComplexity == NULLREGION)
896 {
897 prcOut->left = 0;
898 prcOut->top = 0;
899 prcOut->right = 0;
900 prcOut->bottom = 0;
901 }
902 else
903 {
904 if (Rgn_Attr->iComplexity != SIMPLEREGION)
905 return NtGdiGetRgnBox(hrgn, prcOut);
906 /* WARNING! prcOut is never checked newbies! */
907 RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT));
908 }
909 return Rgn_Attr->iComplexity;
910 }
911
912 /*
913 * @implemented
914 */
915 INT
916 WINAPI
917 IntersectClipRect(
918 _In_ HDC hdc,
919 _In_ INT nLeft,
920 _In_ INT nTop,
921 _In_ INT nRight,
922 _In_ INT nBottom)
923 {
924 HANDLE_METADC(INT, IntersectClipRect, ERROR, hdc, nLeft, nTop, nRight, nBottom);
925 return NtGdiIntersectClipRect(hdc, nLeft, nTop, nRight, nBottom);
926 }
927
928 /*
929 * @implemented
930 */
931 BOOL
932 WINAPI
933 MirrorRgn(HWND hwnd, HRGN hrgn)
934 {
935 RECT Rect;
936 GetWindowRect(hwnd, &Rect);
937 return MirrorRgnByWidth(hrgn, Rect.right - Rect.left, NULL);
938 }
939
940 /*
941 * @implemented
942 */
943 INT
944 WINAPI
945 OffsetClipRgn(
946 HDC hdc,
947 INT nXOffset,
948 INT nYOffset)
949 {
950 HANDLE_METADC(INT, OffsetClipRgn, ERROR, hdc, nXOffset, nYOffset);
951 return NtGdiOffsetClipRgn(hdc, nXOffset, nYOffset);
952 }
953
954 /*
955 * @implemented
956 *
957 */
958 INT
959 WINAPI
960 OffsetRgn( HRGN hrgn,
961 int nXOffset,
962 int nYOffset)
963 {
964 PRGN_ATTR pRgn_Attr;
965 int nLeftRect, nTopRect, nRightRect, nBottomRect;
966
967 // HACKFIX
968 // if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
969 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
970
971 if ( pRgn_Attr->iComplexity == NULLREGION)
972 return pRgn_Attr->iComplexity;
973
974 if ( pRgn_Attr->iComplexity != SIMPLEREGION)
975 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
976
977 nLeftRect = pRgn_Attr->Rect.left;
978 nTopRect = pRgn_Attr->Rect.top;
979 nRightRect = pRgn_Attr->Rect.right;
980 nBottomRect = pRgn_Attr->Rect.bottom;
981
982 if (nLeftRect < nRightRect)
983 {
984 if (nTopRect < nBottomRect)
985 {
986 nLeftRect = nXOffset + nLeftRect;
987 nTopRect = nYOffset + nTopRect;
988 nRightRect = nXOffset + nRightRect;
989 nBottomRect = nYOffset + nBottomRect;
990
991 /* Check 28 bit limit. Chp 9 Areas, pg 560. */
992 if ( nLeftRect < -(1<<27) ||
993 nTopRect < -(1<<27) ||
994 nRightRect > (1<<27)-1 ||
995 nBottomRect > (1<<27)-1 )
996 {
997 return ERROR;
998 }
999
1000 pRgn_Attr->Rect.top = nTopRect;
1001 pRgn_Attr->Rect.left = nLeftRect;
1002 pRgn_Attr->Rect.right = nRightRect;
1003 pRgn_Attr->Rect.bottom = nBottomRect;
1004 pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
1005 }
1006 }
1007 return pRgn_Attr->iComplexity;
1008 }
1009
1010 /*
1011 * @implemented
1012 */
1013 BOOL
1014 WINAPI
1015 PtInRegion(IN HRGN hrgn,
1016 int x,
1017 int y)
1018 {
1019 PRGN_ATTR pRgn_Attr;
1020
1021 // HACKFIX
1022 //if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
1023 return NtGdiPtInRegion(hrgn,x,y);
1024
1025 if ( pRgn_Attr->iComplexity == NULLREGION)
1026 return FALSE;
1027
1028 if ( pRgn_Attr->iComplexity != SIMPLEREGION)
1029 return NtGdiPtInRegion(hrgn,x,y);
1030
1031 return INRECT( pRgn_Attr->Rect, x, y);
1032 }
1033
1034 /*
1035 * @implemented
1036 */
1037 BOOL
1038 WINAPI
1039 RectInRegion(HRGN hrgn,
1040 LPCRECT prcl)
1041 {
1042 PRGN_ATTR pRgn_Attr;
1043 RECTL rc;
1044
1045 // HACKFIX
1046 //if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
1047 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
1048
1049 if ( pRgn_Attr->iComplexity == NULLREGION)
1050 return FALSE;
1051
1052 if ( pRgn_Attr->iComplexity != SIMPLEREGION)
1053 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
1054
1055 /* swap the coordinates to make right >= left and bottom >= top */
1056 /* (region building rectangles are normalized the same way) */
1057 if ( prcl->top > prcl->bottom)
1058 {
1059 rc.top = prcl->bottom;
1060 rc.bottom = prcl->top;
1061 }
1062 else
1063 {
1064 rc.top = prcl->top;
1065 rc.bottom = prcl->bottom;
1066 }
1067 if ( prcl->right < prcl->left)
1068 {
1069 rc.right = prcl->left;
1070 rc.left = prcl->right;
1071 }
1072 else
1073 {
1074 rc.right = prcl->right;
1075 rc.left = prcl->left;
1076 }
1077
1078 if ( ComplexityFromRects( &pRgn_Attr->Rect, &rc) != DIFF_RGN )
1079 return TRUE;
1080
1081 return FALSE;
1082 }
1083
1084 /*
1085 * @implemented
1086 */
1087 int
1088 WINAPI
1089 SelectClipRgn(
1090 _In_ HDC hdc,
1091 _In_ HRGN hrgn)
1092 {
1093 return ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
1094 }
1095
1096 /*
1097 * @implemented
1098 */
1099 BOOL
1100 WINAPI
1101 SetRectRgn(
1102 _In_ HRGN hrgn,
1103 _In_ INT xLeft,
1104 _In_ INT yTop,
1105 _In_ INT xRight,
1106 _In_ INT yBottom)
1107 {
1108 PRGN_ATTR prngattr;
1109
1110 /* Try to get the region attribute */
1111 prngattr = GdiGetRgnAttr(hrgn);
1112 if (prngattr == NULL)
1113 {
1114 return NtGdiSetRectRgn(hrgn, xLeft, yTop, xRight, yBottom);
1115 }
1116
1117 /* check for NULL region */
1118 if ((xLeft == xRight) || (yTop == yBottom))
1119 {
1120 IntSetNullRgn(prngattr);
1121 return TRUE;
1122 }
1123
1124 if (xLeft > xRight)
1125 {
1126 prngattr->Rect.left = xRight;
1127 prngattr->Rect.right = xLeft;
1128 }
1129 else
1130 {
1131 prngattr->Rect.left = xLeft;
1132 prngattr->Rect.right = xRight;
1133 }
1134
1135 if (yTop > yBottom)
1136 {
1137 prngattr->Rect.top = yBottom;
1138 prngattr->Rect.bottom = yTop;
1139 }
1140 else
1141 {
1142 prngattr->Rect.top = yTop;
1143 prngattr->Rect.bottom = yBottom;
1144 }
1145
1146 prngattr->AttrFlags |= ATTR_RGN_DIRTY ;
1147 prngattr->iComplexity = SIMPLEREGION;
1148
1149 return TRUE;
1150 }
1151
1152 /*
1153 * @implemented
1154 */
1155 int
1156 WINAPI
1157 SetMetaRgn(HDC hDC)
1158 {
1159 if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
1160 return NtGdiSetMetaRgn(hDC);
1161 #if 0
1162 PLDC pLDC = GdiGetLDC(hDC);
1163 if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
1164 {
1165 if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
1166 {
1167 return NtGdiSetMetaRgn(hDC);
1168 }
1169 else
1170 SetLastError(ERROR_INVALID_HANDLE);
1171 }
1172 #endif
1173 return ERROR;
1174 }
1175