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