d3dx9: Unify calling parse_mesh helper functions.
[wine.git] / dlls / win32u / dib.c
blob23dbfbcbfaf2e1bfda4f7264121b50d6b53205c7
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", (int)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_INDICES) return FALSE;
209 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
210 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
211 if (coloruse == DIB_PAL_INDICES && (dst->bmiHeader.biBitCount != 1 ||
212 dst->bmiHeader.biCompression != BI_RGB)) return FALSE;
214 src_colors = (char *)info + info->bmiHeader.biSize;
216 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
218 /* bitfields are always at bmiColors even in larger structures */
219 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
220 dst->bmiHeader.biClrUsed = 0;
222 else if (dst->bmiHeader.biBitCount <= 8)
224 unsigned int colors = dst->bmiHeader.biClrUsed;
225 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
227 if (!colors) colors = max_colors;
228 else colors = min( colors, max_colors );
230 if (coloruse == DIB_PAL_COLORS)
232 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
233 max_colors = colors;
235 else if (coloruse == DIB_PAL_INDICES)
237 dst->bmiColors[0].rgbRed = 0;
238 dst->bmiColors[0].rgbGreen = 0;
239 dst->bmiColors[0].rgbBlue = 0;
240 dst->bmiColors[0].rgbReserved = 0;
241 dst->bmiColors[1].rgbRed = 0xff;
242 dst->bmiColors[1].rgbGreen = 0xff;
243 dst->bmiColors[1].rgbBlue = 0xff;
244 dst->bmiColors[1].rgbReserved = 0;
245 colors = max_colors;
247 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
249 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
251 else
253 unsigned int i;
254 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
255 for (i = 0; i < colors; i++)
257 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
258 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
259 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
260 dst->bmiColors[i].rgbReserved = 0;
263 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
264 dst->bmiHeader.biClrUsed = max_colors;
266 else dst->bmiHeader.biClrUsed = 0;
268 return TRUE;
271 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
273 PALETTEENTRY palEntry[256];
274 HPALETTE palette = NtGdiGetDCObject( hdc, NTGDI_OBJ_PAL );
275 int i, colors = 1 << info->bmiHeader.biBitCount;
277 info->bmiHeader.biClrUsed = colors;
279 if (!palette) return 0;
281 memset( palEntry, 0, sizeof(palEntry) );
282 if (!get_palette_entries( palette, 0, colors, palEntry ))
283 return 0;
285 for (i = 0; i < colors; i++)
287 info->bmiColors[i].rgbRed = palEntry[i].peRed;
288 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
289 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
290 info->bmiColors[i].rgbReserved = 0;
293 return colors;
296 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
298 PALETTEENTRY entries[256];
299 RGBQUAD table[256];
300 HPALETTE palette;
301 const WORD *index = (const WORD *)info->bmiColors;
302 int i, count, colors = info->bmiHeader.biClrUsed;
304 if (!colors) return TRUE;
305 if (!(palette = NtGdiGetDCObject( hdc, NTGDI_OBJ_PAL )))
306 return FALSE;
307 if (!(count = get_palette_entries( palette, 0, colors, entries ))) return FALSE;
309 for (i = 0; i < colors; i++, index++)
311 table[i].rgbRed = entries[*index % count].peRed;
312 table[i].rgbGreen = entries[*index % count].peGreen;
313 table[i].rgbBlue = entries[*index % count].peBlue;
314 table[i].rgbReserved = 0;
316 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
317 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
318 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
319 return TRUE;
322 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
324 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
325 const int bpp = info->bmiHeader.biBitCount;
327 if (height > 0)
328 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
329 else
330 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
333 static BOOL build_rle_bitmap( BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
335 DWORD i = 0;
336 int left, right;
337 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
338 HRGN run = NULL;
339 BYTE skip, num, data;
340 BYTE *out_bits, *in_bits = bits->ptr;
342 if (clip) *clip = NULL;
344 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
346 out_bits = calloc( 1, get_dib_image_size( info ) );
347 if (!out_bits) goto fail;
349 if (clip)
351 *clip = NtGdiCreateRectRgn( 0, 0, 0, 0 );
352 run = NtGdiCreateRectRgn( 0, 0, 0, 0 );
353 if (!*clip || !run) goto fail;
356 x = left = right = 0;
357 y = height - 1;
359 while (i < info->bmiHeader.biSizeImage - 1)
361 num = in_bits[i];
362 data = in_bits[i + 1];
363 i += 2;
365 if (num)
367 if (x + num > width) num = width - x;
368 if (num)
370 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
371 if (info->bmiHeader.biBitCount == 8)
372 memset( out_ptr, s, num );
373 else
375 if(x & 1)
377 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
378 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
379 out_ptr++;
380 x++;
381 num--;
383 /* this will write one too many if num is odd, but that doesn't matter */
384 if (num) memset( out_ptr, s, (num + 1) / 2 );
387 x += num;
388 right = x;
390 else
392 if (data < 3)
394 if(left != right && clip)
396 NtGdiSetRectRgn( run, left, y, right, y + 1 );
397 NtGdiCombineRgn( *clip, run, *clip, RGN_OR );
399 switch (data)
401 case 0: /* eol */
402 left = right = x = 0;
403 y--;
404 if(y < 0) goto done;
405 break;
407 case 1: /* eod */
408 goto done;
410 case 2: /* delta */
411 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
412 x += in_bits[i];
413 if (x > width) x = width;
414 left = right = x;
415 y -= in_bits[i + 1];
416 if(y < 0) goto done;
417 i += 2;
420 else /* data bytes of data */
422 num = data;
423 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
424 if (skip > info->bmiHeader.biSizeImage - i) goto done;
425 skip = (skip + 1) & ~1;
426 if (x + num > width) num = width - x;
427 if (num)
429 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
430 if (info->bmiHeader.biBitCount == 8)
431 memcpy( out_ptr, in_bits + i, num );
432 else
434 if(x & 1)
436 const BYTE *in_ptr = in_bits + i;
437 for ( ; num; num--, x++)
439 if (x & 1)
441 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
442 out_ptr++;
444 else
445 *out_ptr = (*in_ptr++ << 4) & 0xf0;
448 else
449 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
452 x += num;
453 right = x;
454 i += skip;
459 done:
460 if (run) NtGdiDeleteObjectApp( run );
461 if (bits->free) bits->free( bits );
463 bits->ptr = out_bits;
464 bits->is_copy = TRUE;
465 bits->free = free_heap_bits;
466 info->bmiHeader.biSizeImage = get_dib_image_size( info );
468 return TRUE;
470 fail:
471 if (run) NtGdiDeleteObjectApp( run );
472 if (clip && *clip) NtGdiDeleteObjectApp( *clip );
473 free( out_bits );
474 return FALSE;
479 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
480 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
481 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
483 DC *dc = get_nulldrv_dc( dev );
484 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
485 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
486 struct bitblt_coords src, dst;
487 struct gdi_image_bits src_bits;
488 DWORD err;
489 HRGN clip = NULL;
490 INT ret = 0;
491 INT height = abs( src_info->bmiHeader.biHeight );
492 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
493 RECT rect;
495 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
496 xSrc, ySrc, widthSrc, heightSrc, (int)rop);
498 src_bits.ptr = (void*)bits;
499 src_bits.is_copy = FALSE;
500 src_bits.free = NULL;
502 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
504 rect.left = xDst;
505 rect.top = yDst;
506 rect.right = xDst + widthDst;
507 rect.bottom = yDst + heightDst;
508 lp_to_dp( dc, (POINT *)&rect, 2 );
509 dst.x = rect.left;
510 dst.y = rect.top;
511 dst.width = rect.right - rect.left;
512 dst.height = rect.bottom - rect.top;
514 if (dc->attr->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
516 dst.x += dst.width;
517 dst.width = -dst.width;
519 rop &= ~NOMIRRORBITMAP;
521 src.x = xSrc;
522 src.width = widthSrc;
523 src.y = ySrc;
524 src.height = heightSrc;
526 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
527 non_stretch_from_origin = TRUE;
529 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
531 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
532 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
535 if (rop != SRCCOPY || non_stretch_from_origin)
537 if (dst.width == 1 && src.width > 1) src.width--;
538 if (dst.height == 1 && src.height > 1) src.height--;
541 if (rop != SRCCOPY)
543 if (dst.width < 0 && dst.width == src.width)
545 /* This is off-by-one, but that's what Windows does */
546 dst.x += dst.width;
547 src.x += src.width;
548 dst.width = -dst.width;
549 src.width = -src.width;
551 if (dst.height < 0 && dst.height == src.height)
553 dst.y += dst.height;
554 src.y += src.height;
555 dst.height = -dst.height;
556 src.height = -src.height;
560 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
562 if (src.y >= height && src.y + src.height + 1 < height)
563 src.y = height - 1;
564 else if (src.y > 0 && src.y + src.height + 1 < 0)
565 src.y = -src.height - 1;
567 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
569 src.visrect.left = 0;
570 src.visrect.right = src_info->bmiHeader.biWidth;
571 src.visrect.top = 0;
572 src.visrect.bottom = height;
573 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
575 if (rop == SRCCOPY) ret = height;
576 else ret = src_info->bmiHeader.biHeight;
578 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
580 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
582 if (!intersect_vis_rectangles( &dst, &src )) goto done;
584 if (clip) NtGdiOffsetRgn( clip, dst.x - src.x, dst.y - src.y );
586 dev = GET_DC_PHYSDEV( dc, pPutImage );
587 copy_bitmapinfo( dst_info, src_info );
588 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
589 if (err == ERROR_BAD_FORMAT)
591 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
593 /* 1-bpp destination without a color table requires a fake 1-entry table
594 * that contains only the background color. There is no source DC to get
595 * it from, so the background is hardcoded to the default color. */
596 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
598 static const RGBQUAD default_bg = { 255, 255, 255 };
599 dst_info->bmiColors[0] = default_bg;
600 dst_info->bmiHeader.biClrUsed = 1;
603 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
605 /* get rid of the fake 1-bpp table */
606 dst_info->bmiHeader.biClrUsed = dst_colors;
607 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
611 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
613 copy_bitmapinfo( src_info, dst_info );
614 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, dc->attr->stretch_blt_mode );
615 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
617 if (err) ret = 0;
619 done:
620 if (src_bits.free) src_bits.free( &src_bits );
621 if (clip) NtGdiDeleteObjectApp( clip );
622 return ret;
625 /***********************************************************************
626 * NtGdiStretchDIBitsInternal (win32u.@)
628 INT WINAPI NtGdiStretchDIBitsInternal( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
629 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
630 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
631 DWORD rop, UINT max_info, UINT max_bits, HANDLE xform )
633 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
634 BITMAPINFO *info = (BITMAPINFO *)buffer;
635 PHYSDEV physdev;
636 DC *dc;
637 INT ret = 0;
639 if (!bits) return 0;
640 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
642 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
643 return 0;
646 if ((dc = get_dc_ptr( hdc )))
648 update_dc( dc );
649 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
650 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
651 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
652 release_dc_ptr( dc );
654 return ret;
658 /* Sets pixels in a bitmap using colors from DIB, see SetDIBits */
659 static int set_di_bits( HDC hdc, HBITMAP hbitmap, UINT startscan,
660 UINT lines, LPCVOID bits, const BITMAPINFO *info,
661 UINT coloruse )
663 BITMAPOBJ *bitmap;
664 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
665 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
666 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
667 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
668 INT result = 0;
669 DWORD err;
670 struct gdi_image_bits src_bits;
671 struct bitblt_coords src, dst;
672 INT src_to_dst_offset;
673 HRGN clip = 0;
675 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ))
677 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
678 return 0;
680 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
682 DWORD *masks = (DWORD *)src_info->bmiColors;
683 if (!masks[0] || !masks[1] || !masks[2])
685 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
686 return 0;
690 src_bits.ptr = (void *)bits;
691 src_bits.is_copy = FALSE;
692 src_bits.free = NULL;
693 src_bits.param = NULL;
695 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
697 if (!(bitmap = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP ))) return 0;
699 if (coloruse == DIB_PAL_INDICES && bitmap->dib.dsBm.bmBitsPixel != 1) return 0;
701 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
703 if (lines == 0) goto done;
704 else lines = src_info->bmiHeader.biHeight;
705 startscan = 0;
707 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
710 dst.visrect.left = 0;
711 dst.visrect.top = 0;
712 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
713 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
715 src.visrect.left = 0;
716 src.visrect.top = 0;
717 src.visrect.right = src_info->bmiHeader.biWidth;
718 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
720 if (src_info->bmiHeader.biHeight > 0)
722 src_to_dst_offset = -startscan;
723 lines = min( lines, src.visrect.bottom - startscan );
724 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
726 else
728 src_to_dst_offset = src.visrect.bottom - lines - startscan;
729 /* Unlike the bottom-up case, Windows doesn't limit lines. */
730 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
733 result = lines;
735 OffsetRect( &src.visrect, 0, src_to_dst_offset );
736 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
737 src.visrect = dst.visrect;
738 OffsetRect( &src.visrect, 0, -src_to_dst_offset );
740 src.x = src.visrect.left;
741 src.y = src.visrect.top;
742 src.width = src.visrect.right - src.visrect.left;
743 src.height = src.visrect.bottom - src.visrect.top;
745 dst.x = dst.visrect.left;
746 dst.y = dst.visrect.top;
747 dst.width = dst.visrect.right - dst.visrect.left;
748 dst.height = dst.visrect.bottom - dst.visrect.top;
750 copy_bitmapinfo( dst_info, src_info );
752 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
753 if (err == ERROR_BAD_FORMAT)
755 err = convert_bits( src_info, &src, dst_info, &src_bits );
756 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
758 if(err) result = 0;
760 done:
761 if (src_bits.free) src_bits.free( &src_bits );
762 if (clip) NtGdiDeleteObjectApp( clip );
763 GDI_ReleaseObj( hbitmap );
764 return result;
768 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
769 INT x_src, INT y_src, UINT startscan, UINT lines,
770 const void *bits, BITMAPINFO *src_info, UINT coloruse )
772 DC *dc = get_nulldrv_dc( dev );
773 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
774 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
775 struct bitblt_coords src, dst;
776 struct gdi_image_bits src_bits;
777 HRGN clip = 0;
778 DWORD err;
779 UINT height;
780 BOOL top_down;
781 POINT pt;
782 RECT rect;
784 top_down = (src_info->bmiHeader.biHeight < 0);
785 height = abs( src_info->bmiHeader.biHeight );
787 src_bits.ptr = (void *)bits;
788 src_bits.is_copy = FALSE;
789 src_bits.free = NULL;
791 if (!lines) return 0;
792 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
794 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
796 startscan = 0;
797 lines = height;
798 src_info->bmiHeader.biWidth = x_src + cx;
799 src_info->bmiHeader.biHeight = y_src + cy;
800 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
801 src.x = x_src;
802 src.y = 0;
803 src.width = cx;
804 src.height = cy;
805 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
807 else
809 if (startscan >= height) return 0;
810 if (!top_down && lines > height - startscan) lines = height - startscan;
812 /* map src to top-down coordinates with startscan as origin */
813 src.x = x_src;
814 src.y = startscan + lines - (y_src + cy);
815 src.width = cx;
816 src.height = cy;
817 if (src.y > 0)
819 if (!top_down)
821 /* get rid of unnecessary lines */
822 if (src.y >= lines) return 0;
823 lines -= src.y;
824 src.y = 0;
826 else if (src.y >= lines) return lines;
828 src_info->bmiHeader.biHeight = top_down ? -min( lines, height ) : lines;
829 src_info->bmiHeader.biSizeImage = get_dib_image_size( src_info );
832 src.visrect.left = src.x;
833 src.visrect.top = src.y;
834 src.visrect.right = src.x + cx;
835 src.visrect.bottom = src.y + cy;
836 rect.left = 0;
837 rect.top = 0;
838 rect.right = src_info->bmiHeader.biWidth;
839 rect.bottom = abs( src_info->bmiHeader.biHeight );
840 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
842 lines = 0;
843 goto done;
846 pt.x = x_dst;
847 pt.y = y_dst;
848 lp_to_dp( dc, &pt, 1 );
849 dst.x = pt.x;
850 dst.y = pt.y;
851 dst.width = cx;
852 dst.height = cy;
853 if (dc->attr->layout & LAYOUT_RTL) dst.x -= cx - 1;
855 rect.left = dst.x;
856 rect.top = dst.y;
857 rect.right = dst.x + cx;
858 rect.bottom = dst.y + cy;
859 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
861 OffsetRect( &src.visrect, dst.x - src.x, dst.y - src.y );
862 intersect_rect( &rect, &src.visrect, &dst.visrect );
863 src.visrect = dst.visrect = rect;
864 OffsetRect( &src.visrect, src.x - dst.x, src.y - dst.y );
865 if (IsRectEmpty( &dst.visrect )) goto done;
866 if (clip) NtGdiOffsetRgn( clip, dst.x - src.x, dst.y - src.y );
868 dev = GET_DC_PHYSDEV( dc, pPutImage );
869 copy_bitmapinfo( dst_info, src_info );
870 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
871 if (err == ERROR_BAD_FORMAT)
873 err = convert_bits( src_info, &src, dst_info, &src_bits );
874 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
876 if (err) lines = 0;
878 done:
879 if (src_bits.free) src_bits.free( &src_bits );
880 if (clip) NtGdiDeleteObjectApp( clip );
881 return lines;
884 /***********************************************************************
885 * NtGdiSetDIBitsToDeviceInternal (win32u.@)
887 INT WINAPI NtGdiSetDIBitsToDeviceInternal( HDC hdc, INT xDest, INT yDest, DWORD cx,
888 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
889 UINT lines, const void *bits, const BITMAPINFO *bmi,
890 UINT coloruse, UINT max_bits, UINT max_info,
891 BOOL xform_coords, HANDLE xform )
893 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
894 BITMAPINFO *info = (BITMAPINFO *)buffer;
895 PHYSDEV physdev;
896 INT ret = 0;
897 DC *dc;
899 if (xform) return set_di_bits( hdc, xform, startscan, lines, bits, bmi, coloruse );
901 if (!bits) return 0;
902 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
904 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
905 return 0;
908 if ((dc = get_dc_ptr( hdc )))
910 update_dc( dc );
911 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
912 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
913 ySrc, startscan, lines, bits, info, coloruse );
914 release_dc_ptr( dc );
916 return ret;
919 UINT set_dib_dc_color_table( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
921 DC * dc;
922 UINT i, result = 0;
923 BITMAPOBJ * bitmap;
925 if (!(dc = get_dc_ptr( hdc ))) return 0;
927 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
929 if (startpos < bitmap->dib.dsBmih.biClrUsed)
931 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
932 for (i = 0; i < result; i++)
934 bitmap->color_table[startpos + i].rgbBlue = colors[i].rgbBlue;
935 bitmap->color_table[startpos + i].rgbGreen = colors[i].rgbGreen;
936 bitmap->color_table[startpos + i].rgbRed = colors[i].rgbRed;
937 bitmap->color_table[startpos + i].rgbReserved = 0;
940 GDI_ReleaseObj( dc->hBitmap );
942 if (result) /* update colors of selected objects */
944 NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, dc->attr->text_color, NULL );
945 NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, dc->attr->background_color, NULL );
946 NtGdiSelectPen( hdc, dc->hPen );
947 NtGdiSelectBrush( hdc, dc->hBrush );
950 release_dc_ptr( dc );
951 return result;
955 UINT get_dib_dc_color_table( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
957 DC * dc;
958 BITMAPOBJ *bitmap;
959 UINT result = 0;
961 if (!(dc = get_dc_ptr( hdc ))) return 0;
963 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
965 if (startpos < bitmap->dib.dsBmih.biClrUsed)
967 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
968 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
970 GDI_ReleaseObj( dc->hBitmap );
972 release_dc_ptr( dc );
973 return result;
976 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
977 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
979 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
981 BITMAPINFOHEADER header;
983 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
984 header.biWidth = bmp->dib.dsBm.bmWidth;
985 header.biHeight = bmp->dib.dsBm.bmHeight;
986 header.biPlanes = 1;
987 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
989 switch (header.biBitCount)
991 case 16:
992 case 32:
993 header.biCompression = BI_BITFIELDS;
994 break;
995 default:
996 header.biCompression = BI_RGB;
997 break;
1000 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
1001 header.biXPelsPerMeter = 0;
1002 header.biYPelsPerMeter = 0;
1003 header.biClrUsed = 0;
1004 header.biClrImportant = 0;
1006 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
1008 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
1010 coreheader->bcWidth = header.biWidth;
1011 coreheader->bcHeight = header.biHeight;
1012 coreheader->bcPlanes = header.biPlanes;
1013 coreheader->bcBitCount = header.biBitCount;
1015 else
1016 info->bmiHeader = header;
1018 return bmp->dib.dsBm.bmHeight;
1021 /************************************************************************
1022 * copy_color_info
1024 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1026 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1028 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1030 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1032 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1033 if (coloruse == DIB_PAL_COLORS)
1034 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1035 else
1037 unsigned int i;
1038 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1040 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1041 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1042 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1046 else
1048 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1050 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1051 /* bitfields are always at bmiColors even in larger structures */
1052 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1053 else if (src->bmiHeader.biClrUsed)
1055 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1056 unsigned int size;
1058 if (coloruse == DIB_PAL_COLORS)
1059 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1060 else
1061 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1062 memcpy( colorptr, src->bmiColors, size );
1067 const RGBQUAD *get_default_color_table( int bpp )
1069 static const RGBQUAD table_1[2] =
1071 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1073 static const RGBQUAD table_4[16] =
1075 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1076 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1077 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1078 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1080 static const RGBQUAD table_8[256] =
1082 /* first and last 10 entries are the default system palette entries */
1083 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1084 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1085 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1086 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1087 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1088 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1089 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1090 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1091 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1092 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1093 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1094 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1095 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1096 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1097 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1098 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1099 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1100 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1101 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1102 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1103 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1104 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1105 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1106 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1107 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1108 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1109 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1110 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1111 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1112 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1113 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1114 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1115 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1116 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1117 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1118 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1119 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1120 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1121 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1122 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1123 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1124 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1125 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1126 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1127 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1128 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1129 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1130 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1131 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1132 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1133 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1134 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1135 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1136 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1137 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1138 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1139 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1140 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1141 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1142 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1143 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1144 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1145 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1146 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1149 switch (bpp)
1151 case 1: return table_1;
1152 case 4: return table_4;
1153 case 8: return table_8;
1154 default: return NULL;
1158 void fill_default_color_table( BITMAPINFO *info )
1160 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1161 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1162 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1165 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1167 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1168 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1169 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1170 info->bmiHeader.biPlanes = 1;
1171 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1172 info->bmiHeader.biCompression = BI_RGB;
1173 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1174 info->bmiHeader.biXPelsPerMeter = 0;
1175 info->bmiHeader.biYPelsPerMeter = 0;
1176 info->bmiHeader.biClrUsed = 0;
1177 info->bmiHeader.biClrImportant = 0;
1180 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1182 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1183 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1184 unsigned int info_size;
1186 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1188 info_size = get_dib_info_size( info, usage );
1189 if ((ret = malloc( info_size + info->bmiHeader.biSizeImage )))
1191 memcpy( ret, info, info_size );
1192 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1193 info->bmiHeader.biSizeImage );
1195 return ret;
1198 /******************************************************************************
1199 * NtGdiGetDIBitsInternal (win32u.@)
1201 * Retrieves bits of bitmap and copies to buffer.
1203 INT WINAPI NtGdiGetDIBitsInternal( HDC hdc, HBITMAP hbitmap, UINT startscan, UINT lines,
1204 void *bits, BITMAPINFO *info, UINT coloruse,
1205 UINT max_bits, UINT max_info )
1207 DC * dc;
1208 BITMAPOBJ * bmp;
1209 int i, dst_to_src_offset, ret = 0;
1210 DWORD err;
1211 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1212 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1213 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1214 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1215 struct gdi_image_bits src_bits;
1216 struct bitblt_coords src, dst;
1217 BOOL empty_rect = FALSE;
1219 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1220 own copy and transfer the colour info back at the end */
1221 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1222 if (coloruse > DIB_PAL_COLORS) return 0;
1223 if (bits &&
1224 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1225 return 0;
1226 dst_info->bmiHeader.biClrUsed = 0;
1227 dst_info->bmiHeader.biClrImportant = 0;
1229 if (!(dc = get_dc_ptr( hdc )))
1231 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1232 return 0;
1234 update_dc( dc );
1235 if (!(bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP )))
1237 release_dc_ptr( dc );
1238 return 0;
1241 src.visrect.left = 0;
1242 src.visrect.top = 0;
1243 src.visrect.right = bmp->dib.dsBm.bmWidth;
1244 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1246 dst.visrect.left = 0;
1247 dst.visrect.top = 0;
1248 dst.visrect.right = dst_info->bmiHeader.biWidth;
1249 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1251 if (lines == 0 || startscan >= dst.visrect.bottom)
1252 bits = NULL;
1254 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1256 ret = fill_query_info( info, bmp );
1257 goto done;
1260 /* validate parameters */
1262 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1263 if (dst_info->bmiHeader.biHeight == 0) goto done;
1265 switch (dst_info->bmiHeader.biCompression)
1267 case BI_RLE4:
1268 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1269 if (dst_info->bmiHeader.biHeight < 0) goto done;
1270 if (bits) goto done; /* can't retrieve compressed bits */
1271 break;
1272 case BI_RLE8:
1273 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1274 if (dst_info->bmiHeader.biHeight < 0) goto done;
1275 if (bits) goto done; /* can't retrieve compressed bits */
1276 break;
1277 case BI_BITFIELDS:
1278 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1279 /* fall through */
1280 case BI_RGB:
1281 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1282 if (dst_info->bmiHeader.biBitCount == 1) break;
1283 if (dst_info->bmiHeader.biBitCount == 4) break;
1284 if (dst_info->bmiHeader.biBitCount == 8) break;
1285 if (dst_info->bmiHeader.biBitCount == 16) break;
1286 if (dst_info->bmiHeader.biBitCount == 24) break;
1287 if (dst_info->bmiHeader.biBitCount == 32) break;
1288 /* fall through */
1289 default:
1290 goto done;
1293 if (bits)
1295 if (dst_info->bmiHeader.biHeight > 0)
1297 dst_to_src_offset = -startscan;
1298 lines = min( lines, dst.visrect.bottom - startscan );
1299 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1301 else
1303 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1304 if (dst_to_src_offset < 0)
1306 dst_to_src_offset = 0;
1307 lines = dst.visrect.bottom - startscan;
1309 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1312 OffsetRect( &dst.visrect, 0, dst_to_src_offset );
1313 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1314 dst.visrect = src.visrect;
1315 OffsetRect( &dst.visrect, 0, -dst_to_src_offset );
1317 if (dst_info->bmiHeader.biHeight > 0)
1319 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1321 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1322 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1323 memset( bits, 0, pad_bytes );
1324 bits = (char *)bits + pad_bytes;
1327 else
1329 if (dst.visrect.bottom < lines)
1331 int pad_lines = lines - dst.visrect.bottom;
1332 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1333 int pad_bytes = pad_lines * stride;
1334 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1338 if (empty_rect) bits = NULL;
1340 src.x = src.visrect.left;
1341 src.y = src.visrect.top;
1342 src.width = src.visrect.right - src.visrect.left;
1343 src.height = src.visrect.bottom - src.visrect.top;
1345 lines = src.height;
1348 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1350 if (err) goto done;
1352 /* fill out the src colour table, if it needs one */
1353 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1354 fill_default_color_table( src_info );
1356 /* if the src and dst are the same depth, copy the colour info across */
1357 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1359 switch (src_info->bmiHeader.biBitCount)
1361 case 16:
1362 if (src_info->bmiHeader.biCompression == BI_RGB)
1364 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1365 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1367 break;
1368 case 32:
1369 if (src_info->bmiHeader.biCompression == BI_RGB)
1371 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1372 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1374 break;
1376 copy_color_info( dst_info, src_info, coloruse );
1378 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1380 if( coloruse == DIB_PAL_COLORS )
1382 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1384 else
1386 fill_default_color_table( dst_info );
1390 if (bits)
1392 if(dst_info->bmiHeader.biHeight > 0)
1393 dst_info->bmiHeader.biHeight = src.height;
1394 else
1395 dst_info->bmiHeader.biHeight = -src.height;
1396 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1398 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1399 if (src_bits.free) src_bits.free( &src_bits );
1400 ret = lines;
1402 else
1403 ret = !empty_rect;
1405 if (coloruse == DIB_PAL_COLORS)
1407 WORD *index = (WORD *)dst_info->bmiColors;
1408 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1409 *index = i;
1412 copy_color_info( info, dst_info, coloruse );
1413 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1415 info->bmiHeader.biClrUsed = 0;
1416 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1419 done:
1420 release_dc_ptr( dc );
1421 GDI_ReleaseObj( hbitmap );
1422 return ret;
1426 /***********************************************************************
1427 * NtGdiCreateDIBitmapInternal (win32u.@)
1429 * Creates a DDB (device dependent bitmap) from a DIB.
1430 * The DDB will have the same color depth as the reference DC.
1432 HBITMAP WINAPI NtGdiCreateDIBitmapInternal( HDC hdc, INT width, INT height, DWORD init,
1433 const void *bits, const BITMAPINFO *data,
1434 UINT coloruse, UINT max_info, UINT max_bits,
1435 ULONG flags, HANDLE xform )
1437 HBITMAP handle;
1439 if (coloruse > DIB_PAL_COLORS + 1 || width < 0) return 0;
1441 /* Top-down DIBs have a negative height */
1442 height = abs( height );
1444 TRACE( "hdc=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d)\n",
1445 hdc, (int)init, bits, data, coloruse, width, height );
1447 if (hdc == NULL)
1448 handle = NtGdiCreateBitmap( width, height, 1, 1, NULL );
1449 else
1450 handle = NtGdiCreateCompatibleBitmap( hdc, width, height );
1452 if (handle)
1454 if (init & CBM_INIT)
1456 if (set_di_bits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1458 NtGdiDeleteObjectApp( handle );
1459 handle = 0;
1464 return handle;
1468 /***********************************************************************
1469 * NtGdiCreateDIBSection (win32u.@)
1471 HBITMAP WINAPI NtGdiCreateDIBSection( HDC hdc, HANDLE section, DWORD offset, const BITMAPINFO *bmi,
1472 UINT usage, UINT header_size, ULONG flags,
1473 ULONG_PTR color_space, void **bits )
1475 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1476 BITMAPINFO *info = (BITMAPINFO *)buffer;
1477 HBITMAP ret = 0;
1478 BITMAPOBJ *bmp;
1479 void *mapBits = NULL;
1481 if (bits) *bits = NULL;
1482 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1483 if (usage > DIB_PAL_COLORS) return 0;
1484 if (info->bmiHeader.biPlanes != 1)
1486 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1487 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1490 if (!(bmp = calloc( 1, sizeof(*bmp) ))) return 0;
1492 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1493 (int)info->bmiHeader.biWidth, (int)info->bmiHeader.biHeight,
1494 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1495 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1496 (int)info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1498 bmp->dib.dsBm.bmType = 0;
1499 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1500 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1501 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1502 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1503 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1504 bmp->dib.dsBmih = info->bmiHeader;
1506 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1508 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1509 goto error;
1510 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1511 if (!(bmp->color_table = malloc( bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1512 goto error;
1513 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1516 /* set dsBitfields values */
1517 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1519 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1520 bmp->dib.dsBitfields[0] = 0x7c00;
1521 bmp->dib.dsBitfields[1] = 0x03e0;
1522 bmp->dib.dsBitfields[2] = 0x001f;
1524 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1526 if (usage == DIB_PAL_COLORS) goto error;
1527 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1528 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1529 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1530 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1532 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1534 /* get storage location for DIB bits */
1536 if (section)
1538 LARGE_INTEGER map_offset;
1539 SIZE_T map_size;
1541 map_offset.QuadPart = offset - (offset % system_info.AllocationGranularity);
1542 map_size = bmp->dib.dsBmih.biSizeImage + (offset - map_offset.QuadPart);
1543 if (NtMapViewOfSection( section, GetCurrentProcess(), &mapBits, 0, 0, &map_offset,
1544 &map_size, ViewShare, 0, PAGE_READWRITE ))
1545 goto error;
1546 bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - map_offset.QuadPart);
1548 else
1550 SIZE_T size = bmp->dib.dsBmih.biSizeImage;
1551 offset = 0;
1552 if (NtAllocateVirtualMemory( GetCurrentProcess(), &bmp->dib.dsBm.bmBits, zero_bits,
1553 &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ))
1554 goto error;
1556 bmp->dib.dshSection = section;
1557 bmp->dib.dsOffset = offset;
1559 if ((ret = alloc_gdi_handle( &bmp->obj, NTGDI_OBJ_BITMAP, &dib_funcs )))
1561 if (bits) *bits = bmp->dib.dsBm.bmBits;
1562 return ret;
1565 if (section) NtUnmapViewOfSection( GetCurrentProcess(), mapBits );
1566 else
1568 SIZE_T size = 0;
1569 NtFreeVirtualMemory( GetCurrentProcess(), &bmp->dib.dsBm.bmBits, &size, MEM_RELEASE );
1571 error:
1572 free( bmp->color_table );
1573 free( bmp );
1574 return 0;
1578 static BOOL memory_dib_DeleteObject( HGDIOBJ handle )
1580 BITMAPOBJ *bmp;
1582 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1584 free( bmp->color_table );
1585 free( bmp );
1586 return TRUE;
1590 static const struct gdi_obj_funcs memory_dib_funcs =
1592 .pGetObjectW = DIB_GetObject,
1593 .pDeleteObject = memory_dib_DeleteObject,
1596 /***********************************************************************
1597 * NtGdiDdDDICreateDCFromMemory (win32u.@)
1599 NTSTATUS WINAPI NtGdiDdDDICreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1601 const struct d3dddi_format_info
1603 D3DDDIFORMAT format;
1604 unsigned int bit_count;
1605 DWORD compression;
1606 unsigned int palette_size;
1607 DWORD mask_r, mask_g, mask_b;
1608 } *format = NULL;
1609 BITMAPOBJ *bmp = NULL;
1610 HBITMAP bitmap;
1611 unsigned int i;
1612 HDC dc;
1614 static const struct d3dddi_format_info format_info[] =
1616 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1617 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1618 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1619 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1620 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1621 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1622 { D3DDDIFMT_A4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1623 { D3DDDIFMT_X4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1624 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1627 if (!desc) return STATUS_INVALID_PARAMETER;
1629 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1630 desc->pMemory, desc->Format, desc->Width, desc->Height,
1631 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1633 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1635 for (i = 0; i < ARRAY_SIZE( format_info ); ++i)
1637 if (format_info[i].format == desc->Format)
1639 format = &format_info[i];
1640 break;
1643 if (!format) return STATUS_INVALID_PARAMETER;
1645 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1646 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1647 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1649 if (!desc->hDeviceDc || !(dc = NtGdiCreateCompatibleDC( desc->hDeviceDc )))
1650 return STATUS_INVALID_PARAMETER;
1652 if (!(bmp = calloc( 1, sizeof(*bmp) ))) goto error;
1654 bmp->dib.dsBm.bmWidth = desc->Width;
1655 bmp->dib.dsBm.bmHeight = desc->Height;
1656 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1657 bmp->dib.dsBm.bmPlanes = 1;
1658 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1659 bmp->dib.dsBm.bmBits = desc->pMemory;
1661 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1662 bmp->dib.dsBmih.biWidth = desc->Width;
1663 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1664 bmp->dib.dsBmih.biPlanes = 1;
1665 bmp->dib.dsBmih.biBitCount = format->bit_count;
1666 bmp->dib.dsBmih.biCompression = format->compression;
1667 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1668 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1670 bmp->dib.dsBitfields[0] = format->mask_r;
1671 bmp->dib.dsBitfields[1] = format->mask_g;
1672 bmp->dib.dsBitfields[2] = format->mask_b;
1674 if (format->palette_size)
1676 if (!(bmp->color_table = malloc( format->palette_size * sizeof(*bmp->color_table) )))
1677 goto error;
1678 if (desc->pColorTable)
1680 for (i = 0; i < format->palette_size; ++i)
1682 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1683 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1684 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1685 bmp->color_table[i].rgbReserved = 0;
1688 else
1690 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1691 format->palette_size * sizeof(*bmp->color_table) );
1695 if (!(bitmap = alloc_gdi_handle( &bmp->obj, NTGDI_OBJ_BITMAP, &memory_dib_funcs ))) goto error;
1697 desc->hDc = dc;
1698 desc->hBitmap = bitmap;
1699 NtGdiSelectBitmap( dc, bitmap );
1700 return STATUS_SUCCESS;
1702 error:
1703 if (bmp) free( bmp->color_table );
1704 free( bmp );
1705 NtGdiDeleteObjectApp( dc );
1706 return STATUS_INVALID_PARAMETER;
1710 /***********************************************************************
1711 * NtGdiDdDDIDestroyDCFromMemory (win32u.@)
1713 NTSTATUS WINAPI NtGdiDdDDIDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1715 if (!desc) return STATUS_INVALID_PARAMETER;
1717 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1719 if (get_gdi_object_type( desc->hDc ) != NTGDI_OBJ_MEMDC ||
1720 get_gdi_object_type( desc->hBitmap ) != NTGDI_OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1721 NtGdiDeleteObjectApp( desc->hBitmap );
1722 NtGdiDeleteObjectApp( desc->hDc );
1724 return STATUS_SUCCESS;
1728 /***********************************************************************
1729 * DIB_GetObject
1731 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1733 INT ret = 0;
1734 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, NTGDI_OBJ_BITMAP );
1736 if (!bmp) return 0;
1738 if (!buffer) ret = sizeof(BITMAP);
1739 else if (count >= sizeof(DIBSECTION))
1741 DIBSECTION *dib = buffer;
1742 *dib = bmp->dib;
1743 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1744 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1745 ret = sizeof(DIBSECTION);
1747 else if (count >= sizeof(BITMAP))
1749 BITMAP *bitmap = buffer;
1750 *bitmap = bmp->dib.dsBm;
1751 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1752 ret = sizeof(BITMAP);
1755 GDI_ReleaseObj( handle );
1756 return ret;
1760 /***********************************************************************
1761 * DIB_DeleteObject
1763 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1765 BITMAPOBJ *bmp;
1767 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1769 if (bmp->dib.dshSection)
1771 NtUnmapViewOfSection( GetCurrentProcess(), (char *)bmp->dib.dsBm.bmBits -
1772 (bmp->dib.dsOffset % system_info.AllocationGranularity) );
1774 else
1776 SIZE_T size = 0;
1777 NtFreeVirtualMemory( GetCurrentProcess(), &bmp->dib.dsBm.bmBits, &size, MEM_RELEASE );
1780 free( bmp->color_table );
1781 free( bmp );
1782 return TRUE;