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