win32u: Support wow64 in NtAllocateVirtualMemory calls.
[wine.git] / dlls / win32u / dib.c
blobe7a5a50e201dba07fb35068bb66c29fb9ce666e5
1 /*
2 * GDI device-independent bitmaps
4 * Copyright 1993,1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 Important information:
24 * Current Windows versions support two different DIB structures:
26 - BITMAPCOREINFO / BITMAPCOREHEADER (legacy structures; used in OS/2)
27 - BITMAPINFO / BITMAPINFOHEADER
29 Most Windows API functions taking a BITMAPINFO* / BITMAPINFOHEADER* also
30 accept the old "core" structures, and so must WINE.
31 You can distinguish them by looking at the first member (bcSize/biSize).
34 * The palettes are stored in different formats:
36 - BITMAPCOREINFO: Array of RGBTRIPLE
37 - BITMAPINFO: Array of RGBQUAD
40 * There are even more DIB headers, but they all extend BITMAPINFOHEADER:
42 - BITMAPV4HEADER: Introduced in Windows 95 / NT 4.0
43 - BITMAPV5HEADER: Introduced in Windows 98 / 2000
45 If biCompression is BI_BITFIELDS, the color masks are at the same position
46 in all the headers (they start at bmiColors of BITMAPINFOHEADER), because
47 the new headers have structure members for the masks.
50 * You should never access the color table using the bmiColors member,
51 because the passed structure may have one of the extended headers
52 mentioned above. Use this to calculate the location:
54 BITMAPINFO* info;
55 void* colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
58 * More information:
59 Search for "Bitmap Structures" in MSDN
62 #if 0
63 #pragma makedep unix
64 #endif
66 #include <stdarg.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <assert.h>
71 #include "ntstatus.h"
72 #define WIN32_NO_STATUS
73 #include "windef.h"
74 #include "winbase.h"
75 #include "wingdi.h"
76 #include "winternl.h"
77 #include "ddk/d3dkmthk.h"
79 #include "ntgdi_private.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
85 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
86 static BOOL DIB_DeleteObject( HGDIOBJ handle );
88 static const struct gdi_obj_funcs dib_funcs =
90 DIB_GetObject, /* pGetObjectW */
91 NULL, /* pUnrealizeObject */
92 DIB_DeleteObject /* pDeleteObject */
95 /***********************************************************************
96 * bitmap_info_size
98 * Return the size of the bitmap info structure including color table.
100 static int bitmap_info_size( const BITMAPINFO *info, WORD coloruse )
102 unsigned int colors, size, masks = 0;
104 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
106 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
107 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
108 return sizeof(BITMAPCOREHEADER) + colors *
109 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
111 else /* assume BITMAPINFOHEADER */
113 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
114 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
115 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
116 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
117 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
121 /*******************************************************************************************
122 * Verify that the DIB parameters are valid.
124 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
126 if (info->biWidth <= 0) return FALSE;
127 if (info->biHeight == 0) return FALSE;
129 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
131 if (info->biHeight < 0) return FALSE;
132 if (!info->biSizeImage) return FALSE;
133 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
136 if (!info->biPlanes) return FALSE;
138 /* check for size overflow */
139 if (!info->biBitCount) return FALSE;
140 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
141 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
143 switch (info->biBitCount)
145 case 1:
146 case 4:
147 case 8:
148 case 24:
149 return (info->biCompression == BI_RGB);
150 case 16:
151 case 32:
152 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
153 default:
154 return FALSE;
158 /*******************************************************************************************
159 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
161 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
163 if (!info) return FALSE;
165 if (info->biSize == sizeof(BITMAPCOREHEADER))
167 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
168 dst->biWidth = core->bcWidth;
169 dst->biHeight = core->bcHeight;
170 dst->biPlanes = core->bcPlanes;
171 dst->biBitCount = core->bcBitCount;
172 dst->biCompression = BI_RGB;
173 dst->biXPelsPerMeter = 0;
174 dst->biYPelsPerMeter = 0;
175 dst->biClrUsed = 0;
176 dst->biClrImportant = 0;
178 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
180 *dst = *info;
182 else
184 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
185 return FALSE;
188 dst->biSize = sizeof(*dst);
189 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
190 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
191 return TRUE;
194 /*******************************************************************************************
195 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
197 * The resulting sanitized BITMAPINFO is guaranteed to have:
198 * - biSize set to sizeof(BITMAPINFOHEADER)
199 * - biSizeImage set to the actual image size even for non-compressed DIB
200 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
201 * - color table present only for <= 8 bpp, always starts at info->bmiColors
203 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
204 UINT coloruse, BOOL allow_compression )
206 void *src_colors;
208 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
209 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
210 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
212 src_colors = (char *)info + info->bmiHeader.biSize;
214 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
216 /* bitfields are always at bmiColors even in larger structures */
217 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
218 dst->bmiHeader.biClrUsed = 0;
220 else if (dst->bmiHeader.biBitCount <= 8)
222 unsigned int colors = dst->bmiHeader.biClrUsed;
223 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
225 if (!colors) colors = max_colors;
226 else colors = min( colors, max_colors );
228 if (coloruse == DIB_PAL_COLORS)
230 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
231 max_colors = colors;
233 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
235 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
237 else
239 unsigned int i;
240 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
241 for (i = 0; i < colors; i++)
243 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
244 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
245 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
246 dst->bmiColors[i].rgbReserved = 0;
249 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
250 dst->bmiHeader.biClrUsed = max_colors;
252 else dst->bmiHeader.biClrUsed = 0;
254 return TRUE;
257 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
259 PALETTEENTRY palEntry[256];
260 HPALETTE palette = NtGdiGetDCObject( hdc, NTGDI_OBJ_PAL );
261 int i, colors = 1 << info->bmiHeader.biBitCount;
263 info->bmiHeader.biClrUsed = colors;
265 if (!palette) return 0;
267 memset( palEntry, 0, sizeof(palEntry) );
268 if (!get_palette_entries( palette, 0, colors, palEntry ))
269 return 0;
271 for (i = 0; i < colors; i++)
273 info->bmiColors[i].rgbRed = palEntry[i].peRed;
274 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
275 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
276 info->bmiColors[i].rgbReserved = 0;
279 return colors;
282 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
284 PALETTEENTRY entries[256];
285 RGBQUAD table[256];
286 HPALETTE palette;
287 const WORD *index = (const WORD *)info->bmiColors;
288 int i, count, colors = info->bmiHeader.biClrUsed;
290 if (!colors) return TRUE;
291 if (!(palette = NtGdiGetDCObject( hdc, NTGDI_OBJ_PAL )))
292 return FALSE;
293 if (!(count = get_palette_entries( palette, 0, colors, entries ))) return FALSE;
295 for (i = 0; i < colors; i++, index++)
297 table[i].rgbRed = entries[*index % count].peRed;
298 table[i].rgbGreen = entries[*index % count].peGreen;
299 table[i].rgbBlue = entries[*index % count].peBlue;
300 table[i].rgbReserved = 0;
302 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
303 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
304 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
305 return TRUE;
308 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
310 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
311 const int bpp = info->bmiHeader.biBitCount;
313 if (height > 0)
314 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
315 else
316 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
319 static BOOL build_rle_bitmap( BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
321 DWORD i = 0;
322 int left, right;
323 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
324 HRGN run = NULL;
325 BYTE skip, num, data;
326 BYTE *out_bits, *in_bits = bits->ptr;
328 if (clip) *clip = NULL;
330 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
332 out_bits = calloc( 1, get_dib_image_size( info ) );
333 if (!out_bits) goto fail;
335 if (clip)
337 *clip = NtGdiCreateRectRgn( 0, 0, 0, 0 );
338 run = NtGdiCreateRectRgn( 0, 0, 0, 0 );
339 if (!*clip || !run) goto fail;
342 x = left = right = 0;
343 y = height - 1;
345 while (i < info->bmiHeader.biSizeImage - 1)
347 num = in_bits[i];
348 data = in_bits[i + 1];
349 i += 2;
351 if (num)
353 if (x + num > width) num = width - x;
354 if (num)
356 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
357 if (info->bmiHeader.biBitCount == 8)
358 memset( out_ptr, s, num );
359 else
361 if(x & 1)
363 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
364 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
365 out_ptr++;
366 x++;
367 num--;
369 /* this will write one too many if num is odd, but that doesn't matter */
370 if (num) memset( out_ptr, s, (num + 1) / 2 );
373 x += num;
374 right = x;
376 else
378 if (data < 3)
380 if(left != right && clip)
382 NtGdiSetRectRgn( run, left, y, right, y + 1 );
383 NtGdiCombineRgn( *clip, run, *clip, RGN_OR );
385 switch (data)
387 case 0: /* eol */
388 left = right = x = 0;
389 y--;
390 if(y < 0) goto done;
391 break;
393 case 1: /* eod */
394 goto done;
396 case 2: /* delta */
397 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
398 x += in_bits[i];
399 if (x > width) x = width;
400 left = right = x;
401 y -= in_bits[i + 1];
402 if(y < 0) goto done;
403 i += 2;
406 else /* data bytes of data */
408 num = data;
409 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
410 if (skip > info->bmiHeader.biSizeImage - i) goto done;
411 skip = (skip + 1) & ~1;
412 if (x + num > width) num = width - x;
413 if (num)
415 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
416 if (info->bmiHeader.biBitCount == 8)
417 memcpy( out_ptr, in_bits + i, num );
418 else
420 if(x & 1)
422 const BYTE *in_ptr = in_bits + i;
423 for ( ; num; num--, x++)
425 if (x & 1)
427 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
428 out_ptr++;
430 else
431 *out_ptr = (*in_ptr++ << 4) & 0xf0;
434 else
435 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
438 x += num;
439 right = x;
440 i += skip;
445 done:
446 if (run) NtGdiDeleteObjectApp( run );
447 if (bits->free) bits->free( bits );
449 bits->ptr = out_bits;
450 bits->is_copy = TRUE;
451 bits->free = free_heap_bits;
452 info->bmiHeader.biSizeImage = get_dib_image_size( info );
454 return TRUE;
456 fail:
457 if (run) NtGdiDeleteObjectApp( run );
458 if (clip && *clip) NtGdiDeleteObjectApp( *clip );
459 free( out_bits );
460 return FALSE;
465 INT CDECL nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
466 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
467 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
469 DC *dc = get_nulldrv_dc( dev );
470 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
471 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
472 struct bitblt_coords src, dst;
473 struct gdi_image_bits src_bits;
474 DWORD err;
475 HRGN clip = NULL;
476 INT ret = 0;
477 INT height = abs( src_info->bmiHeader.biHeight );
478 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
479 RECT rect;
481 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
482 xSrc, ySrc, widthSrc, heightSrc, rop);
484 src_bits.ptr = (void*)bits;
485 src_bits.is_copy = FALSE;
486 src_bits.free = NULL;
488 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
490 rect.left = xDst;
491 rect.top = yDst;
492 rect.right = xDst + widthDst;
493 rect.bottom = yDst + heightDst;
494 lp_to_dp( dc, (POINT *)&rect, 2 );
495 dst.x = rect.left;
496 dst.y = rect.top;
497 dst.width = rect.right - rect.left;
498 dst.height = rect.bottom - rect.top;
500 if (dc->attr->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
502 dst.x += dst.width;
503 dst.width = -dst.width;
505 rop &= ~NOMIRRORBITMAP;
507 src.x = xSrc;
508 src.width = widthSrc;
509 src.y = ySrc;
510 src.height = heightSrc;
512 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
513 non_stretch_from_origin = TRUE;
515 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
517 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
518 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
521 if (rop != SRCCOPY || non_stretch_from_origin)
523 if (dst.width == 1 && src.width > 1) src.width--;
524 if (dst.height == 1 && src.height > 1) src.height--;
527 if (rop != SRCCOPY)
529 if (dst.width < 0 && dst.width == src.width)
531 /* This is off-by-one, but that's what Windows does */
532 dst.x += dst.width;
533 src.x += src.width;
534 dst.width = -dst.width;
535 src.width = -src.width;
537 if (dst.height < 0 && dst.height == src.height)
539 dst.y += dst.height;
540 src.y += src.height;
541 dst.height = -dst.height;
542 src.height = -src.height;
546 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
548 if (src.y >= height && src.y + src.height + 1 < height)
549 src.y = height - 1;
550 else if (src.y > 0 && src.y + src.height + 1 < 0)
551 src.y = -src.height - 1;
553 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
555 src.visrect.left = 0;
556 src.visrect.right = src_info->bmiHeader.biWidth;
557 src.visrect.top = 0;
558 src.visrect.bottom = height;
559 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
561 if (rop == SRCCOPY) ret = height;
562 else ret = src_info->bmiHeader.biHeight;
564 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
566 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
568 if (!intersect_vis_rectangles( &dst, &src )) goto done;
570 if (clip) NtGdiOffsetRgn( clip, dst.x - src.x, dst.y - src.y );
572 dev = GET_DC_PHYSDEV( dc, pPutImage );
573 copy_bitmapinfo( dst_info, src_info );
574 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
575 if (err == ERROR_BAD_FORMAT)
577 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
579 /* 1-bpp destination without a color table requires a fake 1-entry table
580 * that contains only the background color. There is no source DC to get
581 * it from, so the background is hardcoded to the default color. */
582 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
584 static const RGBQUAD default_bg = { 255, 255, 255 };
585 dst_info->bmiColors[0] = default_bg;
586 dst_info->bmiHeader.biClrUsed = 1;
589 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
591 /* get rid of the fake 1-bpp table */
592 dst_info->bmiHeader.biClrUsed = dst_colors;
593 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
597 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
599 copy_bitmapinfo( src_info, dst_info );
600 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, dc->attr->stretch_blt_mode );
601 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
603 if (err) ret = 0;
605 done:
606 if (src_bits.free) src_bits.free( &src_bits );
607 if (clip) NtGdiDeleteObjectApp( clip );
608 return ret;
611 /***********************************************************************
612 * NtGdiStretchDIBitsInternal (win32u.@)
614 INT WINAPI NtGdiStretchDIBitsInternal( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
615 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
616 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
617 DWORD rop, UINT max_info, UINT max_bits, HANDLE xform )
619 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
620 BITMAPINFO *info = (BITMAPINFO *)buffer;
621 PHYSDEV physdev;
622 DC *dc;
623 INT ret = 0;
625 if (!bits) return 0;
626 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
628 SetLastError( ERROR_INVALID_PARAMETER );
629 return 0;
632 if ((dc = get_dc_ptr( hdc )))
634 update_dc( dc );
635 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
636 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
637 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
638 release_dc_ptr( dc );
640 return ret;
644 /******************************************************************************
645 * SetDIBits [GDI32.@]
647 * Sets pixels in a bitmap using colors from DIB.
649 * PARAMS
650 * hdc [I] Handle to device context
651 * hbitmap [I] Handle to bitmap
652 * startscan [I] Starting scan line
653 * lines [I] Number of scan lines
654 * bits [I] Array of bitmap bits
655 * info [I] Address of structure with data
656 * coloruse [I] Type of color indexes to use
658 * RETURNS
659 * Success: Number of scan lines copied
660 * Failure: 0
662 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
663 UINT lines, LPCVOID bits, const BITMAPINFO *info,
664 UINT coloruse )
666 BITMAPOBJ *bitmap;
667 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
668 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
669 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
670 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
671 INT result = 0;
672 DWORD err;
673 struct gdi_image_bits src_bits;
674 struct bitblt_coords src, dst;
675 INT src_to_dst_offset;
676 HRGN clip = 0;
678 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
680 SetLastError( ERROR_INVALID_PARAMETER );
681 return 0;
683 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
685 DWORD *masks = (DWORD *)src_info->bmiColors;
686 if (!masks[0] || !masks[1] || !masks[2])
688 SetLastError( ERROR_INVALID_PARAMETER );
689 return 0;
693 src_bits.ptr = (void *)bits;
694 src_bits.is_copy = FALSE;
695 src_bits.free = NULL;
696 src_bits.param = NULL;
698 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
700 if (!(bitmap = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP ))) return 0;
702 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
704 if (lines == 0) goto done;
705 else lines = src_info->bmiHeader.biHeight;
706 startscan = 0;
708 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
711 dst.visrect.left = 0;
712 dst.visrect.top = 0;
713 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
714 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
716 src.visrect.left = 0;
717 src.visrect.top = 0;
718 src.visrect.right = src_info->bmiHeader.biWidth;
719 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
721 if (src_info->bmiHeader.biHeight > 0)
723 src_to_dst_offset = -startscan;
724 lines = min( lines, src.visrect.bottom - startscan );
725 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
727 else
729 src_to_dst_offset = src.visrect.bottom - lines - startscan;
730 /* Unlike the bottom-up case, Windows doesn't limit lines. */
731 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
734 result = lines;
736 OffsetRect( &src.visrect, 0, src_to_dst_offset );
737 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
738 src.visrect = dst.visrect;
739 OffsetRect( &src.visrect, 0, -src_to_dst_offset );
741 src.x = src.visrect.left;
742 src.y = src.visrect.top;
743 src.width = src.visrect.right - src.visrect.left;
744 src.height = src.visrect.bottom - src.visrect.top;
746 dst.x = dst.visrect.left;
747 dst.y = dst.visrect.top;
748 dst.width = dst.visrect.right - dst.visrect.left;
749 dst.height = dst.visrect.bottom - dst.visrect.top;
751 copy_bitmapinfo( dst_info, src_info );
753 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
754 if (err == ERROR_BAD_FORMAT)
756 err = convert_bits( src_info, &src, dst_info, &src_bits );
757 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
759 if(err) result = 0;
761 done:
762 if (src_bits.free) src_bits.free( &src_bits );
763 if (clip) NtGdiDeleteObjectApp( clip );
764 GDI_ReleaseObj( hbitmap );
765 return result;
769 INT CDECL nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
770 INT x_src, INT y_src, UINT startscan, UINT lines,
771 const void *bits, BITMAPINFO *src_info, UINT coloruse )
773 DC *dc = get_nulldrv_dc( dev );
774 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
775 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
776 struct bitblt_coords src, dst;
777 struct gdi_image_bits src_bits;
778 HRGN clip = 0;
779 DWORD err;
780 UINT height;
781 BOOL top_down;
782 POINT pt;
783 RECT rect;
785 top_down = (src_info->bmiHeader.biHeight < 0);
786 height = abs( src_info->bmiHeader.biHeight );
788 src_bits.ptr = (void *)bits;
789 src_bits.is_copy = FALSE;
790 src_bits.free = NULL;
792 if (!lines) return 0;
793 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
795 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
797 startscan = 0;
798 lines = height;
799 src_info->bmiHeader.biWidth = x_src + cx;
800 src_info->bmiHeader.biHeight = y_src + cy;
801 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
802 src.x = x_src;
803 src.y = 0;
804 src.width = cx;
805 src.height = cy;
806 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
808 else
810 if (startscan >= height) return 0;
811 if (!top_down && lines > height - startscan) lines = height - startscan;
813 /* map src to top-down coordinates with startscan as origin */
814 src.x = x_src;
815 src.y = startscan + lines - (y_src + cy);
816 src.width = cx;
817 src.height = cy;
818 if (src.y > 0)
820 if (!top_down)
822 /* get rid of unnecessary lines */
823 if (src.y >= lines) return 0;
824 lines -= src.y;
825 src.y = 0;
827 else if (src.y >= lines) return lines;
829 src_info->bmiHeader.biHeight = top_down ? -min( lines, height ) : lines;
830 src_info->bmiHeader.biSizeImage = get_dib_image_size( src_info );
833 src.visrect.left = src.x;
834 src.visrect.top = src.y;
835 src.visrect.right = src.x + cx;
836 src.visrect.bottom = src.y + cy;
837 rect.left = 0;
838 rect.top = 0;
839 rect.right = src_info->bmiHeader.biWidth;
840 rect.bottom = abs( src_info->bmiHeader.biHeight );
841 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
843 lines = 0;
844 goto done;
847 pt.x = x_dst;
848 pt.y = y_dst;
849 lp_to_dp( dc, &pt, 1 );
850 dst.x = pt.x;
851 dst.y = pt.y;
852 dst.width = cx;
853 dst.height = cy;
854 if (dc->attr->layout & LAYOUT_RTL) dst.x -= cx - 1;
856 rect.left = dst.x;
857 rect.top = dst.y;
858 rect.right = dst.x + cx;
859 rect.bottom = dst.y + cy;
860 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
862 OffsetRect( &src.visrect, dst.x - src.x, dst.y - src.y );
863 intersect_rect( &rect, &src.visrect, &dst.visrect );
864 src.visrect = dst.visrect = rect;
865 OffsetRect( &src.visrect, src.x - dst.x, src.y - dst.y );
866 if (IsRectEmpty( &dst.visrect )) goto done;
867 if (clip) NtGdiOffsetRgn( clip, dst.x - src.x, dst.y - src.y );
869 dev = GET_DC_PHYSDEV( dc, pPutImage );
870 copy_bitmapinfo( dst_info, src_info );
871 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
872 if (err == ERROR_BAD_FORMAT)
874 err = convert_bits( src_info, &src, dst_info, &src_bits );
875 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
877 if (err) lines = 0;
879 done:
880 if (src_bits.free) src_bits.free( &src_bits );
881 if (clip) NtGdiDeleteObjectApp( clip );
882 return lines;
885 /***********************************************************************
886 * NtGdiSetDIBitsToDeviceInternal (win32u.@)
888 INT WINAPI NtGdiSetDIBitsToDeviceInternal( HDC hdc, INT xDest, INT yDest, DWORD cx,
889 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
890 UINT lines, const void *bits, const BITMAPINFO *bmi,
891 UINT coloruse, UINT max_bits, UINT max_info,
892 BOOL xform_coords, HANDLE xform )
894 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
895 BITMAPINFO *info = (BITMAPINFO *)buffer;
896 PHYSDEV physdev;
897 INT ret = 0;
898 DC *dc;
900 if (!bits) return 0;
901 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
903 SetLastError( ERROR_INVALID_PARAMETER );
904 return 0;
907 if ((dc = get_dc_ptr( hdc )))
909 update_dc( dc );
910 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
911 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
912 ySrc, startscan, lines, bits, info, coloruse );
913 release_dc_ptr( dc );
915 return ret;
918 UINT set_dib_dc_color_table( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
920 DC * dc;
921 UINT i, result = 0;
922 BITMAPOBJ * bitmap;
924 if (!(dc = get_dc_ptr( hdc ))) return 0;
926 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
928 if (startpos < bitmap->dib.dsBmih.biClrUsed)
930 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
931 for (i = 0; i < result; i++)
933 bitmap->color_table[startpos + i].rgbBlue = colors[i].rgbBlue;
934 bitmap->color_table[startpos + i].rgbGreen = colors[i].rgbGreen;
935 bitmap->color_table[startpos + i].rgbRed = colors[i].rgbRed;
936 bitmap->color_table[startpos + i].rgbReserved = 0;
939 GDI_ReleaseObj( dc->hBitmap );
941 if (result) /* update colors of selected objects */
943 NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, dc->attr->text_color, NULL );
944 NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, dc->attr->background_color, NULL );
945 NtGdiSelectPen( hdc, dc->hPen );
946 NtGdiSelectBrush( hdc, dc->hBrush );
949 release_dc_ptr( dc );
950 return result;
954 UINT get_dib_dc_color_table( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
956 DC * dc;
957 BITMAPOBJ *bitmap;
958 UINT result = 0;
960 if (!(dc = get_dc_ptr( hdc ))) return 0;
962 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
964 if (startpos < bitmap->dib.dsBmih.biClrUsed)
966 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
967 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
969 GDI_ReleaseObj( dc->hBitmap );
971 release_dc_ptr( dc );
972 return result;
975 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
976 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
978 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
980 BITMAPINFOHEADER header;
982 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
983 header.biWidth = bmp->dib.dsBm.bmWidth;
984 header.biHeight = bmp->dib.dsBm.bmHeight;
985 header.biPlanes = 1;
986 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
988 switch (header.biBitCount)
990 case 16:
991 case 32:
992 header.biCompression = BI_BITFIELDS;
993 break;
994 default:
995 header.biCompression = BI_RGB;
996 break;
999 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
1000 header.biXPelsPerMeter = 0;
1001 header.biYPelsPerMeter = 0;
1002 header.biClrUsed = 0;
1003 header.biClrImportant = 0;
1005 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
1007 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
1009 coreheader->bcWidth = header.biWidth;
1010 coreheader->bcHeight = header.biHeight;
1011 coreheader->bcPlanes = header.biPlanes;
1012 coreheader->bcBitCount = header.biBitCount;
1014 else
1015 info->bmiHeader = header;
1017 return bmp->dib.dsBm.bmHeight;
1020 /************************************************************************
1021 * copy_color_info
1023 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1025 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1027 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1029 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1031 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1032 if (coloruse == DIB_PAL_COLORS)
1033 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1034 else
1036 unsigned int i;
1037 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1039 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1040 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1041 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1045 else
1047 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1049 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1050 /* bitfields are always at bmiColors even in larger structures */
1051 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1052 else if (src->bmiHeader.biClrUsed)
1054 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1055 unsigned int size;
1057 if (coloruse == DIB_PAL_COLORS)
1058 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1059 else
1060 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1061 memcpy( colorptr, src->bmiColors, size );
1066 const RGBQUAD *get_default_color_table( int bpp )
1068 static const RGBQUAD table_1[2] =
1070 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1072 static const RGBQUAD table_4[16] =
1074 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1075 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1076 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1077 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1079 static const RGBQUAD table_8[256] =
1081 /* first and last 10 entries are the default system palette entries */
1082 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1083 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1084 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1085 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1086 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1087 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1088 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1089 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1090 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1091 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1092 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1093 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1094 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1095 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1096 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1097 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1098 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1099 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1100 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1101 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1102 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1103 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1104 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1105 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1106 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1107 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1108 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1109 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1110 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1111 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1112 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1113 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1114 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1115 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1116 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1117 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1118 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1119 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1120 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1121 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1122 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1123 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1124 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1125 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1126 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1127 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1128 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1129 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1130 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1131 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1132 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1133 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1134 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1135 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1136 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1137 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1138 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1139 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1140 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1141 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1142 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1143 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1144 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1145 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1148 switch (bpp)
1150 case 1: return table_1;
1151 case 4: return table_4;
1152 case 8: return table_8;
1153 default: return NULL;
1157 void fill_default_color_table( BITMAPINFO *info )
1159 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1160 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1161 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1164 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1166 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1167 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1168 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1169 info->bmiHeader.biPlanes = 1;
1170 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1171 info->bmiHeader.biCompression = BI_RGB;
1172 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1173 info->bmiHeader.biXPelsPerMeter = 0;
1174 info->bmiHeader.biYPelsPerMeter = 0;
1175 info->bmiHeader.biClrUsed = 0;
1176 info->bmiHeader.biClrImportant = 0;
1179 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1181 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1182 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1183 unsigned int info_size;
1185 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1187 info_size = get_dib_info_size( info, usage );
1188 if ((ret = malloc( info_size + info->bmiHeader.biSizeImage )))
1190 memcpy( ret, info, info_size );
1191 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1192 info->bmiHeader.biSizeImage );
1194 return ret;
1197 /******************************************************************************
1198 * NtGdiGetDIBitsInternal (win32u.@)
1200 * Retrieves bits of bitmap and copies to buffer.
1202 INT WINAPI NtGdiGetDIBitsInternal( HDC hdc, HBITMAP hbitmap, UINT startscan, UINT lines,
1203 void *bits, BITMAPINFO *info, UINT coloruse,
1204 UINT max_bits, UINT max_info )
1206 DC * dc;
1207 BITMAPOBJ * bmp;
1208 int i, dst_to_src_offset, ret = 0;
1209 DWORD err;
1210 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1211 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1212 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1213 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1214 struct gdi_image_bits src_bits;
1215 struct bitblt_coords src, dst;
1216 BOOL empty_rect = FALSE;
1218 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1219 own copy and transfer the colour info back at the end */
1220 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1221 if (coloruse > DIB_PAL_COLORS) return 0;
1222 if (bits &&
1223 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1224 return 0;
1225 dst_info->bmiHeader.biClrUsed = 0;
1226 dst_info->bmiHeader.biClrImportant = 0;
1228 if (!(dc = get_dc_ptr( hdc )))
1230 SetLastError( ERROR_INVALID_PARAMETER );
1231 return 0;
1233 update_dc( dc );
1234 if (!(bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP )))
1236 release_dc_ptr( dc );
1237 return 0;
1240 src.visrect.left = 0;
1241 src.visrect.top = 0;
1242 src.visrect.right = bmp->dib.dsBm.bmWidth;
1243 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1245 dst.visrect.left = 0;
1246 dst.visrect.top = 0;
1247 dst.visrect.right = dst_info->bmiHeader.biWidth;
1248 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1250 if (lines == 0 || startscan >= dst.visrect.bottom)
1251 bits = NULL;
1253 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1255 ret = fill_query_info( info, bmp );
1256 goto done;
1259 /* validate parameters */
1261 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1262 if (dst_info->bmiHeader.biHeight == 0) goto done;
1264 switch (dst_info->bmiHeader.biCompression)
1266 case BI_RLE4:
1267 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1268 if (dst_info->bmiHeader.biHeight < 0) goto done;
1269 if (bits) goto done; /* can't retrieve compressed bits */
1270 break;
1271 case BI_RLE8:
1272 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1273 if (dst_info->bmiHeader.biHeight < 0) goto done;
1274 if (bits) goto done; /* can't retrieve compressed bits */
1275 break;
1276 case BI_BITFIELDS:
1277 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1278 /* fall through */
1279 case BI_RGB:
1280 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1281 if (dst_info->bmiHeader.biBitCount == 1) break;
1282 if (dst_info->bmiHeader.biBitCount == 4) break;
1283 if (dst_info->bmiHeader.biBitCount == 8) break;
1284 if (dst_info->bmiHeader.biBitCount == 16) break;
1285 if (dst_info->bmiHeader.biBitCount == 24) break;
1286 if (dst_info->bmiHeader.biBitCount == 32) break;
1287 /* fall through */
1288 default:
1289 goto done;
1292 if (bits)
1294 if (dst_info->bmiHeader.biHeight > 0)
1296 dst_to_src_offset = -startscan;
1297 lines = min( lines, dst.visrect.bottom - startscan );
1298 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1300 else
1302 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1303 if (dst_to_src_offset < 0)
1305 dst_to_src_offset = 0;
1306 lines = dst.visrect.bottom - startscan;
1308 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1311 OffsetRect( &dst.visrect, 0, dst_to_src_offset );
1312 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1313 dst.visrect = src.visrect;
1314 OffsetRect( &dst.visrect, 0, -dst_to_src_offset );
1316 if (dst_info->bmiHeader.biHeight > 0)
1318 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1320 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1321 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1322 memset( bits, 0, pad_bytes );
1323 bits = (char *)bits + pad_bytes;
1326 else
1328 if (dst.visrect.bottom < lines)
1330 int pad_lines = lines - dst.visrect.bottom;
1331 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1332 int pad_bytes = pad_lines * stride;
1333 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1337 if (empty_rect) bits = NULL;
1339 src.x = src.visrect.left;
1340 src.y = src.visrect.top;
1341 src.width = src.visrect.right - src.visrect.left;
1342 src.height = src.visrect.bottom - src.visrect.top;
1344 lines = src.height;
1347 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1349 if (err) goto done;
1351 /* fill out the src colour table, if it needs one */
1352 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1353 fill_default_color_table( src_info );
1355 /* if the src and dst are the same depth, copy the colour info across */
1356 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1358 switch (src_info->bmiHeader.biBitCount)
1360 case 16:
1361 if (src_info->bmiHeader.biCompression == BI_RGB)
1363 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1364 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1366 break;
1367 case 32:
1368 if (src_info->bmiHeader.biCompression == BI_RGB)
1370 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1371 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1373 break;
1375 copy_color_info( dst_info, src_info, coloruse );
1377 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1379 if( coloruse == DIB_PAL_COLORS )
1381 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1383 else
1385 fill_default_color_table( dst_info );
1389 if (bits)
1391 if(dst_info->bmiHeader.biHeight > 0)
1392 dst_info->bmiHeader.biHeight = src.height;
1393 else
1394 dst_info->bmiHeader.biHeight = -src.height;
1395 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1397 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1398 if (src_bits.free) src_bits.free( &src_bits );
1399 ret = lines;
1401 else
1402 ret = !empty_rect;
1404 if (coloruse == DIB_PAL_COLORS)
1406 WORD *index = (WORD *)dst_info->bmiColors;
1407 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1408 *index = i;
1411 copy_color_info( info, dst_info, coloruse );
1412 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1414 info->bmiHeader.biClrUsed = 0;
1415 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1418 done:
1419 release_dc_ptr( dc );
1420 GDI_ReleaseObj( hbitmap );
1421 return ret;
1425 /***********************************************************************
1426 * NtGdiCreateDIBitmapInternal (win32u.@)
1428 * Creates a DDB (device dependent bitmap) from a DIB.
1429 * The DDB will have the same color depth as the reference DC.
1431 HBITMAP WINAPI NtGdiCreateDIBitmapInternal( HDC hdc, INT width, INT height, DWORD init,
1432 const void *bits, const BITMAPINFO *data,
1433 UINT coloruse, UINT max_info, UINT max_bits,
1434 ULONG flags, HANDLE xform )
1436 HBITMAP handle;
1438 if (coloruse > DIB_PAL_COLORS + 1 || width < 0) return 0;
1440 /* Top-down DIBs have a negative height */
1441 height = abs( height );
1443 TRACE( "hdc=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d)\n",
1444 hdc, init, bits, data, coloruse, width, height );
1446 if (hdc == NULL)
1447 handle = NtGdiCreateBitmap( width, height, 1, 1, NULL );
1448 else
1449 handle = NtGdiCreateCompatibleBitmap( hdc, width, height );
1451 if (handle)
1453 if (init & CBM_INIT)
1455 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1457 NtGdiDeleteObjectApp( handle );
1458 handle = 0;
1463 return handle;
1467 /***********************************************************************
1468 * NtGdiCreateDIBSection (win32u.@)
1470 HBITMAP WINAPI NtGdiCreateDIBSection( HDC hdc, HANDLE section, DWORD offset, const BITMAPINFO *bmi,
1471 UINT usage, UINT header_size, ULONG flags,
1472 ULONG_PTR color_space, void **bits )
1474 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1475 BITMAPINFO *info = (BITMAPINFO *)buffer;
1476 HBITMAP ret = 0;
1477 BITMAPOBJ *bmp;
1478 void *mapBits = NULL;
1480 if (bits) *bits = NULL;
1481 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1482 if (usage > DIB_PAL_COLORS) return 0;
1483 if (info->bmiHeader.biPlanes != 1)
1485 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1486 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1489 if (!(bmp = calloc( 1, sizeof(*bmp) ))) return 0;
1491 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1492 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1493 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1494 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1495 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1497 bmp->dib.dsBm.bmType = 0;
1498 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1499 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1500 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1501 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1502 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1503 bmp->dib.dsBmih = info->bmiHeader;
1505 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1507 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1508 goto error;
1509 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1510 if (!(bmp->color_table = malloc( bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1511 goto error;
1512 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1515 /* set dsBitfields values */
1516 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1518 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1519 bmp->dib.dsBitfields[0] = 0x7c00;
1520 bmp->dib.dsBitfields[1] = 0x03e0;
1521 bmp->dib.dsBitfields[2] = 0x001f;
1523 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1525 if (usage == DIB_PAL_COLORS) goto error;
1526 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1527 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1528 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1529 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1531 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1533 /* get storage location for DIB bits */
1535 if (section)
1537 LARGE_INTEGER map_offset;
1538 SIZE_T map_size;
1540 map_offset.QuadPart = offset - (offset % system_info.AllocationGranularity);
1541 map_size = bmp->dib.dsBmih.biSizeImage + (offset - map_offset.QuadPart);
1542 if (NtMapViewOfSection( section, GetCurrentProcess(), &mapBits, 0, 0, &map_offset,
1543 &map_size, ViewShare, 0, PAGE_READWRITE ))
1544 goto error;
1545 bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - map_offset.QuadPart);
1547 else
1549 SIZE_T size = bmp->dib.dsBmih.biSizeImage;
1550 offset = 0;
1551 if (NtAllocateVirtualMemory( GetCurrentProcess(), &bmp->dib.dsBm.bmBits, zero_bits(),
1552 &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ))
1553 goto error;
1555 bmp->dib.dshSection = section;
1556 bmp->dib.dsOffset = offset;
1558 if ((ret = alloc_gdi_handle( &bmp->obj, NTGDI_OBJ_BITMAP, &dib_funcs )))
1560 if (bits) *bits = bmp->dib.dsBm.bmBits;
1561 return ret;
1564 if (section) NtUnmapViewOfSection( GetCurrentProcess(), mapBits );
1565 else
1567 SIZE_T size = 0;
1568 NtFreeVirtualMemory( GetCurrentProcess(), &bmp->dib.dsBm.bmBits, &size, MEM_RELEASE );
1570 error:
1571 free( bmp->color_table );
1572 free( bmp );
1573 return 0;
1577 static BOOL memory_dib_DeleteObject( HGDIOBJ handle )
1579 BITMAPOBJ *bmp;
1581 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1583 free( bmp->color_table );
1584 free( bmp );
1585 return TRUE;
1589 static const struct gdi_obj_funcs memory_dib_funcs =
1591 .pGetObjectW = DIB_GetObject,
1592 .pDeleteObject = memory_dib_DeleteObject,
1595 /***********************************************************************
1596 * NtGdiDdDDICreateDCFromMemory (win32u.@)
1598 NTSTATUS WINAPI NtGdiDdDDICreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1600 const struct d3dddi_format_info
1602 D3DDDIFORMAT format;
1603 unsigned int bit_count;
1604 DWORD compression;
1605 unsigned int palette_size;
1606 DWORD mask_r, mask_g, mask_b;
1607 } *format = NULL;
1608 BITMAPOBJ *bmp = NULL;
1609 HBITMAP bitmap;
1610 unsigned int i;
1611 HDC dc;
1613 static const struct d3dddi_format_info format_info[] =
1615 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1616 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1617 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1618 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1619 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1620 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1621 { D3DDDIFMT_A4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1622 { D3DDDIFMT_X4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1623 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1626 if (!desc) return STATUS_INVALID_PARAMETER;
1628 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1629 desc->pMemory, desc->Format, desc->Width, desc->Height,
1630 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1632 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1634 for (i = 0; i < ARRAY_SIZE( format_info ); ++i)
1636 if (format_info[i].format == desc->Format)
1638 format = &format_info[i];
1639 break;
1642 if (!format) return STATUS_INVALID_PARAMETER;
1644 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1645 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1646 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1648 if (!desc->hDeviceDc || !(dc = NtGdiCreateCompatibleDC( desc->hDeviceDc )))
1649 return STATUS_INVALID_PARAMETER;
1651 if (!(bmp = calloc( 1, sizeof(*bmp) ))) goto error;
1653 bmp->dib.dsBm.bmWidth = desc->Width;
1654 bmp->dib.dsBm.bmHeight = desc->Height;
1655 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1656 bmp->dib.dsBm.bmPlanes = 1;
1657 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1658 bmp->dib.dsBm.bmBits = desc->pMemory;
1660 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1661 bmp->dib.dsBmih.biWidth = desc->Width;
1662 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1663 bmp->dib.dsBmih.biPlanes = 1;
1664 bmp->dib.dsBmih.biBitCount = format->bit_count;
1665 bmp->dib.dsBmih.biCompression = format->compression;
1666 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1667 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1669 bmp->dib.dsBitfields[0] = format->mask_r;
1670 bmp->dib.dsBitfields[1] = format->mask_g;
1671 bmp->dib.dsBitfields[2] = format->mask_b;
1673 if (format->palette_size)
1675 if (!(bmp->color_table = malloc( format->palette_size * sizeof(*bmp->color_table) )))
1676 goto error;
1677 if (desc->pColorTable)
1679 for (i = 0; i < format->palette_size; ++i)
1681 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1682 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1683 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1684 bmp->color_table[i].rgbReserved = 0;
1687 else
1689 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1690 format->palette_size * sizeof(*bmp->color_table) );
1694 if (!(bitmap = alloc_gdi_handle( &bmp->obj, NTGDI_OBJ_BITMAP, &memory_dib_funcs ))) goto error;
1696 desc->hDc = dc;
1697 desc->hBitmap = bitmap;
1698 NtGdiSelectBitmap( dc, bitmap );
1699 return STATUS_SUCCESS;
1701 error:
1702 if (bmp) free( bmp->color_table );
1703 free( bmp );
1704 NtGdiDeleteObjectApp( dc );
1705 return STATUS_INVALID_PARAMETER;
1709 /***********************************************************************
1710 * NtGdiDdDDIDestroyDCFromMemory (win32u.@)
1712 NTSTATUS WINAPI NtGdiDdDDIDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1714 if (!desc) return STATUS_INVALID_PARAMETER;
1716 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1718 if (get_gdi_object_type( desc->hDc ) != NTGDI_OBJ_MEMDC ||
1719 get_gdi_object_type( desc->hBitmap ) != NTGDI_OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1720 NtGdiDeleteObjectApp( desc->hBitmap );
1721 NtGdiDeleteObjectApp( desc->hDc );
1723 return STATUS_SUCCESS;
1727 /***********************************************************************
1728 * DIB_GetObject
1730 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1732 INT ret = 0;
1733 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, NTGDI_OBJ_BITMAP );
1735 if (!bmp) return 0;
1737 if (!buffer) ret = sizeof(BITMAP);
1738 else if (count >= sizeof(DIBSECTION))
1740 DIBSECTION *dib = buffer;
1741 *dib = bmp->dib;
1742 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1743 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1744 ret = sizeof(DIBSECTION);
1746 else if (count >= sizeof(BITMAP))
1748 BITMAP *bitmap = buffer;
1749 *bitmap = bmp->dib.dsBm;
1750 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1751 ret = sizeof(BITMAP);
1754 GDI_ReleaseObj( handle );
1755 return ret;
1759 /***********************************************************************
1760 * DIB_DeleteObject
1762 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1764 BITMAPOBJ *bmp;
1766 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1768 if (bmp->dib.dshSection)
1770 NtUnmapViewOfSection( GetCurrentProcess(), (char *)bmp->dib.dsBm.bmBits -
1771 (bmp->dib.dsOffset % system_info.AllocationGranularity) );
1773 else
1775 SIZE_T size = 0;
1776 NtFreeVirtualMemory( GetCurrentProcess(), &bmp->dib.dsBm.bmBits, &size, MEM_RELEASE );
1779 free( bmp->color_table );
1780 free( bmp );
1781 return TRUE;