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