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