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