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