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