gdi32: Store stretch_blt_mode in DC_ATTR.
[wine.git] / dlls / gdi32 / dib.c
blob432f33151d9f20579d0c48c4f3ec0079a32226f6
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 #include <stdarg.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <assert.h>
67 #include "ntstatus.h"
68 #define WIN32_NO_STATUS
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wingdi.h"
72 #include "winternl.h"
73 #include "ddk/d3dkmthk.h"
75 #include "ntgdi_private.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
81 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
82 static BOOL DIB_DeleteObject( HGDIOBJ handle );
84 static const struct gdi_obj_funcs dib_funcs =
86 DIB_GetObject, /* pGetObjectW */
87 NULL, /* pUnrealizeObject */
88 DIB_DeleteObject /* pDeleteObject */
91 /***********************************************************************
92 * bitmap_info_size
94 * Return the size of the bitmap info structure including color table.
96 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
98 unsigned int colors, size, masks = 0;
100 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
102 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
103 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
104 return sizeof(BITMAPCOREHEADER) + colors *
105 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
107 else /* assume BITMAPINFOHEADER */
109 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
110 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
111 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
112 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
113 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
117 /*******************************************************************************************
118 * Verify that the DIB parameters are valid.
120 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
122 if (info->biWidth <= 0) return FALSE;
123 if (info->biHeight == 0) return FALSE;
125 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
127 if (info->biHeight < 0) return FALSE;
128 if (!info->biSizeImage) return FALSE;
129 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
132 if (!info->biPlanes) return FALSE;
134 /* check for size overflow */
135 if (!info->biBitCount) return FALSE;
136 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
137 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
139 switch (info->biBitCount)
141 case 1:
142 case 4:
143 case 8:
144 case 24:
145 return (info->biCompression == BI_RGB);
146 case 16:
147 case 32:
148 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
149 default:
150 return FALSE;
154 /*******************************************************************************************
155 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
157 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
159 if (!info) return FALSE;
161 if (info->biSize == sizeof(BITMAPCOREHEADER))
163 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
164 dst->biWidth = core->bcWidth;
165 dst->biHeight = core->bcHeight;
166 dst->biPlanes = core->bcPlanes;
167 dst->biBitCount = core->bcBitCount;
168 dst->biCompression = BI_RGB;
169 dst->biXPelsPerMeter = 0;
170 dst->biYPelsPerMeter = 0;
171 dst->biClrUsed = 0;
172 dst->biClrImportant = 0;
174 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
176 *dst = *info;
178 else
180 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
181 return FALSE;
184 dst->biSize = sizeof(*dst);
185 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
186 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
187 return TRUE;
190 /*******************************************************************************************
191 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
193 * The resulting sanitized BITMAPINFO is guaranteed to have:
194 * - biSize set to sizeof(BITMAPINFOHEADER)
195 * - biSizeImage set to the actual image size even for non-compressed DIB
196 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
197 * - color table present only for <= 8 bpp, always starts at info->bmiColors
199 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
200 UINT coloruse, BOOL allow_compression )
202 void *src_colors;
204 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
205 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
206 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
208 src_colors = (char *)info + info->bmiHeader.biSize;
210 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
212 /* bitfields are always at bmiColors even in larger structures */
213 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
214 dst->bmiHeader.biClrUsed = 0;
216 else if (dst->bmiHeader.biBitCount <= 8)
218 unsigned int colors = dst->bmiHeader.biClrUsed;
219 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
221 if (!colors) colors = max_colors;
222 else colors = min( colors, max_colors );
224 if (coloruse == DIB_PAL_COLORS)
226 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
227 max_colors = colors;
229 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
231 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
233 else
235 unsigned int i;
236 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
237 for (i = 0; i < colors; i++)
239 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
240 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
241 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
242 dst->bmiColors[i].rgbReserved = 0;
245 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
246 dst->bmiHeader.biClrUsed = max_colors;
248 else dst->bmiHeader.biClrUsed = 0;
250 return TRUE;
253 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
255 PALETTEENTRY palEntry[256];
256 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
257 int i, colors = 1 << info->bmiHeader.biBitCount;
259 info->bmiHeader.biClrUsed = colors;
261 if (!palette) return 0;
263 memset( palEntry, 0, sizeof(palEntry) );
264 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
265 return 0;
267 for (i = 0; i < colors; i++)
269 info->bmiColors[i].rgbRed = palEntry[i].peRed;
270 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
271 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
272 info->bmiColors[i].rgbReserved = 0;
275 return colors;
278 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
280 PALETTEENTRY entries[256];
281 RGBQUAD table[256];
282 HPALETTE palette;
283 const WORD *index = (const WORD *)info->bmiColors;
284 int i, count, colors = info->bmiHeader.biClrUsed;
286 if (!colors) return TRUE;
287 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
288 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
290 for (i = 0; i < colors; i++, index++)
292 table[i].rgbRed = entries[*index % count].peRed;
293 table[i].rgbGreen = entries[*index % count].peGreen;
294 table[i].rgbBlue = entries[*index % count].peBlue;
295 table[i].rgbReserved = 0;
297 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
298 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
299 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
300 return TRUE;
303 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
305 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
306 const int bpp = info->bmiHeader.biBitCount;
308 if (height > 0)
309 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
310 else
311 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
314 static BOOL build_rle_bitmap( BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
316 DWORD i = 0;
317 int left, right;
318 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
319 HRGN run = NULL;
320 BYTE skip, num, data;
321 BYTE *out_bits, *in_bits = bits->ptr;
323 if (clip) *clip = NULL;
325 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
327 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
328 if (!out_bits) goto fail;
330 if (clip)
332 *clip = NtGdiCreateRectRgn( 0, 0, 0, 0 );
333 run = NtGdiCreateRectRgn( 0, 0, 0, 0 );
334 if (!*clip || !run) goto fail;
337 x = left = right = 0;
338 y = height - 1;
340 while (i < info->bmiHeader.biSizeImage - 1)
342 num = in_bits[i];
343 data = in_bits[i + 1];
344 i += 2;
346 if (num)
348 if (x + num > width) num = width - x;
349 if (num)
351 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
352 if (info->bmiHeader.biBitCount == 8)
353 memset( out_ptr, s, num );
354 else
356 if(x & 1)
358 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
359 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
360 out_ptr++;
361 x++;
362 num--;
364 /* this will write one too many if num is odd, but that doesn't matter */
365 if (num) memset( out_ptr, s, (num + 1) / 2 );
368 x += num;
369 right = x;
371 else
373 if (data < 3)
375 if(left != right && clip)
377 NtGdiSetRectRgn( run, left, y, right, y + 1 );
378 NtGdiCombineRgn( *clip, run, *clip, RGN_OR );
380 switch (data)
382 case 0: /* eol */
383 left = right = x = 0;
384 y--;
385 if(y < 0) goto done;
386 break;
388 case 1: /* eod */
389 goto done;
391 case 2: /* delta */
392 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
393 x += in_bits[i];
394 if (x > width) x = width;
395 left = right = x;
396 y -= in_bits[i + 1];
397 if(y < 0) goto done;
398 i += 2;
401 else /* data bytes of data */
403 num = data;
404 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
405 if (skip > info->bmiHeader.biSizeImage - i) goto done;
406 skip = (skip + 1) & ~1;
407 if (x + num > width) num = width - x;
408 if (num)
410 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
411 if (info->bmiHeader.biBitCount == 8)
412 memcpy( out_ptr, in_bits + i, num );
413 else
415 if(x & 1)
417 const BYTE *in_ptr = in_bits + i;
418 for ( ; num; num--, x++)
420 if (x & 1)
422 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
423 out_ptr++;
425 else
426 *out_ptr = (*in_ptr++ << 4) & 0xf0;
429 else
430 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
433 x += num;
434 right = x;
435 i += skip;
440 done:
441 if (run) DeleteObject( run );
442 if (bits->free) bits->free( bits );
444 bits->ptr = out_bits;
445 bits->is_copy = TRUE;
446 bits->free = free_heap_bits;
447 info->bmiHeader.biSizeImage = get_dib_image_size( info );
449 return TRUE;
451 fail:
452 if (run) DeleteObject( run );
453 if (clip && *clip) DeleteObject( *clip );
454 HeapFree( GetProcessHeap(), 0, out_bits );
455 return FALSE;
460 INT CDECL nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
461 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
462 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
464 DC *dc = get_nulldrv_dc( dev );
465 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
466 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
467 struct bitblt_coords src, dst;
468 struct gdi_image_bits src_bits;
469 DWORD err;
470 HRGN clip = NULL;
471 INT ret = 0;
472 INT height = abs( src_info->bmiHeader.biHeight );
473 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
474 RECT rect;
476 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
477 xSrc, ySrc, widthSrc, heightSrc, rop);
479 src_bits.ptr = (void*)bits;
480 src_bits.is_copy = FALSE;
481 src_bits.free = NULL;
483 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
485 rect.left = xDst;
486 rect.top = yDst;
487 rect.right = xDst + widthDst;
488 rect.bottom = yDst + heightDst;
489 lp_to_dp( dc, (POINT *)&rect, 2 );
490 dst.x = rect.left;
491 dst.y = rect.top;
492 dst.width = rect.right - rect.left;
493 dst.height = rect.bottom - rect.top;
495 if (dc->attr->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
497 dst.x += dst.width;
498 dst.width = -dst.width;
500 rop &= ~NOMIRRORBITMAP;
502 src.x = xSrc;
503 src.width = widthSrc;
504 src.y = ySrc;
505 src.height = heightSrc;
507 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
508 non_stretch_from_origin = TRUE;
510 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
512 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
513 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
516 if (rop != SRCCOPY || non_stretch_from_origin)
518 if (dst.width == 1 && src.width > 1) src.width--;
519 if (dst.height == 1 && src.height > 1) src.height--;
522 if (rop != SRCCOPY)
524 if (dst.width < 0 && dst.width == src.width)
526 /* This is off-by-one, but that's what Windows does */
527 dst.x += dst.width;
528 src.x += src.width;
529 dst.width = -dst.width;
530 src.width = -src.width;
532 if (dst.height < 0 && dst.height == src.height)
534 dst.y += dst.height;
535 src.y += src.height;
536 dst.height = -dst.height;
537 src.height = -src.height;
541 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
543 if (src.y >= height && src.y + src.height + 1 < height)
544 src.y = height - 1;
545 else if (src.y > 0 && src.y + src.height + 1 < 0)
546 src.y = -src.height - 1;
548 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
550 src.visrect.left = 0;
551 src.visrect.right = src_info->bmiHeader.biWidth;
552 src.visrect.top = 0;
553 src.visrect.bottom = height;
554 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
556 if (rop == SRCCOPY) ret = height;
557 else ret = src_info->bmiHeader.biHeight;
559 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
561 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
563 if (!intersect_vis_rectangles( &dst, &src )) goto done;
565 if (clip) NtGdiOffsetRgn( clip, dst.x - src.x, dst.y - src.y );
567 dev = GET_DC_PHYSDEV( dc, pPutImage );
568 copy_bitmapinfo( dst_info, src_info );
569 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
570 if (err == ERROR_BAD_FORMAT)
572 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
574 /* 1-bpp destination without a color table requires a fake 1-entry table
575 * that contains only the background color. There is no source DC to get
576 * it from, so the background is hardcoded to the default color. */
577 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
579 static const RGBQUAD default_bg = { 255, 255, 255 };
580 dst_info->bmiColors[0] = default_bg;
581 dst_info->bmiHeader.biClrUsed = 1;
584 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
586 /* get rid of the fake 1-bpp table */
587 dst_info->bmiHeader.biClrUsed = dst_colors;
588 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
592 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
594 copy_bitmapinfo( src_info, dst_info );
595 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, dc->attr->stretch_blt_mode );
596 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
598 if (err) ret = 0;
600 done:
601 if (src_bits.free) src_bits.free( &src_bits );
602 if (clip) DeleteObject( clip );
603 return ret;
606 /***********************************************************************
607 * StretchDIBits (GDI32.@)
609 INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
610 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
611 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
612 DWORD rop )
614 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
615 BITMAPINFO *info = (BITMAPINFO *)buffer;
616 PHYSDEV physdev;
617 DC *dc;
618 INT ret = 0;
620 if (!bits) return 0;
621 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
623 SetLastError( ERROR_INVALID_PARAMETER );
624 return 0;
627 if ((dc = get_dc_ptr( hdc )))
629 update_dc( dc );
630 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
631 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
632 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
633 release_dc_ptr( dc );
635 return ret;
639 /******************************************************************************
640 * SetDIBits [GDI32.@]
642 * Sets pixels in a bitmap using colors from DIB.
644 * PARAMS
645 * hdc [I] Handle to device context
646 * hbitmap [I] Handle to bitmap
647 * startscan [I] Starting scan line
648 * lines [I] Number of scan lines
649 * bits [I] Array of bitmap bits
650 * info [I] Address of structure with data
651 * coloruse [I] Type of color indexes to use
653 * RETURNS
654 * Success: Number of scan lines copied
655 * Failure: 0
657 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
658 UINT lines, LPCVOID bits, const BITMAPINFO *info,
659 UINT coloruse )
661 BITMAPOBJ *bitmap;
662 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
663 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
664 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
665 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
666 INT result = 0;
667 DWORD err;
668 struct gdi_image_bits src_bits;
669 struct bitblt_coords src, dst;
670 INT src_to_dst_offset;
671 HRGN clip = 0;
673 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
675 SetLastError( ERROR_INVALID_PARAMETER );
676 return 0;
678 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
680 DWORD *masks = (DWORD *)src_info->bmiColors;
681 if (!masks[0] || !masks[1] || !masks[2])
683 SetLastError( ERROR_INVALID_PARAMETER );
684 return 0;
688 src_bits.ptr = (void *)bits;
689 src_bits.is_copy = FALSE;
690 src_bits.free = NULL;
691 src_bits.param = NULL;
693 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
695 if (!(bitmap = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP ))) return 0;
697 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
699 if (lines == 0) goto done;
700 else lines = src_info->bmiHeader.biHeight;
701 startscan = 0;
703 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
706 dst.visrect.left = 0;
707 dst.visrect.top = 0;
708 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
709 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
711 src.visrect.left = 0;
712 src.visrect.top = 0;
713 src.visrect.right = src_info->bmiHeader.biWidth;
714 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
716 if (src_info->bmiHeader.biHeight > 0)
718 src_to_dst_offset = -startscan;
719 lines = min( lines, src.visrect.bottom - startscan );
720 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
722 else
724 src_to_dst_offset = src.visrect.bottom - lines - startscan;
725 /* Unlike the bottom-up case, Windows doesn't limit lines. */
726 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
729 result = lines;
731 offset_rect( &src.visrect, 0, src_to_dst_offset );
732 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
733 src.visrect = dst.visrect;
734 offset_rect( &src.visrect, 0, -src_to_dst_offset );
736 src.x = src.visrect.left;
737 src.y = src.visrect.top;
738 src.width = src.visrect.right - src.visrect.left;
739 src.height = src.visrect.bottom - src.visrect.top;
741 dst.x = dst.visrect.left;
742 dst.y = dst.visrect.top;
743 dst.width = dst.visrect.right - dst.visrect.left;
744 dst.height = dst.visrect.bottom - dst.visrect.top;
746 copy_bitmapinfo( dst_info, src_info );
748 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
749 if (err == ERROR_BAD_FORMAT)
751 err = convert_bits( src_info, &src, dst_info, &src_bits );
752 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
754 if(err) result = 0;
756 done:
757 if (src_bits.free) src_bits.free( &src_bits );
758 if (clip) DeleteObject( clip );
759 GDI_ReleaseObj( hbitmap );
760 return result;
764 INT CDECL nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
765 INT x_src, INT y_src, UINT startscan, UINT lines,
766 const void *bits, BITMAPINFO *src_info, UINT coloruse )
768 DC *dc = get_nulldrv_dc( dev );
769 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
770 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
771 struct bitblt_coords src, dst;
772 struct gdi_image_bits src_bits;
773 HRGN clip = 0;
774 DWORD err;
775 UINT height;
776 BOOL top_down;
777 POINT pt;
778 RECT rect;
780 top_down = (src_info->bmiHeader.biHeight < 0);
781 height = abs( src_info->bmiHeader.biHeight );
783 src_bits.ptr = (void *)bits;
784 src_bits.is_copy = FALSE;
785 src_bits.free = NULL;
787 if (!lines) return 0;
788 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
790 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
792 startscan = 0;
793 lines = height;
794 src_info->bmiHeader.biWidth = x_src + cx;
795 src_info->bmiHeader.biHeight = y_src + cy;
796 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
797 src.x = x_src;
798 src.y = 0;
799 src.width = cx;
800 src.height = cy;
801 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
803 else
805 if (startscan >= height) return 0;
806 if (!top_down && lines > height - startscan) lines = height - startscan;
808 /* map src to top-down coordinates with startscan as origin */
809 src.x = x_src;
810 src.y = startscan + lines - (y_src + cy);
811 src.width = cx;
812 src.height = cy;
813 if (src.y > 0)
815 if (!top_down)
817 /* get rid of unnecessary lines */
818 if (src.y >= lines) return 0;
819 lines -= src.y;
820 src.y = 0;
822 else if (src.y >= lines) return lines;
824 src_info->bmiHeader.biHeight = top_down ? -min( lines, height ) : lines;
825 src_info->bmiHeader.biSizeImage = get_dib_image_size( src_info );
828 src.visrect.left = src.x;
829 src.visrect.top = src.y;
830 src.visrect.right = src.x + cx;
831 src.visrect.bottom = src.y + cy;
832 rect.left = 0;
833 rect.top = 0;
834 rect.right = src_info->bmiHeader.biWidth;
835 rect.bottom = abs( src_info->bmiHeader.biHeight );
836 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
838 lines = 0;
839 goto done;
842 pt.x = x_dst;
843 pt.y = y_dst;
844 lp_to_dp( dc, &pt, 1 );
845 dst.x = pt.x;
846 dst.y = pt.y;
847 dst.width = cx;
848 dst.height = cy;
849 if (dc->attr->layout & LAYOUT_RTL) dst.x -= cx - 1;
851 rect.left = dst.x;
852 rect.top = dst.y;
853 rect.right = dst.x + cx;
854 rect.bottom = dst.y + cy;
855 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
857 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
858 intersect_rect( &rect, &src.visrect, &dst.visrect );
859 src.visrect = dst.visrect = rect;
860 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
861 if (is_rect_empty( &dst.visrect )) goto done;
862 if (clip) NtGdiOffsetRgn( clip, dst.x - src.x, dst.y - src.y );
864 dev = GET_DC_PHYSDEV( dc, pPutImage );
865 copy_bitmapinfo( dst_info, src_info );
866 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
867 if (err == ERROR_BAD_FORMAT)
869 err = convert_bits( src_info, &src, dst_info, &src_bits );
870 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
872 if (err) lines = 0;
874 done:
875 if (src_bits.free) src_bits.free( &src_bits );
876 if (clip) DeleteObject( clip );
877 return lines;
880 /***********************************************************************
881 * SetDIBitsToDevice (GDI32.@)
883 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
884 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
885 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
886 UINT coloruse )
888 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
889 BITMAPINFO *info = (BITMAPINFO *)buffer;
890 PHYSDEV physdev;
891 INT ret = 0;
892 DC *dc;
894 if (!bits) return 0;
895 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
897 SetLastError( ERROR_INVALID_PARAMETER );
898 return 0;
901 if ((dc = get_dc_ptr( hdc )))
903 update_dc( dc );
904 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
905 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
906 ySrc, startscan, lines, bits, info, coloruse );
907 release_dc_ptr( dc );
909 return ret;
912 /***********************************************************************
913 * SetDIBColorTable (GDI32.@)
915 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
917 DC * dc;
918 UINT i, result = 0;
919 BITMAPOBJ * bitmap;
921 if (!(dc = get_dc_ptr( hdc ))) return 0;
923 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
925 if (startpos < bitmap->dib.dsBmih.biClrUsed)
927 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
928 for (i = 0; i < result; i++)
930 bitmap->color_table[startpos + i].rgbBlue = colors[i].rgbBlue;
931 bitmap->color_table[startpos + i].rgbGreen = colors[i].rgbGreen;
932 bitmap->color_table[startpos + i].rgbRed = colors[i].rgbRed;
933 bitmap->color_table[startpos + i].rgbReserved = 0;
936 GDI_ReleaseObj( dc->hBitmap );
938 if (result) /* update colors of selected objects */
940 SetTextColor( hdc, dc->attr->text_color );
941 SetBkColor( hdc, dc->attr->background_color );
942 NtGdiSelectPen( hdc, dc->hPen );
943 NtGdiSelectBrush( hdc, dc->hBrush );
946 release_dc_ptr( dc );
947 return result;
951 /***********************************************************************
952 * GetDIBColorTable (GDI32.@)
954 UINT WINAPI GetDIBColorTable( 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 = HeapAlloc( GetProcessHeap(), 0, 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 * GetDIBits [GDI32.@]
1200 * Retrieves bits of bitmap and copies to buffer.
1202 * RETURNS
1203 * Success: Number of scan lines copied from bitmap
1204 * Failure: 0
1206 INT WINAPI DECLSPEC_HOTPATCH GetDIBits(
1207 HDC hdc, /* [in] Handle to device context */
1208 HBITMAP hbitmap, /* [in] Handle to bitmap */
1209 UINT startscan, /* [in] First scan line to set in dest bitmap */
1210 UINT lines, /* [in] Number of scan lines to copy */
1211 LPVOID bits, /* [out] Address of array for bitmap bits */
1212 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1213 UINT coloruse) /* [in] RGB or palette index */
1215 DC * dc;
1216 BITMAPOBJ * bmp;
1217 int i, dst_to_src_offset, ret = 0;
1218 DWORD err;
1219 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1220 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1221 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1222 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1223 struct gdi_image_bits src_bits;
1224 struct bitblt_coords src, dst;
1225 BOOL empty_rect = FALSE;
1227 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1228 own copy and transfer the colour info back at the end */
1229 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1230 if (coloruse > DIB_PAL_COLORS) return 0;
1231 if (bits &&
1232 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1233 return 0;
1234 dst_info->bmiHeader.biClrUsed = 0;
1235 dst_info->bmiHeader.biClrImportant = 0;
1237 if (!(dc = get_dc_ptr( hdc )))
1239 SetLastError( ERROR_INVALID_PARAMETER );
1240 return 0;
1242 update_dc( dc );
1243 if (!(bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP )))
1245 release_dc_ptr( dc );
1246 return 0;
1249 src.visrect.left = 0;
1250 src.visrect.top = 0;
1251 src.visrect.right = bmp->dib.dsBm.bmWidth;
1252 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1254 dst.visrect.left = 0;
1255 dst.visrect.top = 0;
1256 dst.visrect.right = dst_info->bmiHeader.biWidth;
1257 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1259 if (lines == 0 || startscan >= dst.visrect.bottom)
1260 bits = NULL;
1262 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1264 ret = fill_query_info( info, bmp );
1265 goto done;
1268 /* validate parameters */
1270 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1271 if (dst_info->bmiHeader.biHeight == 0) goto done;
1273 switch (dst_info->bmiHeader.biCompression)
1275 case BI_RLE4:
1276 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1277 if (dst_info->bmiHeader.biHeight < 0) goto done;
1278 if (bits) goto done; /* can't retrieve compressed bits */
1279 break;
1280 case BI_RLE8:
1281 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1282 if (dst_info->bmiHeader.biHeight < 0) goto done;
1283 if (bits) goto done; /* can't retrieve compressed bits */
1284 break;
1285 case BI_BITFIELDS:
1286 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1287 /* fall through */
1288 case BI_RGB:
1289 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1290 if (dst_info->bmiHeader.biBitCount == 1) break;
1291 if (dst_info->bmiHeader.biBitCount == 4) break;
1292 if (dst_info->bmiHeader.biBitCount == 8) break;
1293 if (dst_info->bmiHeader.biBitCount == 16) break;
1294 if (dst_info->bmiHeader.biBitCount == 24) break;
1295 if (dst_info->bmiHeader.biBitCount == 32) break;
1296 /* fall through */
1297 default:
1298 goto done;
1301 if (bits)
1303 if (dst_info->bmiHeader.biHeight > 0)
1305 dst_to_src_offset = -startscan;
1306 lines = min( lines, dst.visrect.bottom - startscan );
1307 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1309 else
1311 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1312 if (dst_to_src_offset < 0)
1314 dst_to_src_offset = 0;
1315 lines = dst.visrect.bottom - startscan;
1317 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1320 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1321 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1322 dst.visrect = src.visrect;
1323 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1325 if (dst_info->bmiHeader.biHeight > 0)
1327 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1329 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1330 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1331 memset( bits, 0, pad_bytes );
1332 bits = (char *)bits + pad_bytes;
1335 else
1337 if (dst.visrect.bottom < lines)
1339 int pad_lines = lines - dst.visrect.bottom;
1340 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1341 int pad_bytes = pad_lines * stride;
1342 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1346 if (empty_rect) bits = NULL;
1348 src.x = src.visrect.left;
1349 src.y = src.visrect.top;
1350 src.width = src.visrect.right - src.visrect.left;
1351 src.height = src.visrect.bottom - src.visrect.top;
1353 lines = src.height;
1356 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1358 if (err) goto done;
1360 /* fill out the src colour table, if it needs one */
1361 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1362 fill_default_color_table( src_info );
1364 /* if the src and dst are the same depth, copy the colour info across */
1365 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1367 switch (src_info->bmiHeader.biBitCount)
1369 case 16:
1370 if (src_info->bmiHeader.biCompression == BI_RGB)
1372 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1373 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1375 break;
1376 case 32:
1377 if (src_info->bmiHeader.biCompression == BI_RGB)
1379 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1380 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1382 break;
1384 copy_color_info( dst_info, src_info, coloruse );
1386 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1388 if( coloruse == DIB_PAL_COLORS )
1390 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1392 else
1394 fill_default_color_table( dst_info );
1398 if (bits)
1400 if(dst_info->bmiHeader.biHeight > 0)
1401 dst_info->bmiHeader.biHeight = src.height;
1402 else
1403 dst_info->bmiHeader.biHeight = -src.height;
1404 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1406 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1407 if (src_bits.free) src_bits.free( &src_bits );
1408 ret = lines;
1410 else
1411 ret = !empty_rect;
1413 if (coloruse == DIB_PAL_COLORS)
1415 WORD *index = (WORD *)dst_info->bmiColors;
1416 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1417 *index = i;
1420 copy_color_info( info, dst_info, coloruse );
1421 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1423 info->bmiHeader.biClrUsed = 0;
1424 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1427 done:
1428 release_dc_ptr( dc );
1429 GDI_ReleaseObj( hbitmap );
1430 return ret;
1434 /***********************************************************************
1435 * CreateDIBitmap (GDI32.@)
1437 * Creates a DDB (device dependent bitmap) from a DIB.
1438 * The DDB will have the same color depth as the reference DC.
1440 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1441 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1442 UINT coloruse )
1444 BITMAPINFOHEADER info;
1445 HBITMAP handle;
1446 LONG height;
1448 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1449 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1450 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1451 if (info.biWidth < 0) return 0;
1453 /* Top-down DIBs have a negative height */
1454 height = abs( info.biHeight );
1456 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1457 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1458 info.biBitCount, info.biCompression);
1460 if (hdc == NULL)
1461 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1462 else
1463 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1465 if (handle)
1467 if (init & CBM_INIT)
1469 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1471 DeleteObject( handle );
1472 handle = 0;
1477 return handle;
1481 /***********************************************************************
1482 * CreateDIBSection (GDI32.@)
1484 HBITMAP WINAPI DECLSPEC_HOTPATCH CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1485 void **bits, HANDLE section, DWORD offset)
1487 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1488 BITMAPINFO *info = (BITMAPINFO *)buffer;
1489 HBITMAP ret = 0;
1490 BITMAPOBJ *bmp;
1491 void *mapBits = NULL;
1493 if (bits) *bits = NULL;
1494 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1495 if (usage > DIB_PAL_COLORS) return 0;
1496 if (info->bmiHeader.biPlanes != 1)
1498 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1499 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1502 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1504 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1505 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1506 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1507 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1508 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1510 bmp->dib.dsBm.bmType = 0;
1511 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1512 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1513 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1514 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1515 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1516 bmp->dib.dsBmih = info->bmiHeader;
1518 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1520 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1521 goto error;
1522 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1523 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1524 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1525 goto error;
1526 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1529 /* set dsBitfields values */
1530 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1532 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1533 bmp->dib.dsBitfields[0] = 0x7c00;
1534 bmp->dib.dsBitfields[1] = 0x03e0;
1535 bmp->dib.dsBitfields[2] = 0x001f;
1537 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1539 if (usage == DIB_PAL_COLORS) goto error;
1540 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1541 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1542 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1543 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1545 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1547 /* get storage location for DIB bits */
1549 if (section)
1551 SYSTEM_INFO SystemInfo;
1552 DWORD mapOffset;
1553 INT mapSize;
1555 GetSystemInfo( &SystemInfo );
1556 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1557 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1558 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1559 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1561 else
1563 offset = 0;
1564 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1565 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1567 bmp->dib.dshSection = section;
1568 bmp->dib.dsOffset = offset;
1570 if (!bmp->dib.dsBm.bmBits) goto error;
1572 if (!(ret = alloc_gdi_handle( &bmp->obj, NTGDI_OBJ_BITMAP, &dib_funcs ))) goto error;
1574 if (bits) *bits = bmp->dib.dsBm.bmBits;
1575 return ret;
1577 error:
1578 if (section) UnmapViewOfFile( mapBits );
1579 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1580 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1581 HeapFree( GetProcessHeap(), 0, bmp );
1582 return 0;
1586 /***********************************************************************
1587 * D3DKMTCreateDCFromMemory (GDI32.@)
1589 NTSTATUS WINAPI D3DKMTCreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1591 const struct d3dddi_format_info
1593 D3DDDIFORMAT format;
1594 unsigned int bit_count;
1595 DWORD compression;
1596 unsigned int palette_size;
1597 DWORD mask_r, mask_g, mask_b;
1598 } *format = NULL;
1599 BITMAPOBJ *bmp = NULL;
1600 HBITMAP bitmap;
1601 unsigned int i;
1602 HDC dc;
1604 static const struct d3dddi_format_info format_info[] =
1606 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1607 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1608 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1609 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1610 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1611 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1612 { D3DDDIFMT_A4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1613 { D3DDDIFMT_X4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1614 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1617 if (!desc) return STATUS_INVALID_PARAMETER;
1619 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1620 desc->pMemory, desc->Format, desc->Width, desc->Height,
1621 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1623 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1625 for (i = 0; i < ARRAY_SIZE( format_info ); ++i)
1627 if (format_info[i].format == desc->Format)
1629 format = &format_info[i];
1630 break;
1633 if (!format) return STATUS_INVALID_PARAMETER;
1635 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1636 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1637 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1639 if (!desc->hDeviceDc || !(dc = CreateCompatibleDC( desc->hDeviceDc ))) return STATUS_INVALID_PARAMETER;
1641 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) goto error;
1643 bmp->dib.dsBm.bmWidth = desc->Width;
1644 bmp->dib.dsBm.bmHeight = desc->Height;
1645 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1646 bmp->dib.dsBm.bmPlanes = 1;
1647 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1648 bmp->dib.dsBm.bmBits = desc->pMemory;
1650 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1651 bmp->dib.dsBmih.biWidth = desc->Width;
1652 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1653 bmp->dib.dsBmih.biPlanes = 1;
1654 bmp->dib.dsBmih.biBitCount = format->bit_count;
1655 bmp->dib.dsBmih.biCompression = format->compression;
1656 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1657 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1659 bmp->dib.dsBitfields[0] = format->mask_r;
1660 bmp->dib.dsBitfields[1] = format->mask_g;
1661 bmp->dib.dsBitfields[2] = format->mask_b;
1663 if (format->palette_size)
1665 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0, format->palette_size * sizeof(*bmp->color_table) )))
1666 goto error;
1667 if (desc->pColorTable)
1669 for (i = 0; i < format->palette_size; ++i)
1671 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1672 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1673 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1674 bmp->color_table[i].rgbReserved = 0;
1677 else
1679 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1680 format->palette_size * sizeof(*bmp->color_table) );
1684 if (!(bitmap = alloc_gdi_handle( &bmp->obj, NTGDI_OBJ_BITMAP, &dib_funcs ))) goto error;
1686 desc->hDc = dc;
1687 desc->hBitmap = bitmap;
1688 NtGdiSelectBitmap( dc, bitmap );
1689 return STATUS_SUCCESS;
1691 error:
1692 if (bmp) HeapFree( GetProcessHeap(), 0, bmp->color_table );
1693 HeapFree( GetProcessHeap(), 0, bmp );
1694 DeleteDC( dc );
1695 return STATUS_INVALID_PARAMETER;
1699 /***********************************************************************
1700 * D3DKMTDestroyDCFromMemory (GDI32.@)
1702 NTSTATUS WINAPI D3DKMTDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1704 if (!desc) return STATUS_INVALID_PARAMETER;
1706 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1708 if (GetObjectType( desc->hDc ) != OBJ_MEMDC ||
1709 GetObjectType( desc->hBitmap ) != OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1710 DeleteObject( desc->hBitmap );
1711 DeleteDC( desc->hDc );
1713 return STATUS_SUCCESS;
1717 /***********************************************************************
1718 * DIB_GetObject
1720 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1722 INT ret = 0;
1723 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, NTGDI_OBJ_BITMAP );
1725 if (!bmp) return 0;
1727 if (!buffer) ret = sizeof(BITMAP);
1728 else if (count >= sizeof(DIBSECTION))
1730 DIBSECTION *dib = buffer;
1731 *dib = bmp->dib;
1732 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1733 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1734 ret = sizeof(DIBSECTION);
1736 else if (count >= sizeof(BITMAP))
1738 BITMAP *bitmap = buffer;
1739 *bitmap = bmp->dib.dsBm;
1740 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1741 ret = sizeof(BITMAP);
1744 GDI_ReleaseObj( handle );
1745 return ret;
1749 /***********************************************************************
1750 * DIB_DeleteObject
1752 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1754 BITMAPOBJ *bmp;
1756 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1758 if (bmp->dib.dshSection)
1760 SYSTEM_INFO SystemInfo;
1761 GetSystemInfo( &SystemInfo );
1762 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1763 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1765 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1767 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1768 HeapFree( GetProcessHeap(), 0, bmp );
1769 return TRUE;