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