Adapted to new input event handling.
[wine] / objects / dib.c
1 /*
2  * GDI device-independent bitmaps
3  *
4  * Copyright 1993,1994  Alexandre Julliard
5  *
6  * TODO: Still contains some references to X11DRV.
7  */
8
9 #include <stdlib.h>
10 #include "dc.h"
11 #include "bitmap.h"
12 #include "callback.h"
13 #include "palette.h"
14 #include "color.h"
15 #include "global.h"
16 #include "debug.h"
17 #include "x11drv.h"
18
19
20 /***********************************************************************
21  *           DIB_GetDIBWidthBytes
22  *
23  * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
24  * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
25  */
26 int DIB_GetDIBWidthBytes( int width, int depth )
27 {
28     int words;
29
30     switch(depth)
31     {
32         case 1:  words = (width + 31) / 32; break;
33         case 4:  words = (width + 7) / 8; break;
34         case 8:  words = (width + 3) / 4; break;
35         case 15:
36         case 16: words = (width + 1) / 2; break;
37         case 24: words = (width * 3 + 3)/4; break;
38
39         default:
40             WARN(bitmap, "(%d): Unsupported depth\n", depth );
41         /* fall through */
42         case 32:
43                 words = width;
44     }
45     return 4 * words;
46 }
47
48
49 /***********************************************************************
50  *           DIB_BitmapInfoSize
51  *
52  * Return the size of the bitmap info structure including color table.
53  */
54 int DIB_BitmapInfoSize( BITMAPINFO * info, WORD coloruse )
55 {
56     int colors;
57
58     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
59     {
60         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
61         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
62         return sizeof(BITMAPCOREHEADER) + colors *
63              ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
64     }
65     else  /* assume BITMAPINFOHEADER */
66     {
67         colors = info->bmiHeader.biClrUsed;
68         if (!colors && (info->bmiHeader.biBitCount <= 8))
69             colors = 1 << info->bmiHeader.biBitCount;
70         return sizeof(BITMAPINFOHEADER) + colors *
71                ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
72     }
73 }
74
75
76 /***********************************************************************
77  *           DIB_GetBitmapInfo
78  *
79  * Get the info from a bitmap header.
80  * Return 1 for INFOHEADER, 0 for COREHEADER, -1 for error.
81  */
82 int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, DWORD *width,
83                               int *height, WORD *bpp, WORD *compr )
84 {
85     if (header->biSize == sizeof(BITMAPINFOHEADER))
86     {
87         *width  = header->biWidth;
88         *height = header->biHeight;
89         *bpp    = header->biBitCount;
90         *compr  = header->biCompression;
91         return 1;
92     }
93     if (header->biSize == sizeof(BITMAPCOREHEADER))
94     {
95         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)header;
96         *width  = core->bcWidth;
97         *height = core->bcHeight;
98         *bpp    = core->bcBitCount;
99         *compr  = 0;
100         return 0;
101     }
102     WARN(bitmap, "(%ld): wrong size for header\n", header->biSize );
103     return -1;
104 }
105
106
107 /***********************************************************************
108  *           StretchDIBits16   (GDI.439)
109  */
110 INT16 WINAPI StretchDIBits16(HDC16 hdc, INT16 xDst, INT16 yDst, INT16 widthDst,
111                        INT16 heightDst, INT16 xSrc, INT16 ySrc, INT16 widthSrc,
112                        INT16 heightSrc, const VOID *bits,
113                        const BITMAPINFO *info, UINT16 wUsage, DWORD dwRop )
114 {
115     return (INT16)StretchDIBits32( hdc, xDst, yDst, widthDst, heightDst,
116                                    xSrc, ySrc, widthSrc, heightSrc, bits,
117                                    info, wUsage, dwRop );
118 }
119
120
121 /***********************************************************************
122  *           StretchDIBits32   (GDI32.351)
123  */
124 INT32 WINAPI StretchDIBits32(HDC32 hdc, INT32 xDst, INT32 yDst, INT32 widthDst,
125                        INT32 heightDst, INT32 xSrc, INT32 ySrc, INT32 widthSrc,
126                        INT32 heightSrc, const void *bits,
127                        const BITMAPINFO *info, UINT32 wUsage, DWORD dwRop )
128 {
129     DC *dc = DC_GetDCPtr( hdc );
130     if(!dc) return FALSE;
131
132     if(dc->funcs->pStretchDIBits)
133            return dc->funcs->pStretchDIBits(dc, xDst, yDst, widthDst, 
134                                             heightDst, xSrc, ySrc, widthSrc,
135                                             heightSrc, bits, info, wUsage,
136                                             dwRop);
137     else { /* use StretchBlt32 */
138         HBITMAP32 hBitmap, hOldBitmap;
139         HDC32 hdcMem;
140     
141         hBitmap = CreateDIBitmap32( hdc, &info->bmiHeader, CBM_INIT,
142                                     bits, info, wUsage );
143         hdcMem = CreateCompatibleDC32( hdc );
144         hOldBitmap = SelectObject32( hdcMem, hBitmap );
145         StretchBlt32( hdc, xDst, yDst, widthDst, heightDst,
146                       hdcMem, xSrc, ySrc, widthSrc, heightSrc, dwRop );
147         SelectObject32( hdcMem, hOldBitmap );
148         DeleteDC32( hdcMem );
149         DeleteObject32( hBitmap );
150         return heightSrc;
151     }
152 }
153
154
155 /***********************************************************************
156  *           SetDIBits16    (GDI.440)
157  */
158 INT16 WINAPI SetDIBits16( HDC16 hdc, HBITMAP16 hbitmap, UINT16 startscan,
159                           UINT16 lines, LPCVOID bits, const BITMAPINFO *info,
160                           UINT16 coloruse )
161 {
162     return SetDIBits32( hdc, hbitmap, startscan, lines, bits, info, coloruse );
163 }
164
165
166 /******************************************************************************
167  * SetDIBits32 [GDI32.312]  Sets pixels in a bitmap using colors from DIB
168  *
169  * PARAMS
170  *    hdc       [I] Handle to device context
171  *    hbitmap   [I] Handle to bitmap
172  *    startscan [I] Starting scan line
173  *    lines     [I] Number of scan lines
174  *    bits      [I] Array of bitmap bits
175  *    info      [I] Address of structure with data
176  *    coloruse  [I] Type of color indexes to use
177  *
178  * RETURNS
179  *    Success: Number of scan lines copied
180  *    Failure: 0
181  */
182 INT32 WINAPI SetDIBits32( HDC32 hdc, HBITMAP32 hbitmap, UINT32 startscan,
183                           UINT32 lines, LPCVOID bits, const BITMAPINFO *info,
184                           UINT32 coloruse )
185 {
186     DIB_SETIMAGEBITS_DESCR descr;
187     BITMAPOBJ * bmp;
188     int height, tmpheight;
189     INT32 result;
190
191       /* Check parameters */
192
193     descr.dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
194     if (!descr.dc) 
195     {
196         descr.dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
197         if (!descr.dc) return 0;
198     }
199     if (!(bmp = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
200     {
201         GDI_HEAP_UNLOCK( hdc );
202         return 0;
203     }
204     if (DIB_GetBitmapInfo( &info->bmiHeader, &descr.infoWidth, &height,
205                            &descr.infoBpp, &descr.compression ) == -1)
206     {
207         GDI_HEAP_UNLOCK( hbitmap );
208         GDI_HEAP_UNLOCK( hdc );
209         return 0;
210     }
211     tmpheight = height;
212     if (height < 0) height = -height;
213     if (!lines || (startscan >= height))
214     {
215         GDI_HEAP_UNLOCK( hbitmap );
216         GDI_HEAP_UNLOCK( hdc );
217         return 0;
218     }
219     if (startscan + lines > height) lines = height - startscan;
220
221     if (descr.infoBpp <= 8)
222     {
223         descr.colorMap = X11DRV_DIB_BuildColorMap( descr.dc, coloruse,
224                                                    bmp->bitmap.bmBitsPixel,
225                                                    info, &descr.nColorMap );
226         if (!descr.colorMap)
227         {
228             GDI_HEAP_UNLOCK( hbitmap );
229             GDI_HEAP_UNLOCK( hdc );
230             return 0;
231         } 
232     } else
233         descr.colorMap = 0;
234
235     /* HACK for now */
236     if(!bmp->DDBitmap)
237         X11DRV_CreateBitmap(hbitmap);
238 {
239     X11DRV_PHYSBITMAP *pbitmap = bmp->DDBitmap->physBitmap;
240
241
242     descr.bits      = bits;
243     descr.image     = NULL;
244     descr.lines     = tmpheight >= 0 ? lines : -lines;
245     descr.depth     = bmp->bitmap.bmBitsPixel;
246     descr.drawable  = pbitmap->pixmap;
247     descr.gc        = BITMAP_GC(bmp);
248     descr.xSrc      = 0;
249     descr.ySrc      = 0;
250     descr.xDest     = 0;
251     descr.yDest     = height - startscan - lines;
252     descr.width     = bmp->bitmap.bmWidth;
253     descr.height    = lines;
254 }
255     EnterCriticalSection( &X11DRV_CritSection );
256     result = CALL_LARGE_STACK( X11DRV_DIB_SetImageBits, &descr );
257     LeaveCriticalSection( &X11DRV_CritSection );
258
259     if (descr.colorMap) HeapFree(GetProcessHeap(), 0, descr.colorMap);
260
261     GDI_HEAP_UNLOCK( hdc );
262     GDI_HEAP_UNLOCK( hbitmap );
263     return result;
264 }
265
266
267 /***********************************************************************
268  *           SetDIBitsToDevice16    (GDI.443)
269  */
270 INT16 WINAPI SetDIBitsToDevice16(HDC16 hdc, INT16 xDest, INT16 yDest, INT16 cx,
271                            INT16 cy, INT16 xSrc, INT16 ySrc, UINT16 startscan,
272                            UINT16 lines, LPCVOID bits, const BITMAPINFO *info,
273                            UINT16 coloruse )
274 {
275     return SetDIBitsToDevice32( hdc, xDest, yDest, cx, cy, xSrc, ySrc,
276                                 startscan, lines, bits, info, coloruse );
277 }
278
279
280 /***********************************************************************
281  *           SetDIBitsToDevice32   (GDI32.313)
282  */
283 INT32 WINAPI SetDIBitsToDevice32(HDC32 hdc, INT32 xDest, INT32 yDest, DWORD cx,
284                            DWORD cy, INT32 xSrc, INT32 ySrc, UINT32 startscan,
285                            UINT32 lines, LPCVOID bits, const BITMAPINFO *info,
286                            UINT32 coloruse )
287 {
288     INT32 ret;
289     DC *dc;
290
291     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
292
293     if(dc->funcs->pSetDIBitsToDevice)
294         ret = dc->funcs->pSetDIBitsToDevice( dc, xDest, yDest, cx, cy, xSrc,
295                                              ySrc, startscan, lines, bits,
296                                              info, coloruse );
297     else {
298         FIXME(bitmap, "unimplemented on hdc %08x\n", hdc);
299         ret = 0;
300     }
301
302     GDI_HEAP_UNLOCK( hdc );
303     return ret;
304 }
305
306 /***********************************************************************
307  *           SetDIBColorTable16    (GDI.602)
308  */
309 UINT16 WINAPI SetDIBColorTable16( HDC16 hdc, UINT16 startpos, UINT16 entries,
310                                   RGBQUAD *colors )
311 {
312     return SetDIBColorTable32( hdc, startpos, entries, colors );
313 }
314
315 /***********************************************************************
316  *           SetDIBColorTable32    (GDI32.311)
317  */
318 UINT32 WINAPI SetDIBColorTable32( HDC32 hdc, UINT32 startpos, UINT32 entries,
319                                   RGBQUAD *colors )
320 {
321     DC * dc;
322     PALETTEENTRY * palEntry;
323     PALETTEOBJ * palette;
324     RGBQUAD *end;
325
326     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
327     if (!dc) 
328     {
329         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
330         if (!dc) return 0;
331     }
332
333     if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->w.hPalette, PALETTE_MAGIC )))
334     {
335         return 0;
336     }
337
338     /* Transfer color info */
339     
340     if (dc->w.bitsPerPixel <= 8) {
341         palEntry = palette->logpalette.palPalEntry + startpos;
342         if (startpos + entries > (1 << dc->w.bitsPerPixel)) {
343             entries = (1 << dc->w.bitsPerPixel) - startpos;
344         }
345         for (end = colors + entries; colors < end; palEntry++, colors++)
346         {
347             palEntry->peRed   = colors->rgbRed;
348             palEntry->peGreen = colors->rgbGreen;
349             palEntry->peBlue  = colors->rgbBlue;
350         }
351     } else {
352         entries = 0;
353     }
354     GDI_HEAP_UNLOCK( dc->w.hPalette );
355     return entries;
356 }
357
358 /***********************************************************************
359  *           GetDIBColorTable16    (GDI.603)
360  */
361 UINT16 WINAPI GetDIBColorTable16( HDC16 hdc, UINT16 startpos, UINT16 entries,
362                                   RGBQUAD *colors )
363 {
364     return GetDIBColorTable32( hdc, startpos, entries, colors );
365 }
366
367 /***********************************************************************
368  *           GetDIBColorTable32    (GDI32.169)
369  */
370 UINT32 WINAPI GetDIBColorTable32( HDC32 hdc, UINT32 startpos, UINT32 entries,
371                                   RGBQUAD *colors )
372 {
373     DC * dc;
374     PALETTEENTRY * palEntry;
375     PALETTEOBJ * palette;
376     RGBQUAD *end;
377
378     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
379     if (!dc) 
380     {
381         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
382         if (!dc) return 0;
383     }
384
385     if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->w.hPalette, PALETTE_MAGIC )))
386     {
387         return 0;
388     }
389
390     /* Transfer color info */
391     
392     if (dc->w.bitsPerPixel <= 8) {
393         palEntry = palette->logpalette.palPalEntry + startpos;
394         if (startpos + entries > (1 << dc->w.bitsPerPixel)) {
395             entries = (1 << dc->w.bitsPerPixel) - startpos;
396         }
397         for (end = colors + entries; colors < end; palEntry++, colors++)
398         {
399             colors->rgbRed      = palEntry->peRed;
400             colors->rgbGreen    = palEntry->peGreen;
401             colors->rgbBlue     = palEntry->peBlue;
402             colors->rgbReserved = 0;
403         }
404     } else {
405         entries = 0;
406     }
407     GDI_HEAP_UNLOCK( dc->w.hPalette );
408     return entries;
409 }
410
411 /***********************************************************************
412  *           GetDIBits16    (GDI.441)
413  */
414 INT16 WINAPI GetDIBits16( HDC16 hdc, HBITMAP16 hbitmap, UINT16 startscan,
415                           UINT16 lines, LPSTR bits, BITMAPINFO * info,
416                           UINT16 coloruse )
417 {
418     return GetDIBits32( hdc, hbitmap, startscan, lines, bits, info, coloruse );
419 }
420
421
422 /******************************************************************************
423  * GetDIBits32 [GDI32.170]  Retrieves bits of bitmap and copies to buffer
424  *
425  * RETURNS
426  *    Success: Number of scan lines copied from bitmap
427  *    Failure: 0
428  *
429  * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/func/src/f30_14.htm
430  */
431 INT32 WINAPI GetDIBits32(
432     HDC32 hdc,         /* [in]  Handle to device context */
433     HBITMAP32 hbitmap, /* [in]  Handle to bitmap */
434     UINT32 startscan,  /* [in]  First scan line to set in dest bitmap */
435     UINT32 lines,      /* [in]  Number of scan lines to copy */
436     LPSTR bits,        /* [out] Address of array for bitmap bits */
437     BITMAPINFO * info, /* [out] Address of structure with bitmap data */
438     UINT32 coloruse)   /* [in]  RGB or palette index */
439 {
440     DC * dc;
441     BITMAPOBJ * bmp;
442     PALETTEENTRY * palEntry;
443     PALETTEOBJ * palette;
444     XImage * bmpImage;
445     int i, x, y;
446
447     if (!lines) return 0;
448     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
449     if (!dc) 
450     {
451         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
452         if (!dc) return 0;
453     }
454     if (!(bmp = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
455         return 0;
456     if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->w.hPalette, PALETTE_MAGIC )))
457     {
458         GDI_HEAP_UNLOCK( hbitmap );
459         return 0;
460     }
461
462       /* Transfer color info */
463     
464     if (info->bmiHeader.biBitCount<=8) {
465         int colors = info->bmiHeader.biClrUsed;
466         if (!colors && (info->bmiHeader.biBitCount <= 8))
467             colors = 1 << info->bmiHeader.biBitCount;
468         palEntry = palette->logpalette.palPalEntry;
469         for (i = 0; i < colors; i++, palEntry++)
470         {
471             if (coloruse == DIB_RGB_COLORS)
472             {
473                 info->bmiColors[i].rgbRed      = palEntry->peRed;
474                 info->bmiColors[i].rgbGreen    = palEntry->peGreen;
475                 info->bmiColors[i].rgbBlue     = palEntry->peBlue;
476                 info->bmiColors[i].rgbReserved = 0;
477             }
478             else ((WORD *)info->bmiColors)[i] = (WORD)i;
479         }
480     }
481
482     if (bits)
483     {   
484         BYTE*   bbits = bits;
485         int     pad, yend, xend = bmp->bitmap.bmWidth;
486
487         TRACE(bitmap, "%u scanlines of (%i,%i) -> (%i,%i) starting from %u\n",
488                             lines, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
489                             (int)info->bmiHeader.biWidth, (int)info->bmiHeader.biHeight, startscan );
490
491         /* adjust number of scanlines to copy */
492
493         if( lines > info->bmiHeader.biHeight ) lines = info->bmiHeader.biHeight;
494         yend = startscan + lines;
495         if( startscan >= bmp->bitmap.bmHeight ) 
496         {
497             GDI_HEAP_UNLOCK( hbitmap );
498             GDI_HEAP_UNLOCK( dc->w.hPalette );
499             return FALSE;
500         }
501         if( yend > bmp->bitmap.bmHeight ) yend = bmp->bitmap.bmHeight;
502
503         /* adjust scanline width */
504
505         pad = info->bmiHeader.biWidth - bmp->bitmap.bmWidth;
506         if( pad < 0 ) 
507         {
508             /* bitmap is wider than DIB, copy only a part */
509
510             pad = 0;
511             xend = info->bmiHeader.biWidth;
512         }
513
514         /* HACK for now */
515         if(!bmp->DDBitmap)
516             X11DRV_CreateBitmap(hbitmap);
517
518         EnterCriticalSection( &X11DRV_CritSection );
519         bmpImage = (XImage *)CALL_LARGE_STACK( X11DRV_BITMAP_GetXImage, bmp );
520
521         switch( info->bmiHeader.biBitCount )
522         {
523            case 8:
524                 /* pad up to 32 bit */
525                 pad += (4 - (info->bmiHeader.biWidth & 3)) & 3;
526                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
527                 {
528                    for( x = 0; x < xend; x++ )
529                         *bbits++ = XGetPixel( bmpImage, x, y );
530                    bbits += pad;
531                 }
532                 break;
533            case 1:
534                 pad += ((32 - (info->bmiHeader.biWidth & 31)) / 8) & 3;
535                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
536                 {
537                    for( x = 0; x < xend; x++ ) {
538                         if (!(x&7)) *bbits = 0;
539                         *bbits |= XGetPixel( bmpImage, x, y)<<(7-(x&7));
540                         if ((x&7)==7) bbits++;
541                    }
542                    bbits += pad;
543                 }
544                 break;
545            case 4:
546                 pad += ((8 - (info->bmiHeader.biWidth & 7)) / 2) & 3;
547                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
548                 {
549                    for( x = 0; x < xend; x++ ) {
550                         if (!(x&1)) *bbits = 0;
551                         *bbits |= XGetPixel( bmpImage, x, y)<<(4*(1-(x&1)));
552                         if ((x&1)==1) bbits++;
553                    }
554                    bbits += pad;
555                 }
556                 break;
557            case 15:
558            case 16:
559                 pad += (4 - ((info->bmiHeader.biWidth*2) & 3)) & 3;
560                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
561                 {
562                    for( x = 0; x < xend; x++ ) {
563                         unsigned long pixel=XGetPixel( bmpImage, x, y);
564                         *bbits++ = pixel & 0xff;
565                         *bbits++ = (pixel >> 8) & 0xff;
566                    }
567                    bbits += pad;
568                 }
569                 break;
570            case 24:
571                 pad += (4 - ((info->bmiHeader.biWidth*3) & 3)) & 3;
572                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
573                 {
574                    for( x = 0; x < xend; x++ ) {
575                         unsigned long pixel=XGetPixel( bmpImage, x, y);
576                         *bbits++ = (pixel >>16) & 0xff;
577                         *bbits++ = (pixel >> 8) & 0xff;
578                         *bbits++ =  pixel       & 0xff;
579                    }
580                    bbits += pad;
581                 }
582                 break;
583            case 32:
584                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
585                 {
586                    for( x = 0; x < xend; x++ ) {
587                         unsigned long pixel=XGetPixel( bmpImage, x, y);
588                         *bbits++ = (pixel >>16) & 0xff;
589                         *bbits++ = (pixel >> 8) & 0xff;
590                         *bbits++ =  pixel       & 0xff;
591                    }
592                 }
593                 break;
594            default:
595                 WARN(bitmap,"Unsupported depth %d\n",
596                    info->bmiHeader.biBitCount);
597                 break;
598         }
599
600         XDestroyImage( bmpImage );
601         LeaveCriticalSection( &X11DRV_CritSection );
602
603         info->bmiHeader.biCompression = 0;
604     }
605     else if( info->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER) ) 
606     {
607         /* fill in struct members */
608         
609         info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
610         info->bmiHeader.biHeight = bmp->bitmap.bmHeight;
611         info->bmiHeader.biPlanes = 1;
612         info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
613         info->bmiHeader.biSizeImage = bmp->bitmap.bmHeight *
614                              DIB_GetDIBWidthBytes( bmp->bitmap.bmWidth,
615                                                    bmp->bitmap.bmBitsPixel );
616         info->bmiHeader.biCompression = 0;
617     }
618
619     GDI_HEAP_UNLOCK( hbitmap );
620     GDI_HEAP_UNLOCK( dc->w.hPalette );
621     return lines;
622 }
623
624
625 /***********************************************************************
626  *           CreateDIBitmap16    (GDI.442)
627  */
628 HBITMAP16 WINAPI CreateDIBitmap16( HDC16 hdc, const BITMAPINFOHEADER * header,
629                             DWORD init, LPCVOID bits, const BITMAPINFO * data,
630                             UINT16 coloruse )
631 {
632     return CreateDIBitmap32( hdc, header, init, bits, data, coloruse );
633 }
634
635
636 /***********************************************************************
637  *           CreateDIBitmap32    (GDI32.37)
638  */
639 HBITMAP32 WINAPI CreateDIBitmap32( HDC32 hdc, const BITMAPINFOHEADER *header,
640                             DWORD init, LPCVOID bits, const BITMAPINFO *data,
641                             UINT32 coloruse )
642 {
643     HBITMAP32 handle;
644     BOOL32 fColor;
645     DWORD width;
646     int height;
647     WORD bpp;
648     WORD compr;
649
650     if (DIB_GetBitmapInfo( header, &width, &height, &bpp, &compr ) == -1) return 0;
651     if (height < 0) height = -height;
652
653     /* Check if we should create a monochrome or color bitmap. */
654     /* We create a monochrome bitmap only if it has exactly 2  */
655     /* colors, which are either black or white, nothing else.  */
656     /* In all other cases, we create a color bitmap.           */
657
658     if (bpp != 1) fColor = TRUE;
659     else if ((coloruse != DIB_RGB_COLORS) ||
660              (init != CBM_INIT) || !data) fColor = FALSE;
661     else
662     {
663         if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
664         {
665             RGBQUAD *rgb = data->bmiColors;
666             DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
667             if ((col == RGB(0,0,0)) || (col == RGB(0xff,0xff,0xff)))
668             {
669                 rgb++;
670                 col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
671                 fColor = ((col != RGB(0,0,0)) && (col != RGB(0xff,0xff,0xff)));
672             }
673             else fColor = TRUE;
674         }
675         else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
676         {
677             RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors;
678             DWORD col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue );
679             if ((col == RGB(0,0,0)) || (col == RGB(0xff,0xff,0xff)))
680             {
681                 rgb++;
682                 col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue );
683                 fColor = ((col != RGB(0,0,0)) && (col != RGB(0xff,0xff,0xff)));
684             }
685             else fColor = TRUE;
686         }
687         else
688         {
689             WARN(bitmap, "(%ld): wrong size for data\n",
690                      data->bmiHeader.biSize );
691             return 0;
692         }
693     }
694
695     /* Now create the bitmap */
696
697     handle = fColor ? CreateBitmap32( width, height, 1, screenDepth, NULL ) :
698                       CreateBitmap32( width, height, 1, 1, NULL );
699     if (!handle) return 0;
700
701     if (init == CBM_INIT)
702         SetDIBits32( hdc, handle, 0, height, bits, data, coloruse );
703     return handle;
704 }
705
706
707 /***********************************************************************
708  *           DIB_DoProtectDIBSection
709  */
710 static void DIB_DoProtectDIBSection( BITMAPOBJ *bmp, DWORD new_prot )
711 {
712     DIBSECTION *dib = &bmp->dib->dibSection;
713     INT32 effHeight = dib->dsBm.bmHeight >= 0? dib->dsBm.bmHeight
714                                              : -dib->dsBm.bmHeight;
715     INT32 totalSize = dib->dsBmih.biSizeImage? dib->dsBmih.biSizeImage
716                          : dib->dsBm.bmWidthBytes * effHeight;
717     DWORD old_prot;
718
719     VirtualProtect(dib->dsBm.bmBits, totalSize, new_prot, &old_prot);
720     TRACE(bitmap, "Changed protection from %ld to %ld\n", 
721                   old_prot, new_prot);
722 }
723
724 /***********************************************************************
725  *           DIB_DoUpdateDIBSection
726  */
727 static void DIB_DoUpdateDIBSection( BITMAPOBJ *bmp, BOOL32 toDIB )
728 {
729     DIBSECTIONOBJ *dib = bmp->dib;
730     DIB_SETIMAGEBITS_DESCR descr;
731
732     if (DIB_GetBitmapInfo( &dib->dibSection.dsBmih, &descr.infoWidth, &descr.lines,
733                            &descr.infoBpp, &descr.compression ) == -1)
734         return;
735
736     descr.dc        = NULL;
737     descr.image     = dib->image;
738     descr.colorMap  = dib->colorMap;
739     descr.nColorMap = dib->nColorMap;
740     descr.bits      = dib->dibSection.dsBm.bmBits;
741     descr.depth     = bmp->bitmap.bmBitsPixel;
742     
743     /* Hack for now */
744     descr.drawable  = ((X11DRV_PHYSBITMAP *)bmp->DDBitmap->physBitmap)->pixmap;
745     descr.gc        = BITMAP_GC(bmp);
746     descr.xSrc      = 0;
747     descr.ySrc      = 0;
748     descr.xDest     = 0;
749     descr.yDest     = 0;
750     descr.width     = bmp->bitmap.bmWidth;
751     descr.height    = bmp->bitmap.bmHeight;
752
753     if (toDIB)
754     {
755         TRACE(bitmap, "Copying from Pixmap to DIB bits\n");
756         EnterCriticalSection( &X11DRV_CritSection );
757         CALL_LARGE_STACK( X11DRV_DIB_GetImageBits, &descr );
758         LeaveCriticalSection( &X11DRV_CritSection );
759     }
760     else
761     {
762         TRACE(bitmap, "Copying from DIB bits to Pixmap\n"); 
763         EnterCriticalSection( &X11DRV_CritSection );
764         CALL_LARGE_STACK( X11DRV_DIB_SetImageBits, &descr );
765         LeaveCriticalSection( &X11DRV_CritSection );
766     }
767 }
768
769 /***********************************************************************
770  *           DIB_FaultHandler
771  */
772 static BOOL32 DIB_FaultHandler( LPVOID res, LPVOID addr )
773 {
774     BOOL32 handled = FALSE;
775     BITMAPOBJ *bmp;
776
777     bmp = (BITMAPOBJ *)GDI_GetObjPtr( (HBITMAP32)res, BITMAP_MAGIC );
778     if (!bmp) return FALSE;
779
780     if (bmp->dib)
781         switch (bmp->dib->status)
782         {
783         case DIB_GdiMod:
784             TRACE( bitmap, "called in status DIB_GdiMod\n" );
785             DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
786             DIB_DoUpdateDIBSection( bmp, TRUE );
787             DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
788             bmp->dib->status = DIB_InSync;
789             handled = TRUE;
790             break;
791
792         case DIB_InSync:
793             TRACE( bitmap, "called in status DIB_InSync\n" );
794             DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
795             bmp->dib->status = DIB_AppMod;
796             handled = TRUE;
797             break;
798
799         case DIB_AppMod:
800             FIXME( bitmap, "called in status DIB_AppMod: "
801                            "this can't happen!\n" );
802             break;
803
804         case DIB_NoHandler:
805             FIXME( bitmap, "called in status DIB_NoHandler: "
806                            "this can't happen!\n" );
807             break;
808         }
809
810     GDI_HEAP_UNLOCK( (HBITMAP32)res );
811     return handled;
812 }
813
814 /***********************************************************************
815  *           DIB_UpdateDIBSection
816  */
817 void DIB_UpdateDIBSection( DC *dc, BOOL32 toDIB )
818 {
819     BITMAPOBJ *bmp;
820
821     /* Ensure this is a Compatible DC that has a DIB section selected */
822
823     if (!dc) return;
824     if (!(dc->w.flags & DC_MEMORY)) return;
825
826     bmp = (BITMAPOBJ *)GDI_GetObjPtr( dc->w.hBitmap, BITMAP_MAGIC );
827     if (!bmp) return;
828
829     if (!bmp->dib)
830     {
831         GDI_HEAP_UNLOCK(dc->w.hBitmap);
832         return;
833     }
834
835
836     if (!toDIB)
837     {
838         /* Prepare for access to the DIB by GDI functions */
839
840         switch (bmp->dib->status)
841         {
842         default:
843         case DIB_NoHandler:
844             DIB_DoUpdateDIBSection( bmp, FALSE );
845             break;
846
847         case DIB_GdiMod:
848             TRACE( bitmap, "fromDIB called in status DIB_GdiMod\n" );
849             /* nothing to do */
850             break;
851
852         case DIB_InSync:
853             TRACE( bitmap, "fromDIB called in status DIB_InSync\n" );
854             /* nothing to do */
855             break;
856
857         case DIB_AppMod:
858             TRACE( bitmap, "fromDIB called in status DIB_AppMod\n" );
859             DIB_DoUpdateDIBSection( bmp, FALSE );
860             DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
861             bmp->dib->status = DIB_InSync;
862             break;
863         }
864     }
865     else
866     {
867         /* Acknowledge write access to the DIB by GDI functions */
868
869         switch (bmp->dib->status)
870         {
871         default:
872         case DIB_NoHandler:
873             DIB_DoUpdateDIBSection( bmp, TRUE );
874             break;
875
876         case DIB_GdiMod:
877             TRACE( bitmap, "  toDIB called in status DIB_GdiMod\n" );
878             /* nothing to do */
879             break;
880
881         case DIB_InSync:
882             TRACE( bitmap, "  toDIB called in status DIB_InSync\n" );
883             DIB_DoProtectDIBSection( bmp, PAGE_NOACCESS );
884             bmp->dib->status = DIB_GdiMod;
885             break;
886
887         case DIB_AppMod:
888             FIXME( bitmap, "  toDIB called in status DIB_AppMod: "
889                            "this can't happen!\n" );
890             break;
891         }
892     }
893
894   
895     GDI_HEAP_UNLOCK(dc->w.hBitmap);
896 }
897
898 /***********************************************************************
899  *           CreateDIBSection16    (GDI.489)
900  */
901 HBITMAP16 WINAPI CreateDIBSection16 (HDC16 hdc, BITMAPINFO *bmi, UINT16 usage,
902                                      LPVOID **bits, HANDLE32 section,
903                                      DWORD offset)
904 {
905     return CreateDIBSection32(hdc, bmi, usage, bits, section, offset);
906 }
907
908 /***********************************************************************
909  *           CreateDIBSection32    (GDI32.36)
910  */
911 HBITMAP32 WINAPI CreateDIBSection32 (HDC32 hdc, BITMAPINFO *bmi, UINT32 usage,
912                                      LPVOID **bits,HANDLE32 section,
913                                      DWORD offset)
914 {
915     HBITMAP32 res = 0;
916     BITMAPOBJ *bmp = NULL;
917     DIBSECTIONOBJ *dib = NULL;
918     int *colorMap = NULL;
919     int nColorMap;
920
921     /* Fill BITMAP32 structure with DIB data */
922     BITMAPINFOHEADER *bi = &bmi->bmiHeader;
923     INT32 effHeight, totalSize;
924     BITMAP32 bm;
925
926     TRACE(bitmap, "format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
927           bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
928           bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
929
930     bm.bmType = 0;
931     bm.bmWidth = bi->biWidth;
932     bm.bmHeight = bi->biHeight;
933     bm.bmWidthBytes = DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
934     bm.bmPlanes = bi->biPlanes;
935     bm.bmBitsPixel = bi->biBitCount;
936     bm.bmBits = NULL;
937
938     /* Get storage location for DIB bits */
939     effHeight = bm.bmHeight >= 0 ? bm.bmHeight : -bm.bmHeight;
940     totalSize = bi->biSizeImage? bi->biSizeImage : bm.bmWidthBytes * effHeight;
941
942     if (section)
943         bm.bmBits = MapViewOfFile(section, FILE_MAP_ALL_ACCESS, 
944                                   0L, offset, totalSize);
945     else
946         bm.bmBits = VirtualAlloc(NULL, totalSize, 
947                                  MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
948
949     /* Create Color Map */
950     if (bm.bmBits && bm.bmBitsPixel <= 8)
951     {
952         DC *dc = hdc? (DC *)GDI_GetObjPtr(hdc, DC_MAGIC) : NULL;
953         if (hdc && !dc) dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
954
955         if (!hdc || dc)
956             colorMap = X11DRV_DIB_BuildColorMap( dc, usage, bm.bmBitsPixel,
957                                                  bmi, &nColorMap );
958         GDI_HEAP_UNLOCK(hdc);
959     }
960
961     /* Allocate Memory for DIB and fill structure */
962     if (bm.bmBits)
963         dib = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIBSECTIONOBJ));
964     if (dib)
965     {
966         dib->dibSection.dsBm = bm;
967         dib->dibSection.dsBmih = *bi;
968         /* FIXME: dib->dibSection.dsBitfields ??? */
969         dib->dibSection.dshSection = section;
970         dib->dibSection.dsOffset = offset;
971
972         dib->status    = DIB_NoHandler;
973         
974         dib->nColorMap = nColorMap;
975         dib->colorMap  = colorMap;
976     }
977
978     /* Create Device Dependent Bitmap and add DIB pointer */
979     if (dib) 
980     {
981        res = CreateDIBitmap32(hdc, bi, 0, NULL, bmi, usage);
982        bmp = (BITMAPOBJ *) GDI_GetObjPtr(res, BITMAP_MAGIC);
983        if (bmp) bmp->dib = dib;
984
985        /* HACK for now */
986        if(!bmp->DDBitmap)
987           X11DRV_CreateBitmap(res); 
988     }
989
990     /* Create XImage */
991     if (dib && bmp)
992         XCREATEIMAGE( dib->image, bm.bmWidth, effHeight, bmp->bitmap.bmBitsPixel );
993
994     /* Clean up in case of errors */
995     if (!res || !bmp || !dib || !bm.bmBits || (bm.bmBitsPixel <= 8 && !colorMap))
996     {
997         if (bm.bmBits)
998         {
999             if (section)
1000                 UnmapViewOfFile(bm.bmBits), bm.bmBits = NULL;
1001             else
1002                 VirtualFree(bm.bmBits, MEM_RELEASE, 0L), bm.bmBits = NULL;
1003         }
1004
1005         if (dib->image) XDestroyImage(dib->image), dib->image = NULL;
1006         if (colorMap) HeapFree(GetProcessHeap(), 0, colorMap), colorMap = NULL;
1007         if (dib) HeapFree(GetProcessHeap(), 0, dib), dib = NULL;
1008         if (res) DeleteObject32(res), res = 0;
1009     }
1010
1011     /* Install fault handler, if possible */
1012     if (bm.bmBits)
1013         if (VIRTUAL_SetFaultHandler(bm.bmBits, DIB_FaultHandler, (LPVOID)res))
1014         {
1015             DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
1016             dib->status = DIB_InSync;
1017         }
1018
1019     /* Return BITMAP handle and storage location */
1020     if (res) GDI_HEAP_UNLOCK(res);
1021     if (bm.bmBits && bits) *bits = bm.bmBits;
1022     return res;
1023 }
1024
1025 /***********************************************************************
1026  *           DIB_DeleteDIBSection
1027  */
1028 void DIB_DeleteDIBSection( BITMAPOBJ *bmp )
1029 {
1030     if (bmp && bmp->dib)
1031     {
1032         DIBSECTIONOBJ *dib = bmp->dib;
1033
1034         if (dib->dibSection.dsBm.bmBits)
1035         {
1036             if (dib->dibSection.dshSection)
1037                 UnmapViewOfFile(dib->dibSection.dsBm.bmBits);
1038             else
1039                 VirtualFree(dib->dibSection.dsBm.bmBits, MEM_RELEASE, 0L);
1040         }
1041
1042         if (dib->image) 
1043             XDestroyImage( dib->image );
1044
1045         if (dib->colorMap)
1046             HeapFree(GetProcessHeap(), 0, dib->colorMap);
1047
1048         HeapFree(GetProcessHeap(), 0, dib);
1049         bmp->dib = NULL;
1050     }
1051 }
1052
1053 /***********************************************************************
1054  *           DIB_FixColorsToLoadflags
1055  *
1056  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1057  * are in loadflags
1058  */
1059 void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT32 loadflags, BYTE pix)
1060 {
1061   int colors;
1062   COLORREF c_W, c_S, c_F, c_L, c_C;
1063   int incr,i;
1064   RGBQUAD *ptr;
1065
1066   if (bmi->bmiHeader.biBitCount > 8) return;
1067   if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
1068   else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
1069   else {
1070     WARN(bitmap, "Wrong bitmap header size!\n");
1071     return;
1072   }
1073   colors = bmi->bmiHeader.biClrUsed;
1074   if (!colors && (bmi->bmiHeader.biBitCount <= 8))
1075     colors = 1 << bmi->bmiHeader.biBitCount;
1076   c_W = GetSysColor32(COLOR_WINDOW);
1077   c_S = GetSysColor32(COLOR_3DSHADOW);
1078   c_F = GetSysColor32(COLOR_3DFACE);
1079   c_L = GetSysColor32(COLOR_3DLIGHT);
1080   if (loadflags & LR_LOADTRANSPARENT) {
1081     switch (bmi->bmiHeader.biBitCount) {
1082       case 1: pix = pix >> 7; break;
1083       case 4: pix = pix >> 4; break;
1084       case 8: break;
1085       default: 
1086         WARN(bitmap, "(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount); 
1087         return;
1088     }
1089     if (pix >= colors) {
1090       WARN(bitmap, "pixel has color index greater than biClrUsed!\n");
1091       return;
1092     }
1093     if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
1094     ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
1095     ptr->rgbBlue = GetBValue(c_W);
1096     ptr->rgbGreen = GetGValue(c_W);
1097     ptr->rgbRed = GetRValue(c_W);
1098   }
1099   if (loadflags & LR_LOADMAP3DCOLORS)
1100     for (i=0; i<colors; i++) {
1101       ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
1102       c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
1103       if (c_C == RGB(128, 128, 128)) { 
1104         ptr->rgbRed = GetRValue(c_S);
1105         ptr->rgbGreen = GetGValue(c_S);
1106         ptr->rgbBlue = GetBValue(c_S);
1107       } else if (c_C == RGB(192, 192, 192)) { 
1108         ptr->rgbRed = GetRValue(c_F);
1109         ptr->rgbGreen = GetGValue(c_F);
1110         ptr->rgbBlue = GetBValue(c_F);
1111       } else if (c_C == RGB(223, 223, 223)) { 
1112         ptr->rgbRed = GetRValue(c_L);
1113         ptr->rgbGreen = GetGValue(c_L);
1114         ptr->rgbBlue = GetBValue(c_L);
1115       } 
1116     }
1117 }