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