1 #include "precomp.h"
3 #define INRECT(r, x, y) \
4 ( ( ((r).right > x)) && \
5 ( ((r).left <= x)) && \
6 ( ((r).bottom > y)) && \
7 ( ((r).top <= y)) )
9 static
10 INT
11 FASTCALL
12 ComplexityFromRects( PRECT prc1, PRECT prc2)
13 {
14 if ( prc2->left >= prc1->left )
15 {
16 if ( ( prc1->right >= prc2->right) &&
17 ( prc1->top <= prc2->top ) &&
18 ( prc1->bottom <= prc2->bottom ) )
19 return SIMPLEREGION;
21 if ( prc2->left > prc1->left )
22 {
23 if ( ( prc1->left >= prc2->right ) ||
24 ( prc1->right <= prc2->left ) ||
25 ( prc1->top >= prc2->bottom ) ||
26 ( prc1->bottom <= prc2->top ) )
27 return COMPLEXREGION;
28 }
29 }
31 if ( ( prc2->right < prc1->right ) ||
32 ( prc2->top > prc1->top ) ||
33 ( prc2->bottom < prc1->bottom ) )
34 {
35 if ( ( prc1->left >= prc2->right ) ||
36 ( prc1->right <= prc2->left ) ||
37 ( prc1->top >= prc2->bottom ) ||
38 ( prc1->bottom <= prc2->top ) )
39 return COMPLEXREGION;
40 }
41 else
42 {
43 return NULLREGION;
44 }
46 return ERROR;
47 }
49 static
50 VOID
51 FASTCALL
52 SortRects(PRECT pRect, INT nCount)
53 {
54 INT i = 0, a = 0, b = 0, c, s;
55 RECT sRect;
57 if (nCount > 0)
58 {
59 i = 1; // set index point
60 c = nCount; // set inverse count
61 do
62 {
63 s = i; // set sort count
64 if ( i < nCount )
65 {
66 a = i - 1;
67 b = i;
68 do
69 {
70 if(pRect[b].top != pRect[i].bottom) break;
71 if(pRect[b].left < pRect[a].left)
72 {
73 sRect = pRect[a];
74 pRect[a] = pRect[b];
75 pRect[b] = sRect;
76 }
77 ++s;
78 ++b;
79 } while ( s < nCount );
80 }
81 ++i;
82 } while ( c-- != 1 );
83 }
84 }
86 /*
87 * I thought it was okay to have this in DeleteObject but~ Speed. (jt)
88 */
89 BOOL
90 FASTCALL
91 DeleteRegion( HRGN hRgn )
92 {
93 #if 0
94 PRGN_ATTR Rgn_Attr;
96 if ((GdiGetHandleUserData((HGDIOBJ) hRgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr)) &&
97 ( Rgn_Attr != NULL ))
98 {
99 PTEB pTeb = NtCurrentTeb();
101 {
102 if ((pTeb->GdiTebBatch.Offset + sizeof(GDIBSOBJECT)) <= GDIBATCHBUFSIZE)
103 {
104 PGDIBSOBJECT pgO = (PGDIBSOBJECT)(&pTeb->GdiTebBatch.Buffer[0] +
105 pTeb->GdiTebBatch.Offset);
106 pgO->gbHdr.Cmd = GdiBCDelRgn;
107 pgO->gbHdr.Size = sizeof(GDIBSOBJECT);
108 pgO->hgdiobj = (HGDIOBJ)hRgn;
110 pTeb->GdiTebBatch.Offset += sizeof(GDIBSOBJECT);
111 pTeb->GdiBatchCount++;
112 if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
113 return TRUE;
114 }
115 }
116 }
117 #endif
118 return NtGdiDeleteObjectApp((HGDIOBJ) hRgn);
119 }
121 INT
122 FASTCALL
123 MirrorRgnByWidth(HRGN hRgn, INT Width, HRGN *phRgn)
124 {
125 INT cRgnDSize, Ret = 0;
126 PRGNDATA pRgnData;
128 cRgnDSize = NtGdiGetRegionData(hRgn, 0, NULL);
130 if (cRgnDSize)
131 {
132 pRgnData = LocalAlloc(LMEM_FIXED, cRgnDSize * sizeof(LONG));
133 if (pRgnData)
134 {
135 if ( GetRegionData(hRgn, cRgnDSize, pRgnData) )
136 {
137 HRGN hRgnex;
138 UINT i;
139 INT SaveL = pRgnData->rdh.rcBound.left;
140 pRgnData->rdh.rcBound.left = Width - pRgnData->rdh.rcBound.right;
141 pRgnData->rdh.rcBound.right = Width - SaveL;
142 if (pRgnData->rdh.nCount > 0)
143 {
144 PRECT pRect = (PRECT)&pRgnData->Buffer;
145 for (i = 0; i < pRgnData->rdh.nCount; i++)
146 {
147 SaveL = pRect[i].left;
148 pRect[i].left = Width - pRect[i].right;
149 pRect[i].right = Width - SaveL;
150 }
151 }
152 SortRects((PRECT)&pRgnData->Buffer, pRgnData->rdh.nCount);
153 hRgnex = ExtCreateRegion(NULL, cRgnDSize , pRgnData);
154 if (hRgnex)
155 {
156 if (phRgn) phRgn = (HRGN *)hRgnex;
157 else
158 {
159 CombineRgn(hRgn, hRgnex, 0, RGN_COPY);
160 DeleteObject(hRgnex);
161 }
162 Ret = 1;
163 }
164 }
165 LocalFree(pRgnData);
166 }
167 }
168 return Ret;
169 }
171 INT
172 WINAPI
173 MirrorRgnDC(HDC hdc, HRGN hRgn, HRGN *phRgn)
174 {
175 if (!GdiIsHandleValid((HGDIOBJ) hdc) ||
176 (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)) return 0;
178 return MirrorRgnByWidth(hRgn, NtGdiGetDeviceWidth(hdc), phRgn);
179 }
181 /* FUNCTIONS *****************************************************************/
183 /*
184 * @unimplemented
185 */
186 INT
187 WINAPI
188 CombineRgn(HRGN hDest,
189 HRGN hSrc1,
190 HRGN hSrc2,
191 INT CombineMode)
192 {
193 /* FIXME some part should be done in user mode */
194 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
195 }
197 /*
198 * @implemented
199 */
200 HRGN
201 WINAPI
202 CreatePolygonRgn( const POINT * lppt, int cPoints, int fnPolyFillMode)
203 {
204 return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) &cPoints, 1, GdiPolyPolyRgn);
205 }
207 /*
208 * @implemented
209 */
210 HRGN
211 WINAPI
212 CreatePolyPolygonRgn( const POINT* lppt,
213 const INT* lpPolyCounts,
214 int nCount,
215 int fnPolyFillMode)
216 {
217 return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) lpPolyCounts, (ULONG) nCount, GdiPolyPolyRgn );
218 }
220 /*
221 * @implemented
222 */
223 HRGN
224 WINAPI
225 CreateEllipticRgnIndirect(
226 const RECT *prc
227 )
228 {
229 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
230 return NtGdiCreateEllipticRgn(prc->left, prc->top, prc->right, prc->bottom);
232 }
234 /*
235 * @implemented
236 */
237 HRGN
238 WINAPI
239 CreateRectRgn(int x1, int y1, int x2, int y2)
240 {
241 PRGN_ATTR pRgn_Attr;
242 HRGN hrgn;
243 int x, y;
245 /* Normalize points */
246 x = x1;
247 if ( x1 > x2 )
248 {
249 x1 = x2;
250 x2 = x;
251 }
253 y = y1;
254 if ( y1 > y2 )
255 {
256 y1 = y2;
257 y2 = y;
258 }
260 if ( (UINT)x1 < 0x80000000 ||
261 (UINT)y1 < 0x80000000 ||
262 (UINT)x2 > 0x7FFFFFFF ||
263 (UINT)y2 > 0x7FFFFFFF )
264 {
265 SetLastError(ERROR_INVALID_PARAMETER);
266 return NULL;
267 }
268 //// Remove when Brush/Pen/Rgn Attr is ready!
269 return NtGdiCreateRectRgn(x1,y1,x2,y2);
270 ////
271 hrgn = hGetPEBHandle(hctRegionHandle, 0);
273 if (!hrgn)
274 hrgn = NtGdiCreateRectRgn(0, 0, 1, 1);
276 if (!hrgn)
277 return hrgn;
279 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
280 {
281 DeleteRegion(hrgn);
282 return NULL;
283 }
285 if (( x1 == x2) || (y1 == y2))
286 {
287 pRgn_Attr->Flags = NULLREGION;
288 pRgn_Attr->Rect.left = pRgn_Attr->Rect.top =
289 pRgn_Attr->Rect.right = pRgn_Attr->Rect.bottom = 0;
290 }
291 else
292 {
293 pRgn_Attr->Flags = SIMPLEREGION;
294 pRgn_Attr->Rect.left = x1;
295 pRgn_Attr->Rect.top = y1;
296 pRgn_Attr->Rect.right = x2;
297 pRgn_Attr->Rect.bottom = y2;
298 }
300 pRgn_Attr->AttrFlags = (ATTR_RGN_DIRTY|ATTR_RGN_VALID);
302 return hrgn;
303 }
305 /*
306 * @implemented
307 */
308 HRGN
309 WINAPI
310 CreateRectRgnIndirect(
311 const RECT *prc
312 )
313 {
314 /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
315 return CreateRectRgn(prc->left, prc->top, prc->right, prc->bottom);
317 }
319 /*
320 * @implemented
321 */
322 INT
323 WINAPI
324 ExcludeClipRect(IN HDC hdc, IN INT xLeft, IN INT yTop, IN INT xRight, IN INT yBottom)
325 {
326 #if 0
327 // Handle something other than a normal dc object.
328 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
329 {
331 return MFDRV_ExcludeClipRect( hdc, xLeft, yTop, xRight, yBottom);
332 else
333 {
334 PLDC pLDC = GdiGetLDC(hdc);
335 if ( pLDC )
336 {
337 if (pLDC->iType != LDC_EMFLDC || EMFDRV_ExcludeClipRect( hdc, xLeft, yTop, xRight, yBottom))
338 return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
339 }
340 else
341 SetLastError(ERROR_INVALID_HANDLE);
342 return ERROR;
343 }
344 }
345 #endif
346 return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
347 }
349 /*
350 * @implemented
351 */
352 HRGN
353 WINAPI
354 ExtCreateRegion(
355 CONST XFORM * lpXform,
356 DWORD nCount,
357 CONST RGNDATA * lpRgnData
358 )
359 {
360 if (lpRgnData)
361 {
362 if ((!lpXform) && (lpRgnData->rdh.nCount == 1))
363 {
364 PRECT pRect = (PRECT)&lpRgnData->Buffer[0];
365 return CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
366 }
367 return NtGdiExtCreateRegion((LPXFORM) lpXform, nCount,(LPRGNDATA) lpRgnData);
368 }
369 SetLastError(ERROR_INVALID_PARAMETER);
370 return NULL;
371 }
373 /*
374 * @implemented
375 */
376 INT
377 WINAPI
378 ExtSelectClipRgn( IN HDC hdc, IN HRGN hrgn, IN INT iMode)
379 {
380 /* FIXME some part need be done on user mode size */
381 return NtGdiExtSelectClipRgn(hdc,hrgn, iMode);
382 }
384 /*
385 * @implemented
386 */
387 int
388 WINAPI
389 GetClipRgn(
390 HDC hdc,
391 HRGN hrgn
392 )
393 {
394 INT Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
395 // if (Ret)
396 // {
397 // if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL);
398 // }
399 return Ret;
400 }
402 /*
403 * @implemented
404 */
405 int
406 WINAPI
407 GetMetaRgn(HDC hdc,
408 HRGN hrgn)
409 {
410 return NtGdiGetRandomRgn(hdc, hrgn, METARGN);
411 }
413 /*
414 * @implemented
415 *
416 */
417 DWORD
418 WINAPI
419 GetRegionData(HRGN hrgn,
420 DWORD nCount,
421 LPRGNDATA lpRgnData)
422 {
423 if (!lpRgnData)
424 {
425 nCount = 0;
426 }
428 return NtGdiGetRegionData(hrgn,nCount,lpRgnData);
429 }
431 /*
432 * @implemented
433 *
434 */
435 INT
436 WINAPI
437 GetRgnBox(HRGN hrgn,
438 LPRECT prcOut)
439 {
440 PRGN_ATTR Rgn_Attr;
442 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
443 return NtGdiGetRgnBox(hrgn, prcOut);
445 if (Rgn_Attr->Flags == NULLREGION)
446 {
447 prcOut->left = 0;
448 prcOut->top = 0;
449 prcOut->right = 0;
450 prcOut->bottom = 0;
451 }
452 else
453 {
454 if (Rgn_Attr->Flags != SIMPLEREGION)
455 return NtGdiGetRgnBox(hrgn, prcOut);
456 /* WARNING! prcOut is never checked newbies! */
457 RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT));
458 }
459 return Rgn_Attr->Flags;
460 }
462 /*
463 * @implemented
464 */
465 INT
466 WINAPI
467 IntersectClipRect(HDC hdc,
468 int nLeftRect,
469 int nTopRect,
470 int nRightRect,
471 int nBottomRect)
472 {
473 #if 0
474 // Handle something other than a normal dc object.
475 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
476 {
478 return MFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
479 else
480 {
481 PLDC pLDC = GdiGetLDC(hdc);
482 if ( pLDC )
483 {
484 if (pLDC->iType != LDC_EMFLDC || EMFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect))
485 return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
486 }
487 else
488 SetLastError(ERROR_INVALID_HANDLE);
489 return ERROR;
490 }
491 }
492 #endif
493 return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
494 }
496 /*
497 * @implemented
498 */
499 BOOL
500 WINAPI
501 MirrorRgn(HWND hwnd, HRGN hrgn)
502 {
503 RECT Rect;
504 GetWindowRect(hwnd, &Rect);
505 return MirrorRgnByWidth(hrgn, Rect.right - Rect.left, NULL);
506 }
508 /*
509 * @implemented
510 */
511 INT
512 WINAPI
513 OffsetClipRgn(HDC hdc,
514 int nXOffset,
515 int nYOffset)
516 {
517 #if 0
518 // Handle something other than a normal dc object.
519 if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
520 {
522 return MFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset );
523 else
524 {
525 PLDC pLDC = GdiGetLDC(hdc);
526 if ( !pLDC )
527 {
528 SetLastError(ERROR_INVALID_HANDLE);
529 return ERROR;
530 }
531 if (pLDC->iType == LDC_EMFLDC && !EMFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset ))
532 return ERROR;
533 return NtGdiOffsetClipRgn( hdc, nXOffset, nYOffset);
534 }
535 }
536 #endif
537 return NtGdiOffsetClipRgn( hdc, nXOffset, nYOffset);
538 }
540 /*
541 * @implemented
542 *
543 */
544 INT
545 WINAPI
546 OffsetRgn( HRGN hrgn,
547 int nXOffset,
548 int nYOffset)
549 {
550 PRGN_ATTR pRgn_Attr;
551 int nLeftRect, nTopRect, nRightRect, nBottomRect;
553 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
554 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
556 if ( pRgn_Attr->Flags == NULLREGION)
557 return pRgn_Attr->Flags;
559 if ( pRgn_Attr->Flags != SIMPLEREGION)
560 return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
562 nLeftRect = pRgn_Attr->Rect.left;
563 nTopRect = pRgn_Attr->Rect.top;
564 nRightRect = pRgn_Attr->Rect.right;
565 nBottomRect = pRgn_Attr->Rect.bottom;
567 if (nLeftRect < nRightRect)
568 {
569 if (nTopRect < nBottomRect)
570 {
571 nLeftRect = nXOffset + nLeftRect;
572 nTopRect = nYOffset + nTopRect;
573 nRightRect = nXOffset + nRightRect;
574 nBottomRect = nYOffset + nBottomRect;
576 /* Mask and bit test. */
577 if ( ( nLeftRect & 0xF8000000 &&
578 (nLeftRect & 0xF8000000) != 0x80000000 ) ||
579 ( nTopRect & 0xF8000000 &&
580 (nTopRect & 0xF8000000) != 0x80000000 ) ||
581 ( nRightRect & 0xF8000000 &&
582 (nRightRect & 0xF8000000) != 0x80000000 ) ||
583 ( nBottomRect & 0xF8000000 &&
584 (nBottomRect & 0xF8000000) != 0x80000000 ) )
585 {
586 return ERROR;
587 }
588 else
589 {
590 pRgn_Attr->Rect.top = nTopRect;
591 pRgn_Attr->Rect.left = nLeftRect;
592 pRgn_Attr->Rect.right = nRightRect;
593 pRgn_Attr->Rect.bottom = nBottomRect;
594 pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
595 }
596 }
597 }
598 return pRgn_Attr->Flags;
599 }
601 /*
602 * @implemented
603 */
604 BOOL
605 WINAPI
606 PtInRegion(IN HRGN hrgn,
607 int x,
608 int y)
609 {
610 PRGN_ATTR pRgn_Attr;
612 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
613 return NtGdiPtInRegion(hrgn,x,y);
615 if ( pRgn_Attr->Flags == NULLREGION)
616 return FALSE;
618 if ( pRgn_Attr->Flags != SIMPLEREGION)
619 return NtGdiPtInRegion(hrgn,x,y);
621 return INRECT( pRgn_Attr->Rect, x, y);
622 }
624 /*
625 * @implemented
626 */
627 BOOL
628 WINAPI
629 RectInRegion(HRGN hrgn,
630 LPCRECT prcl)
631 {
632 PRGN_ATTR pRgn_Attr;
633 RECT rc;
635 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
636 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
638 if ( pRgn_Attr->Flags == NULLREGION)
639 return FALSE;
641 if ( pRgn_Attr->Flags != SIMPLEREGION)
642 return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
644 /* swap the coordinates to make right >= left and bottom >= top */
645 /* (region building rectangles are normalized the same way) */
646 if ( prcl->top > prcl->bottom)
647 {
648 rc.top = prcl->bottom;
649 rc.bottom = prcl->top;
650 }
651 else
652 {
653 rc.top = prcl->top;
654 rc.bottom = prcl->bottom;
655 }
656 if ( prcl->right < prcl->left)
657 {
658 rc.right = prcl->left;
659 rc.left = prcl->right;
660 }
661 else
662 {
663 rc.right = prcl->right;
664 rc.left = prcl->left;
665 }
667 if ( ComplexityFromRects( (PRECT)&pRgn_Attr->Rect, &rc) != COMPLEXREGION )
668 return TRUE;
670 return FALSE;
671 }
673 /*
674 * @implemented
675 */
676 int WINAPI
677 SelectClipRgn(
678 HDC hdc,
679 HRGN hrgn
680 )
681 {
682 return ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
683 }
685 /*
686 * @implemented
687 */
688 BOOL
689 WINAPI
690 SetRectRgn(HRGN hrgn,
691 int nLeftRect,
692 int nTopRect,
693 int nRightRect,
694 int nBottomRect)
695 {
696 PRGN_ATTR Rgn_Attr;
698 if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
699 return NtGdiSetRectRgn(hrgn, nLeftRect, nTopRect, nRightRect, nBottomRect);
701 if ((nLeftRect == nRightRect) || (nTopRect == nBottomRect))
702 {
703 Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
704 Rgn_Attr->Flags = NULLREGION;
705 Rgn_Attr->Rect.left = Rgn_Attr->Rect.top =
706 Rgn_Attr->Rect.right = Rgn_Attr->Rect.bottom = 0;
707 return TRUE;
708 }
710 Rgn_Attr->Rect.left = nLeftRect;
711 Rgn_Attr->Rect.top = nTopRect;
712 Rgn_Attr->Rect.right = nRightRect;
713 Rgn_Attr->Rect.bottom = nBottomRect;
715 if(nLeftRect > nRightRect)
716 {
717 Rgn_Attr->Rect.left = nRightRect;
718 Rgn_Attr->Rect.right = nLeftRect;
719 }
720 if(nTopRect > nBottomRect)
721 {
722 Rgn_Attr->Rect.top = nBottomRect;
723 Rgn_Attr->Rect.bottom = nTopRect;
724 }
726 Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY ;
727 Rgn_Attr->Flags = SIMPLEREGION;
728 return TRUE;
729 }
731 /*
732 * @implemented
733 */
734 int
735 WINAPI
736 SetMetaRgn( HDC hDC )
737 {
738 if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
739 return NtGdiSetMetaRgn(hDC);
740 #if 0
741 PLDC pLDC = GdiGetLDC(hDC);
742 if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
743 {
744 if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
745 {
746 return NtGdiSetMetaRgn(hDC);
747 }
748 else
749 SetLastError(ERROR_INVALID_HANDLE);
750 }
751 #endif
752 return ERROR;
753 }