- made string operations consistent wrt whitespace handling (which
[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  *           create_default_clip_rgn
56  *
57  * Create a default clipping region when none already exists.
58  */
59 static inline void create_default_clip_region( DC * dc )
60 {
61     dc->hClipRgn = CreateRectRgn(0, 0,
62         GetDeviceCaps( dc->hSelf, HORZRES ),
63         GetDeviceCaps( dc->hSelf, VERTRES ));
64 }
65
66
67 /***********************************************************************
68  *           SelectClipRgn    (GDI32.@)
69  */
70 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
71 {
72     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
73 }
74
75
76 /******************************************************************************
77  *              ExtSelectClipRgn        [GDI32.@]
78  */
79 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
80 {
81     INT retval;
82     RECT rect;
83     DC * dc = DC_GetDCUpdate( hdc );
84     if (!dc) return ERROR;
85
86     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
87
88     if (dc->funcs->pExtSelectClipRgn)
89     {
90         retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
91         GDI_ReleaseObj( hdc );
92         return retval;
93     }
94
95     if (!hrgn)
96     {
97         if (fnMode == RGN_COPY)
98         {
99             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
100             dc->hClipRgn = 0;
101         }
102         else
103         {
104             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
105             GDI_ReleaseObj( hdc );
106             return ERROR;
107         }
108     }
109     else
110     {
111         if (!dc->hClipRgn)
112             create_default_clip_region( dc );
113
114         if(fnMode == RGN_COPY)
115             CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
116         else
117             CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
118     }
119
120     CLIPPING_UpdateGCRegion( dc );
121     GDI_ReleaseObj( hdc );
122
123     return GetClipBox(hdc, &rect);
124 }
125
126 /***********************************************************************
127  *           SelectVisRgn   (GDI.105)
128  */
129 INT16 WINAPI SelectVisRgn16( HDC16 hdc16, HRGN16 hrgn )
130 {
131     int retval;
132     HDC hdc = HDC_32( hdc16 );
133     DC * dc;
134
135     if (!hrgn) return ERROR;
136     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
137
138     TRACE("%p %04x\n", hdc, hrgn );
139
140     dc->flags &= ~DC_DIRTY;
141
142     retval = CombineRgn( dc->hVisRgn, HRGN_32(hrgn), 0, RGN_COPY );
143     CLIPPING_UpdateGCRegion( dc );
144     GDI_ReleaseObj( hdc );
145     return retval;
146 }
147
148
149 /***********************************************************************
150  *           OffsetClipRgn    (GDI32.@)
151  */
152 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
153 {
154     INT ret = SIMPLEREGION;
155     DC *dc = DC_GetDCUpdate( hdc );
156     if (!dc) return ERROR;
157
158     TRACE("%p %d,%d\n", hdc, x, y );
159
160     if(dc->funcs->pOffsetClipRgn)
161         ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
162     else if (dc->hClipRgn) {
163         ret = OffsetRgn( dc->hClipRgn, MulDiv( x, dc->vportExtX, dc->wndExtX ),
164                          MulDiv( y, dc->vportExtY, dc->wndExtY ) );
165         CLIPPING_UpdateGCRegion( dc );
166     }
167     GDI_ReleaseObj( hdc );
168     return ret;
169 }
170
171
172 /***********************************************************************
173  *           OffsetVisRgn    (GDI.102)
174  */
175 INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y )
176 {
177     INT16 retval;
178     HDC hdc = HDC_32( hdc16 );
179     DC * dc = DC_GetDCUpdate( hdc );
180     if (!dc) return ERROR;
181     TRACE("%p %d,%d\n", hdc, x, y );
182     retval = OffsetRgn( dc->hVisRgn, x, y );
183     CLIPPING_UpdateGCRegion( dc );
184     GDI_ReleaseObj( hdc );
185     return retval;
186 }
187
188
189 /***********************************************************************
190  *           ExcludeClipRect    (GDI32.@)
191  */
192 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
193                                 INT right, INT bottom )
194 {
195     HRGN newRgn;
196     INT ret;
197     DC *dc = DC_GetDCUpdate( hdc );
198     if (!dc) return ERROR;
199
200     TRACE("%p %dx%d,%dx%d\n", hdc, left, top, right, bottom );
201
202     if(dc->funcs->pExcludeClipRect)
203         ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
204     else
205     {
206         POINT pt[2];
207
208         pt[0].x = left;
209         pt[0].y = top;
210         pt[1].x = right;
211         pt[1].y = bottom;
212         LPtoDP( hdc, pt, 2 );
213         if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
214         else
215         {
216             if (!dc->hClipRgn)
217                 create_default_clip_region( dc );
218             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
219             DeleteObject( newRgn );
220         }
221         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
222     }
223     GDI_ReleaseObj( hdc );
224     return ret;
225 }
226
227
228 /***********************************************************************
229  *           IntersectClipRect    (GDI32.@)
230  */
231 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
232 {
233     INT ret;
234     DC *dc = DC_GetDCUpdate( hdc );
235     if (!dc) return ERROR;
236
237     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
238
239     if(dc->funcs->pIntersectClipRect)
240         ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
241     else
242     {
243         POINT pt[2];
244
245         pt[0].x = left;
246         pt[0].y = top;
247         pt[1].x = right;
248         pt[1].y = bottom;
249
250         LPtoDP( hdc, pt, 2 );
251
252         if (!dc->hClipRgn)
253         {
254             dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y );
255             ret = SIMPLEREGION;
256         }
257         else
258         {
259             HRGN newRgn;
260
261             if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
262             else
263             {
264                 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
265                 DeleteObject( newRgn );
266             }
267         }
268         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
269     }
270     GDI_ReleaseObj( hdc );
271     return ret;
272 }
273
274
275 /***********************************************************************
276  *           ExcludeVisRect   (GDI.73)
277  */
278 INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
279 {
280     HRGN tempRgn;
281     INT16 ret;
282     POINT pt[2];
283     HDC hdc = HDC_32( hdc16 );
284     DC * dc = DC_GetDCUpdate( hdc );
285     if (!dc) return ERROR;
286
287     pt[0].x = left;
288     pt[0].y = top;
289     pt[1].x = right;
290     pt[1].y = bottom;
291
292     LPtoDP( hdc, pt, 2 );
293
294     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
295
296     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
297     else
298     {
299         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF );
300         DeleteObject( tempRgn );
301     }
302     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
303     GDI_ReleaseObj( hdc );
304     return ret;
305 }
306
307
308 /***********************************************************************
309  *           IntersectVisRect   (GDI.98)
310  */
311 INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
312 {
313     HRGN tempRgn;
314     INT16 ret;
315     POINT pt[2];
316     HDC hdc = HDC_32( hdc16 );
317     DC * dc = DC_GetDCUpdate( hdc );
318     if (!dc) return ERROR;
319
320     pt[0].x = left;
321     pt[0].y = top;
322     pt[1].x = right;
323     pt[1].y = bottom;
324
325     LPtoDP( hdc, pt, 2 );
326
327     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
328
329
330     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
331     else
332     {
333         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND );
334         DeleteObject( tempRgn );
335     }
336     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
337     GDI_ReleaseObj( hdc );
338     return ret;
339 }
340
341
342 /***********************************************************************
343  *           PtVisible    (GDI32.@)
344  */
345 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
346 {
347     POINT pt;
348     BOOL ret;
349     DC *dc = DC_GetDCUpdate( hdc );
350
351     TRACE("%p %d,%d\n", hdc, x, y );
352     if (!dc) return FALSE;
353
354     pt.x = x;
355     pt.y = y;
356     LPtoDP( hdc, &pt, 1 );
357     ret = PtInRegion( dc->hVisRgn, pt.x, pt.y );
358     if (ret && dc->hClipRgn) ret = PtInRegion( dc->hClipRgn, pt.x, pt.y );
359     GDI_ReleaseObj( hdc );
360     return ret;
361 }
362
363
364 /***********************************************************************
365  *           RectVisible    (GDI32.@)
366  */
367 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
368 {
369     RECT tmpRect;
370     BOOL ret;
371     DC *dc = DC_GetDCUpdate( hdc );
372     if (!dc) return FALSE;
373     TRACE("%p %ld,%ldx%ld,%ld\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
374
375     tmpRect = *rect;
376     LPtoDP( hdc, (POINT *)&tmpRect, 2 );
377
378     if (dc->hClipRgn)
379     {
380         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
381         CombineRgn( hrgn, dc->hVisRgn, dc->hClipRgn, RGN_AND );
382         ret = RectInRegion( hrgn, &tmpRect );
383         DeleteObject( hrgn );
384     }
385     else ret = RectInRegion( dc->hVisRgn, &tmpRect );
386     GDI_ReleaseObj( hdc );
387     return ret;
388 }
389
390
391 /***********************************************************************
392  *           GetClipBox    (GDI32.@)
393  */
394 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
395 {
396     INT ret;
397     DC *dc = DC_GetDCUpdate( hdc );
398     if (!dc) return ERROR;
399     if (dc->hClipRgn)
400     {
401         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
402         CombineRgn( hrgn, dc->hVisRgn, dc->hClipRgn, RGN_AND );
403         ret = GetRgnBox( hrgn, rect );
404         DeleteObject( hrgn );
405     }
406     else ret = GetRgnBox( dc->hVisRgn, rect );
407     DPtoLP( hdc, (LPPOINT)rect, 2 );
408     GDI_ReleaseObj( hdc );
409     return ret;
410 }
411
412
413 /***********************************************************************
414  *           GetClipRgn  (GDI32.@)
415  */
416 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
417 {
418     INT ret = -1;
419     DC * dc;
420     if (hRgn && (dc = DC_GetDCPtr( hdc )))
421     {
422       if( dc->hClipRgn )
423       {
424           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
425       }
426       else ret = 0;
427       GDI_ReleaseObj( hdc );
428     }
429     return ret;
430 }
431
432 /***********************************************************************
433  *           SaveVisRgn   (GDI.129)
434  */
435 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 )
436 {
437     HRGN copy;
438     GDIOBJHDR *obj, *copyObj;
439     HDC hdc = HDC_32( hdc16 );
440     DC *dc = DC_GetDCUpdate( hdc );
441
442     if (!dc) return 0;
443     TRACE("%p\n", hdc );
444
445     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
446     {
447         GDI_ReleaseObj( hdc );
448         return 0;
449     }
450     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
451     {
452         GDI_ReleaseObj( dc->hVisRgn );
453         GDI_ReleaseObj( hdc );
454         return 0;
455     }
456     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
457     if (!(copyObj = GDI_GetObjPtr( copy, REGION_MAGIC )))
458     {
459         DeleteObject( copy );
460         GDI_ReleaseObj( dc->hVisRgn );
461         GDI_ReleaseObj( hdc );
462         return 0;
463     }
464     copyObj->hNext = obj->hNext;
465     obj->hNext = HRGN_16(copy);
466     GDI_ReleaseObj( copy );
467     GDI_ReleaseObj( dc->hVisRgn );
468     GDI_ReleaseObj( hdc );
469     return HRGN_16(copy);
470 }
471
472
473 /***********************************************************************
474  *           RestoreVisRgn   (GDI.130)
475  */
476 INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
477 {
478     HRGN saved;
479     GDIOBJHDR *obj, *savedObj;
480     HDC hdc = HDC_32( hdc16 );
481     DC *dc = DC_GetDCPtr( hdc );
482     INT16 ret = ERROR;
483
484     if (!dc) return ERROR;
485
486     TRACE("%p\n", hdc );
487
488     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
489     saved = HRGN_32(obj->hNext);
490
491     if ((savedObj = GDI_GetObjPtr( saved, REGION_MAGIC )))
492     {
493         ret = CombineRgn( dc->hVisRgn, saved, 0, RGN_COPY );
494         obj->hNext = savedObj->hNext;
495         GDI_ReleaseObj( saved );
496         DeleteObject( saved );
497         dc->flags &= ~DC_DIRTY;
498         CLIPPING_UpdateGCRegion( dc );
499     }
500     GDI_ReleaseObj( dc->hVisRgn );
501  done:
502     GDI_ReleaseObj( hdc );
503     return ret;
504 }
505
506
507 /***********************************************************************
508  * GetRandomRgn [GDI32.@]
509  *
510  * NOTES
511  *     This function is documented in MSDN online for the case of
512  *     iCode == SYSRGN (4).
513  *
514  *     For iCode == 1 it should return the clip region
515  *                  2 "    "       "   the meta region
516  *                  3 "    "       "   the intersection of the clip with
517  *                                     the meta region (== 'Rao' region).
518  *
519  *     See http://www.codeproject.com/gdi/cliprgnguide.asp
520  */
521 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, INT iCode)
522 {
523     switch (iCode)
524     {
525     case SYSRGN: /* == 4 */
526         {
527             DC *dc = DC_GetDCPtr (hDC);
528             if (!dc) return -1;
529
530             CombineRgn (hRgn, dc->hVisRgn, 0, RGN_COPY);
531             GDI_ReleaseObj( hDC );
532             /*
533              *     On Windows NT/2000,
534              *           the region returned is in screen coordinates.
535              *     On Windows 95/98,
536              *           the region returned is in window coordinates
537              */
538             if (!(GetVersion() & 0x80000000))
539             {
540                 POINT org;
541                 GetDCOrgEx(hDC, &org);
542                 OffsetRgn(hRgn, org.x, org.y);
543             }
544             return 1;
545         }
546
547     case 1: /* clip region */
548             return GetClipRgn (hDC, hRgn);
549
550     default:
551         WARN("Unknown iCode %d\n", iCode);
552         return -1;
553     }
554
555     return -1;
556 }
557
558
559 /***********************************************************************
560  *           GetMetaRgn    (GDI32.@)
561  */
562 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
563 {
564     FIXME( "stub\n" );
565
566     return 0;
567 }
568
569
570 /***********************************************************************
571  *           SetMetaRgn    (GDI32.@)
572  */
573 INT WINAPI SetMetaRgn( HDC hdc )
574 {
575     FIXME( "stub\n" );
576
577     return ERROR;
578 }