Implement AlphaBlend using the XRENDER extension.
[wine] / dlls / gdi / clipping.c
1 /*
2  * DC clipping functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "wownt32.h"
27 #include "wine/winuser16.h"
28 #include "gdi.h"
29 #include "gdi_private.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
33
34
35 /***********************************************************************
36  *           CLIPPING_UpdateGCRegion
37  *
38  * Update the GC clip region when the ClipRgn or VisRgn have changed.
39  */
40 void CLIPPING_UpdateGCRegion( DC * dc )
41 {
42     if (!dc->hVisRgn)
43     {
44         ERR("hVisRgn is zero. Please report this.\n" );
45         exit(1);
46     }
47
48     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
49
50     if (dc->funcs->pSetDeviceClipping)
51         dc->funcs->pSetDeviceClipping( dc->physDev, dc->hVisRgn, dc->hClipRgn );
52 }
53
54
55 /***********************************************************************
56  *           SelectClipRgn    (GDI32.@)
57  */
58 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
59 {
60     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
61 }
62
63
64 /******************************************************************************
65  *              ExtSelectClipRgn        [GDI32.@]
66  */
67 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
68 {
69     INT retval;
70     RECT rect;
71     DC * dc = DC_GetDCUpdate( hdc );
72     if (!dc) return ERROR;
73
74     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
75
76     if (dc->funcs->pExtSelectClipRgn)
77     {
78         retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
79         GDI_ReleaseObj( hdc );
80         return retval;
81     }
82
83     if (!hrgn)
84     {
85         if (fnMode == RGN_COPY)
86         {
87             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
88             dc->hClipRgn = 0;
89         }
90         else
91         {
92             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
93             GDI_ReleaseObj( hdc );
94             return ERROR;
95         }
96     }
97     else
98     {
99         if (!dc->hClipRgn)
100         {
101             RECT rect;
102             GetRgnBox( dc->hVisRgn, &rect );
103             dc->hClipRgn = CreateRectRgnIndirect( &rect );
104         }
105
106         if(fnMode == RGN_COPY)
107             CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
108         else
109             CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
110     }
111
112     CLIPPING_UpdateGCRegion( dc );
113     GDI_ReleaseObj( hdc );
114
115     return GetClipBox(hdc, &rect);
116 }
117
118 /***********************************************************************
119  *           SelectVisRgn   (GDI.105)
120  */
121 INT16 WINAPI SelectVisRgn16( HDC16 hdc16, HRGN16 hrgn )
122 {
123     int retval;
124     HDC hdc = HDC_32( hdc16 );
125     DC * dc;
126
127     if (!hrgn) return ERROR;
128     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
129
130     TRACE("%p %04x\n", hdc, hrgn );
131
132     dc->flags &= ~DC_DIRTY;
133
134     retval = CombineRgn( dc->hVisRgn, HRGN_32(hrgn), 0, RGN_COPY );
135     CLIPPING_UpdateGCRegion( dc );
136     GDI_ReleaseObj( hdc );
137     return retval;
138 }
139
140
141 /***********************************************************************
142  *           OffsetClipRgn    (GDI32.@)
143  */
144 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
145 {
146     INT ret = SIMPLEREGION;
147     DC *dc = DC_GetDCUpdate( hdc );
148     if (!dc) return ERROR;
149
150     TRACE("%p %d,%d\n", hdc, x, y );
151
152     if(dc->funcs->pOffsetClipRgn)
153         ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
154     else if (dc->hClipRgn) {
155         ret = OffsetRgn( dc->hClipRgn, MulDiv( x, dc->vportExtX, dc->wndExtX ),
156                          MulDiv( y, dc->vportExtY, dc->wndExtY ) );
157         CLIPPING_UpdateGCRegion( dc );
158     }
159     GDI_ReleaseObj( hdc );
160     return ret;
161 }
162
163
164 /***********************************************************************
165  *           OffsetVisRgn    (GDI.102)
166  */
167 INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y )
168 {
169     INT16 retval;
170     HDC hdc = HDC_32( hdc16 );
171     DC * dc = DC_GetDCUpdate( hdc );
172     if (!dc) return ERROR;
173     TRACE("%p %d,%d\n", hdc, x, y );
174     retval = OffsetRgn( dc->hVisRgn, x, y );
175     CLIPPING_UpdateGCRegion( dc );
176     GDI_ReleaseObj( hdc );
177     return retval;
178 }
179
180
181 /***********************************************************************
182  *           ExcludeClipRect    (GDI32.@)
183  */
184 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
185                                 INT right, INT bottom )
186 {
187     HRGN newRgn;
188     INT ret;
189     DC *dc = DC_GetDCUpdate( hdc );
190     if (!dc) return ERROR;
191
192     TRACE("%p %dx%d,%dx%d\n", hdc, left, top, right, bottom );
193
194     if(dc->funcs->pExcludeClipRect)
195         ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
196     else
197     {
198         POINT pt[2];
199
200         pt[0].x = left;
201         pt[0].y = top;
202         pt[1].x = right;
203         pt[1].y = bottom;
204         LPtoDP( hdc, pt, 2 );
205         if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
206         else
207         {
208             if (!dc->hClipRgn)
209             {
210                 dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
211                 CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY );
212             }
213             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
214             DeleteObject( newRgn );
215         }
216         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
217     }
218     GDI_ReleaseObj( hdc );
219     return ret;
220 }
221
222
223 /***********************************************************************
224  *           IntersectClipRect    (GDI32.@)
225  */
226 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
227 {
228     INT ret;
229     DC *dc = DC_GetDCUpdate( hdc );
230     if (!dc) return ERROR;
231
232     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
233
234     if(dc->funcs->pIntersectClipRect)
235         ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
236     else
237     {
238         POINT pt[2];
239
240         pt[0].x = left;
241         pt[0].y = top;
242         pt[1].x = right;
243         pt[1].y = bottom;
244
245         LPtoDP( hdc, pt, 2 );
246
247         if (!dc->hClipRgn)
248         {
249             dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y );
250             ret = SIMPLEREGION;
251         }
252         else
253         {
254             HRGN newRgn;
255
256             if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
257             else
258             {
259                 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
260                 DeleteObject( newRgn );
261             }
262         }
263         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
264     }
265     GDI_ReleaseObj( hdc );
266     return ret;
267 }
268
269
270 /***********************************************************************
271  *           ExcludeVisRect   (GDI.73)
272  */
273 INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
274 {
275     HRGN tempRgn;
276     INT16 ret;
277     POINT pt[2];
278     HDC hdc = HDC_32( hdc16 );
279     DC * dc = DC_GetDCUpdate( hdc );
280     if (!dc) return ERROR;
281
282     pt[0].x = left;
283     pt[0].y = top;
284     pt[1].x = right;
285     pt[1].y = bottom;
286
287     LPtoDP( hdc, pt, 2 );
288
289     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
290
291     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
292     else
293     {
294         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF );
295         DeleteObject( tempRgn );
296     }
297     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
298     GDI_ReleaseObj( hdc );
299     return ret;
300 }
301
302
303 /***********************************************************************
304  *           IntersectVisRect   (GDI.98)
305  */
306 INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
307 {
308     HRGN tempRgn;
309     INT16 ret;
310     POINT pt[2];
311     HDC hdc = HDC_32( hdc16 );
312     DC * dc = DC_GetDCUpdate( hdc );
313     if (!dc) return ERROR;
314
315     pt[0].x = left;
316     pt[0].y = top;
317     pt[1].x = right;
318     pt[1].y = bottom;
319
320     LPtoDP( hdc, pt, 2 );
321
322     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
323
324
325     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
326     else
327     {
328         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND );
329         DeleteObject( tempRgn );
330     }
331     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
332     GDI_ReleaseObj( hdc );
333     return ret;
334 }
335
336
337 /***********************************************************************
338  *           PtVisible    (GDI32.@)
339  */
340 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
341 {
342     POINT pt;
343     BOOL ret;
344     DC *dc = DC_GetDCUpdate( hdc );
345
346     TRACE("%p %d,%d\n", hdc, x, y );
347     if (!dc) return FALSE;
348
349     pt.x = x;
350     pt.y = y;
351     LPtoDP( hdc, &pt, 1 );
352     ret = PtInRegion( dc->hVisRgn, pt.x, pt.y );
353     if (ret && dc->hClipRgn) ret = PtInRegion( dc->hClipRgn, pt.x, pt.y );
354     GDI_ReleaseObj( hdc );
355     return ret;
356 }
357
358
359 /***********************************************************************
360  *           RectVisible    (GDI32.@)
361  */
362 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
363 {
364     RECT tmpRect;
365     BOOL ret;
366     DC *dc = DC_GetDCUpdate( hdc );
367     if (!dc) return FALSE;
368     TRACE("%p %ld,%ldx%ld,%ld\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
369
370     tmpRect = *rect;
371     LPtoDP( hdc, (POINT *)&tmpRect, 2 );
372
373     if (dc->hClipRgn)
374     {
375         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
376         CombineRgn( hrgn, dc->hVisRgn, dc->hClipRgn, RGN_AND );
377         ret = RectInRegion( hrgn, &tmpRect );
378         DeleteObject( hrgn );
379     }
380     else ret = RectInRegion( dc->hVisRgn, &tmpRect );
381     GDI_ReleaseObj( hdc );
382     return ret;
383 }
384
385
386 /***********************************************************************
387  *           GetClipBox    (GDI32.@)
388  */
389 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
390 {
391     INT ret;
392     DC *dc = DC_GetDCUpdate( hdc );
393     if (!dc) return ERROR;
394     if (dc->hClipRgn)
395     {
396         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
397         CombineRgn( hrgn, dc->hVisRgn, dc->hClipRgn, RGN_AND );
398         ret = GetRgnBox( hrgn, rect );
399         DeleteObject( hrgn );
400     }
401     else ret = GetRgnBox( dc->hVisRgn, rect );
402     DPtoLP( hdc, (LPPOINT)rect, 2 );
403     GDI_ReleaseObj( hdc );
404     return ret;
405 }
406
407
408 /***********************************************************************
409  *           GetClipRgn  (GDI32.@)
410  */
411 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
412 {
413     INT ret = -1;
414     DC * dc;
415     if (hRgn && (dc = DC_GetDCPtr( hdc )))
416     {
417       if( dc->hClipRgn )
418       {
419           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
420       }
421       else ret = 0;
422       GDI_ReleaseObj( hdc );
423     }
424     return ret;
425 }
426
427 /***********************************************************************
428  *           SaveVisRgn   (GDI.129)
429  */
430 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 )
431 {
432     HRGN copy;
433     GDIOBJHDR *obj, *copyObj;
434     HDC hdc = HDC_32( hdc16 );
435     DC *dc = DC_GetDCUpdate( hdc );
436
437     if (!dc) return 0;
438     TRACE("%p\n", hdc );
439
440     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
441     {
442         GDI_ReleaseObj( hdc );
443         return 0;
444     }
445     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
446     {
447         GDI_ReleaseObj( dc->hVisRgn );
448         GDI_ReleaseObj( hdc );
449         return 0;
450     }
451     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
452     if (!(copyObj = GDI_GetObjPtr( copy, REGION_MAGIC )))
453     {
454         DeleteObject( copy );
455         GDI_ReleaseObj( dc->hVisRgn );
456         GDI_ReleaseObj( hdc );
457         return 0;
458     }
459     copyObj->hNext = obj->hNext;
460     obj->hNext = HRGN_16(copy);
461     GDI_ReleaseObj( copy );
462     GDI_ReleaseObj( dc->hVisRgn );
463     GDI_ReleaseObj( hdc );
464     return HRGN_16(copy);
465 }
466
467
468 /***********************************************************************
469  *           RestoreVisRgn   (GDI.130)
470  */
471 INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
472 {
473     HRGN saved;
474     GDIOBJHDR *obj, *savedObj;
475     HDC hdc = HDC_32( hdc16 );
476     DC *dc = DC_GetDCPtr( hdc );
477     INT16 ret = ERROR;
478
479     if (!dc) return ERROR;
480
481     TRACE("%p\n", hdc );
482
483     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
484     saved = HRGN_32(obj->hNext);
485
486     if ((savedObj = GDI_GetObjPtr( saved, REGION_MAGIC )))
487     {
488         ret = CombineRgn( dc->hVisRgn, saved, 0, RGN_COPY );
489         obj->hNext = savedObj->hNext;
490         GDI_ReleaseObj( saved );
491         DeleteObject( saved );
492         dc->flags &= ~DC_DIRTY;
493         CLIPPING_UpdateGCRegion( dc );
494     }
495     GDI_ReleaseObj( dc->hVisRgn );
496  done:
497     GDI_ReleaseObj( hdc );
498     return ret;
499 }
500
501
502 /***********************************************************************
503  * GetRandomRgn [GDI32.@]
504  *
505  * NOTES
506  *     This function is documented in MSDN online for the case of
507  *     dwCode == SYSRGN (4).
508  *
509  *     For dwCode == 1 it should return the clip region
510  *                   2 "    "       "   the meta region
511  *                   3 "    "       "   the intersection of the clip with
512  *                                      the meta region (== 'Rao' region).
513  *
514  *     See http://www.codeproject.com/gdi/cliprgnguide.asp
515  */
516 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, DWORD dwCode)
517 {
518     switch (dwCode)
519     {
520     case SYSRGN: /* == 4 */
521         {
522             DC *dc = DC_GetDCPtr (hDC);
523             if (!dc) return -1;
524
525             CombineRgn (hRgn, dc->hVisRgn, 0, RGN_COPY);
526             GDI_ReleaseObj( hDC );
527             /*
528              *     On Windows NT/2000,
529              *           the region returned is in screen coordinates.
530              *     On Windows 95/98,
531              *           the region returned is in window coordinates
532              */
533             if (!(GetVersion() & 0x80000000))
534             {
535                 POINT org;
536                 GetDCOrgEx(hDC, &org);
537                 OffsetRgn(hRgn, org.x, org.y);
538             }
539             return 1;
540         }
541
542     case 1: /* clip region */
543             return GetClipRgn (hDC, hRgn);
544
545     default:
546         WARN("Unknown dwCode %ld\n", dwCode);
547         return -1;
548     }
549
550     return -1;
551 }
552
553
554 /***********************************************************************
555  *           GetMetaRgn    (GDI32.@)
556  */
557 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
558 {
559     FIXME( "stub\n" );
560
561     return 0;
562 }
563
564
565 /***********************************************************************
566  *           SetMetaRgn    (GDI32.@)
567  */
568 INT WINAPI SetMetaRgn( HDC hdc )
569 {
570     FIXME( "stub\n" );
571
572     return ERROR;
573 }