ddraw/tests: Add another invalid arguments test for surface QI.
[wine.git] / dlls / gdi32 / dib.c
blob2eb0e91aa37cab40808c1d9caacfd608927f027a
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 "config.h"
64 #include <stdarg.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <assert.h>
69 #include "ntstatus.h"
70 #define WIN32_NO_STATUS
71 #include "windef.h"
72 #include "winbase.h"
73 #include "wingdi.h"
74 #include "winternl.h"
75 #include "ddk/d3dkmthk.h"
77 #include "gdi_private.h"
78 #include "wine/debug.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
83 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc );
84 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
85 static BOOL DIB_DeleteObject( HGDIOBJ handle );
87 static const struct gdi_obj_funcs dib_funcs =
89 DIB_SelectObject, /* pSelectObject */
90 DIB_GetObject, /* pGetObjectA */
91 DIB_GetObject, /* pGetObjectW */
92 NULL, /* pUnrealizeObject */
93 DIB_DeleteObject /* pDeleteObject */
96 /***********************************************************************
97 * bitmap_info_size
99 * Return the size of the bitmap info structure including color table.
101 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
103 unsigned int colors, size, masks = 0;
105 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
107 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
108 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
109 return sizeof(BITMAPCOREHEADER) + colors *
110 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
112 else /* assume BITMAPINFOHEADER */
114 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
115 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
116 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
117 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
118 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
122 /*******************************************************************************************
123 * Verify that the DIB parameters are valid.
125 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
127 if (info->biWidth <= 0) return FALSE;
128 if (info->biHeight == 0) return FALSE;
130 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
132 if (info->biHeight < 0) return FALSE;
133 if (!info->biSizeImage) return FALSE;
134 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
137 if (!info->biPlanes) return FALSE;
139 /* check for size overflow */
140 if (!info->biBitCount) return FALSE;
141 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
142 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
144 switch (info->biBitCount)
146 case 1:
147 case 4:
148 case 8:
149 case 24:
150 return (info->biCompression == BI_RGB);
151 case 16:
152 case 32:
153 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
154 default:
155 return FALSE;
159 /*******************************************************************************************
160 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
162 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
164 if (!info) return FALSE;
166 if (info->biSize == sizeof(BITMAPCOREHEADER))
168 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
169 dst->biWidth = core->bcWidth;
170 dst->biHeight = core->bcHeight;
171 dst->biPlanes = core->bcPlanes;
172 dst->biBitCount = core->bcBitCount;
173 dst->biCompression = BI_RGB;
174 dst->biXPelsPerMeter = 0;
175 dst->biYPelsPerMeter = 0;
176 dst->biClrUsed = 0;
177 dst->biClrImportant = 0;
179 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
181 *dst = *info;
183 else
185 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
186 return FALSE;
189 dst->biSize = sizeof(*dst);
190 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
191 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
192 return TRUE;
195 /*******************************************************************************************
196 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
198 * The resulting sanitized BITMAPINFO is guaranteed to have:
199 * - biSize set to sizeof(BITMAPINFOHEADER)
200 * - biSizeImage set to the actual image size even for non-compressed DIB
201 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
202 * - color table present only for <= 8 bpp, always starts at info->bmiColors
204 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
205 UINT coloruse, BOOL allow_compression )
207 void *src_colors;
209 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
210 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
211 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
213 src_colors = (char *)info + info->bmiHeader.biSize;
215 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
217 /* bitfields are always at bmiColors even in larger structures */
218 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
219 dst->bmiHeader.biClrUsed = 0;
221 else if (dst->bmiHeader.biBitCount <= 8)
223 unsigned int colors = dst->bmiHeader.biClrUsed;
224 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
226 if (!colors) colors = max_colors;
227 else colors = min( colors, max_colors );
229 if (coloruse == DIB_PAL_COLORS)
231 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
232 max_colors = colors;
234 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
236 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
238 else
240 unsigned int i;
241 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
242 for (i = 0; i < colors; i++)
244 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
245 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
246 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
247 dst->bmiColors[i].rgbReserved = 0;
250 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
251 dst->bmiHeader.biClrUsed = max_colors;
253 else dst->bmiHeader.biClrUsed = 0;
255 return TRUE;
258 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
260 PALETTEENTRY palEntry[256];
261 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
262 int i, colors = 1 << info->bmiHeader.biBitCount;
264 info->bmiHeader.biClrUsed = colors;
266 if (!palette) return 0;
268 memset( palEntry, 0, sizeof(palEntry) );
269 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
270 return 0;
272 for (i = 0; i < colors; i++)
274 info->bmiColors[i].rgbRed = palEntry[i].peRed;
275 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
276 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
277 info->bmiColors[i].rgbReserved = 0;
280 return colors;
283 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
285 PALETTEENTRY entries[256];
286 RGBQUAD table[256];
287 HPALETTE palette;
288 const WORD *index = (const WORD *)info->bmiColors;
289 int i, count, colors = info->bmiHeader.biClrUsed;
291 if (!colors) return TRUE;
292 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
293 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
295 for (i = 0; i < colors; i++, index++)
297 table[i].rgbRed = entries[*index % count].peRed;
298 table[i].rgbGreen = entries[*index % count].peGreen;
299 table[i].rgbBlue = entries[*index % count].peBlue;
300 table[i].rgbReserved = 0;
302 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
303 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
304 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
305 return TRUE;
308 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
310 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
311 const int bpp = info->bmiHeader.biBitCount;
313 if (height > 0)
314 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
315 else
316 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
319 static BOOL build_rle_bitmap( BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
321 DWORD i = 0;
322 int left, right;
323 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
324 HRGN run = NULL;
325 BYTE skip, num, data;
326 BYTE *out_bits, *in_bits = bits->ptr;
328 if (clip) *clip = NULL;
330 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
332 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
333 if (!out_bits) goto fail;
335 if (clip)
337 *clip = CreateRectRgn( 0, 0, 0, 0 );
338 run = CreateRectRgn( 0, 0, 0, 0 );
339 if (!*clip || !run) goto fail;
342 x = left = right = 0;
343 y = height - 1;
345 while (i < info->bmiHeader.biSizeImage - 1)
347 num = in_bits[i];
348 data = in_bits[i + 1];
349 i += 2;
351 if (num)
353 if (x + num > width) num = width - x;
354 if (num)
356 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
357 if (info->bmiHeader.biBitCount == 8)
358 memset( out_ptr, s, num );
359 else
361 if(x & 1)
363 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
364 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
365 out_ptr++;
366 x++;
367 num--;
369 /* this will write one too many if num is odd, but that doesn't matter */
370 if (num) memset( out_ptr, s, (num + 1) / 2 );
373 x += num;
374 right = x;
376 else
378 if (data < 3)
380 if(left != right && clip)
382 SetRectRgn( run, left, y, right, y + 1 );
383 CombineRgn( *clip, run, *clip, RGN_OR );
385 switch (data)
387 case 0: /* eol */
388 left = right = x = 0;
389 y--;
390 if(y < 0) goto done;
391 break;
393 case 1: /* eod */
394 goto done;
396 case 2: /* delta */
397 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
398 x += in_bits[i];
399 if (x > width) x = width;
400 left = right = x;
401 y -= in_bits[i + 1];
402 if(y < 0) goto done;
403 i += 2;
406 else /* data bytes of data */
408 num = data;
409 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
410 if (skip > info->bmiHeader.biSizeImage - i) goto done;
411 skip = (skip + 1) & ~1;
412 if (x + num > width) num = width - x;
413 if (num)
415 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
416 if (info->bmiHeader.biBitCount == 8)
417 memcpy( out_ptr, in_bits + i, num );
418 else
420 if(x & 1)
422 const BYTE *in_ptr = in_bits + i;
423 for ( ; num; num--, x++)
425 if (x & 1)
427 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
428 out_ptr++;
430 else
431 *out_ptr = (*in_ptr++ << 4) & 0xf0;
434 else
435 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
438 x += num;
439 right = x;
440 i += skip;
445 done:
446 if (run) DeleteObject( run );
447 if (bits->free) bits->free( bits );
449 bits->ptr = out_bits;
450 bits->is_copy = TRUE;
451 bits->free = free_heap_bits;
452 info->bmiHeader.biSizeImage = get_dib_image_size( info );
454 return TRUE;
456 fail:
457 if (run) DeleteObject( run );
458 if (clip && *clip) DeleteObject( *clip );
459 HeapFree( GetProcessHeap(), 0, out_bits );
460 return FALSE;
465 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
466 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
467 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
469 DC *dc = get_nulldrv_dc( dev );
470 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
471 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
472 struct bitblt_coords src, dst;
473 struct gdi_image_bits src_bits;
474 DWORD err;
475 HRGN clip = NULL;
476 INT ret = 0;
477 INT height = abs( src_info->bmiHeader.biHeight );
478 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
479 RECT rect;
481 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
482 xSrc, ySrc, widthSrc, heightSrc, rop);
484 src_bits.ptr = (void*)bits;
485 src_bits.is_copy = FALSE;
486 src_bits.free = NULL;
488 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
490 rect.left = xDst;
491 rect.top = yDst;
492 rect.right = xDst + widthDst;
493 rect.bottom = yDst + heightDst;
494 lp_to_dp( dc, (POINT *)&rect, 2 );
495 dst.x = rect.left;
496 dst.y = rect.top;
497 dst.width = rect.right - rect.left;
498 dst.height = rect.bottom - rect.top;
500 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
502 dst.x += dst.width;
503 dst.width = -dst.width;
505 rop &= ~NOMIRRORBITMAP;
507 src.x = xSrc;
508 src.width = widthSrc;
509 src.y = ySrc;
510 src.height = heightSrc;
512 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
513 non_stretch_from_origin = TRUE;
515 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
517 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
518 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
521 if (rop != SRCCOPY || non_stretch_from_origin)
523 if (dst.width == 1 && src.width > 1) src.width--;
524 if (dst.height == 1 && src.height > 1) src.height--;
527 if (rop != SRCCOPY)
529 if (dst.width < 0 && dst.width == src.width)
531 /* This is off-by-one, but that's what Windows does */
532 dst.x += dst.width;
533 src.x += src.width;
534 dst.width = -dst.width;
535 src.width = -src.width;
537 if (dst.height < 0 && dst.height == src.height)
539 dst.y += dst.height;
540 src.y += src.height;
541 dst.height = -dst.height;
542 src.height = -src.height;
546 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
548 if (src.y >= height && src.y + src.height + 1 < height)
549 src.y = height - 1;
550 else if (src.y > 0 && src.y + src.height + 1 < 0)
551 src.y = -src.height - 1;
553 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
555 src.visrect.left = 0;
556 src.visrect.right = src_info->bmiHeader.biWidth;
557 src.visrect.top = 0;
558 src.visrect.bottom = height;
559 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
561 if (rop == SRCCOPY) ret = height;
562 else ret = src_info->bmiHeader.biHeight;
564 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
566 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
568 if (!intersect_vis_rectangles( &dst, &src )) goto done;
570 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
572 dev = GET_DC_PHYSDEV( dc, pPutImage );
573 copy_bitmapinfo( dst_info, src_info );
574 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
575 if (err == ERROR_BAD_FORMAT)
577 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
579 /* 1-bpp destination without a color table requires a fake 1-entry table
580 * that contains only the background color. There is no source DC to get
581 * it from, so the background is hardcoded to the default color. */
582 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
584 static const RGBQUAD default_bg = { 255, 255, 255 };
585 dst_info->bmiColors[0] = default_bg;
586 dst_info->bmiHeader.biClrUsed = 1;
589 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
591 /* get rid of the fake 1-bpp table */
592 dst_info->bmiHeader.biClrUsed = dst_colors;
593 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
597 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
599 copy_bitmapinfo( src_info, dst_info );
600 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, dc->stretchBltMode );
601 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
603 if (err) ret = 0;
605 done:
606 if (src_bits.free) src_bits.free( &src_bits );
607 if (clip) DeleteObject( clip );
608 return ret;
611 /***********************************************************************
612 * StretchDIBits (GDI32.@)
614 INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
615 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
616 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
617 DWORD rop )
619 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
620 BITMAPINFO *info = (BITMAPINFO *)buffer;
621 PHYSDEV physdev;
622 DC *dc;
623 INT ret = 0;
625 if (!bits) return 0;
626 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
628 SetLastError( ERROR_INVALID_PARAMETER );
629 return 0;
632 if ((dc = get_dc_ptr( hdc )))
634 update_dc( dc );
635 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
636 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
637 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
638 release_dc_ptr( dc );
640 return ret;
644 /******************************************************************************
645 * SetDIBits [GDI32.@]
647 * Sets pixels in a bitmap using colors from DIB.
649 * PARAMS
650 * hdc [I] Handle to device context
651 * hbitmap [I] Handle to bitmap
652 * startscan [I] Starting scan line
653 * lines [I] Number of scan lines
654 * bits [I] Array of bitmap bits
655 * info [I] Address of structure with data
656 * coloruse [I] Type of color indexes to use
658 * RETURNS
659 * Success: Number of scan lines copied
660 * Failure: 0
662 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
663 UINT lines, LPCVOID bits, const BITMAPINFO *info,
664 UINT coloruse )
666 BITMAPOBJ *bitmap;
667 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
668 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
669 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
670 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
671 INT result = 0;
672 DWORD err;
673 struct gdi_image_bits src_bits;
674 struct bitblt_coords src, dst;
675 INT src_to_dst_offset;
676 HRGN clip = 0;
678 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
680 SetLastError( ERROR_INVALID_PARAMETER );
681 return 0;
683 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
685 DWORD *masks = (DWORD *)src_info->bmiColors;
686 if (!masks[0] || !masks[1] || !masks[2])
688 SetLastError( ERROR_INVALID_PARAMETER );
689 return 0;
693 src_bits.ptr = (void *)bits;
694 src_bits.is_copy = FALSE;
695 src_bits.free = NULL;
696 src_bits.param = NULL;
698 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
700 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
702 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
704 if (lines == 0) goto done;
705 else lines = src_info->bmiHeader.biHeight;
706 startscan = 0;
708 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
711 dst.visrect.left = 0;
712 dst.visrect.top = 0;
713 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
714 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
716 src.visrect.left = 0;
717 src.visrect.top = 0;
718 src.visrect.right = src_info->bmiHeader.biWidth;
719 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
721 if (src_info->bmiHeader.biHeight > 0)
723 src_to_dst_offset = -startscan;
724 lines = min( lines, src.visrect.bottom - startscan );
725 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
727 else
729 src_to_dst_offset = src.visrect.bottom - lines - startscan;
730 /* Unlike the bottom-up case, Windows doesn't limit lines. */
731 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
734 result = lines;
736 offset_rect( &src.visrect, 0, src_to_dst_offset );
737 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
738 src.visrect = dst.visrect;
739 offset_rect( &src.visrect, 0, -src_to_dst_offset );
741 src.x = src.visrect.left;
742 src.y = src.visrect.top;
743 src.width = src.visrect.right - src.visrect.left;
744 src.height = src.visrect.bottom - src.visrect.top;
746 dst.x = dst.visrect.left;
747 dst.y = dst.visrect.top;
748 dst.width = dst.visrect.right - dst.visrect.left;
749 dst.height = dst.visrect.bottom - dst.visrect.top;
751 copy_bitmapinfo( dst_info, src_info );
753 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
754 if (err == ERROR_BAD_FORMAT)
756 err = convert_bits( src_info, &src, dst_info, &src_bits );
757 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
759 if(err) result = 0;
761 done:
762 if (src_bits.free) src_bits.free( &src_bits );
763 if (clip) DeleteObject( clip );
764 GDI_ReleaseObj( hbitmap );
765 return result;
769 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
770 INT x_src, INT y_src, UINT startscan, UINT lines,
771 const void *bits, BITMAPINFO *src_info, UINT coloruse )
773 DC *dc = get_nulldrv_dc( dev );
774 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
775 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
776 struct bitblt_coords src, dst;
777 struct gdi_image_bits src_bits;
778 HRGN clip = 0;
779 DWORD err;
780 UINT height;
781 BOOL top_down;
782 POINT pt;
783 RECT rect;
785 top_down = (src_info->bmiHeader.biHeight < 0);
786 height = abs( src_info->bmiHeader.biHeight );
788 src_bits.ptr = (void *)bits;
789 src_bits.is_copy = FALSE;
790 src_bits.free = NULL;
792 if (!lines) return 0;
793 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
795 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
797 startscan = 0;
798 lines = height;
799 src_info->bmiHeader.biWidth = x_src + cx;
800 src_info->bmiHeader.biHeight = y_src + cy;
801 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
802 src.x = x_src;
803 src.y = 0;
804 src.width = cx;
805 src.height = cy;
806 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
808 else
810 if (startscan >= height) return 0;
811 if (!top_down && lines > height - startscan) lines = height - startscan;
813 /* map src to top-down coordinates with startscan as origin */
814 src.x = x_src;
815 src.y = startscan + lines - (y_src + cy);
816 src.width = cx;
817 src.height = cy;
818 if (src.y > 0)
820 if (!top_down)
822 /* get rid of unnecessary lines */
823 if (src.y >= lines) return 0;
824 lines -= src.y;
825 src.y = 0;
827 else if (src.y >= lines) return lines;
829 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
830 src_info->bmiHeader.biSizeImage = get_dib_image_size( src_info );
833 src.visrect.left = src.x;
834 src.visrect.top = src.y;
835 src.visrect.right = src.x + cx;
836 src.visrect.bottom = src.y + cy;
837 rect.left = 0;
838 rect.top = 0;
839 rect.right = src_info->bmiHeader.biWidth;
840 rect.bottom = abs( src_info->bmiHeader.biHeight );
841 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
843 lines = 0;
844 goto done;
847 pt.x = x_dst;
848 pt.y = y_dst;
849 lp_to_dp( dc, &pt, 1 );
850 dst.x = pt.x;
851 dst.y = pt.y;
852 dst.width = cx;
853 dst.height = cy;
854 if (dc->layout & LAYOUT_RTL) dst.x -= cx - 1;
856 rect.left = dst.x;
857 rect.top = dst.y;
858 rect.right = dst.x + cx;
859 rect.bottom = dst.y + cy;
860 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
862 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
863 intersect_rect( &rect, &src.visrect, &dst.visrect );
864 src.visrect = dst.visrect = rect;
865 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
866 if (is_rect_empty( &dst.visrect )) goto done;
867 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
869 dev = GET_DC_PHYSDEV( dc, pPutImage );
870 copy_bitmapinfo( dst_info, src_info );
871 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
872 if (err == ERROR_BAD_FORMAT)
874 err = convert_bits( src_info, &src, dst_info, &src_bits );
875 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
877 if (err) lines = 0;
879 done:
880 if (src_bits.free) src_bits.free( &src_bits );
881 if (clip) DeleteObject( clip );
882 return lines;
885 /***********************************************************************
886 * SetDIBitsToDevice (GDI32.@)
888 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
889 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
890 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
891 UINT coloruse )
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 (!bits) return 0;
900 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
902 SetLastError( ERROR_INVALID_PARAMETER );
903 return 0;
906 if ((dc = get_dc_ptr( hdc )))
908 update_dc( dc );
909 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
910 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
911 ySrc, startscan, lines, bits, info, coloruse );
912 release_dc_ptr( dc );
914 return ret;
917 /***********************************************************************
918 * SetDIBColorTable (GDI32.@)
920 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
922 DC * dc;
923 UINT i, result = 0;
924 BITMAPOBJ * bitmap;
926 if (!(dc = get_dc_ptr( hdc ))) return 0;
928 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
930 if (startpos < bitmap->dib.dsBmih.biClrUsed)
932 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
933 for (i = 0; i < result; i++)
935 bitmap->color_table[startpos + i].rgbBlue = colors[i].rgbBlue;
936 bitmap->color_table[startpos + i].rgbGreen = colors[i].rgbGreen;
937 bitmap->color_table[startpos + i].rgbRed = colors[i].rgbRed;
938 bitmap->color_table[startpos + i].rgbReserved = 0;
941 GDI_ReleaseObj( dc->hBitmap );
943 if (result) /* update colors of selected objects */
945 SetTextColor( hdc, dc->textColor );
946 SetBkColor( hdc, dc->backgroundColor );
947 SelectObject( hdc, dc->hPen );
948 SelectObject( hdc, dc->hBrush );
951 release_dc_ptr( dc );
952 return result;
956 /***********************************************************************
957 * GetDIBColorTable (GDI32.@)
959 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
961 DC * dc;
962 BITMAPOBJ *bitmap;
963 UINT result = 0;
965 if (!(dc = get_dc_ptr( hdc ))) return 0;
967 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
969 if (startpos < bitmap->dib.dsBmih.biClrUsed)
971 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
972 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
974 GDI_ReleaseObj( dc->hBitmap );
976 release_dc_ptr( dc );
977 return result;
980 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
981 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
983 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
985 BITMAPINFOHEADER header;
987 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
988 header.biWidth = bmp->dib.dsBm.bmWidth;
989 header.biHeight = bmp->dib.dsBm.bmHeight;
990 header.biPlanes = 1;
991 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
993 switch (header.biBitCount)
995 case 16:
996 case 32:
997 header.biCompression = BI_BITFIELDS;
998 break;
999 default:
1000 header.biCompression = BI_RGB;
1001 break;
1004 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
1005 header.biXPelsPerMeter = 0;
1006 header.biYPelsPerMeter = 0;
1007 header.biClrUsed = 0;
1008 header.biClrImportant = 0;
1010 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
1012 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
1014 coreheader->bcWidth = header.biWidth;
1015 coreheader->bcHeight = header.biHeight;
1016 coreheader->bcPlanes = header.biPlanes;
1017 coreheader->bcBitCount = header.biBitCount;
1019 else
1020 info->bmiHeader = header;
1022 return bmp->dib.dsBm.bmHeight;
1025 /************************************************************************
1026 * copy_color_info
1028 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1030 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1032 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1034 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1036 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1037 if (coloruse == DIB_PAL_COLORS)
1038 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1039 else
1041 unsigned int i;
1042 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1044 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1045 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1046 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1050 else
1052 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1054 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1055 /* bitfields are always at bmiColors even in larger structures */
1056 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1057 else if (src->bmiHeader.biClrUsed)
1059 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1060 unsigned int size;
1062 if (coloruse == DIB_PAL_COLORS)
1063 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1064 else
1065 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1066 memcpy( colorptr, src->bmiColors, size );
1071 const RGBQUAD *get_default_color_table( int bpp )
1073 static const RGBQUAD table_1[2] =
1075 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1077 static const RGBQUAD table_4[16] =
1079 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1080 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1081 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1082 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1084 static const RGBQUAD table_8[256] =
1086 /* first and last 10 entries are the default system palette entries */
1087 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1088 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1089 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1090 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1091 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1092 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1093 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1094 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1095 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1096 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1097 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1098 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1099 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1100 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1101 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1102 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1103 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1104 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1105 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1106 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1107 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1108 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1109 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1110 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1111 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1112 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1113 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1114 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1115 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1116 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1117 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1118 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1119 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1120 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1121 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1122 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1123 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1124 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1125 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1126 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1127 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1128 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1129 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1130 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1131 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1132 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1133 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1134 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1135 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1136 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1137 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1138 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1139 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1140 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1141 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1142 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1143 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1144 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1145 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1146 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1147 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1148 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1149 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1150 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1153 switch (bpp)
1155 case 1: return table_1;
1156 case 4: return table_4;
1157 case 8: return table_8;
1158 default: return NULL;
1162 void fill_default_color_table( BITMAPINFO *info )
1164 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1165 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1166 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1169 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1171 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1172 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1173 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1174 info->bmiHeader.biPlanes = 1;
1175 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1176 info->bmiHeader.biCompression = BI_RGB;
1177 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1178 info->bmiHeader.biXPelsPerMeter = 0;
1179 info->bmiHeader.biYPelsPerMeter = 0;
1180 info->bmiHeader.biClrUsed = 0;
1181 info->bmiHeader.biClrImportant = 0;
1184 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1186 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1187 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1188 unsigned int info_size;
1190 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1192 info_size = get_dib_info_size( info, usage );
1193 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1195 memcpy( ret, info, info_size );
1196 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1197 info->bmiHeader.biSizeImage );
1199 return ret;
1202 /******************************************************************************
1203 * GetDIBits [GDI32.@]
1205 * Retrieves bits of bitmap and copies to buffer.
1207 * RETURNS
1208 * Success: Number of scan lines copied from bitmap
1209 * Failure: 0
1211 INT WINAPI GetDIBits(
1212 HDC hdc, /* [in] Handle to device context */
1213 HBITMAP hbitmap, /* [in] Handle to bitmap */
1214 UINT startscan, /* [in] First scan line to set in dest bitmap */
1215 UINT lines, /* [in] Number of scan lines to copy */
1216 LPVOID bits, /* [out] Address of array for bitmap bits */
1217 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1218 UINT coloruse) /* [in] RGB or palette index */
1220 DC * dc;
1221 BITMAPOBJ * bmp;
1222 int i, dst_to_src_offset, ret = 0;
1223 DWORD err;
1224 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1225 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1226 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1227 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1228 struct gdi_image_bits src_bits;
1229 struct bitblt_coords src, dst;
1230 BOOL empty_rect = FALSE;
1232 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1233 own copy and transfer the colour info back at the end */
1234 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1235 if (coloruse > DIB_PAL_COLORS) return 0;
1236 if (bits &&
1237 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1238 return 0;
1239 dst_info->bmiHeader.biClrUsed = 0;
1240 dst_info->bmiHeader.biClrImportant = 0;
1242 if (!(dc = get_dc_ptr( hdc )))
1244 SetLastError( ERROR_INVALID_PARAMETER );
1245 return 0;
1247 update_dc( dc );
1248 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1250 release_dc_ptr( dc );
1251 return 0;
1254 src.visrect.left = 0;
1255 src.visrect.top = 0;
1256 src.visrect.right = bmp->dib.dsBm.bmWidth;
1257 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1259 dst.visrect.left = 0;
1260 dst.visrect.top = 0;
1261 dst.visrect.right = dst_info->bmiHeader.biWidth;
1262 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1264 if (lines == 0 || startscan >= dst.visrect.bottom)
1265 bits = NULL;
1267 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1269 ret = fill_query_info( info, bmp );
1270 goto done;
1273 /* validate parameters */
1275 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1276 if (dst_info->bmiHeader.biHeight == 0) goto done;
1278 switch (dst_info->bmiHeader.biCompression)
1280 case BI_RLE4:
1281 if (dst_info->bmiHeader.biBitCount != 4) 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_RLE8:
1286 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1287 if (dst_info->bmiHeader.biHeight < 0) goto done;
1288 if (bits) goto done; /* can't retrieve compressed bits */
1289 break;
1290 case BI_BITFIELDS:
1291 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1292 /* fall through */
1293 case BI_RGB:
1294 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1295 if (dst_info->bmiHeader.biBitCount == 1) break;
1296 if (dst_info->bmiHeader.biBitCount == 4) break;
1297 if (dst_info->bmiHeader.biBitCount == 8) break;
1298 if (dst_info->bmiHeader.biBitCount == 16) break;
1299 if (dst_info->bmiHeader.biBitCount == 24) break;
1300 if (dst_info->bmiHeader.biBitCount == 32) break;
1301 /* fall through */
1302 default:
1303 goto done;
1306 if (bits)
1308 if (dst_info->bmiHeader.biHeight > 0)
1310 dst_to_src_offset = -startscan;
1311 lines = min( lines, dst.visrect.bottom - startscan );
1312 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1314 else
1316 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1317 if (dst_to_src_offset < 0)
1319 dst_to_src_offset = 0;
1320 lines = dst.visrect.bottom - startscan;
1322 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1325 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1326 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1327 dst.visrect = src.visrect;
1328 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1330 if (dst_info->bmiHeader.biHeight > 0)
1332 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1334 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1335 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1336 memset( bits, 0, pad_bytes );
1337 bits = (char *)bits + pad_bytes;
1340 else
1342 if (dst.visrect.bottom < lines)
1344 int pad_lines = lines - dst.visrect.bottom;
1345 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1346 int pad_bytes = pad_lines * stride;
1347 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1351 if (empty_rect) bits = NULL;
1353 src.x = src.visrect.left;
1354 src.y = src.visrect.top;
1355 src.width = src.visrect.right - src.visrect.left;
1356 src.height = src.visrect.bottom - src.visrect.top;
1358 lines = src.height;
1361 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1363 if (err) goto done;
1365 /* fill out the src colour table, if it needs one */
1366 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1367 fill_default_color_table( src_info );
1369 /* if the src and dst are the same depth, copy the colour info across */
1370 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1372 switch (src_info->bmiHeader.biBitCount)
1374 case 16:
1375 if (src_info->bmiHeader.biCompression == BI_RGB)
1377 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1378 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1380 break;
1381 case 32:
1382 if (src_info->bmiHeader.biCompression == BI_RGB)
1384 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1385 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1387 break;
1389 copy_color_info( dst_info, src_info, coloruse );
1391 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1393 if( coloruse == DIB_PAL_COLORS )
1395 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1397 else
1399 fill_default_color_table( dst_info );
1403 if (bits)
1405 if(dst_info->bmiHeader.biHeight > 0)
1406 dst_info->bmiHeader.biHeight = src.height;
1407 else
1408 dst_info->bmiHeader.biHeight = -src.height;
1409 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1411 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1412 if (src_bits.free) src_bits.free( &src_bits );
1413 ret = lines;
1415 else
1416 ret = !empty_rect;
1418 if (coloruse == DIB_PAL_COLORS)
1420 WORD *index = (WORD *)dst_info->bmiColors;
1421 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1422 *index = i;
1425 copy_color_info( info, dst_info, coloruse );
1426 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1428 info->bmiHeader.biClrUsed = 0;
1429 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1432 done:
1433 release_dc_ptr( dc );
1434 GDI_ReleaseObj( hbitmap );
1435 return ret;
1439 /***********************************************************************
1440 * CreateDIBitmap (GDI32.@)
1442 * Creates a DDB (device dependent bitmap) from a DIB.
1443 * The DDB will have the same color depth as the reference DC.
1445 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1446 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1447 UINT coloruse )
1449 BITMAPINFOHEADER info;
1450 HBITMAP handle;
1451 LONG height;
1453 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1454 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1455 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1456 if (info.biWidth < 0) return 0;
1458 /* Top-down DIBs have a negative height */
1459 height = abs( info.biHeight );
1461 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1462 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1463 info.biBitCount, info.biCompression);
1465 if (hdc == NULL)
1466 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1467 else
1468 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1470 if (handle)
1472 if (init & CBM_INIT)
1474 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1476 DeleteObject( handle );
1477 handle = 0;
1482 return handle;
1486 /***********************************************************************
1487 * CreateDIBSection (GDI32.@)
1489 HBITMAP WINAPI DECLSPEC_HOTPATCH CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1490 void **bits, HANDLE section, DWORD offset)
1492 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1493 BITMAPINFO *info = (BITMAPINFO *)buffer;
1494 HBITMAP ret = 0;
1495 BITMAPOBJ *bmp;
1496 void *mapBits = NULL;
1498 if (bits) *bits = NULL;
1499 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1500 if (usage > DIB_PAL_COLORS) return 0;
1501 if (info->bmiHeader.biPlanes != 1)
1503 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1504 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1507 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1509 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1510 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1511 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1512 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1513 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1515 bmp->dib.dsBm.bmType = 0;
1516 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1517 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1518 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1519 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1520 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1521 bmp->dib.dsBmih = info->bmiHeader;
1523 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1525 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1526 goto error;
1527 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1528 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1529 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1530 goto error;
1531 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1534 /* set dsBitfields values */
1535 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1537 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1538 bmp->dib.dsBitfields[0] = 0x7c00;
1539 bmp->dib.dsBitfields[1] = 0x03e0;
1540 bmp->dib.dsBitfields[2] = 0x001f;
1542 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1544 if (usage == DIB_PAL_COLORS) goto error;
1545 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1546 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1547 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1548 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1550 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1552 /* get storage location for DIB bits */
1554 if (section)
1556 SYSTEM_INFO SystemInfo;
1557 DWORD mapOffset;
1558 INT mapSize;
1560 GetSystemInfo( &SystemInfo );
1561 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1562 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1563 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1564 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1566 else
1568 offset = 0;
1569 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1570 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1572 bmp->dib.dshSection = section;
1573 bmp->dib.dsOffset = offset;
1575 if (!bmp->dib.dsBm.bmBits) goto error;
1577 if (!(ret = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1579 if (bits) *bits = bmp->dib.dsBm.bmBits;
1580 return ret;
1582 error:
1583 if (section) UnmapViewOfFile( mapBits );
1584 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1585 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1586 HeapFree( GetProcessHeap(), 0, bmp );
1587 return 0;
1591 /***********************************************************************
1592 * D3DKMTCreateDCFromMemory (GDI32.@)
1594 NTSTATUS WINAPI D3DKMTCreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1596 const struct d3dddi_format_info
1598 D3DDDIFORMAT format;
1599 unsigned int bit_count;
1600 DWORD compression;
1601 unsigned int palette_size;
1602 DWORD mask_r, mask_g, mask_b;
1603 } *format = NULL;
1604 BITMAPOBJ *bmp = NULL;
1605 HBITMAP bitmap;
1606 unsigned int i;
1607 HDC dc;
1609 static const struct d3dddi_format_info format_info[] =
1611 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1612 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1613 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1614 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1615 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1616 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1617 { D3DDDIFMT_A4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1618 { D3DDDIFMT_X4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1619 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1622 if (!desc) return STATUS_INVALID_PARAMETER;
1624 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1625 desc->pMemory, desc->Format, desc->Width, desc->Height,
1626 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1628 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1630 for (i = 0; i < sizeof(format_info) / sizeof(*format_info); ++i)
1632 if (format_info[i].format == desc->Format)
1634 format = &format_info[i];
1635 break;
1638 if (!format) return STATUS_INVALID_PARAMETER;
1640 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1641 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1642 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1644 if (!desc->hDeviceDc || !(dc = CreateCompatibleDC( desc->hDeviceDc ))) return STATUS_INVALID_PARAMETER;
1646 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) goto error;
1648 bmp->dib.dsBm.bmWidth = desc->Width;
1649 bmp->dib.dsBm.bmHeight = desc->Height;
1650 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1651 bmp->dib.dsBm.bmPlanes = 1;
1652 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1653 bmp->dib.dsBm.bmBits = desc->pMemory;
1655 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1656 bmp->dib.dsBmih.biWidth = desc->Width;
1657 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1658 bmp->dib.dsBmih.biPlanes = 1;
1659 bmp->dib.dsBmih.biBitCount = format->bit_count;
1660 bmp->dib.dsBmih.biCompression = format->compression;
1661 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1662 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1664 bmp->dib.dsBitfields[0] = format->mask_r;
1665 bmp->dib.dsBitfields[1] = format->mask_g;
1666 bmp->dib.dsBitfields[2] = format->mask_b;
1668 if (format->palette_size)
1670 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0, format->palette_size * sizeof(*bmp->color_table) )))
1671 goto error;
1672 if (desc->pColorTable)
1674 for (i = 0; i < format->palette_size; ++i)
1676 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1677 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1678 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1679 bmp->color_table[i].rgbReserved = 0;
1682 else
1684 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1685 format->palette_size * sizeof(*bmp->color_table) );
1689 if (!(bitmap = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1691 desc->hDc = dc;
1692 desc->hBitmap = bitmap;
1693 SelectObject( dc, bitmap );
1694 return STATUS_SUCCESS;
1696 error:
1697 if (bmp) HeapFree( GetProcessHeap(), 0, bmp->color_table );
1698 HeapFree( GetProcessHeap(), 0, bmp );
1699 DeleteDC( dc );
1700 return STATUS_INVALID_PARAMETER;
1704 /***********************************************************************
1705 * D3DKMTDestroyDCFromMemory (GDI32.@)
1707 NTSTATUS WINAPI D3DKMTDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1709 if (!desc) return STATUS_INVALID_PARAMETER;
1711 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1713 if (GetObjectType( desc->hDc ) != OBJ_MEMDC ||
1714 GetObjectType( desc->hBitmap ) != OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1715 DeleteObject( desc->hBitmap );
1716 DeleteDC( desc->hDc );
1718 return STATUS_SUCCESS;
1722 /***********************************************************************
1723 * DIB_SelectObject
1725 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1727 HGDIOBJ ret;
1728 BITMAPOBJ *bitmap;
1729 DC *dc;
1730 PHYSDEV physdev;
1732 if (!(dc = get_dc_ptr( hdc ))) return 0;
1734 if (GetObjectType( hdc ) != OBJ_MEMDC)
1736 ret = 0;
1737 goto done;
1739 ret = dc->hBitmap;
1740 if (handle == dc->hBitmap) goto done; /* nothing to do */
1742 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1744 ret = 0;
1745 goto done;
1748 if (GDI_get_ref_count( handle ))
1750 WARN( "Bitmap already selected in another DC\n" );
1751 GDI_ReleaseObj( handle );
1752 ret = 0;
1753 goto done;
1756 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1757 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1759 GDI_ReleaseObj( handle );
1760 ret = 0;
1762 else
1764 dc->hBitmap = handle;
1765 GDI_inc_ref_count( handle );
1766 dc->dirty = 0;
1767 dc->vis_rect.left = 0;
1768 dc->vis_rect.top = 0;
1769 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1770 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1771 dc->device_rect = dc->vis_rect;
1772 GDI_ReleaseObj( handle );
1773 DC_InitDC( dc );
1774 GDI_dec_ref_count( ret );
1777 done:
1778 release_dc_ptr( dc );
1779 return ret;
1783 /***********************************************************************
1784 * DIB_GetObject
1786 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1788 INT ret = 0;
1789 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1791 if (!bmp) return 0;
1793 if (!buffer) ret = sizeof(BITMAP);
1794 else if (count >= sizeof(DIBSECTION))
1796 DIBSECTION *dib = buffer;
1797 *dib = bmp->dib;
1798 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1799 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1800 ret = sizeof(DIBSECTION);
1802 else if (count >= sizeof(BITMAP))
1804 BITMAP *bitmap = buffer;
1805 *bitmap = bmp->dib.dsBm;
1806 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1807 ret = sizeof(BITMAP);
1810 GDI_ReleaseObj( handle );
1811 return ret;
1815 /***********************************************************************
1816 * DIB_DeleteObject
1818 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1820 BITMAPOBJ *bmp;
1822 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1824 if (bmp->dib.dshSection)
1826 SYSTEM_INFO SystemInfo;
1827 GetSystemInfo( &SystemInfo );
1828 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1829 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1831 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1833 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1834 return HeapFree( GetProcessHeap(), 0, bmp );