1 #undef WIN32_LEAN_AND_MEAN
4 #include <win32k/bitmaps.h>
5 #include <win32k/debug.h>
7 #include "../eng/handle.h"
8 #include <ntos/minmax.h>
10 VOID BitmapToSurf(HDC hdc, PSURFGDI SurfGDI, PSURFOBJ SurfObj, PBITMAPOBJ Bitmap);
12 UINT STDCALL W32kSetDIBColorTable(HDC hDC,
15 CONST RGBQUAD *Colors)
18 PALETTEENTRY * palEntry;
22 if (!(dc = (PDC)AccessUserObject(hDC))) return 0;
24 if (!(palette = (PPALOBJ)AccessUserObject(dc->DevInfo.hpalDefault)))
26 // GDI_ReleaseObj( hdc );
30 // Transfer color info
32 if (dc->w.bitsPerPixel <= 8) {
33 palEntry = palette->logpalette->palPalEntry + StartIndex;
34 if (StartIndex + Entries > (1 << dc->w.bitsPerPixel))
35 Entries = (1 << dc->w.bitsPerPixel) - StartIndex;
37 if (StartIndex + Entries > palette->logpalette->palNumEntries)
38 Entries = palette->logpalette->palNumEntries - StartIndex;
40 for (end = Colors + Entries; Colors < end; palEntry++, Colors++)
42 palEntry->peRed = Colors->rgbRed;
43 palEntry->peGreen = Colors->rgbGreen;
44 palEntry->peBlue = Colors->rgbBlue;
50 // GDI_ReleaseObj(dc->DevInfo.hpalDefault);
51 // GDI_ReleaseObj(hdc);
56 // Converts a DIB to a device-dependent bitmap
57 INT STDCALL W32kSetDIBits(HDC hDC,
62 CONST BITMAPINFO *bmi,
67 HBITMAP SourceBitmap, DestBitmap;
70 PSURFOBJ DestSurf, SourceSurf;
78 HPALETTE DDB_Palette, DIB_Palette;
79 ULONG DDB_Palette_Type, DIB_Palette_Type;
81 INT scanDirection = 1, DIBWidth;
84 if (!(dc = DC_HandleToPtr(hDC)))
87 if (!(bitmap = (BITMAPOBJ *)GDIOBJ_LockObj(hBitmap, GO_BITMAP_MAGIC)))
94 if (ColorUse == DIB_PAL_COLORS)
95 lpRGB = DIB_MapPaletteColors(hDC, bmi);
97 lpRGB = &bmi->bmiColors[0];
99 // Create a temporary surface for the destination bitmap
100 DestBitmap = (HBITMAP)CreateGDIHandle(sizeof(SURFGDI), sizeof(SURFOBJ));
102 DestSurf = (PSURFOBJ) AccessUserObject( DestBitmap );
103 DestGDI = (PSURFGDI) AccessInternalObject( DestBitmap );
105 BitmapToSurf(hDC, DestGDI, DestSurf, bitmap);
107 // Create source surface
108 SourceSize.cx = bmi->bmiHeader.biWidth;
109 SourceSize.cy = abs(bmi->bmiHeader.biHeight);
111 // Determine width of DIB
112 DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
114 // Determine DIB Vertical Orientation
115 if(bmi->bmiHeader.biHeight > 0)
118 vBits += DIBWidth * bmi->bmiHeader.biHeight - DIBWidth;
121 SourceBitmap = EngCreateBitmap(SourceSize,
122 DIBWidth * scanDirection,
123 BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
126 SourceSurf = (PSURFOBJ)AccessUserObject(SourceBitmap);
128 // Destination palette obtained from the hDC
129 hDCPalette = (PPALGDI)AccessInternalObject(dc->DevInfo.hpalDefault);
130 DDB_Palette_Type = hDCPalette->Mode;
131 DDB_Palette = dc->DevInfo.hpalDefault;
133 // Source palette obtained from the BITMAPINFO
134 DIB_Palette = BuildDIBPalette(bmi, &DIB_Palette_Type);
136 // Determine XLATEOBJ for color translation
137 XlateObj = EngCreateXlate(DDB_Palette_Type, DIB_Palette_Type, DDB_Palette, DIB_Palette);
143 // Determine destination rectangle
146 DestRect.right = SourceSize.cx;
147 DestRect.bottom = SourceSize.cy;
149 copyBitsResult = EngCopyBits(DestSurf, SourceSurf, NULL, XlateObj, &DestRect, &ZeroPoint);
151 // If it succeeded, return number of scanlines copies
152 if(copyBitsResult == TRUE)
154 result = SourceSize.cy - 1;
158 EngDeleteSurface(SourceBitmap);
159 EngDeleteSurface(DestBitmap);
161 // if (ColorUse == DIB_PAL_COLORS)
162 // WinFree((LPSTR)lpRGB);
164 // GDI_ReleaseObj(hBitmap); unlock?
165 GDIOBJ_UnlockObj(hBitmap, GO_BITMAP_MAGIC);
171 INT STDCALL W32kSetDIBitsToDevice(HDC hDC,
181 CONST BITMAPINFO *bmi,
187 UINT STDCALL W32kGetDIBColorTable(HDC hDC,
195 // Converts a device-dependent bitmap to a DIB
196 INT STDCALL W32kGetDIBits(HDC hDC,
207 INT STDCALL W32kStretchDIBits(HDC hDC,
217 CONST BITMAPINFO *BitsInfo,
224 LONG STDCALL W32kGetBitmapBits(HBITMAP hBitmap,
231 bmp = BITMAPOBJ_HandleToPtr (hBitmap);
237 /* If the bits vector is null, the function should return the read size */
240 return bmp->bitmap.bmWidthBytes * bmp->bitmap.bmHeight;
245 DPRINT ("(%ld): Negative number of bytes passed???\n", Count);
249 /* Only get entire lines */
250 height = Count / bmp->bitmap.bmWidthBytes;
251 if (height > bmp->bitmap.bmHeight)
253 height = bmp->bitmap.bmHeight;
255 Count = height * bmp->bitmap.bmWidthBytes;
258 DPRINT("Less then one entire line requested\n");
262 DPRINT("(%08x, %ld, %p) %dx%d %d colors fetched height: %ld\n",
263 hBitmap, Count, Bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
264 1 << bmp->bitmap.bmBitsPixel, height );
266 /* FIXME: Call DDI CopyBits here if available */
269 DPRINT("Calling device specific BitmapBits\n");
270 if(bmp->DDBitmap->funcs->pBitmapBits)
272 ret = bmp->DDBitmap->funcs->pBitmapBits(hbitmap, bits, count,
277 ERR_(bitmap)("BitmapBits == NULL??\n");
284 if(!bmp->bitmap.bmBits)
286 DPRINT ("Bitmap is empty\n");
291 memcpy(Bits, bmp->bitmap.bmBits, Count);
299 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
300 // The DDB that is created will be whatever bit depth your reference DC is
301 HBITMAP STDCALL W32kCreateDIBitmap(HDC hdc, const BITMAPINFOHEADER *header,
302 DWORD init, LPCVOID bits, const BITMAPINFO *data,
312 if (DIB_GetBitmapInfo( header, &width, &height, &bpp, &compr ) == -1) return 0;
313 if (height < 0) height = -height;
315 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
316 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
318 if (bpp != 1) fColor = TRUE;
319 else if ((coloruse != DIB_RGB_COLORS) ||
320 (init != CBM_INIT) || !data) fColor = FALSE;
323 if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
325 RGBQUAD *rgb = data->bmiColors;
326 DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
328 // Check if the first color of the colormap is black
329 if ((col == RGB(0, 0, 0)))
332 col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
334 // If the second color is white, create a monochrome bitmap
335 fColor = (col != RGB(0xff,0xff,0xff));
339 else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
341 RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors;
342 DWORD col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue);
344 if ((col == RGB(0,0,0)))
347 col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue );
348 fColor = (col != RGB(0xff,0xff,0xff));
354 DbgPrint("(%ld): wrong size for data\n", data->bmiHeader.biSize );
359 // Now create the bitmap
363 // If we are using indexed colors, then we need to create a bitmap that is compatible with the palette
364 if(coloruse == DIB_PAL_COLORS)
366 handle = W32kCreateCompatibleBitmap(hdc, width, height);
368 else if(coloruse == DIB_RGB_COLORS) {
369 handle = W32kCreateBitmap(width, height, 1, 24, NULL);
372 else handle = W32kCreateBitmap(width, height, 1, 1, NULL);
374 if (!handle) return 0;
376 if (init == CBM_INIT)
378 W32kSetDIBits(hdc, handle, 0, height, bits, data, coloruse);
384 HBITMAP STDCALL W32kCreateDIBSection(HDC hDC,
385 CONST BITMAPINFO *bmi,
393 BOOL bDesktopDC = FALSE;
395 // If the reference hdc is null, take the desktop dc
398 hDC = W32kCreateCompatableDC(0);
402 if ((dc = DC_HandleToPtr(hDC)))
404 hbitmap = DIB_CreateDIBSection(dc, bmi, Usage, Bits, hSection, dwOffset, 0);
414 HBITMAP DIB_CreateDIBSection(
415 PDC dc, BITMAPINFO *bmi, UINT usage,
416 LPVOID *bits, HANDLE section,
417 DWORD offset, DWORD ovr_pitch)
420 BITMAPOBJ *bmp = NULL;
421 DIBSECTION *dib = NULL;
423 // Fill BITMAP32 structure with DIB data
424 BITMAPINFOHEADER *bi = &bmi->bmiHeader;
425 INT effHeight, totalSize;
429 DbgPrint("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
430 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
431 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
433 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
435 bm.bmWidth = bi->biWidth;
436 bm.bmHeight = effHeight;
437 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
439 bm.bmPlanes = bi->biPlanes;
440 bm.bmBitsPixel = bi->biBitCount;
443 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
444 // we're dealing with a compressed bitmap. Otherwise, use width * height.
445 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
446 ? bi->biSizeImage : bm.bmWidthBytes * effHeight;
449 /* bm.bmBits = MapViewOfFile(section, FILE_MAP_ALL_ACCESS,
450 0L, offset, totalSize); */
451 DbgPrint("DIB_CreateDIBSection: Cannot yet handle section DIBs\n");
452 else if (ovr_pitch && offset)
453 bm.bmBits = (LPVOID) offset;
456 bm.bmBits = EngAllocUserMem(totalSize, 0);
459 /* bm.bmBits = ExAllocatePool(NonPagedPool, totalSize); */
461 if(usage == DIB_PAL_COLORS) memcpy(bmi->bmiColors, (UINT *)DIB_MapPaletteColors(dc, bmi), sizeof(UINT *));
463 // Allocate Memory for DIB and fill structure
466 dib = ExAllocatePool(PagedPool, sizeof(DIBSECTION));
467 RtlZeroMemory(dib, sizeof(DIBSECTION));
474 dib->dsBmih.biSizeImage = totalSize;
476 /* Set dsBitfields values */
477 if ( usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
479 dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
481 else switch(bi->biBitCount)
484 dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0x7c00;
485 dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0x03e0;
486 dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0x001f;
490 dib->dsBitfields[0] = 0xff;
491 dib->dsBitfields[1] = 0xff00;
492 dib->dsBitfields[2] = 0xff0000;
496 dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0xff;
497 dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0xff00;
498 dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0xff0000;
501 dib->dshSection = section;
502 dib->dsOffset = offset;
505 // Create Device Dependent Bitmap and add DIB pointer
508 res = W32kCreateDIBitmap(dc->hSelf, bi, 0, NULL, bmi, usage);
511 bmp = BITMAPOBJ_HandleToPtr (res);
514 bmp->dib = (DIBSECTION *) dib;
518 /* WINE NOTE: WINE makes use of a colormap, which is a color translation table between the DIB and the X physical
519 device. Obviously, this is left out of the ReactOS implementation. Instead, we call
520 W32kSetDIBColorTable. */
521 if(bi->biBitCount == 1) { Entries = 2; } else
522 if(bi->biBitCount == 4) { Entries = 16; } else
523 if(bi->biBitCount == 8) { Entries = 256; }
525 bmp->ColorMap = ExAllocatePool(NonPagedPool, sizeof(RGBQUAD)*Entries);
526 RtlCopyMemory(bmp->ColorMap, bmi->bmiColors, sizeof(RGBQUAD)*Entries);
529 // Clean up in case of errors
530 if (!res || !bmp || !dib || !bm.bmBits)
532 DbgPrint("got an error res=%08x, bmp=%p, dib=%p, bm.bmBits=%p\n", res, bmp, dib, bm.bmBits);
536 UnmapViewOfFile(bm.bmBits), bm.bmBits = NULL;
538 VirtualFree(bm.bmBits, 0L, MEM_RELEASE), bm.bmBits = NULL;
541 if (dib) { ExFreePool(dib); dib = NULL; }
542 if (bmp) { bmp = NULL; }
543 if (res) { GDIOBJ_FreeObj(res, GO_BITMAP_MAGIC, GDIOBJFLAG_DEFAULT); res = 0; }
546 // Install fault handler, if possible
549 if (VIRTUAL_SetFaultHandler(bm.bmBits, DIB_FaultHandler, (LPVOID)res))
551 if (section || offset)
553 DIB_DoProtectDIBSection( bmp, PAGE_READWRITE );
554 if (dib) dib->status = DIB_AppMod;
558 DIB_DoProtectDIBSection( bmp, PAGE_READONLY );
559 if (dib) dib->status = DIB_InSync;
565 BITMAPOBJ_ReleasePtr(res);
567 // Return BITMAP handle and storage location
568 if (bm.bmBits && bits) *bits = bm.bmBits;
573 /***********************************************************************
574 * DIB_GetDIBWidthBytes
576 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
577 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
578 * 11/16/1999 (RJJ) lifted from wine
580 int DIB_GetDIBWidthBytes(int width, int depth)
586 case 1: words = (width + 31) / 32; break;
587 case 4: words = (width + 7) / 8; break;
588 case 8: words = (width + 3) / 4; break;
590 case 16: words = (width + 1) / 2; break;
591 case 24: words = (width * 3 + 3)/4; break;
594 DPRINT("(%d): Unsupported depth\n", depth );
602 /***********************************************************************
603 * DIB_GetDIBImageBytes
605 * Return the number of bytes used to hold the image in a DIB bitmap.
606 * 11/16/1999 (RJJ) lifted from wine
609 int DIB_GetDIBImageBytes (int width, int height, int depth)
611 return DIB_GetDIBWidthBytes( width, depth ) * (height < 0 ? -height : height);
614 /***********************************************************************
617 * Return the size of the bitmap info structure including color table.
618 * 11/16/1999 (RJJ) lifted from wine
621 int DIB_BitmapInfoSize (const BITMAPINFO * info, WORD coloruse)
625 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
627 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
628 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
629 return sizeof(BITMAPCOREHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
631 else /* assume BITMAPINFOHEADER */
633 colors = info->bmiHeader.biClrUsed;
634 if (!colors && (info->bmiHeader.biBitCount <= 8)) colors = 1 << info->bmiHeader.biBitCount;
635 return sizeof(BITMAPINFOHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
639 int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, DWORD *width,
640 int *height, WORD *bpp, WORD *compr )
642 if (header->biSize == sizeof(BITMAPINFOHEADER))
644 *width = header->biWidth;
645 *height = header->biHeight;
646 *bpp = header->biBitCount;
647 *compr = header->biCompression;
650 if (header->biSize == sizeof(BITMAPCOREHEADER))
652 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)header;
653 *width = core->bcWidth;
654 *height = core->bcHeight;
655 *bpp = core->bcBitCount;
659 DbgPrint("(%ld): wrong size for header\n", header->biSize );
663 // Converts a Device Independent Bitmap (DIB) to a Device Dependant Bitmap (DDB)
664 // The specified Device Context (DC) defines what the DIB should be converted to
665 PBITMAPOBJ DIBtoDDB(HGLOBAL hPackedDIB, HDC hdc) // FIXME: This should be removed. All references to this function should
666 // change to W32kSetDIBits
669 PBITMAPOBJ pBmp = NULL;
673 // Get a pointer to the packed DIB's data
674 // pPackedDIB = (LPBYTE)GlobalLock(hPackedDIB);
677 pbits = (dib + DIB_BitmapInfoSize(&dib->dsBmih, DIB_RGB_COLORS));
679 // Create a DDB from the DIB
680 hBmp = W32kCreateDIBitmap(hdc, &dib->dsBmih, CBM_INIT, (LPVOID)pbits, &dib->dsBmih, DIB_RGB_COLORS);
682 // GlobalUnlock(hPackedDIB);
684 // Retrieve the internal Pixmap from the DDB
685 pBmp = (BITMAPOBJ *)GDIOBJ_LockObj(hBmp, GO_BITMAP_MAGIC);
690 RGBQUAD *DIB_MapPaletteColors(PDC dc, LPBITMAPINFO lpbmi)
697 palObj = AccessUserObject(dc->DevInfo.hpalDefault);
699 if (palObj == NULL) {
700 // RELEASEDCINFO(hDC);
704 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
705 if (lpbmi->bmiHeader.biClrUsed)
706 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
708 lpRGB = (RGBQUAD *)ExAllocatePool(NonPagedPool, sizeof(RGBQUAD) * nNumColors);
709 lpIndex = (DWORD *)&lpbmi->bmiColors[0];
711 for (i=0; i<nNumColors; i++) {
712 lpRGB[i].rgbRed = palObj->logpalette->palPalEntry[*lpIndex].peRed;
713 lpRGB[i].rgbGreen = palObj->logpalette->palPalEntry[*lpIndex].peGreen;
714 lpRGB[i].rgbBlue = palObj->logpalette->palPalEntry[*lpIndex].peBlue;
717 // RELEASEDCINFO(hDC);
718 // RELEASEPALETTEINFO(hPalette);
722 PALETTEENTRY *DIBColorTableToPaletteEntries(PALETTEENTRY *palEntries, const RGBQUAD *DIBColorTable, ULONG ColorCount)
726 for(i=0; i<ColorCount; i++)
728 palEntries->peRed = DIBColorTable->rgbRed;
729 palEntries->peGreen = DIBColorTable->rgbGreen;
730 palEntries->peBlue = DIBColorTable->rgbBlue;
736 HPALETTE BuildDIBPalette(BITMAPINFO *bmi, PINT paletteType)
740 PALETTEENTRY *palEntries;
743 // Determine Bits Per Pixel
744 bits = bmi->bmiHeader.biBitCount;
746 // Determine paletteType from Bits Per Pixel
749 *paletteType = PAL_INDEXED;
753 *paletteType = PAL_BITFIELDS;
755 *paletteType = PAL_RGB; // Would it be BGR, considering the BGR nature of the DIB color table?
758 if (bmi->bmiHeader.biClrUsed == 0 &&
759 bmi->bmiHeader.biBitCount <= 8)
761 ColorCount = 1 << bmi->bmiHeader.biBitCount;
765 ColorCount = bmi->bmiHeader.biClrUsed;
768 palEntries = ExAllocatePool(NonPagedPool, sizeof(PALETTEENTRY)*ColorCount);
769 DIBColorTableToPaletteEntries(palEntries, bmi->bmiColors, ColorCount);
770 hPal = EngCreatePalette(*paletteType, ColorCount, palEntries, 0, 0, 0);
771 ExFreePool(palEntries);