[win32k]
[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 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 INT Ret;
583 HRGN NewRgn = NULL;
584
585 #if 0
586 // Handle something other than a normal dc object.
587 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
588 {
589 if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
590 return MFDRV_ExtSelectClipRgn( hdc, );
591 else
592 {
593 PLDC pLDC = GdiGetLDC(hdc);
594 if ( pLDC )
595 {
596 if (pLDC->iType != LDC_EMFLDC || EMFDRV_ExtSelectClipRgn( hdc, ))
597 return NtGdiExtSelectClipRgn(hdc, );
598 }
599 else
600 SetLastError(ERROR_INVALID_HANDLE);
601 return ERROR;
602 }
603 }
604 #endif
605 #if 0
606 if ( hrgn )
607 {
608 if ( GetLayout(hdc) & LAYOUT_RTL )
609 {
610 if ( MirrorRgnDC(hdc, hrgn, &NewRgn) )
611 {
612 if ( NewRgn ) hrgn = NewRgn;
613 }
614 }
615 }
616 #endif
617 /* Batch handles RGN_COPY only! */
618 if (iMode == RGN_COPY)
619 {
620 #if 0
621 PDC_ATTR pDc_Attr;
622 PRGN_ATTR pRgn_Attr = NULL;
623
624 /* hrgn can be NULL unless the RGN_COPY mode is specified. */
625 if (hrgn)
626 GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr);
627
628 if ( GdiGetHandleUserData((HGDIOBJ) hdc, GDI_OBJECT_TYPE_DC, (PVOID) &pDc_Attr) &&
629 pDc_Attr )
630 {
631 PGDI_TABLE_ENTRY pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hdc);
632 PTEB pTeb = NtCurrentTeb();
633
634 if ( pTeb->Win32ThreadInfo != NULL &&
635 pTeb->GdiTebBatch.HDC == hdc &&
636 !(pDc_Attr->ulDirty_ & DC_DIBSECTION) &&
637 !(pEntry->Flags & GDI_ENTRY_VALIDATE_VIS) )
638 {
639 if (!hrgn ||
640 (hrgn && pRgn_Attr && pRgn_Attr->Flags <= SIMPLEREGION) )
641 {
642 if ((pTeb->GdiTebBatch.Offset + sizeof(GDIBSEXTSELCLPRGN)) <= GDIBATCHBUFSIZE)
643 {
644 PGDIBSEXTSELCLPRGN pgO = (PGDIBSEXTSELCLPRGN)(&pTeb->GdiTebBatch.Buffer[0] +
645 pTeb->GdiTebBatch.Offset);
646 pgO->gbHdr.Cmd = GdiBCExtSelClipRgn;
647 pgO->gbHdr.Size = sizeof(GDIBSEXTSELCLPRGN);
648 pgO->fnMode = iMode;
649
650 if ( hrgn && pRgn_Attr )
651 {
652 Ret = pRgn_Attr->Flags;
653
654 if ( pDc_Attr->VisRectRegion.Rect.left >= pRgn_Attr->Rect.right ||
655 pDc_Attr->VisRectRegion.Rect.top >= pRgn_Attr->Rect.bottom ||
656 pDc_Attr->VisRectRegion.Rect.right <= pRgn_Attr->Rect.left ||
657 pDc_Attr->VisRectRegion.Rect.bottom <= pRgn_Attr->Rect.top )
658 Ret = NULLREGION;
659
660 pgO->left = pRgn_Attr->Rect.left;
661 pgO->top = pRgn_Attr->Rect.top;
662 pgO->right = pRgn_Attr->Rect.right;
663 pgO->bottom = pRgn_Attr->Rect.bottom;
664 }
665 else
666 {
667 Ret = pDc_Attr->VisRectRegion.Flags;
668 pgO->fnMode |= 0x80000000; // Set no hrgn mode.
669 }
670 pTeb->GdiTebBatch.Offset += sizeof(GDIBSEXTSELCLPRGN);
671 pTeb->GdiBatchCount++;
672 if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
673 if ( NewRgn ) DeleteObject(NewRgn);
674 return Ret;
675 }
676 }
677 }
678 }
679 #endif
680 }
681 Ret = NtGdiExtSelectClipRgn(hdc, hrgn, iMode);
682
683 if ( NewRgn ) DeleteObject(NewRgn);
684
685 return Ret;
686 }
687
688 /*
689 * @implemented
690 */
691 int
692 WINAPI
693 GetClipRgn(
694 HDC hdc,
695 HRGN hrgn
696 )
697 {
698 INT Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
699 // if (Ret)
700 // {
701 // if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL);
702 // }
703 return Ret;
704 }
705
706 /*
707 * @implemented
708 */
709 int
710 WINAPI
711 GetMetaRgn(HDC hdc,
712 HRGN hrgn)
713 {
714 return NtGdiGetRandomRgn(hdc, hrgn, METARGN);
715 }
716
717 /*
718 * @implemented
719 *
720 */
721 DWORD
722 WINAPI
723 GetRegionData(HRGN hrgn,
724 DWORD nCount,
725 LPRGNDATA lpRgnData)
726 {
727 if (!lpRgnData)
728 {
729 nCount = 0;
730 }
731
732 return NtGdiGetRegionData(hrgn,nCount,lpRgnData);
733 }
734
735 /*
736 * @implemented
737 *
738 */
739 INT
740 WINAPI
741 GetRgnBox(HRGN hrgn,
742 LPRECT prcOut)
743 {
744 PRGN_ATTR Rgn_Attr;
745
746 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
747 return NtGdiGetRgnBox(hrgn, prcOut);
748
749 if (Rgn_Attr->Flags == NULLREGION)
750 {
751 prcOut->left = 0;
752 prcOut->top = 0;
753 prcOut->right = 0;
754 prcOut->bottom = 0;
755 }
756 else
757 {
758 if (Rgn_Attr->Flags != SIMPLEREGION)
759 return NtGdiGetRgnBox(hrgn, prcOut);
760 /* WARNING! prcOut is never checked newbies! */
761 RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT));
762 }
763 return Rgn_Attr->Flags;
764 }
765
766 /*
767 * @implemented
768 */
769 INT
770 WINAPI
771 IntersectClipRect(HDC hdc,
772 int nLeftRect,
773 int nTopRect,
774 int nRightRect,
775 int nBottomRect)
776 {
777 #if 0
778 // Handle something other than a normal dc object.
779 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
780 {
781 if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
782 return MFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
783 else
784 {
785 PLDC pLDC = GdiGetLDC(hdc);
786 if ( pLDC )
787 {
788 if (pLDC->iType != LDC_EMFLDC || EMFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect))
789 return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
790 }
791 else
792 SetLastError(ERROR_INVALID_HANDLE);
793 return ERROR;
794 }
795 }
796 #endif
797 return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
798 }
799
800 /*
801 * @implemented
802 */
803 BOOL
804 WINAPI
805 MirrorRgn(HWND hwnd, HRGN hrgn)
806 {
807 RECT Rect;
808 GetWindowRect(hwnd, &Rect);
809 return MirrorRgnByWidth(hrgn, Rect.right - Rect.left, NULL);
810 }
811
812 /*
813 * @implemented
814 */
815 INT
816 WINAPI
817 OffsetClipRgn(HDC hdc,
818 int nXOffset,
819 int nYOffset)
820 {
821 #if 0
822 // Handle something other than a normal dc object.
823 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
824 {
825 if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
826 return MFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset );
827 else
828 {
829 PLDC pLDC = GdiGetLDC(hdc);
830 if ( !pLDC )
831 {
832 SetLastError(ERROR_INVALID_HANDLE);
833 return ERROR;
834 }
835 if (pLDC->iType == LDC_EMFLDC && !EMFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset ))
836 return ERROR;
837 return NtGdiOffsetClipRgn( hdc, nXOffset, nYOffset);
838 }
839 }
840 #endif
841 return NtGdiOffsetClipRgn( hdc, nXOffset, nYOffset);
842 }
843
844 /*
845 * @implemented
846 *
847 */
848 INT
849 WINAPI
850 OffsetRgn( HRGN hrgn,
851 int nXOffset,
852 int nYOffset)
853 {
854 PRGN_ATTR pRgn_Attr;
855 int nLeftRect, nTopRect, nRightRect, nBottomRect;
856
857 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
858 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
859
860 if ( pRgn_Attr->Flags == NULLREGION)
861 return pRgn_Attr->Flags;
862
863 if ( pRgn_Attr->Flags != SIMPLEREGION)
864 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
865
866 nLeftRect = pRgn_Attr->Rect.left;
867 nTopRect = pRgn_Attr->Rect.top;
868 nRightRect = pRgn_Attr->Rect.right;
869 nBottomRect = pRgn_Attr->Rect.bottom;
870
871 if (nLeftRect < nRightRect)
872 {
873 if (nTopRect < nBottomRect)
874 {
875 nLeftRect = nXOffset + nLeftRect;
876 nTopRect = nYOffset + nTopRect;
877 nRightRect = nXOffset + nRightRect;
878 nBottomRect = nYOffset + nBottomRect;
879
880 /* Check 28 bit limit. Chp 9 Areas, pg 560. */
881 if ( nLeftRect < -(1<<27) ||
882 nTopRect < -(1<<27) ||
883 nRightRect > (1<<27)-1 ||
884 nBottomRect > (1<<27)-1 )
885 {
886 return ERROR;
887 }
888
889 pRgn_Attr->Rect.top = nTopRect;
890 pRgn_Attr->Rect.left = nLeftRect;
891 pRgn_Attr->Rect.right = nRightRect;
892 pRgn_Attr->Rect.bottom = nBottomRect;
893 pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
894 }
895 }
896 return pRgn_Attr->Flags;
897 }
898
899 /*
900 * @implemented
901 */
902 BOOL
903 WINAPI
904 PtInRegion(IN HRGN hrgn,
905 int x,
906 int y)
907 {
908 PRGN_ATTR pRgn_Attr;
909
910 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
911 return NtGdiPtInRegion(hrgn,x,y);
912
913 if ( pRgn_Attr->Flags == NULLREGION)
914 return FALSE;
915
916 if ( pRgn_Attr->Flags != SIMPLEREGION)
917 return NtGdiPtInRegion(hrgn,x,y);
918
919 return INRECT( pRgn_Attr->Rect, x, y);
920 }
921
922 /*
923 * @implemented
924 */
925 BOOL
926 WINAPI
927 RectInRegion(HRGN hrgn,
928 LPCRECT prcl)
929 {
930 PRGN_ATTR pRgn_Attr;
931 RECTL rc;
932
933 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
934 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
935
936 if ( pRgn_Attr->Flags == NULLREGION)
937 return FALSE;
938
939 if ( pRgn_Attr->Flags != SIMPLEREGION)
940 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
941
942 /* swap the coordinates to make right >= left and bottom >= top */
943 /* (region building rectangles are normalized the same way) */
944 if ( prcl->top > prcl->bottom)
945 {
946 rc.top = prcl->bottom;
947 rc.bottom = prcl->top;
948 }
949 else
950 {
951 rc.top = prcl->top;
952 rc.bottom = prcl->bottom;
953 }
954 if ( prcl->right < prcl->left)
955 {
956 rc.right = prcl->left;
957 rc.left = prcl->right;
958 }
959 else
960 {
961 rc.right = prcl->right;
962 rc.left = prcl->left;
963 }
964
965 if ( ComplexityFromRects( &pRgn_Attr->Rect, &rc) != DIFF_RGN )
966 return TRUE;
967
968 return FALSE;
969 }
970
971 /*
972 * @implemented
973 */
974 int WINAPI
975 SelectClipRgn(
976 HDC hdc,
977 HRGN hrgn
978 )
979 {
980 return ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
981 }
982
983 /*
984 * @implemented
985 */
986 BOOL
987 WINAPI
988 SetRectRgn(HRGN hrgn,
989 int nLeftRect,
990 int nTopRect,
991 int nRightRect,
992 int nBottomRect)
993 {
994 PRGN_ATTR Rgn_Attr;
995
996 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
997 return NtGdiSetRectRgn(hrgn, nLeftRect, nTopRect, nRightRect, nBottomRect);
998
999 if ((nLeftRect == nRightRect) || (nTopRect == nBottomRect))
1000 {
1001 Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
1002 Rgn_Attr->Flags = NULLREGION;
1003 Rgn_Attr->Rect.left = Rgn_Attr->Rect.top =
1004 Rgn_Attr->Rect.right = Rgn_Attr->Rect.bottom = 0;
1005 return TRUE;
1006 }
1007
1008 Rgn_Attr->Rect.left = nLeftRect;
1009 Rgn_Attr->Rect.top = nTopRect;
1010 Rgn_Attr->Rect.right = nRightRect;
1011 Rgn_Attr->Rect.bottom = nBottomRect;
1012
1013 if(nLeftRect > nRightRect)
1014 {
1015 Rgn_Attr->Rect.left = nRightRect;
1016 Rgn_Attr->Rect.right = nLeftRect;
1017 }
1018 if(nTopRect > nBottomRect)
1019 {
1020 Rgn_Attr->Rect.top = nBottomRect;
1021 Rgn_Attr->Rect.bottom = nTopRect;
1022 }
1023
1024 Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY ;
1025 Rgn_Attr->Flags = SIMPLEREGION;
1026 return TRUE;
1027 }
1028
1029 /*
1030 * @implemented
1031 */
1032 int
1033 WINAPI
1034 SetMetaRgn( HDC hDC )
1035 {
1036 if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
1037 return NtGdiSetMetaRgn(hDC);
1038 #if 0
1039 PLDC pLDC = GdiGetLDC(hDC);
1040 if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
1041 {
1042 if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
1043 {
1044 return NtGdiSetMetaRgn(hDC);
1045 }
1046 else
1047 SetLastError(ERROR_INVALID_HANDLE);
1048 }
1049 #endif
1050 return ERROR;
1051 }
1052