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