Fail if less then one entire line requested in GetBitmapBits32.
[wine] / objects / clipping.c
1 /*
2  * DC clipping functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "dc.h"
8 #include "metafile.h"
9 #include "region.h"
10 #include "debug.h"
11
12 #define UPDATE_DIRTY_DC(dc) \
13  do { \
14    if ((dc)->hookProc && !((dc)->w.flags & (DC_SAVED | DC_MEMORY))) \
15      (dc)->hookProc( (dc)->hSelf, DCHC_INVALIDVISRGN, (dc)->dwHookData, 0 ); \
16  } while(0)
17
18
19
20 /***********************************************************************
21  *           CLIPPING_UpdateGCRegion
22  *
23  * Update the GC clip region when the ClipRgn or VisRgn have changed.
24  */
25 void CLIPPING_UpdateGCRegion( DC * dc )
26 {
27     if (!dc->w.hGCClipRgn) dc->w.hGCClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
28
29     if (!dc->w.hVisRgn)
30     {
31         ERR(region, "hVisRgn is zero. Please report this.\n" );
32         exit(1);
33     }
34
35     if (dc->w.flags & DC_DIRTY)
36     {
37         UPDATE_DIRTY_DC(dc);
38         dc->w.flags &= ~DC_DIRTY;
39     }
40
41     if (!dc->w.hClipRgn)
42         CombineRgn32( dc->w.hGCClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
43     else
44         CombineRgn32(dc->w.hGCClipRgn, dc->w.hClipRgn, dc->w.hVisRgn, RGN_AND);
45     if (dc->funcs->pSetDeviceClipping) dc->funcs->pSetDeviceClipping( dc );
46 }
47
48
49 /***********************************************************************
50  *           SelectClipRgn16    (GDI.44)
51  */
52 INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
53 {
54     return (INT16)SelectClipRgn32( hdc, hrgn );
55 }
56
57
58 /***********************************************************************
59  *           SelectClipRgn32    (GDI32.297)
60  */
61 INT32 WINAPI SelectClipRgn32( HDC32 hdc, HRGN32 hrgn )
62 {
63     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
64 }
65
66 /******************************************************************************
67  *              ExtSelectClipRgn        [GDI32.97]
68  */
69 INT32 WINAPI ExtSelectClipRgn( HDC32 hdc, HRGN32 hrgn, INT32 fnMode )
70 {
71     INT32 retval;
72     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
73     if (!dc) return ERROR;
74
75     TRACE( clipping, "%04x %04x %d\n", hdc, hrgn, fnMode );
76
77     if (!hrgn)
78     {
79         if (fnMode == RGN_COPY)
80         {
81             if (dc->w.hClipRgn) DeleteObject16( dc->w.hClipRgn );
82             dc->w.hClipRgn = 0;
83             retval = SIMPLEREGION; /* Clip region == whole DC */
84         }
85         else
86         {
87             FIXME(clipping, "Unimplemented: hrgn NULL in mode: %d\n", fnMode); 
88             return ERROR;
89         }
90     }
91     else 
92     {
93         if (!dc->w.hClipRgn)
94         {
95             RECT32 rect;
96             GetRgnBox32( dc->w.hVisRgn, &rect );
97             dc->w.hClipRgn = CreateRectRgnIndirect32( &rect );
98         }
99
100         OffsetRgn32( dc->w.hClipRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
101         retval = CombineRgn32( dc->w.hClipRgn, hrgn, dc->w.hClipRgn, fnMode );
102         OffsetRgn32( dc->w.hClipRgn, dc->w.DCOrgX, dc->w.DCOrgY );
103     }
104
105
106     CLIPPING_UpdateGCRegion( dc );
107     GDI_HEAP_UNLOCK( hdc );
108     return retval;
109 }
110
111 /***********************************************************************
112  *           SelectVisRgn    (GDI.105)
113  */
114 INT16 WINAPI SelectVisRgn( HDC16 hdc, HRGN16 hrgn )
115 {
116     int retval;
117     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
118     if (!dc || !hrgn) return ERROR;
119
120     TRACE(clipping, "%04x %04x\n", hdc, hrgn );
121
122     dc->w.flags &= ~DC_DIRTY;
123
124     retval = CombineRgn16( dc->w.hVisRgn, hrgn, 0, RGN_COPY );
125     CLIPPING_UpdateGCRegion( dc );
126     GDI_HEAP_UNLOCK( hdc );
127     return retval;
128 }
129
130
131 /***********************************************************************
132  *           OffsetClipRgn16    (GDI.32)
133  */
134 INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
135 {
136     return (INT16)OffsetClipRgn32( hdc, x, y );
137 }
138
139
140 /***********************************************************************
141  *           OffsetClipRgn32    (GDI32.255)
142  */
143 INT32 WINAPI OffsetClipRgn32( HDC32 hdc, INT32 x, INT32 y )
144 {
145     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
146     if (!dc) 
147     {
148         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
149         if (!dc) return ERROR;
150         MF_MetaParam2(dc, META_OFFSETCLIPRGN, x, y);
151         GDI_HEAP_UNLOCK( hdc );
152         return NULLREGION;   /* ?? */
153     }
154
155     TRACE(clipping, "%04x %d,%d\n", hdc, x, y );
156
157     if (dc->w.hClipRgn)
158     {
159         INT32 ret = OffsetRgn32( dc->w.hClipRgn, XLPTODP(dc,x), YLPTODP(dc,y));
160         CLIPPING_UpdateGCRegion( dc );
161         GDI_HEAP_UNLOCK( hdc );
162         return ret;
163     }
164     GDI_HEAP_UNLOCK( hdc );
165     return SIMPLEREGION; /* Clip region == client area */
166 }
167
168
169 /***********************************************************************
170  *           OffsetVisRgn    (GDI.102)
171  */
172 INT16 WINAPI OffsetVisRgn( HDC16 hdc, INT16 x, INT16 y )
173 {
174     INT16 retval;
175     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
176     if (!dc) return ERROR;    
177     TRACE(clipping, "%04x %d,%d\n", hdc, x, y );
178     retval = OffsetRgn32( dc->w.hVisRgn, x, y );
179     CLIPPING_UpdateGCRegion( dc );
180     GDI_HEAP_UNLOCK( hdc );
181     return retval;
182 }
183
184
185 /***********************************************************************
186  *           CLIPPING_IntersectClipRect
187  *
188  * Helper function for {Intersect,Exclude}ClipRect, can be called from
189  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
190  * coordinate conversion.
191  */
192 INT32 CLIPPING_IntersectClipRect( DC * dc, INT32 left, INT32 top,
193                                   INT32 right, INT32 bottom, UINT32 flags )
194 {
195     HRGN32 newRgn;
196     INT32 ret;
197
198     left   += dc->w.DCOrgX;
199     right  += dc->w.DCOrgX;
200     top    += dc->w.DCOrgY;
201     bottom += dc->w.DCOrgY;
202
203     if (!(newRgn = CreateRectRgn32( left, top, right, bottom ))) return ERROR;
204     if (!dc->w.hClipRgn)
205     {
206        if( flags & CLIP_INTERSECT )
207        {
208            dc->w.hClipRgn = newRgn;
209            CLIPPING_UpdateGCRegion( dc );
210            return SIMPLEREGION;
211        }
212        else if( flags & CLIP_EXCLUDE )
213        {
214            dc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
215            CombineRgn32( dc->w.hClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
216        }
217        else WARN(clipping,"No hClipRgn and flags are %x\n",flags);
218     }
219
220     ret = CombineRgn32( newRgn, dc->w.hClipRgn, newRgn, 
221                         (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND );
222     if (ret != ERROR)
223     {
224         if (!(flags & CLIP_KEEPRGN)) DeleteObject32( dc->w.hClipRgn );
225         dc->w.hClipRgn = newRgn;    
226         CLIPPING_UpdateGCRegion( dc );
227     }
228     else DeleteObject32( newRgn );
229     return ret;
230 }
231
232
233 /***********************************************************************
234  *           ExcludeClipRect16    (GDI.21)
235  */
236 INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
237                                 INT16 right, INT16 bottom )
238 {
239     return (INT16)ExcludeClipRect32( hdc, left, top, right, bottom );
240 }
241
242
243 /***********************************************************************
244  *           ExcludeClipRect32    (GDI32.92)
245  */
246 INT32 WINAPI ExcludeClipRect32( HDC32 hdc, INT32 left, INT32 top,
247                                 INT32 right, INT32 bottom )
248 {
249     INT32 ret;
250     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
251     if (!dc) 
252     {
253         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
254         if (!dc) return ERROR;
255         MF_MetaParam4(dc, META_EXCLUDECLIPRECT, left, top, right, bottom);
256         GDI_HEAP_UNLOCK( hdc );
257         return NULLREGION;   /* ?? */
258     }
259
260     left   = XLPTODP( dc, left );
261     right  = XLPTODP( dc, right );
262     top    = YLPTODP( dc, top );
263     bottom = YLPTODP( dc, bottom );
264
265     TRACE(clipping, "%04x %dx%d,%dx%d\n",
266             hdc, left, top, right, bottom );
267     ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE );
268     GDI_HEAP_UNLOCK( hdc );
269     return ret;
270 }
271
272
273 /***********************************************************************
274  *           IntersectClipRect16    (GDI.22)
275  */
276 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
277                                   INT16 right, INT16 bottom )
278 {
279     return (INT16)IntersectClipRect32( hdc, left, top, right, bottom );
280 }
281
282
283 /***********************************************************************
284  *           IntersectClipRect32    (GDI32.245)
285  */
286 INT32 WINAPI IntersectClipRect32( HDC32 hdc, INT32 left, INT32 top,
287                                   INT32 right, INT32 bottom )
288 {
289     INT32 ret;
290     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
291     if (!dc) 
292     {
293         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
294         if (!dc) return ERROR;
295         MF_MetaParam4(dc, META_INTERSECTCLIPRECT, left, top, right, bottom);
296         GDI_HEAP_UNLOCK( hdc );
297         return NULLREGION;   /* ?? */
298     }
299
300     left   = XLPTODP( dc, left );
301     right  = XLPTODP( dc, right );
302     top    = YLPTODP( dc, top );
303     bottom = YLPTODP( dc, bottom );
304
305     TRACE(clipping, "%04x %dx%d,%dx%d\n",
306             hdc, left, top, right, bottom );
307     ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT );
308     GDI_HEAP_UNLOCK( hdc );
309     return ret;
310 }
311
312
313 /***********************************************************************
314  *           CLIPPING_IntersectVisRect
315  *
316  * Helper function for {Intersect,Exclude}VisRect, can be called from
317  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
318  * coordinate conversion.
319  */
320 INT32 CLIPPING_IntersectVisRect( DC * dc, INT32 left, INT32 top,
321                                  INT32 right, INT32 bottom,
322                                  BOOL32 exclude )
323 {
324     HRGN32 tempRgn, newRgn;
325     INT32 ret;
326
327     left   += dc->w.DCOrgX;
328     right  += dc->w.DCOrgX;
329     top    += dc->w.DCOrgY;
330     bottom += dc->w.DCOrgY;
331
332     if (!(newRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return ERROR;
333     if (!(tempRgn = CreateRectRgn32( left, top, right, bottom )))
334     {
335         DeleteObject32( newRgn );
336         return ERROR;
337     }
338     ret = CombineRgn32( newRgn, dc->w.hVisRgn, tempRgn,
339                         exclude ? RGN_DIFF : RGN_AND );
340     DeleteObject32( tempRgn );
341
342     if (ret != ERROR)
343     {
344         RGNOBJ *newObj  = (RGNOBJ*)GDI_GetObjPtr( newRgn, REGION_MAGIC);
345         RGNOBJ *prevObj = (RGNOBJ*)GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC);
346         if (newObj && prevObj) newObj->header.hNext = prevObj->header.hNext;
347         DeleteObject32( dc->w.hVisRgn );
348         dc->w.hVisRgn = newRgn;    
349         CLIPPING_UpdateGCRegion( dc );
350         GDI_HEAP_UNLOCK( newRgn );
351     }
352     else DeleteObject32( newRgn );
353     return ret;
354 }
355
356
357 /***********************************************************************
358  *           ExcludeVisRect    (GDI.73)
359  */
360 INT16 WINAPI ExcludeVisRect( HDC16 hdc, INT16 left, INT16 top,
361                              INT16 right, INT16 bottom )
362 {
363     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
364     if (!dc) return ERROR;    
365
366     left   = XLPTODP( dc, left );
367     right  = XLPTODP( dc, right );
368     top    = YLPTODP( dc, top );
369     bottom = YLPTODP( dc, bottom );
370
371     TRACE(clipping, "%04x %dx%d,%dx%d\n",
372             hdc, left, top, right, bottom );
373
374     return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE );
375 }
376
377
378 /***********************************************************************
379  *           IntersectVisRect    (GDI.98)
380  */
381 INT16 WINAPI IntersectVisRect( HDC16 hdc, INT16 left, INT16 top,
382                                INT16 right, INT16 bottom )
383 {
384     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
385     if (!dc) return ERROR;    
386
387     left   = XLPTODP( dc, left );
388     right  = XLPTODP( dc, right );
389     top    = YLPTODP( dc, top );
390     bottom = YLPTODP( dc, bottom );
391
392     TRACE(clipping, "%04x %dx%d,%dx%d\n",
393             hdc, left, top, right, bottom );
394
395     return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE );
396 }
397
398
399 /***********************************************************************
400  *           PtVisible16    (GDI.103)
401  */
402 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
403 {
404     return PtVisible32( hdc, x, y );
405 }
406
407
408 /***********************************************************************
409  *           PtVisible32    (GDI32.279)
410  */
411 BOOL32 WINAPI PtVisible32( HDC32 hdc, INT32 x, INT32 y )
412 {
413     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
414     if (!dc) return ERROR;    
415
416     TRACE(clipping, "%04x %d,%d\n", hdc, x, y );
417     if (!dc->w.hGCClipRgn) return FALSE;
418
419     if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
420     dc->w.flags &= ~DC_DIRTY;
421
422     return PtInRegion32( dc->w.hGCClipRgn, XLPTODP(dc,x) + dc->w.DCOrgX, 
423                                            YLPTODP(dc,y) + dc->w.DCOrgY );
424 }
425
426
427 /***********************************************************************
428  *           RectVisible16    (GDI.104)
429  */
430 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect )
431 {
432     RECT16 tmpRect;
433     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
434     if (!dc) return FALSE;
435     TRACE(clipping,"%04x %d,%dx%d,%d\n",
436                      hdc, rect->left, rect->top, rect->right, rect->bottom );
437     if (!dc->w.hGCClipRgn) return FALSE;
438     /* copy rectangle to avoid overwriting by LPtoDP */
439     tmpRect = *rect;
440     LPtoDP16( hdc, (LPPOINT16)&tmpRect, 2 );
441     OffsetRect16( &tmpRect, dc->w.DCOrgX, dc->w.DCOrgY );
442     return RectInRegion16( dc->w.hGCClipRgn, &tmpRect );
443 }
444
445
446 /***********************************************************************
447  *           RectVisible32    (GDI32.282)
448  */
449 BOOL32 WINAPI RectVisible32( HDC32 hdc, const RECT32* rect )
450 {
451     RECT16 rect16;
452     CONV_RECT32TO16( rect, &rect16 );
453     return RectVisible16( (HDC16)hdc, &rect16 );
454 }
455
456
457 /***********************************************************************
458  *           GetClipBox16    (GDI.77)
459  */
460 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
461 {
462     int ret;
463     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
464     if (!dc) return ERROR;    
465     ret = GetRgnBox16( dc->w.hGCClipRgn, rect );
466     OffsetRect16( rect, -dc->w.DCOrgX, -dc->w.DCOrgY );
467     DPtoLP16( hdc, (LPPOINT16)rect, 2 );
468     TRACE(clipping, "%d,%d-%d,%d\n", 
469             rect->left,rect->top,rect->right,rect->bottom );
470     return ret;
471 }
472
473
474 /***********************************************************************
475  *           GetClipBox32    (GDI32.162)
476  */
477 INT32 WINAPI GetClipBox32( HDC32 hdc, LPRECT32 rect )
478 {
479     INT32 ret;
480     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
481     if (!dc) return ERROR;    
482     ret = GetRgnBox32( dc->w.hGCClipRgn, rect );
483     OffsetRect32( rect, -dc->w.DCOrgX, -dc->w.DCOrgY );
484     DPtoLP32( hdc, (LPPOINT32)rect, 2 );
485     return ret;
486 }
487
488
489 /***********************************************************************
490  *           GetClipRgn32  (GDI32.163)
491  */
492 INT32 WINAPI GetClipRgn32( HDC32 hdc, HRGN32 hRgn )
493 {
494     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
495     if( dc && hRgn )
496     {
497       if( dc->w.hClipRgn )
498       { 
499         /* this assumes that dc->w.hClipRgn is in coordinates
500            relative to the device (not DC origin) */
501
502         if( CombineRgn32(hRgn, dc->w.hClipRgn, 0, RGN_COPY) != ERROR )
503         {
504             OffsetRgn32( hRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
505             return 1;
506         }
507       }
508       else return 0;
509     }
510     return -1;
511 }
512
513 /***********************************************************************
514  *           SaveVisRgn    (GDI.129)
515  */
516 HRGN16 WINAPI SaveVisRgn( HDC16 hdc )
517 {
518     HRGN32 copy;
519     RGNOBJ *obj, *copyObj;
520     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
521     if (!dc) return 0;
522     TRACE(clipping, "%04x\n", hdc );
523     if (!dc->w.hVisRgn)
524     {
525         ERR(region, "hVisRgn is zero. Please report this.\n" );
526         exit(1);
527     }
528     if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
529     dc->w.flags &= ~DC_DIRTY;
530
531     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
532     {
533         GDI_HEAP_UNLOCK( hdc );
534         return 0;
535     }
536     if (!(copy = CreateRectRgn32( 0, 0, 0, 0 )))
537     {
538         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
539         GDI_HEAP_UNLOCK( hdc );
540         return 0;
541     }  
542     CombineRgn32( copy, dc->w.hVisRgn, 0, RGN_COPY );
543     if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
544     {
545         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
546         GDI_HEAP_UNLOCK( hdc );
547         return 0;
548     }
549     copyObj->header.hNext = obj->header.hNext;
550     obj->header.hNext = copy;
551     GDI_HEAP_UNLOCK( dc->w.hVisRgn );
552     GDI_HEAP_UNLOCK( hdc );
553     GDI_HEAP_UNLOCK( copy );
554     return copy;
555 }
556
557
558 /***********************************************************************
559  *           RestoreVisRgn    (GDI.130)
560  */
561 INT16 WINAPI RestoreVisRgn( HDC16 hdc )
562 {
563     HRGN32 saved;
564     RGNOBJ *obj, *savedObj;
565     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
566     INT16 ret;
567
568     if (!dc) return ERROR;    
569     if (!dc->w.hVisRgn)
570     {
571         GDI_HEAP_UNLOCK( hdc );
572         return ERROR;    
573     }
574     TRACE(clipping, "%04x\n", hdc );
575     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
576     {
577         GDI_HEAP_UNLOCK( hdc );
578         return ERROR;
579     }
580     if (!(saved = obj->header.hNext)) 
581     {
582         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
583         GDI_HEAP_UNLOCK( hdc );
584         return ERROR;
585     }
586     if (!(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC )))
587     {
588         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
589         GDI_HEAP_UNLOCK( hdc );
590         return ERROR;
591     }
592     DeleteObject32( dc->w.hVisRgn );
593     dc->w.hVisRgn = saved;
594     CLIPPING_UpdateGCRegion( dc );
595     GDI_HEAP_UNLOCK( hdc );
596     ret = savedObj->rgn->type; /* FIXME */
597     GDI_HEAP_UNLOCK( saved );
598     return ret;
599 }