update for HEAD-2003091401
[reactos.git] / subsys / win32k / objects / dib.c
1 /*
2  * $Id$
3  *
4  * ReactOS W32 Subsystem
5  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #undef WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #include <stdlib.h>
25 #include <win32k/bitmaps.h>
26 #include <win32k/debug.h>
27 #include "../eng/handle.h"
28 #include <ntos/minmax.h>
29 #include <include/error.h>
30 #include <include/inteng.h>
31 #include <include/eng.h>
32 #include <include/dib.h>
33 #include <internal/safe.h>
34 #include <include/surface.h>
35 #include <include/palette.h>
36
37 #define NDEBUG
38 #include <win32k/debug1.h>
39
40 UINT STDCALL NtGdiSetDIBColorTable(HDC  hDC,
41                            UINT  StartIndex,
42                            UINT  Entries,
43                            CONST RGBQUAD  *Colors)
44 {
45   PDC dc;
46   PALETTEENTRY * palEntry;
47   PPALOBJ palette;
48   const RGBQUAD *end;
49
50   if (!(dc = (PDC)AccessUserObject((ULONG)hDC))) return 0;
51
52   if (!(palette = (PPALOBJ)PALETTE_LockPalette((ULONG)dc->DevInfo->hpalDefault)))
53   {
54 //    GDI_ReleaseObj( hdc );
55     return 0;
56   }
57
58   // Transfer color info
59
60   if (dc->w.bitsPerPixel <= 8)
61   {
62     palEntry = palette->logpalette->palPalEntry + StartIndex;
63     if (StartIndex + Entries > (UINT) (1 << dc->w.bitsPerPixel))
64       Entries = (1 << dc->w.bitsPerPixel) - StartIndex;
65
66     if (StartIndex + Entries > palette->logpalette->palNumEntries)
67       Entries = palette->logpalette->palNumEntries - StartIndex;
68
69     for (end = Colors + Entries; Colors < end; palEntry++, Colors++)
70     {
71       palEntry->peRed   = Colors->rgbRed;
72       palEntry->peGreen = Colors->rgbGreen;
73       palEntry->peBlue  = Colors->rgbBlue;
74     }
75   }
76   else
77   {
78     Entries = 0;
79   }
80
81   PALETTE_UnlockPalette(dc->DevInfo->hpalDefault);
82 //  GDI_ReleaseObj(hdc);
83
84   return Entries;
85 }
86
87 // Converts a DIB to a device-dependent bitmap
88 INT STDCALL
89 NtGdiSetDIBits(
90         HDC  hDC,
91         HBITMAP  hBitmap,
92         UINT  StartScan,
93         UINT  ScanLines,
94         CONST VOID  *Bits,
95         CONST BITMAPINFO  *bmi,
96         UINT  ColorUse)
97 {
98   DC         *dc;
99   BITMAPOBJ  *bitmap;
100   HBITMAP     SourceBitmap, DestBitmap;
101   INT         result = 0;
102   BOOL        copyBitsResult;
103   PSURFOBJ    DestSurf, SourceSurf;
104   PSURFGDI    DestGDI;
105   SIZEL       SourceSize;
106   POINTL      ZeroPoint;
107   RECTL       DestRect;
108   PXLATEOBJ   XlateObj;
109   PPALGDI     hDCPalette;
110   //RGBQUAD  *lpRGB;
111   HPALETTE    DDB_Palette, DIB_Palette;
112   ULONG       DDB_Palette_Type, DIB_Palette_Type;
113   const BYTE *vBits = (const BYTE*)Bits;
114   INT         scanDirection = 1, DIBWidth;
115
116   // Check parameters
117   if (!(dc = DC_LockDc(hDC)))
118      return 0;
119
120   if (!(bitmap = BITMAPOBJ_LockBitmap(hBitmap)))
121   {
122     DC_UnlockDc(hDC);
123     return 0;
124   }
125
126   // Get RGB values
127   //if (ColorUse == DIB_PAL_COLORS)
128   //  lpRGB = DIB_MapPaletteColors(hDC, bmi);
129   //else
130   //  lpRGB = &bmi->bmiColors[0];
131
132   // Create a temporary surface for the destination bitmap
133   DestBitmap = BitmapToSurf(bitmap);
134
135   DestSurf   = (PSURFOBJ) AccessUserObject( (ULONG)DestBitmap );
136   DestGDI    = (PSURFGDI) AccessInternalObject( (ULONG)DestBitmap );
137
138   // Create source surface
139   SourceSize.cx = bmi->bmiHeader.biWidth;
140   SourceSize.cy = abs(bmi->bmiHeader.biHeight);
141
142   // Determine width of DIB
143   DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
144
145   // Determine DIB Vertical Orientation
146   if(bmi->bmiHeader.biHeight > 0)
147   {
148     scanDirection = -1;
149     vBits += DIBWidth * bmi->bmiHeader.biHeight - DIBWidth;
150   }
151
152   SourceBitmap = EngCreateBitmap(SourceSize,
153                                  DIBWidth * scanDirection,
154                                  BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
155                                  0,
156                                  (PVOID)vBits );
157   SourceSurf = (PSURFOBJ)AccessUserObject((ULONG)SourceBitmap);
158
159   // Destination palette obtained from the hDC
160   hDCPalette = PALETTE_LockPalette(dc->DevInfo->hpalDefault);
161   DDB_Palette_Type = hDCPalette->Mode;
162   DDB_Palette = dc->DevInfo->hpalDefault;
163   PALETTE_UnlockPalette(dc->DevInfo->hpalDefault);
164
165   // Source palette obtained from the BITMAPINFO
166   DIB_Palette = BuildDIBPalette ( (PBITMAPINFO)bmi, (PINT)&DIB_Palette_Type );
167
168   // Determine XLATEOBJ for color translation
169   XlateObj = IntEngCreateXlate(DDB_Palette_Type, DIB_Palette_Type, DDB_Palette, DIB_Palette);
170
171   // Zero point
172   ZeroPoint.x = 0;
173   ZeroPoint.y = 0;
174
175   // Determine destination rectangle
176   DestRect.top  = 0;
177   DestRect.left = 0;
178   DestRect.right        = SourceSize.cx;
179   DestRect.bottom       = SourceSize.cy;
180
181   copyBitsResult = EngCopyBits(DestSurf, SourceSurf, NULL, XlateObj, &DestRect, &ZeroPoint);
182
183   // If it succeeded, return number of scanlines copies
184   if(copyBitsResult == TRUE)
185   {
186     result = SourceSize.cy - 1;
187   }
188
189   // Clean up
190   EngDeleteXlate(XlateObj);
191   PALETTE_FreePalette(DIB_Palette);
192   EngDeleteSurface(SourceBitmap);
193   EngDeleteSurface(DestBitmap);
194
195 //  if (ColorUse == DIB_PAL_COLORS)
196 //    WinFree((LPSTR)lpRGB);
197
198   BITMAPOBJ_UnlockBitmap(hBitmap);
199   DC_UnlockDc(hDC);
200
201   return result;
202 }
203
204 INT STDCALL
205 NtGdiSetDIBitsToDevice(
206         HDC  hDC,
207         INT  XDest,
208         INT  YDest,
209         DWORD  Width,
210         DWORD  Height,
211         INT  XSrc,
212         INT  YSrc,
213         UINT  StartScan,
214         UINT  ScanLines,
215         CONST VOID  *Bits,
216         CONST BITMAPINFO  *bmi,
217         UINT  ColorUse)
218 {
219   UNIMPLEMENTED;
220   return 0;
221 }
222
223 UINT STDCALL NtGdiGetDIBColorTable(HDC  hDC,
224                            UINT  StartIndex,
225                            UINT  Entries,
226                            RGBQUAD  *Colors)
227 {
228   UNIMPLEMENTED;
229 }
230
231 // Converts a device-dependent bitmap to a DIB
232 INT STDCALL NtGdiGetDIBits(HDC  hDC,
233                    HBITMAP hBitmap,
234                    UINT  StartScan,
235                    UINT  ScanLines,
236                    LPVOID  Bits,
237                    LPBITMAPINFO UnsafeInfo,
238                    UINT  Usage)
239 {
240   BITMAPINFO Info;
241   BITMAPCOREHEADER *Core;
242   PBITMAPOBJ BitmapObj;
243   INT Result;
244   NTSTATUS Status;
245   PDC DCObj;
246   PPALGDI PalGdi;
247   struct
248     {
249     BITMAPINFO Info;
250     DWORD BitFields[3];
251     } InfoWithBitFields;
252   DWORD *BitField;
253   DWORD InfoSize;
254
255   BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
256   if (NULL == BitmapObj)
257     {
258       SetLastWin32Error(ERROR_INVALID_HANDLE);
259       return 0;
260     }
261
262   RtlZeroMemory(&Info, sizeof(BITMAPINFO));
263   Status = MmCopyFromCaller(&(Info.bmiHeader.biSize),
264                             &(UnsafeInfo->bmiHeader.biSize),
265                             sizeof(DWORD));
266   if (! NT_SUCCESS(Status))
267     {
268     SetLastNtError(Status);
269     BITMAPOBJ_UnlockBitmap(hBitmap);
270     return 0;
271     }
272
273   /* If the bits are not requested, UnsafeInfo can point to either a
274      BITMAPINFOHEADER or a BITMAPCOREHEADER */
275   if (sizeof(BITMAPINFOHEADER) != Info.bmiHeader.biSize &&
276       (sizeof(BITMAPCOREHEADER) != Info.bmiHeader.biSize ||
277        NULL != Bits))
278     {
279       SetLastWin32Error(ERROR_INVALID_PARAMETER);
280       BITMAPOBJ_UnlockBitmap(hBitmap);
281       return 0;
282     }
283
284   Status = MmCopyFromCaller(&(Info.bmiHeader),
285                             &(UnsafeInfo->bmiHeader),
286                             Info.bmiHeader.biSize);
287   if (! NT_SUCCESS(Status))
288     {
289       SetLastNtError(Status);
290       BITMAPOBJ_UnlockBitmap(hBitmap);
291       return 0;
292     }
293
294   if (NULL == Bits)
295     {
296       if (sizeof(BITMAPINFOHEADER) == Info.bmiHeader.biSize)
297         {
298           if (0 != Info.bmiHeader.biBitCount)
299             {
300               UNIMPLEMENTED;
301             }
302
303           Info.bmiHeader.biWidth = BitmapObj->bitmap.bmWidth;
304           Info.bmiHeader.biHeight = BitmapObj->bitmap.bmHeight;
305           Info.bmiHeader.biPlanes = BitmapObj->bitmap.bmPlanes;
306           Info.bmiHeader.biBitCount = BitmapObj->bitmap.bmBitsPixel;
307           Info.bmiHeader.biCompression = BI_RGB;
308           Info.bmiHeader.biSizeImage = BitmapObj->bitmap.bmHeight * BitmapObj->bitmap.bmWidthBytes;
309         }
310       else
311         {
312           Core = (BITMAPCOREHEADER *)(&Info.bmiHeader);
313           if (0 != Core->bcBitCount)
314             {
315               UNIMPLEMENTED;
316             }
317
318           Core->bcWidth = BitmapObj->bitmap.bmWidth;
319           Core->bcHeight = BitmapObj->bitmap.bmHeight;
320           Core->bcPlanes = BitmapObj->bitmap.bmPlanes;
321           Core->bcBitCount = BitmapObj->bitmap.bmBitsPixel;
322         }
323
324       Status = MmCopyToCaller(UnsafeInfo, &Info, Info.bmiHeader.biSize);
325       if (! NT_SUCCESS(Status))
326         {
327           SetLastNtError(Status);
328           BITMAPOBJ_UnlockBitmap(hBitmap);
329           return 0;
330         }
331       Result = 1;
332     }
333   else if (0 == StartScan && Info.bmiHeader.biHeight == (LONG) (StartScan + ScanLines) &&
334            Info.bmiHeader.biWidth == BitmapObj->bitmap.bmWidth &&
335            Info.bmiHeader.biHeight == BitmapObj->bitmap.bmHeight &&
336            Info.bmiHeader.biPlanes == BitmapObj->bitmap.bmPlanes &&
337            Info.bmiHeader.biBitCount == BitmapObj->bitmap.bmBitsPixel &&
338            8 < Info.bmiHeader.biBitCount)
339     {
340       Info.bmiHeader.biSizeImage = BitmapObj->bitmap.bmHeight * BitmapObj->bitmap.bmWidthBytes;
341       Status = MmCopyToCaller(Bits, BitmapObj->bitmap.bmBits, Info.bmiHeader.biSizeImage);
342       if (! NT_SUCCESS(Status))
343         {
344           SetLastNtError(Status);
345           BITMAPOBJ_UnlockBitmap(hBitmap);
346           return 0;
347         }
348       RtlZeroMemory(&InfoWithBitFields, sizeof(InfoWithBitFields));
349       RtlCopyMemory(&(InfoWithBitFields.Info), &Info, sizeof(BITMAPINFO));
350       if (BI_BITFIELDS == Info.bmiHeader.biCompression)
351         {
352           DCObj = DC_LockDc(hDC);
353           if (NULL == DCObj)
354             {
355               SetLastWin32Error(ERROR_INVALID_HANDLE);
356               BITMAPOBJ_UnlockBitmap(hBitmap);
357               return 0;
358             }
359           PalGdi = PALETTE_LockPalette(DCObj->w.hPalette);
360           BitField = (DWORD *) ((char *) &InfoWithBitFields + InfoWithBitFields.Info.bmiHeader.biSize);
361           BitField[0] = PalGdi->RedMask;
362           BitField[1] = PalGdi->GreenMask;
363           BitField[2] = PalGdi->BlueMask;
364           PALETTE_UnlockPalette(DCObj->w.hPalette);
365           InfoSize = InfoWithBitFields.Info.bmiHeader.biSize + 3 * sizeof(DWORD);
366           DC_UnlockDc(hDC);
367         }
368       else
369         {
370           InfoSize = Info.bmiHeader.biSize;
371         }
372       Status = MmCopyToCaller(UnsafeInfo, &InfoWithBitFields, InfoSize);
373       if (! NT_SUCCESS(Status))
374         {
375           SetLastNtError(Status);
376           BITMAPOBJ_UnlockBitmap(hBitmap);
377           return 0;
378         }
379     }
380   else
381     {
382     UNIMPLEMENTED;
383     }
384
385   BITMAPOBJ_UnlockBitmap(hBitmap);
386
387   return Result;
388 }
389
390 INT STDCALL NtGdiStretchDIBits(HDC  hDC,
391                        INT  XDest,
392                        INT  YDest,
393                        INT  DestWidth,
394                        INT  DestHeight,
395                        INT  XSrc,
396                        INT  YSrc,
397                        INT  SrcWidth,
398                        INT  SrcHeight,
399                        CONST VOID  *Bits,
400                        CONST BITMAPINFO  *BitsInfo,
401                        UINT  Usage,
402                        DWORD  ROP)
403 {
404   UNIMPLEMENTED;
405 }
406
407 LONG STDCALL NtGdiGetBitmapBits(HBITMAP  hBitmap,
408                         LONG  Count,
409                         LPVOID  Bits)
410 {
411   PBITMAPOBJ  bmp;
412   LONG  height, ret;
413
414   bmp = BITMAPOBJ_LockBitmap (hBitmap);
415   if (!bmp)
416   {
417     return 0;
418   }
419
420   /* If the bits vector is null, the function should return the read size */
421   if (Bits == NULL)
422   {
423     return bmp->bitmap.bmWidthBytes * bmp->bitmap.bmHeight;
424   }
425
426   if (Count < 0)
427   {
428     DPRINT ("(%ld): Negative number of bytes passed???\n", Count);
429     Count = -Count;
430   }
431
432   /* Only get entire lines */
433   height = Count / bmp->bitmap.bmWidthBytes;
434   if (height > bmp->bitmap.bmHeight)
435   {
436     height = bmp->bitmap.bmHeight;
437   }
438   Count = height * bmp->bitmap.bmWidthBytes;
439   if (Count == 0)
440   {
441     DPRINT("Less then one entire line requested\n");
442     return  0;
443   }
444
445   DPRINT("(%08x, %ld, %p) %dx%d %d colors fetched height: %ld\n",
446          hBitmap, Count, Bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
447          1 << bmp->bitmap.bmBitsPixel, height );
448 #if 0
449   /* FIXME: Call DDI CopyBits here if available  */
450   if(bmp->DDBitmap)
451   {
452     DPRINT("Calling device specific BitmapBits\n");
453     if(bmp->DDBitmap->funcs->pBitmapBits)
454     {
455       ret = bmp->DDBitmap->funcs->pBitmapBits(hbitmap, bits, count,
456                                               DDB_GET);
457     }
458     else
459     {
460       ERR_(bitmap)("BitmapBits == NULL??\n");
461       ret = 0;
462     }
463   }
464   else
465 #endif
466   {
467     if(!bmp->bitmap.bmBits)
468     {
469       DPRINT ("Bitmap is empty\n");
470       ret = 0;
471     }
472     else
473     {
474       memcpy(Bits, bmp->bitmap.bmBits, Count);
475       ret = Count;
476     }
477   }
478
479   return  ret;
480 }
481
482 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
483 // The DDB that is created will be whatever bit depth your reference DC is
484 HBITMAP STDCALL NtGdiCreateDIBitmap(HDC hdc, const BITMAPINFOHEADER *header,
485                                DWORD init, LPCVOID bits, const BITMAPINFO *data,
486                                UINT coloruse)
487 {
488   HBITMAP handle;
489   BOOL fColor;
490   DWORD width;
491   int height;
492   WORD bpp;
493   WORD compr;
494
495   if (DIB_GetBitmapInfo( header, &width, &height, &bpp, &compr ) == -1) return 0;
496   if (height < 0) height = -height;
497
498   // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
499   // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
500
501   if (bpp != 1) fColor = TRUE;
502   else if ((coloruse != DIB_RGB_COLORS) ||
503            (init != CBM_INIT) || !data) fColor = FALSE;
504   else
505   {
506     if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
507     {
508       RGBQUAD *rgb = data->bmiColors;
509       DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
510
511       // Check if the first color of the colormap is black
512       if ((col == RGB(0, 0, 0)))
513       {
514         rgb++;
515         col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
516
517         // If the second color is white, create a monochrome bitmap
518         fColor =  (col != RGB(0xff,0xff,0xff));
519       }
520     else fColor = TRUE;
521   }
522   else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
523   {
524     RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors;
525      DWORD col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue);
526
527     if ((col == RGB(0,0,0)))
528     {
529       rgb++;
530       col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue );
531       fColor = (col != RGB(0xff,0xff,0xff));
532     }
533     else fColor = TRUE;
534   }
535   else
536   {
537       DPRINT("(%ld): wrong size for data\n", data->bmiHeader.biSize );
538       return 0;
539     }
540   }
541
542   // Now create the bitmap
543
544   if (init == CBM_INIT)
545     {
546       handle = NtGdiCreateCompatibleBitmap(hdc, width, height);
547     }
548   else
549     {
550       handle = NtGdiCreateBitmap(width, height, 1, bpp, NULL);
551     }
552
553   if (!handle) return 0;
554
555   if (init == CBM_INIT)
556   {
557     NtGdiSetDIBits(hdc, handle, 0, height, bits, data, coloruse);
558   }
559
560   return handle;
561 }
562
563 HBITMAP STDCALL NtGdiCreateDIBSection(HDC hDC,
564                               CONST BITMAPINFO  *bmi,
565                               UINT  Usage,
566                               VOID  *Bits,
567                               HANDLE  hSection,
568                               DWORD  dwOffset)
569 {
570   HBITMAP hbitmap = 0;
571   DC *dc;
572   BOOL bDesktopDC = FALSE;
573
574   // If the reference hdc is null, take the desktop dc
575   if (hDC == 0)
576   {
577     hDC = NtGdiCreateCompatableDC(0);
578     bDesktopDC = TRUE;
579   }
580
581   if ((dc = DC_LockDc(hDC)))
582   {
583     hbitmap = DIB_CreateDIBSection ( dc, (BITMAPINFO*)bmi, Usage, Bits,
584       hSection, dwOffset, 0);
585     DC_UnlockDc(hDC);
586   }
587
588   if (bDesktopDC)
589     NtGdiDeleteDC(hDC);
590
591   return hbitmap;
592 }
593
594 HBITMAP STDCALL
595 DIB_CreateDIBSection(
596   PDC dc, BITMAPINFO *bmi, UINT usage,
597   LPVOID *bits, HANDLE section,
598   DWORD offset, DWORD ovr_pitch)
599 {
600   HBITMAP res = 0;
601   BITMAPOBJ *bmp = NULL;
602   DIBSECTION *dib = NULL;
603
604   // Fill BITMAP32 structure with DIB data
605   BITMAPINFOHEADER *bi = &bmi->bmiHeader;
606   INT effHeight;
607   ULONG totalSize;
608   UINT Entries = 0;
609   BITMAP bm;
610
611   DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
612         bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
613         bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
614
615   effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
616   bm.bmType = 0;
617   bm.bmWidth = bi->biWidth;
618   bm.bmHeight = effHeight;
619   bm.bmWidthBytes = ovr_pitch ? ovr_pitch : (ULONG) DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
620
621   bm.bmPlanes = bi->biPlanes;
622   bm.bmBitsPixel = bi->biBitCount;
623   bm.bmBits = NULL;
624
625   // Get storage location for DIB bits.  Only use biSizeImage if it's valid and
626   // we're dealing with a compressed bitmap.  Otherwise, use width * height.
627   totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
628     ? bi->biSizeImage : (ULONG) (bm.bmWidthBytes * effHeight);
629
630   if (section)
631 /*    bm.bmBits = MapViewOfFile(section, FILE_MAP_ALL_ACCESS,
632                               0L, offset, totalSize); */
633     DbgPrint("DIB_CreateDIBSection: Cannot yet handle section DIBs\n");
634   else if (ovr_pitch && offset)
635     bm.bmBits = (LPVOID) offset;
636   else {
637     offset = 0;
638     bm.bmBits = EngAllocUserMem(totalSize, 0);
639   }
640
641 /*  bm.bmBits = ExAllocatePool(NonPagedPool, totalSize); */
642
643   if(usage == DIB_PAL_COLORS) memcpy(bmi->bmiColors, (UINT *)DIB_MapPaletteColors(dc, bmi), sizeof(UINT *));
644
645   // Allocate Memory for DIB and fill structure
646   if (bm.bmBits)
647   {
648     dib = ExAllocatePool(PagedPool, sizeof(DIBSECTION));
649     RtlZeroMemory(dib, sizeof(DIBSECTION));
650   }
651
652   if (dib)
653   {
654     dib->dsBm = bm;
655     dib->dsBmih = *bi;
656     dib->dsBmih.biSizeImage = totalSize;
657
658     /* Set dsBitfields values */
659     if ( usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
660     {
661       dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
662     }
663     else switch(bi->biBitCount)
664     {
665       case 16:
666         dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0x7c00;
667         dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0x03e0;
668         dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0x001f;
669         break;
670
671       case 24:
672         dib->dsBitfields[0] = 0xff;
673         dib->dsBitfields[1] = 0xff00;
674         dib->dsBitfields[2] = 0xff0000;
675         break;
676
677       case 32:
678         dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0xff;
679         dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0xff00;
680         dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0xff0000;
681         break;
682     }
683     dib->dshSection = section;
684     dib->dsOffset = offset;
685   }
686
687   // Create Device Dependent Bitmap and add DIB pointer
688   if (dib)
689   {
690     res = NtGdiCreateDIBitmap(dc->hSelf, bi, 0, NULL, bmi, usage);
691     if (! res)
692       {
693         return NULL;
694       } 
695     bmp = BITMAPOBJ_LockBitmap(res);
696     if (NULL == bmp)
697       {
698         NtGdiDeleteObject(bmp);
699         return NULL;
700       }
701     bmp->dib = (DIBSECTION *) dib;
702     /* Install user-mode bits instead of kernel-mode bits */
703     ExFreePool(bmp->bitmap.bmBits);
704     bmp->bitmap.bmBits = bm.bmBits;
705
706     /* WINE NOTE: WINE makes use of a colormap, which is a color translation table between the DIB and the X physical
707                   device. Obviously, this is left out of the ReactOS implementation. Instead, we call
708                   NtGdiSetDIBColorTable. */
709     if(bi->biBitCount == 1) { Entries = 2; } else
710     if(bi->biBitCount == 4) { Entries = 16; } else
711     if(bi->biBitCount == 8) { Entries = 256; }
712
713     bmp->ColorMap = ExAllocatePool(NonPagedPool, sizeof(RGBQUAD)*Entries);
714     RtlCopyMemory(bmp->ColorMap, bmi->bmiColors, sizeof(RGBQUAD)*Entries);
715   }
716
717   // Clean up in case of errors
718   if (!res || !bmp || !dib || !bm.bmBits)
719   {
720     DPRINT("got an error res=%08x, bmp=%p, dib=%p, bm.bmBits=%p\n", res, bmp, dib, bm.bmBits);
721 /*      if (bm.bmBits)
722       {
723       if (section)
724         UnmapViewOfFile(bm.bmBits), bm.bmBits = NULL;
725       else if (!offset)
726       VirtualFree(bm.bmBits, 0L, MEM_RELEASE), bm.bmBits = NULL;
727     } */
728
729     if (dib) { ExFreePool(dib); dib = NULL; }
730     if (bmp) { bmp = NULL; }
731     if (res) { BITMAPOBJ_FreeBitmap(res); res = 0; }
732   }
733
734   if (bmp)
735     {
736       BITMAPOBJ_UnlockBitmap(res);
737     }
738
739   // Return BITMAP handle and storage location
740   if (NULL != bm.bmBits && NULL != bits)
741     {
742       *bits = bm.bmBits;
743     }
744
745   return res;
746 }
747
748 /***********************************************************************
749  *           DIB_GetDIBWidthBytes
750  *
751  * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
752  * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
753  * 11/16/1999 (RJJ) lifted from wine
754  */
755 INT FASTCALL DIB_GetDIBWidthBytes (INT width, INT depth)
756 {
757   int words;
758
759   switch(depth)
760   {
761     case 1:  words = (width + 31) / 32; break;
762     case 4:  words = (width + 7) / 8; break;
763     case 8:  words = (width + 3) / 4; break;
764     case 15:
765     case 16: words = (width + 1) / 2; break;
766     case 24: words = (width * 3 + 3)/4; break;
767
768     default:
769       DPRINT("(%d): Unsupported depth\n", depth );
770       /* fall through */
771     case 32:
772       words = width;
773   }
774   return 4 * words;
775 }
776
777 /***********************************************************************
778  *           DIB_GetDIBImageBytes
779  *
780  * Return the number of bytes used to hold the image in a DIB bitmap.
781  * 11/16/1999 (RJJ) lifted from wine
782  */
783
784 INT STDCALL DIB_GetDIBImageBytes (INT  width, INT height, INT depth)
785 {
786   return DIB_GetDIBWidthBytes( width, depth ) * (height < 0 ? -height : height);
787 }
788
789 /***********************************************************************
790  *           DIB_BitmapInfoSize
791  *
792  * Return the size of the bitmap info structure including color table.
793  * 11/16/1999 (RJJ) lifted from wine
794  */
795
796 INT FASTCALL DIB_BitmapInfoSize (const BITMAPINFO * info, WORD coloruse)
797 {
798   int colors;
799
800   if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
801   {
802     BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
803     colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
804     return sizeof(BITMAPCOREHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
805   }
806   else  /* assume BITMAPINFOHEADER */
807   {
808     colors = info->bmiHeader.biClrUsed;
809     if (!colors && (info->bmiHeader.biBitCount <= 8)) colors = 1 << info->bmiHeader.biBitCount;
810     return sizeof(BITMAPINFOHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
811   }
812 }
813
814 INT STDCALL DIB_GetBitmapInfo (const BITMAPINFOHEADER *header,
815                                PDWORD width,
816                                PINT height,
817                                PWORD bpp,
818                                PWORD compr)
819 {
820   if (header->biSize == sizeof(BITMAPINFOHEADER))
821   {
822     *width  = header->biWidth;
823     *height = header->biHeight;
824     *bpp    = header->biBitCount;
825     *compr  = header->biCompression;
826     return 1;
827   }
828   if (header->biSize == sizeof(BITMAPCOREHEADER))
829   {
830     BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)header;
831     *width  = core->bcWidth;
832     *height = core->bcHeight;
833     *bpp    = core->bcBitCount;
834     *compr  = 0;
835     return 0;
836   }
837   DPRINT("(%ld): wrong size for header\n", header->biSize );
838   return -1;
839 }
840
841 // Converts a Device Independent Bitmap (DIB) to a Device Dependant Bitmap (DDB)
842 // The specified Device Context (DC) defines what the DIB should be converted to
843 PBITMAPOBJ FASTCALL DIBtoDDB(HGLOBAL hPackedDIB, HDC hdc) // FIXME: This should be removed. All references to this function should
844                                                  // change to NtGdiSetDIBits
845 {
846   HBITMAP hBmp = 0;
847   PBITMAPOBJ pBmp = NULL;
848   DIBSECTION *dib;
849   LPBYTE pbits = NULL;
850
851   // Get a pointer to the packed DIB's data
852   // pPackedDIB = (LPBYTE)GlobalLock(hPackedDIB);
853   dib = hPackedDIB;
854
855   pbits = (LPBYTE)(dib + DIB_BitmapInfoSize((BITMAPINFO*)&dib->dsBmih, DIB_RGB_COLORS));
856
857   // Create a DDB from the DIB
858   hBmp = NtGdiCreateDIBitmap ( hdc, &dib->dsBmih, CBM_INIT,
859     (LPVOID)pbits, (BITMAPINFO*)&dib->dsBmih, DIB_RGB_COLORS);
860
861   // GlobalUnlock(hPackedDIB);
862
863   // Retrieve the internal Pixmap from the DDB
864   pBmp = BITMAPOBJ_LockBitmap(hBmp);
865
866   return pBmp;
867 }
868
869 RGBQUAD * FASTCALL
870 DIB_MapPaletteColors(PDC dc, CONST BITMAPINFO* lpbmi)
871 {
872   RGBQUAD *lpRGB;
873   ULONG nNumColors,i;
874   DWORD *lpIndex;
875   PPALOBJ palObj;
876
877   palObj = (PPALOBJ) PALETTE_LockPalette(dc->DevInfo->hpalDefault);
878
879   if (NULL == palObj)
880     {
881 //      RELEASEDCINFO(hDC);
882       return NULL;
883     }
884
885   nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
886   if (lpbmi->bmiHeader.biClrUsed)
887     {
888       nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
889     }
890
891   lpRGB = (RGBQUAD *)ExAllocatePool(NonPagedPool, sizeof(RGBQUAD) * nNumColors);
892   lpIndex = (DWORD *)&lpbmi->bmiColors[0];
893
894   for (i = 0; i < nNumColors; i++)
895     {
896       lpRGB[i].rgbRed = palObj->logpalette->palPalEntry[*lpIndex].peRed;
897       lpRGB[i].rgbGreen = palObj->logpalette->palPalEntry[*lpIndex].peGreen;
898       lpRGB[i].rgbBlue = palObj->logpalette->palPalEntry[*lpIndex].peBlue;
899       lpIndex++;
900     }
901 //    RELEASEDCINFO(hDC);
902   PALETTE_UnlockPalette(dc->DevInfo->hpalDefault);
903
904   return lpRGB;
905 }
906
907 PPALETTEENTRY STDCALL
908 DIBColorTableToPaletteEntries (
909         PPALETTEENTRY palEntries,
910         const RGBQUAD *DIBColorTable,
911         ULONG ColorCount
912         )
913 {
914   ULONG i;
915
916   for (i = 0; i < ColorCount; i++)
917     {
918       palEntries->peRed   = DIBColorTable->rgbRed;
919       palEntries->peGreen = DIBColorTable->rgbGreen;
920       palEntries->peBlue  = DIBColorTable->rgbBlue;
921       palEntries++;
922       DIBColorTable++;
923     }
924
925   return palEntries;
926 }
927
928 HPALETTE FASTCALL
929 BuildDIBPalette (PBITMAPINFO bmi, PINT paletteType)
930 {
931   BYTE bits;
932   ULONG ColorCount;
933   PALETTEENTRY *palEntries = NULL;
934   HPALETTE hPal;
935
936   // Determine Bits Per Pixel
937   bits = bmi->bmiHeader.biBitCount;
938
939   // Determine paletteType from Bits Per Pixel
940   if (bits <= 8)
941     {
942       *paletteType = PAL_INDEXED;
943     }
944   else if(bits < 24)
945     {
946       *paletteType = PAL_BITFIELDS;
947     }
948   else
949     {
950       *paletteType = PAL_BGR;
951     }
952
953   if (bmi->bmiHeader.biClrUsed == 0)
954     {
955       ColorCount = 1 << bmi->bmiHeader.biBitCount;
956     }
957   else
958     {
959       ColorCount = bmi->bmiHeader.biClrUsed;
960     }
961
962   if (PAL_INDEXED == *paletteType)
963     {
964       palEntries = ExAllocatePool(NonPagedPool, sizeof(PALETTEENTRY)*ColorCount);
965       DIBColorTableToPaletteEntries(palEntries, bmi->bmiColors, ColorCount);
966     }
967   hPal = PALETTE_AllocPalette( *paletteType, ColorCount, (ULONG*)palEntries, 0, 0, 0 );
968   if (NULL != palEntries)
969     {
970       ExFreePool(palEntries);
971     }
972
973   return hPal;
974 }
975
976 /* EOF */