ea88cf3047c93c8601ec8bfda8ca280c3ab8d60a
[reactos.git] / reactos / subsystems / win32 / win32k / objects / cliprgn.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <win32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 int FASTCALL
26 CLIPPING_UpdateGCRegion(DC* Dc)
27 {
28 PROSRGNDATA CombinedRegion;
29 HRGN hRgnVis = NULL;
30
31 /* Experiment with API region based on wine.. */
32 if (Dc->rosdc.hClipRgn && Dc->dclevel.prgnMeta)
33 {
34 PROSRGNDATA pClipRgn;
35
36 if ((pClipRgn = RGNOBJAPI_Lock(Dc->rosdc.hClipRgn, NULL)))
37 {
38 if (!Dc->prgnAPI) Dc->prgnAPI = IntSysCreateRectpRgn( 0, 0, 0, 0 );
39
40 IntGdiCombineRgn( Dc->prgnAPI,
41 pClipRgn,
42 Dc->dclevel.prgnMeta,
43 RGN_AND );
44 RGNOBJAPI_Unlock(pClipRgn);
45 }
46 }
47 else
48 {
49 if (Dc->prgnAPI)
50 GreDeleteObject(((PROSRGNDATA)Dc->prgnAPI)->BaseObject.hHmgr);
51 Dc->prgnAPI = NULL;
52 }
53
54
55 if (Dc->rosdc.hGCClipRgn == NULL)
56 Dc->rosdc.hGCClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
57
58 if (Dc->rosdc.hClipRgn == NULL)
59 NtGdiCombineRgn(Dc->rosdc.hGCClipRgn, ((PROSRGNDATA)Dc->prgnVis)->BaseObject.hHmgr, 0, RGN_COPY);
60 else
61 NtGdiCombineRgn(Dc->rosdc.hGCClipRgn, Dc->rosdc.hClipRgn, hRgnVis, RGN_AND);
62
63 NtGdiOffsetRgn(Dc->rosdc.hGCClipRgn, Dc->ptlDCOrig.x, Dc->ptlDCOrig.y);
64
65 if((CombinedRegion = RGNOBJAPI_Lock(Dc->rosdc.hGCClipRgn, NULL)))
66 {
67 CLIPOBJ *CombinedClip;
68
69 CombinedClip = IntEngCreateClipRegion(CombinedRegion->rdh.nCount,
70 CombinedRegion->Buffer,
71 &CombinedRegion->rdh.rcBound);
72
73 RGNOBJAPI_Unlock(CombinedRegion);
74
75 if (!CombinedClip)
76 {
77 DPRINT1("IntEngCreateClipRegion() failed\n");
78 return ERROR;
79 }
80
81 if (Dc->rosdc.CombinedClip != NULL)
82 IntEngDeleteClipRegion(Dc->rosdc.CombinedClip);
83
84 Dc->rosdc.CombinedClip = CombinedClip;
85 }
86
87
88 return NtGdiOffsetRgn(Dc->rosdc.hGCClipRgn, -Dc->ptlDCOrig.x, -Dc->ptlDCOrig.y);
89 }
90
91 INT FASTCALL
92 GdiSelectVisRgn(HDC hdc, HRGN hrgn)
93 {
94 int retval;
95 DC *dc;
96
97 if (!hrgn)
98 {
99 SetLastWin32Error(ERROR_INVALID_PARAMETER);
100 return ERROR;
101 }
102 if (!(dc = DC_LockDc(hdc)))
103 {
104 SetLastWin32Error(ERROR_INVALID_HANDLE);
105 return ERROR;
106 }
107
108 dc->fs &= ~DC_FLAG_DIRTY_RAO;
109
110 if (dc->prgnVis == NULL)
111 {
112 dc->prgnVis = IntSysCreateRectpRgn(0, 0, 0, 0);
113 GDIOBJ_CopyOwnership(hdc, ((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr);
114 }
115
116 retval = NtGdiCombineRgn(((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr, hrgn, 0, RGN_COPY);
117 if ( retval != ERROR )
118 {
119 NtGdiOffsetRgn(((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr, -dc->ptlDCOrig.x, -dc->ptlDCOrig.y);
120 CLIPPING_UpdateGCRegion(dc);
121 }
122
123 DC_UnlockDc(dc);
124
125 return retval;
126 }
127
128
129 int FASTCALL GdiExtSelectClipRgn(PDC dc,
130 HRGN hrgn,
131 int fnMode)
132 {
133 // dc->fs &= ~DC_FLAG_DIRTY_RAO;
134
135 if (!hrgn)
136 {
137 if (fnMode == RGN_COPY)
138 {
139 if (dc->rosdc.hClipRgn != NULL)
140 {
141 REGION_FreeRgnByHandle(dc->rosdc.hClipRgn);
142 dc->rosdc.hClipRgn = NULL;
143 }
144 }
145 else
146 {
147 SetLastWin32Error(ERROR_INVALID_PARAMETER);
148 return ERROR;
149 }
150 }
151 else
152 {
153 if (!dc->rosdc.hClipRgn)
154 {
155 RECTL rect;
156 if(dc->prgnVis)
157 {
158 REGION_GetRgnBox(dc->prgnVis, &rect);
159 dc->rosdc.hClipRgn = IntSysCreateRectRgnIndirect(&rect);
160 }
161 else
162 {
163 dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
164 }
165 }
166 if(fnMode == RGN_COPY)
167 {
168 NtGdiCombineRgn(dc->rosdc.hClipRgn, hrgn, 0, fnMode);
169 }
170 else
171 NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, hrgn, fnMode);
172 }
173 return CLIPPING_UpdateGCRegion(dc);
174 }
175
176
177 int APIENTRY NtGdiExtSelectClipRgn(HDC hDC,
178 HRGN hrgn,
179 int fnMode)
180 {
181 int retval;
182 DC *dc;
183
184 if (!(dc = DC_LockDc(hDC)))
185 {
186 SetLastWin32Error(ERROR_INVALID_HANDLE);
187 return ERROR;
188 }
189
190 retval = GdiExtSelectClipRgn ( dc, hrgn, fnMode );
191
192 DC_UnlockDc(dc);
193 return retval;
194 }
195
196 INT FASTCALL
197 GdiGetClipBox(HDC hDC, PRECTL rc)
198 {
199 INT retval;
200 PDC dc;
201 PROSRGNDATA pRgnNew, pRgn = NULL;
202 BOOL Unlock = FALSE; //Small hack
203
204 if (!(dc = DC_LockDc(hDC)))
205 {
206 return ERROR;
207 }
208
209 /* FIXME! Rao and Vis only! */
210 if (dc->prgnAPI) // APIRGN
211 {
212 pRgn = dc->prgnAPI;
213 }
214 else if (dc->dclevel.prgnMeta) // METARGN
215 {
216 pRgn = dc->dclevel.prgnMeta;
217 }
218 else
219 {
220 Unlock = TRUE ;
221 pRgn = REGION_LockRgn(dc->rosdc.hClipRgn); // CLIPRGN
222 }
223
224 if (pRgn)
225 {
226 pRgnNew = IntSysCreateRectpRgn( 0, 0, 0, 0 );
227
228 if (!pRgnNew)
229 {
230 DC_UnlockDc(dc);
231 if(Unlock) REGION_UnlockRgn(pRgn);
232 return ERROR;
233 }
234
235 IntGdiCombineRgn(pRgnNew, dc->prgnVis, pRgn, RGN_AND);
236
237 retval = REGION_GetRgnBox(pRgnNew, rc);
238
239 REGION_FreeRgnByHandle(pRgnNew->BaseObject.hHmgr);
240 DC_UnlockDc(dc);
241 if(Unlock) REGION_UnlockRgn(pRgn);
242 return retval;
243 }
244
245 retval = REGION_GetRgnBox(dc->prgnVis, rc);
246 IntDPtoLP(dc, (LPPOINT)rc, 2);
247 DC_UnlockDc(dc);
248
249 return retval;
250 }
251
252 INT APIENTRY
253 NtGdiGetAppClipBox(HDC hDC, PRECTL rc)
254 {
255 INT Ret;
256 NTSTATUS Status = STATUS_SUCCESS;
257 RECTL Saferect;
258
259 Ret = GdiGetClipBox(hDC, &Saferect);
260
261 _SEH2_TRY
262 {
263 ProbeForWrite(rc,
264 sizeof(RECT),
265 1);
266 *rc = Saferect;
267 }
268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
269 {
270 Status = _SEH2_GetExceptionCode();
271 }
272 _SEH2_END;
273
274 if(!NT_SUCCESS(Status))
275 {
276 SetLastNtError(Status);
277 return ERROR;
278 }
279
280 return Ret;
281 }
282
283 int APIENTRY NtGdiExcludeClipRect(HDC hDC,
284 int LeftRect,
285 int TopRect,
286 int RightRect,
287 int BottomRect)
288 {
289 INT Result;
290 RECTL Rect;
291 HRGN NewRgn;
292 PDC dc = DC_LockDc(hDC);
293
294 if (!dc)
295 {
296 SetLastWin32Error(ERROR_INVALID_HANDLE);
297 return ERROR;
298 }
299
300 Rect.left = LeftRect;
301 Rect.top = TopRect;
302 Rect.right = RightRect;
303 Rect.bottom = BottomRect;
304
305 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
306
307 NewRgn = IntSysCreateRectRgnIndirect(&Rect);
308 if (!NewRgn)
309 {
310 Result = ERROR;
311 }
312 else
313 {
314 if (!dc->rosdc.hClipRgn)
315 {
316 dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
317 NtGdiCombineRgn(dc->rosdc.hClipRgn, ((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr, NewRgn, RGN_DIFF);
318 Result = SIMPLEREGION;
319 }
320 else
321 {
322 Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_DIFF);
323 }
324 REGION_FreeRgnByHandle(NewRgn);
325 }
326 if (Result != ERROR)
327 CLIPPING_UpdateGCRegion(dc);
328
329 DC_UnlockDc(dc);
330
331 return Result;
332 }
333
334 int APIENTRY NtGdiIntersectClipRect(HDC hDC,
335 int LeftRect,
336 int TopRect,
337 int RightRect,
338 int BottomRect)
339 {
340 INT Result;
341 RECTL Rect;
342 HRGN NewRgn;
343 PDC dc = DC_LockDc(hDC);
344
345 DPRINT("NtGdiIntersectClipRect(%x, %d,%d-%d,%d)\n",
346 hDC, LeftRect, TopRect, RightRect, BottomRect);
347
348 if (!dc)
349 {
350 SetLastWin32Error(ERROR_INVALID_HANDLE);
351 return ERROR;
352 }
353
354 Rect.left = LeftRect;
355 Rect.top = TopRect;
356 Rect.right = RightRect;
357 Rect.bottom = BottomRect;
358
359 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
360
361 NewRgn = IntSysCreateRectRgnIndirect(&Rect);
362 if (!NewRgn)
363 {
364 Result = ERROR;
365 }
366 else if (!dc->rosdc.hClipRgn)
367 {
368 dc->rosdc.hClipRgn = NewRgn;
369 Result = SIMPLEREGION;
370 }
371 else
372 {
373 Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_AND);
374 REGION_FreeRgnByHandle(NewRgn);
375 }
376 if (Result != ERROR)
377 CLIPPING_UpdateGCRegion(dc);
378
379 DC_UnlockDc(dc);
380
381 return Result;
382 }
383
384 int APIENTRY NtGdiOffsetClipRgn(HDC hDC,
385 int XOffset,
386 int YOffset)
387 {
388 INT Result;
389 DC *dc;
390
391 if(!(dc = DC_LockDc(hDC)))
392 {
393 SetLastWin32Error(ERROR_INVALID_HANDLE);
394 return ERROR;
395 }
396
397 if(dc->rosdc.hClipRgn != NULL)
398 {
399 Result = NtGdiOffsetRgn(dc->rosdc.hClipRgn,
400 XOffset,
401 YOffset);
402 CLIPPING_UpdateGCRegion(dc);
403 }
404 else
405 {
406 Result = NULLREGION;
407 }
408
409 DC_UnlockDc(dc);
410 return Result;
411 }
412
413 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
414 int X,
415 int Y)
416 {
417 HRGN rgn;
418 DC *dc;
419
420 if(!(dc = DC_LockDc(hDC)))
421 {
422 SetLastWin32Error(ERROR_INVALID_HANDLE);
423 return FALSE;
424 }
425
426 rgn = dc->rosdc.hGCClipRgn;
427 DC_UnlockDc(dc);
428
429 return (rgn ? NtGdiPtInRegion(rgn, X, Y) : FALSE);
430 }
431
432 BOOL APIENTRY NtGdiRectVisible(HDC hDC,
433 LPRECT UnsafeRect)
434 {
435 NTSTATUS Status = STATUS_SUCCESS;
436 PROSRGNDATA Rgn;
437 PDC dc = DC_LockDc(hDC);
438 BOOL Result = FALSE;
439 RECTL Rect;
440
441 if (!dc)
442 {
443 SetLastWin32Error(ERROR_INVALID_HANDLE);
444 return FALSE;
445 }
446
447 _SEH2_TRY
448 {
449 ProbeForRead(UnsafeRect,
450 sizeof(RECT),
451 1);
452 Rect = *UnsafeRect;
453 }
454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
455 {
456 Status = _SEH2_GetExceptionCode();
457 }
458 _SEH2_END;
459
460 if(!NT_SUCCESS(Status))
461 {
462 DC_UnlockDc(dc);
463 SetLastNtError(Status);
464 return FALSE;
465 }
466
467 if (dc->rosdc.hGCClipRgn)
468 {
469 if((Rgn = (PROSRGNDATA)RGNOBJAPI_Lock(dc->rosdc.hGCClipRgn, NULL)))
470 {
471 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
472 Result = REGION_RectInRegion(Rgn, &Rect);
473 RGNOBJAPI_Unlock(Rgn);
474 }
475 }
476 DC_UnlockDc(dc);
477
478 return Result;
479 }
480
481 int
482 FASTCALL
483 IntGdiSetMetaRgn(PDC pDC)
484 {
485 INT Ret = ERROR;
486 PROSRGNDATA TempRgn;
487
488 if ( pDC->dclevel.prgnMeta )
489 {
490 if ( pDC->dclevel.prgnClip )
491 {
492 TempRgn = IntSysCreateRectpRgn(0,0,0,0);
493 if (TempRgn)
494 {
495 Ret = IntGdiCombineRgn( TempRgn,
496 pDC->dclevel.prgnMeta,
497 pDC->dclevel.prgnClip,
498 RGN_AND);
499 if ( Ret )
500 {
501 GDIOBJ_ShareUnlockObjByPtr(pDC->dclevel.prgnMeta);
502 if (!((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.ulShareCount)
503 REGION_Delete(pDC->dclevel.prgnMeta);
504
505 pDC->dclevel.prgnMeta = TempRgn;
506
507 GDIOBJ_ShareUnlockObjByPtr(pDC->dclevel.prgnClip);
508 if (!((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.ulShareCount)
509 REGION_Delete(pDC->dclevel.prgnClip);
510
511 pDC->dclevel.prgnClip = NULL;
512
513 IntGdiReleaseRaoRgn(pDC);
514 }
515 else
516 REGION_Delete(TempRgn);
517 }
518 }
519 else
520 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
521 }
522 else
523 {
524 if ( pDC->dclevel.prgnClip )
525 {
526 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
527 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
528 pDC->dclevel.prgnClip = NULL;
529 }
530 else
531 Ret = SIMPLEREGION;
532 }
533 return Ret;
534 }
535
536 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
537 {
538 INT Ret;
539 PDC pDC = DC_LockDc(hDC);
540
541 if (!pDC)
542 {
543 SetLastWin32Error(ERROR_INVALID_PARAMETER);
544 return ERROR;
545 }
546 Ret = IntGdiSetMetaRgn(pDC);
547
548 DC_UnlockDc(pDC);
549 return Ret;
550 }
551
552 INT FASTCALL
553 NEW_CLIPPING_UpdateGCRegion(PDC pDC)
554 {
555 CLIPOBJ * co;
556
557 /* Must have VisRgn set to a valid state! */
558 if (!pDC->prgnVis) return ERROR;
559
560 if (pDC->prgnAPI)
561 {
562 REGION_Delete(pDC->prgnAPI);
563 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
564 }
565
566 if (pDC->prgnRao)
567 {
568 REGION_Delete(pDC->prgnRao);
569 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
570 }
571
572 if (pDC->dclevel.prgnMeta && pDC->dclevel.prgnClip)
573 {
574 IntGdiCombineRgn( pDC->prgnAPI,
575 pDC->dclevel.prgnClip,
576 pDC->dclevel.prgnMeta,
577 RGN_AND );
578 }
579 else
580 {
581 if (pDC->dclevel.prgnClip)
582 {
583 IntGdiCombineRgn( pDC->prgnAPI,
584 pDC->dclevel.prgnClip,
585 NULL,
586 RGN_COPY );
587 }
588 else if (pDC->dclevel.prgnMeta)
589 {
590 IntGdiCombineRgn( pDC->prgnAPI,
591 pDC->dclevel.prgnMeta,
592 NULL,
593 RGN_COPY );
594 }
595 }
596
597 IntGdiCombineRgn( pDC->prgnRao,
598 pDC->prgnVis,
599 pDC->prgnAPI,
600 RGN_AND );
601
602 RtlCopyMemory( &pDC->erclClip,
603 &((PROSRGNDATA)pDC->prgnRao)->rdh.rcBound,
604 sizeof(RECTL));
605
606 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
607
608 IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
609
610 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
611 // the rects from region objects rects in pClipRgn->Buffer.
612 // With pDC->co.pClipRgn->Buffer,
613 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
614
615 co = IntEngCreateClipRegion( ((PROSRGNDATA)pDC->prgnRao)->rdh.nCount,
616 ((PROSRGNDATA)pDC->prgnRao)->Buffer,
617 &pDC->erclClip);
618
619 if (co)
620 {
621 if (pDC->rosdc.CombinedClip != NULL)
622 IntEngDeleteClipRegion(pDC->rosdc.CombinedClip);
623
624 pDC->rosdc.CombinedClip = co;
625 }
626
627 return IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
628 }
629
630 /* EOF */