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