- Merge from trunk up to r45543
[reactos.git] / dll / win32 / 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 } while ( s < nCount );
94 }
95 ++i;
96 } while ( c-- != 1 );
97 }
98 }
99
100 /*
101 * I thought it was okay to have this in DeleteObject but~ Speed. (jt)
102 */
103 BOOL
104 FASTCALL
105 DeleteRegion( HRGN hRgn )
106 {
107 PRGN_ATTR Rgn_Attr;
108
109 if ((GdiGetHandleUserData((HGDIOBJ) hRgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr)) &&
110 ( Rgn_Attr != NULL ))
111 {
112 PTEB pTeb = NtCurrentTeb();
113 if (pTeb->Win32ThreadInfo != NULL)
114 {
115 if ((pTeb->GdiTebBatch.Offset + sizeof(GDIBSOBJECT)) <= GDIBATCHBUFSIZE)
116 {
117 PGDIBSOBJECT pgO = (PGDIBSOBJECT)(&pTeb->GdiTebBatch.Buffer[0] +
118 pTeb->GdiTebBatch.Offset);
119 pgO->gbHdr.Cmd = GdiBCDelRgn;
120 pgO->gbHdr.Size = sizeof(GDIBSOBJECT);
121 pgO->hgdiobj = (HGDIOBJ)hRgn;
122
123 pTeb->GdiTebBatch.Offset += sizeof(GDIBSOBJECT);
124 pTeb->GdiBatchCount++;
125 if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
126 return TRUE;
127 }
128 }
129 }
130 return NtGdiDeleteObjectApp((HGDIOBJ) hRgn);
131 }
132
133 INT
134 FASTCALL
135 MirrorRgnByWidth(HRGN hRgn, INT Width, HRGN *phRgn)
136 {
137 INT cRgnDSize, Ret = 0;
138 PRGNDATA pRgnData;
139
140 cRgnDSize = NtGdiGetRegionData(hRgn, 0, NULL);
141
142 if (cRgnDSize)
143 {
144 pRgnData = LocalAlloc(LMEM_FIXED, cRgnDSize * sizeof(LONG));
145 if (pRgnData)
146 {
147 if ( GetRegionData(hRgn, cRgnDSize, pRgnData) )
148 {
149 HRGN hRgnex;
150 UINT i;
151 INT SaveL = pRgnData->rdh.rcBound.left;
152 pRgnData->rdh.rcBound.left = Width - pRgnData->rdh.rcBound.right;
153 pRgnData->rdh.rcBound.right = Width - SaveL;
154 if (pRgnData->rdh.nCount > 0)
155 {
156 PRECT pRect = (PRECT)&pRgnData->Buffer;
157 for (i = 0; i < pRgnData->rdh.nCount; i++)
158 {
159 SaveL = pRect[i].left;
160 pRect[i].left = Width - pRect[i].right;
161 pRect[i].right = Width - SaveL;
162 }
163 }
164 SortRects((PRECT)&pRgnData->Buffer, pRgnData->rdh.nCount);
165 hRgnex = ExtCreateRegion(NULL, cRgnDSize , pRgnData);
166 if (hRgnex)
167 {
168 if (phRgn) phRgn = (HRGN *)hRgnex;
169 else
170 {
171 CombineRgn(hRgn, hRgnex, 0, RGN_COPY);
172 DeleteObject(hRgnex);
173 }
174 Ret = 1;
175 }
176 }
177 LocalFree(pRgnData);
178 }
179 }
180 return Ret;
181 }
182
183 INT
184 WINAPI
185 MirrorRgnDC(HDC hdc, HRGN hRgn, HRGN *phRgn)
186 {
187 if (!GdiIsHandleValid((HGDIOBJ) hdc) ||
188 (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)) return 0;
189
190 return MirrorRgnByWidth(hRgn, NtGdiGetDeviceWidth(hdc), phRgn);
191 }
192
193 /* FUNCTIONS *****************************************************************/
194
195 /*
196 * @implemented
197 */
198 INT
199 WINAPI
200 CombineRgn(HRGN hDest,
201 HRGN hSrc1,
202 HRGN hSrc2,
203 INT CombineMode)
204 {
205 PRGN_ATTR pRgn_Attr_Dest = NULL;
206 PRGN_ATTR pRgn_Attr_Src1 = NULL;
207 PRGN_ATTR pRgn_Attr_Src2 = NULL;
208 INT Complexity;
209 BOOL Ret;
210
211 Ret = GdiGetHandleUserData((HGDIOBJ) hDest, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr_Dest);
212 Ret = GdiGetHandleUserData((HGDIOBJ) hSrc1, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr_Src1);
213
214 if ( !Ret ||
215 !pRgn_Attr_Dest ||
216 !pRgn_Attr_Src1 ||
217 pRgn_Attr_Src1->Flags > SIMPLEREGION )
218 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
219
220 /* Handle COPY and use only src1. */
221 if ( CombineMode == RGN_COPY )
222 {
223 switch (pRgn_Attr_Src1->Flags)
224 {
225 case NULLREGION:
226 Ret = SetRectRgn( hDest, 0, 0, 0, 0);
227 if (Ret)
228 return NULLREGION;
229 goto ERROR_Exit;
230
231 case SIMPLEREGION:
232 Ret = SetRectRgn( hDest,
233 pRgn_Attr_Src1->Rect.left,
234 pRgn_Attr_Src1->Rect.top,
235 pRgn_Attr_Src1->Rect.right,
236 pRgn_Attr_Src1->Rect.bottom );
237 if (Ret)
238 return SIMPLEREGION;
239 goto ERROR_Exit;
240
241 case COMPLEXREGION:
242 default:
243 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
244 }
245 }
246
247 Ret = GdiGetHandleUserData((HGDIOBJ) hSrc2, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr_Src2);
248 if ( !Ret ||
249 !pRgn_Attr_Src2 ||
250 pRgn_Attr_Src2->Flags > SIMPLEREGION )
251 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
252
253 /* All but AND. */
254 if ( CombineMode != RGN_AND)
255 {
256 if ( CombineMode <= RGN_AND)
257 {
258 /*
259 There might be some type of junk in the call, so go K.
260 If this becomes a problem, need to setup parameter check at the top.
261 */
262 DPRINT1("Might be junk! CombineMode %d\n",CombineMode);
263 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
264 }
265
266 if ( CombineMode > RGN_XOR) /* Handle DIFF. */
267 {
268 if ( CombineMode != RGN_DIFF)
269 { /* Filter check! Well, must be junk?, so go K. */
270 DPRINT1("RGN_COPY was handled! CombineMode %d\n",CombineMode);
271 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
272 }
273 /* Now handle DIFF. */
274 if ( pRgn_Attr_Src1->Flags == NULLREGION )
275 {
276 if (SetRectRgn( hDest, 0, 0, 0, 0))
277 return NULLREGION;
278 goto ERROR_Exit;
279 }
280
281 if ( pRgn_Attr_Src2->Flags != NULLREGION )
282 {
283 Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, &pRgn_Attr_Src2->Rect);
284
285 if ( Complexity != DIFF_RGN )
286 {
287 if ( Complexity != INVERTED_RGN)
288 /* If same or overlapping and norm just go K. */
289 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
290
291 if (SetRectRgn( hDest, 0, 0, 0, 0))
292 return NULLREGION;
293 goto ERROR_Exit;
294 }
295 }
296 }
297 else /* Handle OR or XOR. */
298 {
299 if ( pRgn_Attr_Src1->Flags == NULLREGION )
300 {
301 if ( pRgn_Attr_Src2->Flags != NULLREGION )
302 { /* Src1 null and not NULL, set from src2. */
303 Ret = SetRectRgn( hDest,
304 pRgn_Attr_Src2->Rect.left,
305 pRgn_Attr_Src2->Rect.top,
306 pRgn_Attr_Src2->Rect.right,
307 pRgn_Attr_Src2->Rect.bottom );
308 if (Ret)
309 return SIMPLEREGION;
310 goto ERROR_Exit;
311 }
312 /* Both are NULL. */
313 if (SetRectRgn( hDest, 0, 0, 0, 0))
314 return NULLREGION;
315 goto ERROR_Exit;
316 }
317 /* Src1 is not NULL. */
318 if ( pRgn_Attr_Src2->Flags != NULLREGION )
319 {
320 if ( CombineMode != RGN_OR ) /* Filter XOR, so go K. */
321 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
322
323 Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, &pRgn_Attr_Src2->Rect);
324 /* If inverted use Src2. */
325 if ( Complexity == INVERTED_RGN)
326 {
327 Ret = SetRectRgn( hDest,
328 pRgn_Attr_Src2->Rect.left,
329 pRgn_Attr_Src2->Rect.top,
330 pRgn_Attr_Src2->Rect.right,
331 pRgn_Attr_Src2->Rect.bottom );
332 if (Ret)
333 return SIMPLEREGION;
334 goto ERROR_Exit;
335 }
336 /* Not NULL or overlapping or differentiated, go to K. */
337 if ( Complexity != SAME_RGN)
338 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
339 /* If same, just fall through. */
340 }
341 }
342 Ret = SetRectRgn( hDest,
343 pRgn_Attr_Src1->Rect.left,
344 pRgn_Attr_Src1->Rect.top,
345 pRgn_Attr_Src1->Rect.right,
346 pRgn_Attr_Src1->Rect.bottom );
347 if (Ret)
348 return SIMPLEREGION;
349 goto ERROR_Exit;
350 }
351
352 /* Handle AND. */
353 if ( pRgn_Attr_Src1->Flags != NULLREGION &&
354 pRgn_Attr_Src2->Flags != NULLREGION )
355 {
356 Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, &pRgn_Attr_Src2->Rect);
357
358 if ( Complexity == DIFF_RGN ) /* Differentiated in anyway just NULL rgn. */
359 {
360 if (SetRectRgn( hDest, 0, 0, 0, 0))
361 return NULLREGION;
362 goto ERROR_Exit;
363 }
364
365 if ( Complexity != INVERTED_RGN) /* Not inverted and overlapping. */
366 {
367 if ( Complexity != SAME_RGN) /* Must be norm and overlapping. */
368 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
369 /* Merge from src2. */
370 Ret = SetRectRgn( hDest,
371 pRgn_Attr_Src2->Rect.left,
372 pRgn_Attr_Src2->Rect.top,
373 pRgn_Attr_Src2->Rect.right,
374 pRgn_Attr_Src2->Rect.bottom );
375 if (Ret)
376 return SIMPLEREGION;
377 goto ERROR_Exit;
378 }
379 /* Inverted so merge from src1. */
380 Ret = SetRectRgn( hDest,
381 pRgn_Attr_Src1->Rect.left,
382 pRgn_Attr_Src1->Rect.top,
383 pRgn_Attr_Src1->Rect.right,
384 pRgn_Attr_Src1->Rect.bottom );
385 if (Ret)
386 return SIMPLEREGION;
387 goto ERROR_Exit;
388 }
389
390 /* It's all NULL! */
391 if (SetRectRgn( hDest, 0, 0, 0, 0))
392 return NULLREGION;
393
394 ERROR_Exit:
395 /* Even on error the flag is set dirty and force server side to redraw. */
396 pRgn_Attr_Dest->AttrFlags |= ATTR_RGN_DIRTY;
397 return ERROR;
398 }
399
400 /*
401 * @implemented
402 */
403 HRGN
404 WINAPI
405 CreateEllipticRgnIndirect(
406 const RECT *prc
407 )
408 {
409 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
410 return NtGdiCreateEllipticRgn(prc->left, prc->top, prc->right, prc->bottom);
411
412 }
413
414 /*
415 * @implemented
416 */
417 HRGN
418 WINAPI
419 CreatePolygonRgn( const POINT * lppt, int cPoints, int fnPolyFillMode)
420 {
421 return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) &cPoints, 1, GdiPolyPolyRgn);
422 }
423
424 /*
425 * @implemented
426 */
427 HRGN
428 WINAPI
429 CreatePolyPolygonRgn( const POINT* lppt,
430 const INT* lpPolyCounts,
431 int nCount,
432 int fnPolyFillMode)
433 {
434 return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) lpPolyCounts, (ULONG) nCount, GdiPolyPolyRgn );
435 }
436
437 /*
438 * @implemented
439 */
440 HRGN
441 WINAPI
442 CreateRectRgn(int x1, int y1, int x2, int y2)
443 {
444 PRGN_ATTR pRgn_Attr;
445 HRGN hrgn;
446 int tmp;
447
448 /* Normalize points */
449 tmp = x1;
450 if ( x1 > x2 )
451 {
452 x1 = x2;
453 x2 = tmp;
454 }
455
456 tmp = y1;
457 if ( y1 > y2 )
458 {
459 y1 = y2;
460 y2 = tmp;
461 }
462 /* Check outside 24 bit limit for universal set. Chp 9 Areas, pg 560.*/
463 if ( x1 < -(1<<27) ||
464 y1 < -(1<<27) ||
465 x2 > (1<<27)-1 ||
466 y2 > (1<<27)-1 )
467 {
468 SetLastError(ERROR_INVALID_PARAMETER);
469 return NULL;
470 }
471
472 hrgn = hGetPEBHandle(hctRegionHandle, 0);
473
474 if (!hrgn)
475 hrgn = NtGdiCreateRectRgn(0, 0, 1, 1);
476
477 if (!hrgn)
478 return hrgn;
479
480 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
481 {
482 DPRINT1("No Attr for Region handle!!!\n");
483 DeleteRegion(hrgn);
484 return NULL;
485 }
486
487 if (( x1 == x2) || (y1 == y2))
488 {
489 pRgn_Attr->Flags = NULLREGION;
490 pRgn_Attr->Rect.left = pRgn_Attr->Rect.top =
491 pRgn_Attr->Rect.right = pRgn_Attr->Rect.bottom = 0;
492 }
493 else
494 {
495 pRgn_Attr->Flags = SIMPLEREGION;
496 pRgn_Attr->Rect.left = x1;
497 pRgn_Attr->Rect.top = y1;
498 pRgn_Attr->Rect.right = x2;
499 pRgn_Attr->Rect.bottom = y2;
500 }
501
502 pRgn_Attr->AttrFlags = (ATTR_RGN_DIRTY|ATTR_RGN_VALID);
503
504 return hrgn;
505 }
506
507 /*
508 * @implemented
509 */
510 HRGN
511 WINAPI
512 CreateRectRgnIndirect(
513 const RECT *prc
514 )
515 {
516 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
517 return CreateRectRgn(prc->left, prc->top, prc->right, prc->bottom);
518
519 }
520
521 /*
522 * @implemented
523 */
524 INT
525 WINAPI
526 ExcludeClipRect(IN HDC hdc, IN INT xLeft, IN INT yTop, IN INT xRight, IN INT yBottom)
527 {
528 #if 0
529 // Handle something other than a normal dc object.
530 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
531 {
532 if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
533 return MFDRV_ExcludeClipRect( hdc, xLeft, yTop, xRight, yBottom);
534 else
535 {
536 PLDC pLDC = GdiGetLDC(hdc);
537 if ( pLDC )
538 {
539 if (pLDC->iType != LDC_EMFLDC || EMFDRV_ExcludeClipRect( hdc, xLeft, yTop, xRight, yBottom))
540 return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
541 }
542 else
543 SetLastError(ERROR_INVALID_HANDLE);
544 return ERROR;
545 }
546 }
547 #endif
548 return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
549 }
550
551 /*
552 * @implemented
553 */
554 HRGN
555 WINAPI
556 ExtCreateRegion(
557 CONST XFORM * lpXform,
558 DWORD nCount,
559 CONST RGNDATA * lpRgnData
560 )
561 {
562 if (lpRgnData)
563 {
564 if ((!lpXform) && (lpRgnData->rdh.nCount == 1))
565 {
566 PRECT pRect = (PRECT)&lpRgnData->Buffer[0];
567 return CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
568 }
569 return NtGdiExtCreateRegion((LPXFORM) lpXform, nCount,(LPRGNDATA) lpRgnData);
570 }
571 SetLastError(ERROR_INVALID_PARAMETER);
572 return NULL;
573 }
574
575 /*
576 * @implemented
577 */
578 INT
579 WINAPI
580 ExtSelectClipRgn( IN HDC hdc, IN HRGN hrgn, IN INT iMode)
581 {
582 /* FIXME some part need be done on user mode size */
583 return NtGdiExtSelectClipRgn(hdc,hrgn, iMode);
584 }
585
586 /*
587 * @implemented
588 */
589 int
590 WINAPI
591 GetClipRgn(
592 HDC hdc,
593 HRGN hrgn
594 )
595 {
596 INT Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
597 // if (Ret)
598 // {
599 // if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL);
600 // }
601 return Ret;
602 }
603
604 /*
605 * @implemented
606 */
607 int
608 WINAPI
609 GetMetaRgn(HDC hdc,
610 HRGN hrgn)
611 {
612 return NtGdiGetRandomRgn(hdc, hrgn, METARGN);
613 }
614
615 /*
616 * @implemented
617 *
618 */
619 DWORD
620 WINAPI
621 GetRegionData(HRGN hrgn,
622 DWORD nCount,
623 LPRGNDATA lpRgnData)
624 {
625 if (!lpRgnData)
626 {
627 nCount = 0;
628 }
629
630 return NtGdiGetRegionData(hrgn,nCount,lpRgnData);
631 }
632
633 /*
634 * @implemented
635 *
636 */
637 INT
638 WINAPI
639 GetRgnBox(HRGN hrgn,
640 LPRECT prcOut)
641 {
642 PRGN_ATTR Rgn_Attr;
643
644 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
645 return NtGdiGetRgnBox(hrgn, prcOut);
646
647 if (Rgn_Attr->Flags == NULLREGION)
648 {
649 prcOut->left = 0;
650 prcOut->top = 0;
651 prcOut->right = 0;
652 prcOut->bottom = 0;
653 }
654 else
655 {
656 if (Rgn_Attr->Flags != SIMPLEREGION)
657 return NtGdiGetRgnBox(hrgn, prcOut);
658 /* WARNING! prcOut is never checked newbies! */
659 RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT));
660 }
661 return Rgn_Attr->Flags;
662 }
663
664 /*
665 * @implemented
666 */
667 INT
668 WINAPI
669 IntersectClipRect(HDC hdc,
670 int nLeftRect,
671 int nTopRect,
672 int nRightRect,
673 int nBottomRect)
674 {
675 #if 0
676 // Handle something other than a normal dc object.
677 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
678 {
679 if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
680 return MFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
681 else
682 {
683 PLDC pLDC = GdiGetLDC(hdc);
684 if ( pLDC )
685 {
686 if (pLDC->iType != LDC_EMFLDC || EMFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect))
687 return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
688 }
689 else
690 SetLastError(ERROR_INVALID_HANDLE);
691 return ERROR;
692 }
693 }
694 #endif
695 return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
696 }
697
698 /*
699 * @implemented
700 */
701 BOOL
702 WINAPI
703 MirrorRgn(HWND hwnd, HRGN hrgn)
704 {
705 RECT Rect;
706 GetWindowRect(hwnd, &Rect);
707 return MirrorRgnByWidth(hrgn, Rect.right - Rect.left, NULL);
708 }
709
710 /*
711 * @implemented
712 */
713 INT
714 WINAPI
715 OffsetClipRgn(HDC hdc,
716 int nXOffset,
717 int nYOffset)
718 {
719 #if 0
720 // Handle something other than a normal dc object.
721 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
722 {
723 if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
724 return MFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset );
725 else
726 {
727 PLDC pLDC = GdiGetLDC(hdc);
728 if ( !pLDC )
729 {
730 SetLastError(ERROR_INVALID_HANDLE);
731 return ERROR;
732 }
733 if (pLDC->iType == LDC_EMFLDC && !EMFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset ))
734 return ERROR;
735 return NtGdiOffsetClipRgn( hdc, nXOffset, nYOffset);
736 }
737 }
738 #endif
739 return NtGdiOffsetClipRgn( hdc, nXOffset, nYOffset);
740 }
741
742 /*
743 * @implemented
744 *
745 */
746 INT
747 WINAPI
748 OffsetRgn( HRGN hrgn,
749 int nXOffset,
750 int nYOffset)
751 {
752 PRGN_ATTR pRgn_Attr;
753 int nLeftRect, nTopRect, nRightRect, nBottomRect;
754
755 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
756 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
757
758 if ( pRgn_Attr->Flags == NULLREGION)
759 return pRgn_Attr->Flags;
760
761 if ( pRgn_Attr->Flags != SIMPLEREGION)
762 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
763
764 nLeftRect = pRgn_Attr->Rect.left;
765 nTopRect = pRgn_Attr->Rect.top;
766 nRightRect = pRgn_Attr->Rect.right;
767 nBottomRect = pRgn_Attr->Rect.bottom;
768
769 if (nLeftRect < nRightRect)
770 {
771 if (nTopRect < nBottomRect)
772 {
773 nLeftRect = nXOffset + nLeftRect;
774 nTopRect = nYOffset + nTopRect;
775 nRightRect = nXOffset + nRightRect;
776 nBottomRect = nYOffset + nBottomRect;
777
778 /* Check 28 bit limit. Chp 9 Areas, pg 560. */
779 if ( nLeftRect < -(1<<27) ||
780 nTopRect < -(1<<27) ||
781 nRightRect > (1<<27)-1 ||
782 nBottomRect > (1<<27)-1 )
783 {
784 return ERROR;
785 }
786
787 pRgn_Attr->Rect.top = nTopRect;
788 pRgn_Attr->Rect.left = nLeftRect;
789 pRgn_Attr->Rect.right = nRightRect;
790 pRgn_Attr->Rect.bottom = nBottomRect;
791 pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
792 }
793 }
794 return pRgn_Attr->Flags;
795 }
796
797 /*
798 * @implemented
799 */
800 BOOL
801 WINAPI
802 PtInRegion(IN HRGN hrgn,
803 int x,
804 int y)
805 {
806 PRGN_ATTR pRgn_Attr;
807
808 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
809 return NtGdiPtInRegion(hrgn,x,y);
810
811 if ( pRgn_Attr->Flags == NULLREGION)
812 return FALSE;
813
814 if ( pRgn_Attr->Flags != SIMPLEREGION)
815 return NtGdiPtInRegion(hrgn,x,y);
816
817 return INRECT( pRgn_Attr->Rect, x, y);
818 }
819
820 /*
821 * @implemented
822 */
823 BOOL
824 WINAPI
825 RectInRegion(HRGN hrgn,
826 LPCRECT prcl)
827 {
828 PRGN_ATTR pRgn_Attr;
829 RECTL rc;
830
831 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
832 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
833
834 if ( pRgn_Attr->Flags == NULLREGION)
835 return FALSE;
836
837 if ( pRgn_Attr->Flags != SIMPLEREGION)
838 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
839
840 /* swap the coordinates to make right >= left and bottom >= top */
841 /* (region building rectangles are normalized the same way) */
842 if ( prcl->top > prcl->bottom)
843 {
844 rc.top = prcl->bottom;
845 rc.bottom = prcl->top;
846 }
847 else
848 {
849 rc.top = prcl->top;
850 rc.bottom = prcl->bottom;
851 }
852 if ( prcl->right < prcl->left)
853 {
854 rc.right = prcl->left;
855 rc.left = prcl->right;
856 }
857 else
858 {
859 rc.right = prcl->right;
860 rc.left = prcl->left;
861 }
862
863 if ( ComplexityFromRects( &pRgn_Attr->Rect, &rc) != DIFF_RGN )
864 return TRUE;
865
866 return FALSE;
867 }
868
869 /*
870 * @implemented
871 */
872 int WINAPI
873 SelectClipRgn(
874 HDC hdc,
875 HRGN hrgn
876 )
877 {
878 return ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
879 }
880
881 /*
882 * @implemented
883 */
884 BOOL
885 WINAPI
886 SetRectRgn(HRGN hrgn,
887 int nLeftRect,
888 int nTopRect,
889 int nRightRect,
890 int nBottomRect)
891 {
892 PRGN_ATTR Rgn_Attr;
893
894 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
895 return NtGdiSetRectRgn(hrgn, nLeftRect, nTopRect, nRightRect, nBottomRect);
896
897 if ((nLeftRect == nRightRect) || (nTopRect == nBottomRect))
898 {
899 Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
900 Rgn_Attr->Flags = NULLREGION;
901 Rgn_Attr->Rect.left = Rgn_Attr->Rect.top =
902 Rgn_Attr->Rect.right = Rgn_Attr->Rect.bottom = 0;
903 return TRUE;
904 }
905
906 Rgn_Attr->Rect.left = nLeftRect;
907 Rgn_Attr->Rect.top = nTopRect;
908 Rgn_Attr->Rect.right = nRightRect;
909 Rgn_Attr->Rect.bottom = nBottomRect;
910
911 if(nLeftRect > nRightRect)
912 {
913 Rgn_Attr->Rect.left = nRightRect;
914 Rgn_Attr->Rect.right = nLeftRect;
915 }
916 if(nTopRect > nBottomRect)
917 {
918 Rgn_Attr->Rect.top = nBottomRect;
919 Rgn_Attr->Rect.bottom = nTopRect;
920 }
921
922 Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY ;
923 Rgn_Attr->Flags = SIMPLEREGION;
924 return TRUE;
925 }
926
927 /*
928 * @implemented
929 */
930 int
931 WINAPI
932 SetMetaRgn( HDC hDC )
933 {
934 if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
935 return NtGdiSetMetaRgn(hDC);
936 #if 0
937 PLDC pLDC = GdiGetLDC(hDC);
938 if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
939 {
940 if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
941 {
942 return NtGdiSetMetaRgn(hDC);
943 }
944 else
945 SetLastError(ERROR_INVALID_HANDLE);
946 }
947 #endif
948 return ERROR;
949 }
950