Remove X_DC_INFO from DC and make it behave like any other PDEVICE.
[wine] / graphics / x11drv / bitmap.c
1 /*
2  * X11DRV bitmap objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "ts_xlib.h"
10 #include "ts_xutil.h"
11 #include "gdi.h"
12 #include "callback.h"
13 #include "dc.h"
14 #include "bitmap.h"
15 #include "heap.h"
16 #include "debug.h"
17 #include "xmalloc.h"
18 #include "x11drv.h"
19
20   /* GCs used for B&W and color bitmap operations */
21 GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
22
23
24 /***********************************************************************
25  *           X11DRV_BITMAP_Init
26  */
27 BOOL32 X11DRV_BITMAP_Init(void)
28 {
29     Pixmap tmpPixmap;
30     
31       /* Create the necessary GCs */
32     
33     if ((tmpPixmap = TSXCreatePixmap( display, rootWindow, 1, 1, 1 )))
34     {
35         BITMAP_monoGC = TSXCreateGC( display, tmpPixmap, 0, NULL );
36         TSXSetGraphicsExposures( display, BITMAP_monoGC, False );
37         TSXFreePixmap( display, tmpPixmap );
38     }
39
40     if (screenDepth != 1)
41     {
42         if ((tmpPixmap = TSXCreatePixmap(display, rootWindow, 1,1,screenDepth)))
43         {
44             BITMAP_colorGC = TSXCreateGC( display, tmpPixmap, 0, NULL );
45             TSXSetGraphicsExposures( display, BITMAP_colorGC, False );
46             TSXFreePixmap( display, tmpPixmap );
47         }
48     }
49     return TRUE;
50 }
51
52 /***********************************************************************
53  *           X11DRV_BITMAP_SelectObject
54  */
55 HBITMAP32 X11DRV_BITMAP_SelectObject( DC * dc, HBITMAP32 hbitmap,
56                                       BITMAPOBJ * bmp )
57 {
58     HRGN32 hrgn;
59     HBITMAP32 prevHandle = dc->w.hBitmap;
60     X11DRV_PHYSBITMAP *pbitmap;
61     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
62
63
64     if (!(dc->w.flags & DC_MEMORY)) return 0;
65
66     if(!bmp->DDBitmap)
67         if(!X11DRV_CreateBitmap(hbitmap))
68             return 0;
69
70     if(bmp->DDBitmap->funcs != dc->funcs) {
71         WARN(x11drv, "Trying to select non-X11 DDB into an X11 dc\n");
72         return 0;
73     }
74
75     pbitmap = bmp->DDBitmap->physBitmap;
76
77     dc->w.totalExtent.left   = 0;
78     dc->w.totalExtent.top    = 0;
79     dc->w.totalExtent.right  = bmp->bitmap.bmWidth;
80     dc->w.totalExtent.bottom = bmp->bitmap.bmHeight;
81
82     if (dc->w.hVisRgn)
83        SetRectRgn32( dc->w.hVisRgn, 0, 0,
84                      bmp->bitmap.bmWidth, bmp->bitmap.bmHeight );
85     else
86     { 
87        hrgn = CreateRectRgn32(0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight);
88        if (!hrgn) return 0;
89        dc->w.hVisRgn    = hrgn;
90     }
91
92     physDev->drawable = pbitmap->pixmap;
93     dc->w.hBitmap     = hbitmap;
94
95       /* Change GC depth if needed */
96
97     if (dc->w.bitsPerPixel != bmp->bitmap.bmBitsPixel)
98     {
99         TSXFreeGC( display, physDev->gc );
100         physDev->gc = TSXCreateGC( display, physDev->drawable, 0, NULL );
101         dc->w.bitsPerPixel = bmp->bitmap.bmBitsPixel;
102         DC_InitDC( dc );
103     }
104     else CLIPPING_UpdateGCRegion( dc );  /* Just update GC clip region */
105     return prevHandle;
106 }
107
108
109 /***********************************************************************
110  *           XPutImage_wrapper
111  *
112  * Wrapper to call XPutImage with CALL_LARGE_STACK.
113  */
114
115 struct XPutImage_descr
116 {
117     BITMAPOBJ *bmp;
118     XImage    *image;
119     INT32      width;
120     INT32      height;
121 };
122
123 static int XPutImage_wrapper( const struct XPutImage_descr *descr )
124 {
125     return XPutImage( display,
126                ((X11DRV_PHYSBITMAP *)descr->bmp->DDBitmap->physBitmap)->pixmap,
127                BITMAP_GC(descr->bmp),
128                descr->image, 0, 0, 0, 0, descr->width, descr->height );
129 }
130
131
132 /***************************************************************************
133  *
134  *      X11DRV_AllocBitmap
135  *
136  * Allocate DDBitmap and physBitmap
137  *
138  */
139 X11DRV_PHYSBITMAP *X11DRV_AllocBitmap( BITMAPOBJ *bmp )
140 {
141     X11DRV_PHYSBITMAP *pbitmap;
142
143     if(!(bmp->DDBitmap = HeapAlloc(GetProcessHeap(), 0, sizeof(DDBITMAP)))) {
144         WARN(x11drv, "Can't alloc DDBITMAP\n");
145         return NULL;
146     }
147
148     if(!(pbitmap = HeapAlloc(GetProcessHeap(), 0,sizeof(X11DRV_PHYSBITMAP)))) {
149         WARN(x11drv, "Can't alloc X11DRV_PHYSBITMAP\n");
150         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap);
151         return NULL;
152     }
153
154     bmp->DDBitmap->physBitmap = pbitmap;
155     bmp->DDBitmap->funcs = DRIVER_FindDriver( "DISPLAY" );
156     return pbitmap;
157 }
158
159
160 /****************************************************************************
161  *
162  *        X11DRV_CreateBitmap
163  *
164  * Create a device dependent X11 bitmap
165  *
166  * Returns TRUE on success else FALSE
167  *
168  */
169
170 BOOL32 X11DRV_CreateBitmap( HBITMAP32 hbitmap )
171 {
172     X11DRV_PHYSBITMAP *pbitmap;
173     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
174
175     if(!bmp) {
176         WARN(x11drv, "Bad bitmap handle %08x\n", hbitmap);
177         return FALSE;
178     }
179
180       /* Check parameters */
181     if (bmp->bitmap.bmPlanes != 1) return 0;
182     if ((bmp->bitmap.bmBitsPixel != 1) && 
183         (bmp->bitmap.bmBitsPixel != screenDepth)) {
184         ERR(x11drv, "Trying to make bitmap with planes=%d, bpp=%d\n",
185             bmp->bitmap.bmPlanes, bmp->bitmap.bmBitsPixel);
186         GDI_HEAP_UNLOCK( hbitmap );
187         return FALSE;
188     }
189
190     TRACE(x11drv, "(%08x) %dx%d %d bpp\n", hbitmap, bmp->bitmap.bmWidth,
191           bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
192
193     pbitmap = X11DRV_AllocBitmap( bmp );
194     if(!pbitmap) return FALSE;
195
196       /* Create the pixmap */
197     pbitmap->pixmap = TSXCreatePixmap(display, rootWindow, bmp->bitmap.bmWidth,
198                               bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
199     if (!pbitmap->pixmap) {
200         WARN(x11drv, "Can't create Pixmap\n");
201         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap->physBitmap);
202         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap);
203         GDI_HEAP_UNLOCK( hbitmap );
204         return FALSE;
205     }
206
207     if (bmp->bitmap.bmBits) /* Set bitmap bits */
208         X11DRV_BitmapBits( hbitmap, bmp->bitmap.bmBits,
209                            bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes,
210                            DDB_SET );
211
212     GDI_HEAP_UNLOCK( hbitmap );
213     return TRUE;
214 }
215
216
217 /***********************************************************************
218  *           X11DRV_BITMAP_GetXImage
219  *
220  * Get an X image for a bitmap. For use with CALL_LARGE_STACK.
221  */
222 XImage *X11DRV_BITMAP_GetXImage( const BITMAPOBJ *bmp )
223 {
224     return XGetImage( display,
225                       ((X11DRV_PHYSBITMAP *)bmp->DDBitmap->physBitmap)->pixmap,
226                       0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
227                       AllPlanes, ZPixmap );
228 }
229
230
231 /***********************************************************************
232  *           X11DRV_GetBitmapBits
233  * 
234  * RETURNS
235  *    Success: Number of bytes copied
236  *    Failure: 0
237  */
238 static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
239 {
240     LONG old_height, height;
241     XImage *image;
242     LPBYTE tbuf;
243     int h, w, pad;
244
245     TRACE(x11drv, "(bmp=%p, buffer=%p, count=0x%lx)\n", bmp, buffer, count);
246
247     pad = BITMAP_GetPadding(bmp->bitmap.bmWidth, bmp->bitmap.bmBitsPixel);
248
249     if (pad == -1)
250         return 0;
251
252     EnterCriticalSection( &X11DRV_CritSection );
253
254     /* Hack: change the bitmap height temporarily to avoid */
255     /*       getting unnecessary bitmap rows. */
256
257     old_height = bmp->bitmap.bmHeight;
258     height = bmp->bitmap.bmHeight = count / bmp->bitmap.bmWidthBytes;
259
260     image = (XImage *)CALL_LARGE_STACK( X11DRV_BITMAP_GetXImage, bmp );
261
262     bmp->bitmap.bmHeight = old_height;
263
264     /* copy XImage to 16 bit padded image buffer with real bitsperpixel */
265
266     tbuf = buffer;
267     switch (bmp->bitmap.bmBitsPixel)
268     {
269     case 1:
270         for (h=0;h<height;h++)
271         {
272             *tbuf = 0;
273             for (w=0;w<bmp->bitmap.bmWidth;w++)
274             {
275                 if ((w%8) == 0)
276                     *tbuf = 0;
277                 *tbuf |= XGetPixel(image,w,h)<<(7-(w&7));
278                 if ((w&7) == 7) ++tbuf;
279             }
280             tbuf += pad;
281         }
282         break;
283     case 4:
284         for (h=0;h<height;h++)
285         {
286             for (w=0;w<bmp->bitmap.bmWidth;w++)
287             {
288                 if (!(w & 1)) *tbuf = XGetPixel( image, w, h) << 4;
289                 else *tbuf++ |= XGetPixel( image, w, h) & 0x0f;
290             }
291             tbuf += pad;
292         }
293         break;
294     case 8:
295         for (h=0;h<height;h++)
296         {
297             for (w=0;w<bmp->bitmap.bmWidth;w++)
298                 *tbuf++ = XGetPixel(image,w,h);
299             tbuf += pad;
300         }
301         break;
302     case 15:
303     case 16:
304         for (h=0;h<height;h++)
305         {
306             for (w=0;w<bmp->bitmap.bmWidth;w++)
307             {
308                 long pixel = XGetPixel(image,w,h);
309
310                 *tbuf++ = pixel & 0xff;
311                 *tbuf++ = (pixel>>8) & 0xff;
312             }
313         }
314         break;
315     case 24:
316         for (h=0;h<height;h++)
317         {
318             for (w=0;w<bmp->bitmap.bmWidth;w++)
319             {
320                 long pixel = XGetPixel(image,w,h);
321
322                 *tbuf++ = pixel & 0xff;
323                 *tbuf++ = (pixel>> 8) & 0xff;
324                 *tbuf++ = (pixel>>16) & 0xff;
325             }
326             tbuf += pad;
327         }
328         break;
329
330     case 32:
331         for (h=0;h<height;h++)
332         {
333             for (w=0;w<bmp->bitmap.bmWidth;w++)
334             {
335                 long pixel = XGetPixel(image,w,h);
336
337                 *tbuf++ = pixel & 0xff;
338                 *tbuf++ = (pixel>> 8) & 0xff;
339                 *tbuf++ = (pixel>>16) & 0xff;
340                 *tbuf++ = (pixel>>24) & 0xff;
341             }
342             tbuf += pad;
343         }
344         break;
345     default:
346         FIXME(x11drv, "Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
347     }
348     XDestroyImage( image );
349     LeaveCriticalSection( &X11DRV_CritSection );
350
351     return count;
352 }
353
354
355
356 /******************************************************************************
357  *             X11DRV_SetBitmapBits
358  *
359  * RETURNS
360  *    Success: Number of bytes used in setting the bitmap bits
361  *    Failure: 0
362  */
363 static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count)
364 {
365     struct XPutImage_descr descr;
366     LONG height;
367     XImage *image;
368     LPBYTE sbuf;
369     int w, h, pad;
370
371     TRACE(x11drv, "(bmp=%p, bits=%p, count=0x%lx)\n", bmp, bits, count);
372     
373     pad = BITMAP_GetPadding(bmp->bitmap.bmWidth, bmp->bitmap.bmBitsPixel);
374
375     if (pad == -1) 
376         return 0;
377         
378     sbuf = (LPBYTE)bits;
379
380     height = count / bmp->bitmap.bmWidthBytes;
381
382     EnterCriticalSection( &X11DRV_CritSection );
383     image = XCreateImage( display, DefaultVisualOfScreen(screen),
384                           bmp->bitmap.bmBitsPixel, ZPixmap, 0, NULL,
385                           bmp->bitmap.bmWidth, height, 32, 0 );
386     image->data = (LPBYTE)xmalloc(image->bytes_per_line * height);
387     
388     /* copy 16 bit padded image buffer with real bitsperpixel to XImage */
389     sbuf = (LPBYTE)bits;
390     switch (bmp->bitmap.bmBitsPixel)
391     {
392     case 1:
393         for (h=0;h<height;h++)
394         {
395             for (w=0;w<bmp->bitmap.bmWidth;w++)
396             {
397                 XPutPixel(image,w,h,(sbuf[0]>>(7-(w&7))) & 1);
398                 if ((w&7) == 7)
399                     sbuf++;
400             }
401             sbuf += pad;
402         }
403         break;
404     case 4:
405         for (h=0;h<height;h++)
406         {
407             for (w=0;w<bmp->bitmap.bmWidth;w++)
408             {
409                 if (!(w & 1)) XPutPixel( image, w, h, *sbuf >> 4 );
410                 else XPutPixel( image, w, h, *sbuf++ & 0xf );
411             }
412             sbuf += pad;
413         }
414         break;
415     case 8:
416         for (h=0;h<height;h++)
417         {
418             for (w=0;w<bmp->bitmap.bmWidth;w++)
419                 XPutPixel(image,w,h,*sbuf++);
420             sbuf += pad;
421         }
422         break;
423     case 15:
424     case 16:
425         for (h=0;h<height;h++)
426         {
427             for (w=0;w<bmp->bitmap.bmWidth;w++)
428             {
429                 XPutPixel(image,w,h,sbuf[1]*256+sbuf[0]);
430                 sbuf+=2;
431             }
432         }
433         break;
434     case 24: 
435         for (h=0;h<height;h++)
436         {
437             for (w=0;w<bmp->bitmap.bmWidth;w++)
438             {
439                 XPutPixel(image,w,h,(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
440                 sbuf += 3;
441             }
442             sbuf += pad;
443         }
444         break;
445     case 32: 
446         for (h=0;h<height;h++)
447         {
448             for (w=0;w<bmp->bitmap.bmWidth;w++)
449             {
450                 XPutPixel(image,w,h,(sbuf[3]<<24)+(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
451                 sbuf += 4;
452             }
453             sbuf += pad;
454         }
455         break;
456     default:
457       FIXME(x11drv, "Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
458
459     }
460
461     descr.bmp    = bmp;
462     descr.image  = image;
463     descr.width  = bmp->bitmap.bmWidth;
464     descr.height = height;
465
466     CALL_LARGE_STACK( XPutImage_wrapper, &descr );
467     XDestroyImage( image ); /* frees image->data too */
468     LeaveCriticalSection( &X11DRV_CritSection );
469     
470     return count;
471 }
472
473 /***********************************************************************
474  *           X11DRV_BitmapBits
475  */
476 LONG X11DRV_BitmapBits(HBITMAP32 hbitmap, void *bits, LONG count, WORD flags)
477 {
478     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
479     LONG ret;
480     if(!bmp) {
481         WARN(x11drv, "Bad bitmap handle %08x\n", hbitmap);
482         return FALSE;
483     }
484
485     if(flags == DDB_GET)
486         ret = X11DRV_GetBitmapBits(bmp, bits, count);
487     else if(flags == DDB_SET)
488         ret = X11DRV_SetBitmapBits(bmp, bits, count);
489     else {
490         ERR(x11drv, "Unknown flags value %d\n", flags);
491         ret = 0;
492     }
493     
494     GDI_HEAP_UNLOCK( hbitmap );
495     return ret;
496 }
497
498 /***********************************************************************
499  *           X11DRV_BITMAP_DeleteObject
500  */
501 BOOL32 X11DRV_BITMAP_DeleteObject( HBITMAP32 hbitmap, BITMAPOBJ * bmp )
502 {
503     X11DRV_PHYSBITMAP *pbitmap = bmp->DDBitmap->physBitmap;
504
505     TSXFreePixmap( display, pbitmap->pixmap );
506
507     HeapFree( GetProcessHeap(), 0, bmp->DDBitmap->physBitmap );
508     HeapFree( GetProcessHeap(), 0, bmp->DDBitmap );
509     bmp->DDBitmap = NULL;
510
511     return TRUE;
512 }