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