Fixed Filesystem documentation.
[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)StretchDIBits( 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 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst,
130                        INT heightDst, INT xSrc, INT ySrc, INT widthSrc,
131                        INT heightSrc, const void *bits,
132                        const BITMAPINFO *info, UINT 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         HBITMAP hBitmap, hOldBitmap;
144         HDC hdcMem;
145     
146         hBitmap = CreateDIBitmap( hdc, &info->bmiHeader, CBM_INIT,
147                                     bits, info, wUsage );
148         hdcMem = CreateCompatibleDC( hdc );
149         hOldBitmap = SelectObject( hdcMem, hBitmap );
150         /* Origin for DIBitmap is bottom left ! */
151         StretchBlt( hdc, xDst, yDst, widthDst, heightDst,
152                       hdcMem, xSrc, info->bmiHeader.biHeight - heightSrc - ySrc, 
153                       widthSrc, heightSrc, dwRop );
154         SelectObject( hdcMem, hOldBitmap );
155         DeleteDC( hdcMem );
156         DeleteObject( 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 SetDIBits( 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 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
190                           UINT lines, LPCVOID bits, const BITMAPINFO *info,
191                           UINT coloruse )
192 {
193     DIB_SETIMAGEBITS_DESCR descr;
194     BITMAPOBJ * bmp;
195     int height, tmpheight;
196     INT 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 SetDIBitsToDevice( hdc, xDest, yDest, cx, cy, xSrc, ySrc,
283                                 startscan, lines, bits, info, coloruse );
284 }
285
286
287 /***********************************************************************
288  *           SetDIBitsToDevice32   (GDI32.313)
289  */
290 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
291                            DWORD cy, INT xSrc, INT ySrc, UINT startscan,
292                            UINT lines, LPCVOID bits, const BITMAPINFO *info,
293                            UINT coloruse )
294 {
295     INT 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 SetDIBColorTable( hdc, startpos, entries, colors );
320 }
321
322 /***********************************************************************
323  *           SetDIBColorTable32    (GDI32.311)
324  */
325 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT 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 GetDIBColorTable( hdc, startpos, entries, colors );
372 }
373
374 /***********************************************************************
375  *           GetDIBColorTable32    (GDI32.169)
376  */
377 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT 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 GetDIBits( 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 INT WINAPI GetDIBits(
439     HDC hdc,         /* [in]  Handle to device context */
440     HBITMAP hbitmap, /* [in]  Handle to bitmap */
441     UINT startscan,  /* [in]  First scan line to set in dest bitmap */
442     UINT 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     UINT 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, *linestart;
493         int     dstwidth, 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,
498               startscan );
499
500         /* adjust number of scanlines to copy */
501
502         if( lines > info->bmiHeader.biHeight ) lines = info->bmiHeader.biHeight;
503         yend = startscan + lines;
504         if( startscan >= bmp->bitmap.bmHeight ) 
505         {
506             GDI_HEAP_UNLOCK( hbitmap );
507             GDI_HEAP_UNLOCK( dc->w.hPalette );
508             return FALSE;
509         }
510         if( yend > bmp->bitmap.bmHeight ) yend = bmp->bitmap.bmHeight;
511
512         /* adjust scanline width */
513
514         if(bmp->bitmap.bmWidth > info->bmiHeader.biWidth)
515             xend = info->bmiHeader.biWidth;
516
517         /* HACK for now */
518         if(!bmp->DDBitmap)
519             X11DRV_CreateBitmap(hbitmap);
520
521         dstwidth = DIB_GetDIBWidthBytes( info->bmiHeader.biWidth,
522                                          info->bmiHeader.biBitCount );
523
524         EnterCriticalSection( &X11DRV_CritSection );
525         bmpImage = (XImage *)CALL_LARGE_STACK( X11DRV_BITMAP_GetXImage, bmp );
526
527         linestart = bbits;
528         switch( info->bmiHeader.biBitCount )
529         {
530            case 8:
531                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
532                 {
533                    for( x = 0; x < xend; x++ )
534                         *bbits++ = XGetPixel( bmpImage, x, y );
535                    bbits = (linestart += dstwidth);
536                 }
537                 break;
538            case 1:
539                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
540                 {
541                    for( x = 0; x < xend; x++ ) {
542                         if (!(x&7)) *bbits = 0;
543                         *bbits |= XGetPixel( bmpImage, x, y)<<(7-(x&7));
544                         if ((x&7)==7) bbits++;
545                    }
546                    bbits = (linestart += dstwidth);
547                 }
548                 break;
549            case 4:
550                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
551                 {
552                    for( x = 0; x < xend; x++ ) {
553                         if (!(x&1)) *bbits = 0;
554                         *bbits |= XGetPixel( bmpImage, x, y)<<(4*(1-(x&1)));
555                         if ((x&1)==1) bbits++;
556                    }
557                    bbits = (linestart += dstwidth);
558                 }
559                 break;
560            case 15:
561            case 16:
562                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
563                 {
564                    for( x = 0; x < xend; x++ ) {
565                         unsigned long pixel=XGetPixel( bmpImage, x, y);
566                         *bbits++ = pixel & 0xff;
567                         *bbits++ = (pixel >> 8) & 0xff;
568                    }
569                    bbits = (linestart += dstwidth);
570                 }
571                 break;
572            case 24:
573                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
574                 {
575                    for( x = 0; x < xend; x++ ) {
576                         unsigned long pixel=XGetPixel( bmpImage, x, y);
577                         *bbits++ = (pixel >>16) & 0xff;
578                         *bbits++ = (pixel >> 8) & 0xff;
579                         *bbits++ =  pixel       & 0xff;
580                    }
581                    bbits = (linestart += dstwidth);
582                 }
583                 break;
584            case 32:
585                 for( y = yend - 1; (int)y >= (int)startscan; y-- )
586                 {
587                    for( x = 0; x < xend; x++ ) {
588                         unsigned long pixel=XGetPixel( bmpImage, x, y);
589                         *bbits++ = (pixel >>16) & 0xff;
590                         *bbits++ = (pixel >> 8) & 0xff;
591                         *bbits++ =  pixel       & 0xff;
592                    }
593                    bbits = (linestart += dstwidth);
594                 }
595                 break;
596            default:
597                 WARN(bitmap,"Unsupported depth %d\n",
598                    info->bmiHeader.biBitCount);
599                 break;
600         }
601
602         XDestroyImage( bmpImage );
603         LeaveCriticalSection( &X11DRV_CritSection );
604
605         if(bbits - (BYTE *)bits > info->bmiHeader.biSizeImage)
606             ERR(bitmap, "Buffer overrun. Please investigate.\n");
607
608         info->bmiHeader.biCompression = 0;
609     }
610     else if( info->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER) ) 
611     {
612         /* fill in struct members */
613         
614         info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
615         info->bmiHeader.biHeight = bmp->bitmap.bmHeight;
616         info->bmiHeader.biPlanes = 1;
617         info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
618         info->bmiHeader.biSizeImage = bmp->bitmap.bmHeight *
619                              DIB_GetDIBWidthBytes( bmp->bitmap.bmWidth,
620                                                    bmp->bitmap.bmBitsPixel );
621         info->bmiHeader.biCompression = 0;
622     }
623     TRACE(bitmap, "biSizeImage = %ld, biWidth = %ld, biHeight = %ld\n",
624           info->bmiHeader.biSizeImage, info->bmiHeader.biWidth,
625           info->bmiHeader.biHeight);
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 CreateDIBitmap( hdc, header, init, bits, data, coloruse );
640 }
641
642
643 /***********************************************************************
644  *           CreateDIBitmap32    (GDI32.37)
645  */
646 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
647                             DWORD init, LPCVOID bits, const BITMAPINFO *data,
648                             UINT coloruse )
649 {
650     HBITMAP handle;
651     BOOL 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 ? CreateBitmap( width, height, 1, MONITOR_GetDepth(&MONITOR_PrimaryMonitor), NULL ) :
705                       CreateBitmap( width, height, 1, 1, NULL );
706     if (!handle) return 0;
707
708     if (init == CBM_INIT)
709         SetDIBits( 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     INT effHeight = dib->dsBm.bmHeight >= 0? dib->dsBm.bmHeight
721                                              : -dib->dsBm.bmHeight;
722     INT 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, BOOL 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 BOOL DIB_FaultHandler( LPVOID res, LPCVOID addr )
780 {
781     BOOL handled = FALSE;
782     BITMAPOBJ *bmp;
783
784     bmp = (BITMAPOBJ *)GDI_GetObjPtr( (HBITMAP)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( (HBITMAP)res );
818     return handled;
819 }
820
821 /***********************************************************************
822  *           DIB_UpdateDIBSection
823  */
824 void DIB_UpdateDIBSection( DC *dc, BOOL 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                                      SEGPTR *bits, HANDLE section,
910                                      DWORD offset)
911 {
912     HBITMAP res = CreateDIBSection(hdc, bmi, usage, NULL, section,
913                                        offset);
914
915     if ( res )
916     {
917         BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr(res, BITMAP_MAGIC);
918         if ( bmp && bmp->dib )
919         {
920             DIBSECTION *dib = &bmp->dib->dibSection;
921             INT height = dib->dsBm.bmHeight >= 0 ?
922                 dib->dsBm.bmHeight : -dib->dsBm.bmHeight;
923             INT size = dib->dsBmih.biSizeImage ?
924                 dib->dsBmih.biSizeImage : dib->dsBm.bmWidthBytes * height;
925             if ( dib->dsBm.bmBits )
926             {
927                 bmp->dib->selector = 
928                     SELECTOR_AllocBlock( dib->dsBm.bmBits, size, 
929                                          SEGMENT_DATA, FALSE, FALSE );
930             }
931             printf("ptr = %p, size =%d, selector = %04x, segptr = %ld\n",
932                    dib->dsBm.bmBits, size, bmp->dib->selector,
933                    PTR_SEG_OFF_TO_SEGPTR(bmp->dib->selector, 0));
934 }
935         GDI_HEAP_UNLOCK( res );
936
937         if ( bits ) 
938             *bits = PTR_SEG_OFF_TO_SEGPTR( bmp->dib->selector, 0 );
939     }
940
941     return res;
942 }
943
944 /***********************************************************************
945  *           CreateDIBSection32    (GDI32.36)
946  */
947 HBITMAP WINAPI CreateDIBSection (HDC hdc, BITMAPINFO *bmi, UINT usage,
948                                      LPVOID *bits,HANDLE section,
949                                      DWORD offset)
950 {
951     HBITMAP res = 0;
952     BITMAPOBJ *bmp = NULL;
953     DIBSECTIONOBJ *dib = NULL;
954     int *colorMap = NULL;
955     int nColorMap;
956
957     /* Fill BITMAP32 structure with DIB data */
958     BITMAPINFOHEADER *bi = &bmi->bmiHeader;
959     INT effHeight, totalSize;
960     BITMAP bm;
961
962     TRACE(bitmap, "format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
963           bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
964           bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
965
966     bm.bmType = 0;
967     bm.bmWidth = bi->biWidth;
968     bm.bmHeight = bi->biHeight;
969     bm.bmWidthBytes = DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
970     bm.bmPlanes = bi->biPlanes;
971     bm.bmBitsPixel = bi->biBitCount;
972     bm.bmBits = NULL;
973
974     /* Get storage location for DIB bits */
975     effHeight = bm.bmHeight >= 0 ? bm.bmHeight : -bm.bmHeight;
976     totalSize = bi->biSizeImage? bi->biSizeImage : bm.bmWidthBytes * effHeight;
977
978     if (section)
979         bm.bmBits = MapViewOfFile(section, FILE_MAP_ALL_ACCESS, 
980                                   0L, offset, totalSize);
981     else
982         bm.bmBits = VirtualAlloc(NULL, totalSize, 
983                                  MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
984
985     /* Create Color Map */
986     if (bm.bmBits && bm.bmBitsPixel <= 8)
987     {
988         DC *dc = hdc? (DC *)GDI_GetObjPtr(hdc, DC_MAGIC) : NULL;
989         if (hdc && !dc) dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
990
991         if (!hdc || dc)
992             colorMap = X11DRV_DIB_BuildColorMap( dc, usage, bm.bmBitsPixel,
993                                                  bmi, &nColorMap );
994         GDI_HEAP_UNLOCK(hdc);
995     }
996
997     /* Allocate Memory for DIB and fill structure */
998     if (bm.bmBits)
999         dib = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIBSECTIONOBJ));
1000     if (dib)
1001     {
1002         dib->dibSection.dsBm = bm;
1003         dib->dibSection.dsBmih = *bi;
1004         /* FIXME: dib->dibSection.dsBitfields ??? */
1005         dib->dibSection.dshSection = section;
1006         dib->dibSection.dsOffset = offset;
1007
1008         dib->status    = DIB_NoHandler;
1009         dib->selector  = 0;
1010         
1011         dib->nColorMap = nColorMap;
1012         dib->colorMap  = colorMap;
1013     }
1014
1015     /* Create Device Dependent Bitmap and add DIB pointer */
1016     if (dib) 
1017     {
1018        res = CreateDIBitmap(hdc, bi, 0, NULL, bmi, usage);
1019        if (res)
1020        {
1021            bmp = (BITMAPOBJ *) GDI_GetObjPtr(res, BITMAP_MAGIC);
1022            if (bmp)
1023            {
1024                bmp->dib = dib;
1025                /* HACK for now */
1026                if(!bmp->DDBitmap)
1027                    X11DRV_CreateBitmap(res); 
1028            }
1029        }
1030     }
1031
1032     /* Create XImage */
1033     if (dib && bmp)
1034         XCREATEIMAGE( dib->image, bm.bmWidth, effHeight, bmp->bitmap.bmBitsPixel );
1035
1036     /* Clean up in case of errors */
1037     if (!res || !bmp || !dib || !bm.bmBits || (bm.bmBitsPixel <= 8 && !colorMap))
1038     {
1039         TRACE(bitmap, "got an error res=%08x, bmp=%p, dib=%p, bm.bmBits=%p\n",
1040               res, bmp, dib, bm.bmBits);
1041         if (bm.bmBits)
1042         {
1043             if (section)
1044                 UnmapViewOfFile(bm.bmBits), bm.bmBits = NULL;
1045             else
1046                 VirtualFree(bm.bmBits, MEM_RELEASE, 0L), bm.bmBits = NULL;
1047         }
1048
1049         if (dib && dib->image) { XDestroyImage(dib->image); dib->image = NULL; }
1050         if (colorMap) { HeapFree(GetProcessHeap(), 0, colorMap); colorMap = NULL; }
1051         if (dib) { HeapFree(GetProcessHeap(), 0, dib); dib = NULL; }
1052         if (res) { DeleteObject(res); res = 0; }
1053     }
1054
1055     /* Install fault handler, if possible */
1056     if (bm.bmBits)
1057     {
1058         if (VIRTUAL_SetFaultHandler(bm.bmBits, DIB_FaultHandler, (LPVOID)res))
1059         {
1060             DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
1061             if (dib) dib->status = DIB_InSync;
1062         }
1063     }
1064
1065     /* Return BITMAP handle and storage location */
1066     if (res) GDI_HEAP_UNLOCK(res);
1067     if (bm.bmBits && bits) *bits = bm.bmBits;
1068     return res;
1069 }
1070
1071 /***********************************************************************
1072  *           DIB_DeleteDIBSection
1073  */
1074 void DIB_DeleteDIBSection( BITMAPOBJ *bmp )
1075 {
1076     if (bmp && bmp->dib)
1077     {
1078         DIBSECTIONOBJ *dib = bmp->dib;
1079
1080         if (dib->dibSection.dsBm.bmBits)
1081         {
1082             if (dib->dibSection.dshSection)
1083                 UnmapViewOfFile(dib->dibSection.dsBm.bmBits);
1084             else
1085                 VirtualFree(dib->dibSection.dsBm.bmBits, MEM_RELEASE, 0L);
1086         }
1087
1088         if (dib->image) 
1089             XDestroyImage( dib->image );
1090
1091         if (dib->colorMap)
1092             HeapFree(GetProcessHeap(), 0, dib->colorMap);
1093
1094         if (dib->selector)
1095         {
1096             WORD count = (GET_SEL_LIMIT( dib->selector ) >> 16) + 1;
1097             SELECTOR_FreeBlock( dib->selector, count );
1098         }
1099
1100         HeapFree(GetProcessHeap(), 0, dib);
1101         bmp->dib = NULL;
1102     }
1103 }
1104
1105 /***********************************************************************
1106  *           DIB_FixColorsToLoadflags
1107  *
1108  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1109  * are in loadflags
1110  */
1111 void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1112 {
1113   int colors;
1114   COLORREF c_W, c_S, c_F, c_L, c_C;
1115   int incr,i;
1116   RGBQUAD *ptr;
1117
1118   if (bmi->bmiHeader.biBitCount > 8) return;
1119   if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
1120   else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
1121   else {
1122     WARN(bitmap, "Wrong bitmap header size!\n");
1123     return;
1124   }
1125   colors = bmi->bmiHeader.biClrUsed;
1126   if (!colors && (bmi->bmiHeader.biBitCount <= 8))
1127     colors = 1 << bmi->bmiHeader.biBitCount;
1128   c_W = GetSysColor(COLOR_WINDOW);
1129   c_S = GetSysColor(COLOR_3DSHADOW);
1130   c_F = GetSysColor(COLOR_3DFACE);
1131   c_L = GetSysColor(COLOR_3DLIGHT);
1132   if (loadflags & LR_LOADTRANSPARENT) {
1133     switch (bmi->bmiHeader.biBitCount) {
1134       case 1: pix = pix >> 7; break;
1135       case 4: pix = pix >> 4; break;
1136       case 8: break;
1137       default: 
1138         WARN(bitmap, "(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount); 
1139         return;
1140     }
1141     if (pix >= colors) {
1142       WARN(bitmap, "pixel has color index greater than biClrUsed!\n");
1143       return;
1144     }
1145     if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
1146     ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
1147     ptr->rgbBlue = GetBValue(c_W);
1148     ptr->rgbGreen = GetGValue(c_W);
1149     ptr->rgbRed = GetRValue(c_W);
1150   }
1151   if (loadflags & LR_LOADMAP3DCOLORS)
1152     for (i=0; i<colors; i++) {
1153       ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
1154       c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
1155       if (c_C == RGB(128, 128, 128)) { 
1156         ptr->rgbRed = GetRValue(c_S);
1157         ptr->rgbGreen = GetGValue(c_S);
1158         ptr->rgbBlue = GetBValue(c_S);
1159       } else if (c_C == RGB(192, 192, 192)) { 
1160         ptr->rgbRed = GetRValue(c_F);
1161         ptr->rgbGreen = GetGValue(c_F);
1162         ptr->rgbBlue = GetBValue(c_F);
1163       } else if (c_C == RGB(223, 223, 223)) { 
1164         ptr->rgbRed = GetRValue(c_L);
1165         ptr->rgbGreen = GetGValue(c_L);
1166         ptr->rgbBlue = GetBValue(c_L);
1167       } 
1168     }
1169 }