gdi32: Directly use ntgdi interface to select objects.
[wine.git] / dlls / gdi32 / dib.c
blob069b9e77a282614766ceda3b7355c38c43bcea6a
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 "gdi_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, /* pGetObjectA */
87 DIB_GetObject, /* pGetObjectW */
88 NULL, /* pUnrealizeObject */
89 DIB_DeleteObject /* pDeleteObject */
92 /***********************************************************************
93 * bitmap_info_size
95 * Return the size of the bitmap info structure including color table.
97 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
99 unsigned int colors, size, masks = 0;
101 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
103 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
104 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
105 return sizeof(BITMAPCOREHEADER) + colors *
106 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
108 else /* assume BITMAPINFOHEADER */
110 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
111 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
112 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
113 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
114 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
118 /*******************************************************************************************
119 * Verify that the DIB parameters are valid.
121 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
123 if (info->biWidth <= 0) return FALSE;
124 if (info->biHeight == 0) return FALSE;
126 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
128 if (info->biHeight < 0) return FALSE;
129 if (!info->biSizeImage) return FALSE;
130 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
133 if (!info->biPlanes) return FALSE;
135 /* check for size overflow */
136 if (!info->biBitCount) return FALSE;
137 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
138 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
140 switch (info->biBitCount)
142 case 1:
143 case 4:
144 case 8:
145 case 24:
146 return (info->biCompression == BI_RGB);
147 case 16:
148 case 32:
149 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
150 default:
151 return FALSE;
155 /*******************************************************************************************
156 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
158 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
160 if (!info) return FALSE;
162 if (info->biSize == sizeof(BITMAPCOREHEADER))
164 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
165 dst->biWidth = core->bcWidth;
166 dst->biHeight = core->bcHeight;
167 dst->biPlanes = core->bcPlanes;
168 dst->biBitCount = core->bcBitCount;
169 dst->biCompression = BI_RGB;
170 dst->biXPelsPerMeter = 0;
171 dst->biYPelsPerMeter = 0;
172 dst->biClrUsed = 0;
173 dst->biClrImportant = 0;
175 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
177 *dst = *info;
179 else
181 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
182 return FALSE;
185 dst->biSize = sizeof(*dst);
186 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
187 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
188 return TRUE;
191 /*******************************************************************************************
192 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
194 * The resulting sanitized BITMAPINFO is guaranteed to have:
195 * - biSize set to sizeof(BITMAPINFOHEADER)
196 * - biSizeImage set to the actual image size even for non-compressed DIB
197 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
198 * - color table present only for <= 8 bpp, always starts at info->bmiColors
200 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
201 UINT coloruse, BOOL allow_compression )
203 void *src_colors;
205 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
206 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
207 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
209 src_colors = (char *)info + info->bmiHeader.biSize;
211 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
213 /* bitfields are always at bmiColors even in larger structures */
214 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
215 dst->bmiHeader.biClrUsed = 0;
217 else if (dst->bmiHeader.biBitCount <= 8)
219 unsigned int colors = dst->bmiHeader.biClrUsed;
220 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
222 if (!colors) colors = max_colors;
223 else colors = min( colors, max_colors );
225 if (coloruse == DIB_PAL_COLORS)
227 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
228 max_colors = colors;
230 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
232 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
234 else
236 unsigned int i;
237 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
238 for (i = 0; i < colors; i++)
240 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
241 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
242 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
243 dst->bmiColors[i].rgbReserved = 0;
246 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
247 dst->bmiHeader.biClrUsed = max_colors;
249 else dst->bmiHeader.biClrUsed = 0;
251 return TRUE;
254 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
256 PALETTEENTRY palEntry[256];
257 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
258 int i, colors = 1 << info->bmiHeader.biBitCount;
260 info->bmiHeader.biClrUsed = colors;
262 if (!palette) return 0;
264 memset( palEntry, 0, sizeof(palEntry) );
265 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
266 return 0;
268 for (i = 0; i < colors; i++)
270 info->bmiColors[i].rgbRed = palEntry[i].peRed;
271 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
272 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
273 info->bmiColors[i].rgbReserved = 0;
276 return colors;
279 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
281 PALETTEENTRY entries[256];
282 RGBQUAD table[256];
283 HPALETTE palette;
284 const WORD *index = (const WORD *)info->bmiColors;
285 int i, count, colors = info->bmiHeader.biClrUsed;
287 if (!colors) return TRUE;
288 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
289 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
291 for (i = 0; i < colors; i++, index++)
293 table[i].rgbRed = entries[*index % count].peRed;
294 table[i].rgbGreen = entries[*index % count].peGreen;
295 table[i].rgbBlue = entries[*index % count].peBlue;
296 table[i].rgbReserved = 0;
298 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
299 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
300 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
301 return TRUE;
304 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
306 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
307 const int bpp = info->bmiHeader.biBitCount;
309 if (height > 0)
310 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
311 else
312 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
315 static BOOL build_rle_bitmap( BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
317 DWORD i = 0;
318 int left, right;
319 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
320 HRGN run = NULL;
321 BYTE skip, num, data;
322 BYTE *out_bits, *in_bits = bits->ptr;
324 if (clip) *clip = NULL;
326 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
328 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
329 if (!out_bits) goto fail;
331 if (clip)
333 *clip = CreateRectRgn( 0, 0, 0, 0 );
334 run = CreateRectRgn( 0, 0, 0, 0 );
335 if (!*clip || !run) goto fail;
338 x = left = right = 0;
339 y = height - 1;
341 while (i < info->bmiHeader.biSizeImage - 1)
343 num = in_bits[i];
344 data = in_bits[i + 1];
345 i += 2;
347 if (num)
349 if (x + num > width) num = width - x;
350 if (num)
352 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
353 if (info->bmiHeader.biBitCount == 8)
354 memset( out_ptr, s, num );
355 else
357 if(x & 1)
359 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
360 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
361 out_ptr++;
362 x++;
363 num--;
365 /* this will write one too many if num is odd, but that doesn't matter */
366 if (num) memset( out_ptr, s, (num + 1) / 2 );
369 x += num;
370 right = x;
372 else
374 if (data < 3)
376 if(left != right && clip)
378 SetRectRgn( run, left, y, right, y + 1 );
379 CombineRgn( *clip, run, *clip, RGN_OR );
381 switch (data)
383 case 0: /* eol */
384 left = right = x = 0;
385 y--;
386 if(y < 0) goto done;
387 break;
389 case 1: /* eod */
390 goto done;
392 case 2: /* delta */
393 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
394 x += in_bits[i];
395 if (x > width) x = width;
396 left = right = x;
397 y -= in_bits[i + 1];
398 if(y < 0) goto done;
399 i += 2;
402 else /* data bytes of data */
404 num = data;
405 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
406 if (skip > info->bmiHeader.biSizeImage - i) goto done;
407 skip = (skip + 1) & ~1;
408 if (x + num > width) num = width - x;
409 if (num)
411 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
412 if (info->bmiHeader.biBitCount == 8)
413 memcpy( out_ptr, in_bits + i, num );
414 else
416 if(x & 1)
418 const BYTE *in_ptr = in_bits + i;
419 for ( ; num; num--, x++)
421 if (x & 1)
423 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
424 out_ptr++;
426 else
427 *out_ptr = (*in_ptr++ << 4) & 0xf0;
430 else
431 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
434 x += num;
435 right = x;
436 i += skip;
441 done:
442 if (run) DeleteObject( run );
443 if (bits->free) bits->free( bits );
445 bits->ptr = out_bits;
446 bits->is_copy = TRUE;
447 bits->free = free_heap_bits;
448 info->bmiHeader.biSizeImage = get_dib_image_size( info );
450 return TRUE;
452 fail:
453 if (run) DeleteObject( run );
454 if (clip && *clip) DeleteObject( *clip );
455 HeapFree( GetProcessHeap(), 0, out_bits );
456 return FALSE;
461 INT CDECL nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
462 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
463 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
465 DC *dc = get_nulldrv_dc( dev );
466 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
467 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
468 struct bitblt_coords src, dst;
469 struct gdi_image_bits src_bits;
470 DWORD err;
471 HRGN clip = NULL;
472 INT ret = 0;
473 INT height = abs( src_info->bmiHeader.biHeight );
474 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
475 RECT rect;
477 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
478 xSrc, ySrc, widthSrc, heightSrc, rop);
480 src_bits.ptr = (void*)bits;
481 src_bits.is_copy = FALSE;
482 src_bits.free = NULL;
484 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
486 rect.left = xDst;
487 rect.top = yDst;
488 rect.right = xDst + widthDst;
489 rect.bottom = yDst + heightDst;
490 lp_to_dp( dc, (POINT *)&rect, 2 );
491 dst.x = rect.left;
492 dst.y = rect.top;
493 dst.width = rect.right - rect.left;
494 dst.height = rect.bottom - rect.top;
496 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
498 dst.x += dst.width;
499 dst.width = -dst.width;
501 rop &= ~NOMIRRORBITMAP;
503 src.x = xSrc;
504 src.width = widthSrc;
505 src.y = ySrc;
506 src.height = heightSrc;
508 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
509 non_stretch_from_origin = TRUE;
511 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
513 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
514 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
517 if (rop != SRCCOPY || non_stretch_from_origin)
519 if (dst.width == 1 && src.width > 1) src.width--;
520 if (dst.height == 1 && src.height > 1) src.height--;
523 if (rop != SRCCOPY)
525 if (dst.width < 0 && dst.width == src.width)
527 /* This is off-by-one, but that's what Windows does */
528 dst.x += dst.width;
529 src.x += src.width;
530 dst.width = -dst.width;
531 src.width = -src.width;
533 if (dst.height < 0 && dst.height == src.height)
535 dst.y += dst.height;
536 src.y += src.height;
537 dst.height = -dst.height;
538 src.height = -src.height;
542 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
544 if (src.y >= height && src.y + src.height + 1 < height)
545 src.y = height - 1;
546 else if (src.y > 0 && src.y + src.height + 1 < 0)
547 src.y = -src.height - 1;
549 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
551 src.visrect.left = 0;
552 src.visrect.right = src_info->bmiHeader.biWidth;
553 src.visrect.top = 0;
554 src.visrect.bottom = height;
555 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
557 if (rop == SRCCOPY) ret = height;
558 else ret = src_info->bmiHeader.biHeight;
560 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
562 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
564 if (!intersect_vis_rectangles( &dst, &src )) goto done;
566 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
568 dev = GET_DC_PHYSDEV( dc, pPutImage );
569 copy_bitmapinfo( dst_info, src_info );
570 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
571 if (err == ERROR_BAD_FORMAT)
573 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
575 /* 1-bpp destination without a color table requires a fake 1-entry table
576 * that contains only the background color. There is no source DC to get
577 * it from, so the background is hardcoded to the default color. */
578 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
580 static const RGBQUAD default_bg = { 255, 255, 255 };
581 dst_info->bmiColors[0] = default_bg;
582 dst_info->bmiHeader.biClrUsed = 1;
585 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
587 /* get rid of the fake 1-bpp table */
588 dst_info->bmiHeader.biClrUsed = dst_colors;
589 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
593 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
595 copy_bitmapinfo( src_info, dst_info );
596 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, dc->stretchBltMode );
597 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
599 if (err) ret = 0;
601 done:
602 if (src_bits.free) src_bits.free( &src_bits );
603 if (clip) DeleteObject( clip );
604 return ret;
607 /***********************************************************************
608 * StretchDIBits (GDI32.@)
610 INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
611 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
612 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
613 DWORD rop )
615 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
616 BITMAPINFO *info = (BITMAPINFO *)buffer;
617 PHYSDEV physdev;
618 DC *dc;
619 INT ret = 0;
621 if (!bits) return 0;
622 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
624 SetLastError( ERROR_INVALID_PARAMETER );
625 return 0;
628 if ((dc = get_dc_ptr( hdc )))
630 update_dc( dc );
631 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
632 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
633 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
634 release_dc_ptr( dc );
636 return ret;
640 /******************************************************************************
641 * SetDIBits [GDI32.@]
643 * Sets pixels in a bitmap using colors from DIB.
645 * PARAMS
646 * hdc [I] Handle to device context
647 * hbitmap [I] Handle to bitmap
648 * startscan [I] Starting scan line
649 * lines [I] Number of scan lines
650 * bits [I] Array of bitmap bits
651 * info [I] Address of structure with data
652 * coloruse [I] Type of color indexes to use
654 * RETURNS
655 * Success: Number of scan lines copied
656 * Failure: 0
658 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
659 UINT lines, LPCVOID bits, const BITMAPINFO *info,
660 UINT coloruse )
662 BITMAPOBJ *bitmap;
663 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
664 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
665 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
666 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
667 INT result = 0;
668 DWORD err;
669 struct gdi_image_bits src_bits;
670 struct bitblt_coords src, dst;
671 INT src_to_dst_offset;
672 HRGN clip = 0;
674 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
676 SetLastError( ERROR_INVALID_PARAMETER );
677 return 0;
679 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
681 DWORD *masks = (DWORD *)src_info->bmiColors;
682 if (!masks[0] || !masks[1] || !masks[2])
684 SetLastError( ERROR_INVALID_PARAMETER );
685 return 0;
689 src_bits.ptr = (void *)bits;
690 src_bits.is_copy = FALSE;
691 src_bits.free = NULL;
692 src_bits.param = NULL;
694 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
696 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
698 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
700 if (lines == 0) goto done;
701 else lines = src_info->bmiHeader.biHeight;
702 startscan = 0;
704 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
707 dst.visrect.left = 0;
708 dst.visrect.top = 0;
709 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
710 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
712 src.visrect.left = 0;
713 src.visrect.top = 0;
714 src.visrect.right = src_info->bmiHeader.biWidth;
715 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
717 if (src_info->bmiHeader.biHeight > 0)
719 src_to_dst_offset = -startscan;
720 lines = min( lines, src.visrect.bottom - startscan );
721 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
723 else
725 src_to_dst_offset = src.visrect.bottom - lines - startscan;
726 /* Unlike the bottom-up case, Windows doesn't limit lines. */
727 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
730 result = lines;
732 offset_rect( &src.visrect, 0, src_to_dst_offset );
733 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
734 src.visrect = dst.visrect;
735 offset_rect( &src.visrect, 0, -src_to_dst_offset );
737 src.x = src.visrect.left;
738 src.y = src.visrect.top;
739 src.width = src.visrect.right - src.visrect.left;
740 src.height = src.visrect.bottom - src.visrect.top;
742 dst.x = dst.visrect.left;
743 dst.y = dst.visrect.top;
744 dst.width = dst.visrect.right - dst.visrect.left;
745 dst.height = dst.visrect.bottom - dst.visrect.top;
747 copy_bitmapinfo( dst_info, src_info );
749 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
750 if (err == ERROR_BAD_FORMAT)
752 err = convert_bits( src_info, &src, dst_info, &src_bits );
753 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
755 if(err) result = 0;
757 done:
758 if (src_bits.free) src_bits.free( &src_bits );
759 if (clip) DeleteObject( clip );
760 GDI_ReleaseObj( hbitmap );
761 return result;
765 INT CDECL nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
766 INT x_src, INT y_src, UINT startscan, UINT lines,
767 const void *bits, BITMAPINFO *src_info, UINT coloruse )
769 DC *dc = get_nulldrv_dc( dev );
770 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
771 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
772 struct bitblt_coords src, dst;
773 struct gdi_image_bits src_bits;
774 HRGN clip = 0;
775 DWORD err;
776 UINT height;
777 BOOL top_down;
778 POINT pt;
779 RECT rect;
781 top_down = (src_info->bmiHeader.biHeight < 0);
782 height = abs( src_info->bmiHeader.biHeight );
784 src_bits.ptr = (void *)bits;
785 src_bits.is_copy = FALSE;
786 src_bits.free = NULL;
788 if (!lines) return 0;
789 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
791 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
793 startscan = 0;
794 lines = height;
795 src_info->bmiHeader.biWidth = x_src + cx;
796 src_info->bmiHeader.biHeight = y_src + cy;
797 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
798 src.x = x_src;
799 src.y = 0;
800 src.width = cx;
801 src.height = cy;
802 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
804 else
806 if (startscan >= height) return 0;
807 if (!top_down && lines > height - startscan) lines = height - startscan;
809 /* map src to top-down coordinates with startscan as origin */
810 src.x = x_src;
811 src.y = startscan + lines - (y_src + cy);
812 src.width = cx;
813 src.height = cy;
814 if (src.y > 0)
816 if (!top_down)
818 /* get rid of unnecessary lines */
819 if (src.y >= lines) return 0;
820 lines -= src.y;
821 src.y = 0;
823 else if (src.y >= lines) return lines;
825 src_info->bmiHeader.biHeight = top_down ? -min( lines, height ) : lines;
826 src_info->bmiHeader.biSizeImage = get_dib_image_size( src_info );
829 src.visrect.left = src.x;
830 src.visrect.top = src.y;
831 src.visrect.right = src.x + cx;
832 src.visrect.bottom = src.y + cy;
833 rect.left = 0;
834 rect.top = 0;
835 rect.right = src_info->bmiHeader.biWidth;
836 rect.bottom = abs( src_info->bmiHeader.biHeight );
837 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
839 lines = 0;
840 goto done;
843 pt.x = x_dst;
844 pt.y = y_dst;
845 lp_to_dp( dc, &pt, 1 );
846 dst.x = pt.x;
847 dst.y = pt.y;
848 dst.width = cx;
849 dst.height = cy;
850 if (dc->layout & LAYOUT_RTL) dst.x -= cx - 1;
852 rect.left = dst.x;
853 rect.top = dst.y;
854 rect.right = dst.x + cx;
855 rect.bottom = dst.y + cy;
856 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
858 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
859 intersect_rect( &rect, &src.visrect, &dst.visrect );
860 src.visrect = dst.visrect = rect;
861 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
862 if (is_rect_empty( &dst.visrect )) goto done;
863 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
865 dev = GET_DC_PHYSDEV( dc, pPutImage );
866 copy_bitmapinfo( dst_info, src_info );
867 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
868 if (err == ERROR_BAD_FORMAT)
870 err = convert_bits( src_info, &src, dst_info, &src_bits );
871 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
873 if (err) lines = 0;
875 done:
876 if (src_bits.free) src_bits.free( &src_bits );
877 if (clip) DeleteObject( clip );
878 return lines;
881 /***********************************************************************
882 * SetDIBitsToDevice (GDI32.@)
884 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
885 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
886 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
887 UINT coloruse )
889 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
890 BITMAPINFO *info = (BITMAPINFO *)buffer;
891 PHYSDEV physdev;
892 INT ret = 0;
893 DC *dc;
895 if (!bits) return 0;
896 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
898 SetLastError( ERROR_INVALID_PARAMETER );
899 return 0;
902 if ((dc = get_dc_ptr( hdc )))
904 update_dc( dc );
905 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
906 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
907 ySrc, startscan, lines, bits, info, coloruse );
908 release_dc_ptr( dc );
910 return ret;
913 /***********************************************************************
914 * SetDIBColorTable (GDI32.@)
916 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
918 DC * dc;
919 UINT i, result = 0;
920 BITMAPOBJ * bitmap;
922 if (!(dc = get_dc_ptr( hdc ))) return 0;
924 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
926 if (startpos < bitmap->dib.dsBmih.biClrUsed)
928 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
929 for (i = 0; i < result; i++)
931 bitmap->color_table[startpos + i].rgbBlue = colors[i].rgbBlue;
932 bitmap->color_table[startpos + i].rgbGreen = colors[i].rgbGreen;
933 bitmap->color_table[startpos + i].rgbRed = colors[i].rgbRed;
934 bitmap->color_table[startpos + i].rgbReserved = 0;
937 GDI_ReleaseObj( dc->hBitmap );
939 if (result) /* update colors of selected objects */
941 SetTextColor( hdc, dc->textColor );
942 SetBkColor( hdc, dc->backgroundColor );
943 NtGdiSelectPen( hdc, dc->hPen );
944 NtGdiSelectBrush( hdc, dc->hBrush );
947 release_dc_ptr( dc );
948 return result;
952 /***********************************************************************
953 * GetDIBColorTable (GDI32.@)
955 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
957 DC * dc;
958 BITMAPOBJ *bitmap;
959 UINT result = 0;
961 if (!(dc = get_dc_ptr( hdc ))) return 0;
963 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
965 if (startpos < bitmap->dib.dsBmih.biClrUsed)
967 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
968 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
970 GDI_ReleaseObj( dc->hBitmap );
972 release_dc_ptr( dc );
973 return result;
976 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
977 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
979 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
981 BITMAPINFOHEADER header;
983 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
984 header.biWidth = bmp->dib.dsBm.bmWidth;
985 header.biHeight = bmp->dib.dsBm.bmHeight;
986 header.biPlanes = 1;
987 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
989 switch (header.biBitCount)
991 case 16:
992 case 32:
993 header.biCompression = BI_BITFIELDS;
994 break;
995 default:
996 header.biCompression = BI_RGB;
997 break;
1000 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
1001 header.biXPelsPerMeter = 0;
1002 header.biYPelsPerMeter = 0;
1003 header.biClrUsed = 0;
1004 header.biClrImportant = 0;
1006 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
1008 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
1010 coreheader->bcWidth = header.biWidth;
1011 coreheader->bcHeight = header.biHeight;
1012 coreheader->bcPlanes = header.biPlanes;
1013 coreheader->bcBitCount = header.biBitCount;
1015 else
1016 info->bmiHeader = header;
1018 return bmp->dib.dsBm.bmHeight;
1021 /************************************************************************
1022 * copy_color_info
1024 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1026 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1028 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1030 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1032 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1033 if (coloruse == DIB_PAL_COLORS)
1034 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1035 else
1037 unsigned int i;
1038 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1040 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1041 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1042 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1046 else
1048 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1050 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1051 /* bitfields are always at bmiColors even in larger structures */
1052 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1053 else if (src->bmiHeader.biClrUsed)
1055 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1056 unsigned int size;
1058 if (coloruse == DIB_PAL_COLORS)
1059 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1060 else
1061 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1062 memcpy( colorptr, src->bmiColors, size );
1067 const RGBQUAD *get_default_color_table( int bpp )
1069 static const RGBQUAD table_1[2] =
1071 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1073 static const RGBQUAD table_4[16] =
1075 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1076 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1077 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1078 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1080 static const RGBQUAD table_8[256] =
1082 /* first and last 10 entries are the default system palette entries */
1083 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1084 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1085 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1086 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1087 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1088 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1089 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1090 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1091 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1092 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1093 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1094 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1095 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1096 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1097 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1098 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1099 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1100 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1101 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1102 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1103 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1104 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1105 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1106 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1107 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1108 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1109 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1110 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1111 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1112 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1113 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1114 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1115 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1116 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1117 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1118 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1119 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1120 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1121 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1122 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1123 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1124 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1125 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1126 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1127 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1128 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1129 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1130 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1131 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1132 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1133 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1134 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1135 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1136 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1137 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1138 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1139 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1140 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1141 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1142 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1143 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1144 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1145 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1146 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1149 switch (bpp)
1151 case 1: return table_1;
1152 case 4: return table_4;
1153 case 8: return table_8;
1154 default: return NULL;
1158 void fill_default_color_table( BITMAPINFO *info )
1160 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1161 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1162 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1165 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1167 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1168 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1169 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1170 info->bmiHeader.biPlanes = 1;
1171 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1172 info->bmiHeader.biCompression = BI_RGB;
1173 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1174 info->bmiHeader.biXPelsPerMeter = 0;
1175 info->bmiHeader.biYPelsPerMeter = 0;
1176 info->bmiHeader.biClrUsed = 0;
1177 info->bmiHeader.biClrImportant = 0;
1180 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1182 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1183 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1184 unsigned int info_size;
1186 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1188 info_size = get_dib_info_size( info, usage );
1189 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1191 memcpy( ret, info, info_size );
1192 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1193 info->bmiHeader.biSizeImage );
1195 return ret;
1198 /******************************************************************************
1199 * GetDIBits [GDI32.@]
1201 * Retrieves bits of bitmap and copies to buffer.
1203 * RETURNS
1204 * Success: Number of scan lines copied from bitmap
1205 * Failure: 0
1207 INT WINAPI DECLSPEC_HOTPATCH GetDIBits(
1208 HDC hdc, /* [in] Handle to device context */
1209 HBITMAP hbitmap, /* [in] Handle to bitmap */
1210 UINT startscan, /* [in] First scan line to set in dest bitmap */
1211 UINT lines, /* [in] Number of scan lines to copy */
1212 LPVOID bits, /* [out] Address of array for bitmap bits */
1213 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1214 UINT coloruse) /* [in] RGB or palette index */
1216 DC * dc;
1217 BITMAPOBJ * bmp;
1218 int i, dst_to_src_offset, ret = 0;
1219 DWORD err;
1220 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1221 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1222 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1223 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1224 struct gdi_image_bits src_bits;
1225 struct bitblt_coords src, dst;
1226 BOOL empty_rect = FALSE;
1228 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1229 own copy and transfer the colour info back at the end */
1230 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1231 if (coloruse > DIB_PAL_COLORS) return 0;
1232 if (bits &&
1233 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1234 return 0;
1235 dst_info->bmiHeader.biClrUsed = 0;
1236 dst_info->bmiHeader.biClrImportant = 0;
1238 if (!(dc = get_dc_ptr( hdc )))
1240 SetLastError( ERROR_INVALID_PARAMETER );
1241 return 0;
1243 update_dc( dc );
1244 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1246 release_dc_ptr( dc );
1247 return 0;
1250 src.visrect.left = 0;
1251 src.visrect.top = 0;
1252 src.visrect.right = bmp->dib.dsBm.bmWidth;
1253 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1255 dst.visrect.left = 0;
1256 dst.visrect.top = 0;
1257 dst.visrect.right = dst_info->bmiHeader.biWidth;
1258 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1260 if (lines == 0 || startscan >= dst.visrect.bottom)
1261 bits = NULL;
1263 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1265 ret = fill_query_info( info, bmp );
1266 goto done;
1269 /* validate parameters */
1271 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1272 if (dst_info->bmiHeader.biHeight == 0) goto done;
1274 switch (dst_info->bmiHeader.biCompression)
1276 case BI_RLE4:
1277 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1278 if (dst_info->bmiHeader.biHeight < 0) goto done;
1279 if (bits) goto done; /* can't retrieve compressed bits */
1280 break;
1281 case BI_RLE8:
1282 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1283 if (dst_info->bmiHeader.biHeight < 0) goto done;
1284 if (bits) goto done; /* can't retrieve compressed bits */
1285 break;
1286 case BI_BITFIELDS:
1287 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1288 /* fall through */
1289 case BI_RGB:
1290 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1291 if (dst_info->bmiHeader.biBitCount == 1) break;
1292 if (dst_info->bmiHeader.biBitCount == 4) break;
1293 if (dst_info->bmiHeader.biBitCount == 8) break;
1294 if (dst_info->bmiHeader.biBitCount == 16) break;
1295 if (dst_info->bmiHeader.biBitCount == 24) break;
1296 if (dst_info->bmiHeader.biBitCount == 32) break;
1297 /* fall through */
1298 default:
1299 goto done;
1302 if (bits)
1304 if (dst_info->bmiHeader.biHeight > 0)
1306 dst_to_src_offset = -startscan;
1307 lines = min( lines, dst.visrect.bottom - startscan );
1308 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1310 else
1312 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1313 if (dst_to_src_offset < 0)
1315 dst_to_src_offset = 0;
1316 lines = dst.visrect.bottom - startscan;
1318 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1321 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1322 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1323 dst.visrect = src.visrect;
1324 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1326 if (dst_info->bmiHeader.biHeight > 0)
1328 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1330 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1331 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1332 memset( bits, 0, pad_bytes );
1333 bits = (char *)bits + pad_bytes;
1336 else
1338 if (dst.visrect.bottom < lines)
1340 int pad_lines = lines - dst.visrect.bottom;
1341 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1342 int pad_bytes = pad_lines * stride;
1343 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1347 if (empty_rect) bits = NULL;
1349 src.x = src.visrect.left;
1350 src.y = src.visrect.top;
1351 src.width = src.visrect.right - src.visrect.left;
1352 src.height = src.visrect.bottom - src.visrect.top;
1354 lines = src.height;
1357 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1359 if (err) goto done;
1361 /* fill out the src colour table, if it needs one */
1362 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1363 fill_default_color_table( src_info );
1365 /* if the src and dst are the same depth, copy the colour info across */
1366 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1368 switch (src_info->bmiHeader.biBitCount)
1370 case 16:
1371 if (src_info->bmiHeader.biCompression == BI_RGB)
1373 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1374 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1376 break;
1377 case 32:
1378 if (src_info->bmiHeader.biCompression == BI_RGB)
1380 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1381 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1383 break;
1385 copy_color_info( dst_info, src_info, coloruse );
1387 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1389 if( coloruse == DIB_PAL_COLORS )
1391 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1393 else
1395 fill_default_color_table( dst_info );
1399 if (bits)
1401 if(dst_info->bmiHeader.biHeight > 0)
1402 dst_info->bmiHeader.biHeight = src.height;
1403 else
1404 dst_info->bmiHeader.biHeight = -src.height;
1405 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1407 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1408 if (src_bits.free) src_bits.free( &src_bits );
1409 ret = lines;
1411 else
1412 ret = !empty_rect;
1414 if (coloruse == DIB_PAL_COLORS)
1416 WORD *index = (WORD *)dst_info->bmiColors;
1417 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1418 *index = i;
1421 copy_color_info( info, dst_info, coloruse );
1422 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1424 info->bmiHeader.biClrUsed = 0;
1425 info->bmiHeader.biSizeImage = get_dib_image_size( info );
1428 done:
1429 release_dc_ptr( dc );
1430 GDI_ReleaseObj( hbitmap );
1431 return ret;
1435 /***********************************************************************
1436 * CreateDIBitmap (GDI32.@)
1438 * Creates a DDB (device dependent bitmap) from a DIB.
1439 * The DDB will have the same color depth as the reference DC.
1441 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1442 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1443 UINT coloruse )
1445 BITMAPINFOHEADER info;
1446 HBITMAP handle;
1447 LONG height;
1449 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1450 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1451 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1452 if (info.biWidth < 0) return 0;
1454 /* Top-down DIBs have a negative height */
1455 height = abs( info.biHeight );
1457 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1458 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1459 info.biBitCount, info.biCompression);
1461 if (hdc == NULL)
1462 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1463 else
1464 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1466 if (handle)
1468 if (init & CBM_INIT)
1470 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1472 DeleteObject( handle );
1473 handle = 0;
1478 return handle;
1482 /***********************************************************************
1483 * CreateDIBSection (GDI32.@)
1485 HBITMAP WINAPI DECLSPEC_HOTPATCH CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1486 void **bits, HANDLE section, DWORD offset)
1488 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1489 BITMAPINFO *info = (BITMAPINFO *)buffer;
1490 HBITMAP ret = 0;
1491 BITMAPOBJ *bmp;
1492 void *mapBits = NULL;
1494 if (bits) *bits = NULL;
1495 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1496 if (usage > DIB_PAL_COLORS) return 0;
1497 if (info->bmiHeader.biPlanes != 1)
1499 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1500 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1503 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1505 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1506 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1507 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1508 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1509 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1511 bmp->dib.dsBm.bmType = 0;
1512 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1513 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1514 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1515 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1516 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1517 bmp->dib.dsBmih = info->bmiHeader;
1519 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1521 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1522 goto error;
1523 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1524 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1525 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1526 goto error;
1527 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1530 /* set dsBitfields values */
1531 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1533 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1534 bmp->dib.dsBitfields[0] = 0x7c00;
1535 bmp->dib.dsBitfields[1] = 0x03e0;
1536 bmp->dib.dsBitfields[2] = 0x001f;
1538 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1540 if (usage == DIB_PAL_COLORS) goto error;
1541 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1542 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1543 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1544 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1546 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1548 /* get storage location for DIB bits */
1550 if (section)
1552 SYSTEM_INFO SystemInfo;
1553 DWORD mapOffset;
1554 INT mapSize;
1556 GetSystemInfo( &SystemInfo );
1557 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1558 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1559 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1560 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1562 else
1564 offset = 0;
1565 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1566 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1568 bmp->dib.dshSection = section;
1569 bmp->dib.dsOffset = offset;
1571 if (!bmp->dib.dsBm.bmBits) goto error;
1573 if (!(ret = alloc_gdi_handle( &bmp->obj, OBJ_BITMAP, &dib_funcs ))) goto error;
1575 if (bits) *bits = bmp->dib.dsBm.bmBits;
1576 return ret;
1578 error:
1579 if (section) UnmapViewOfFile( mapBits );
1580 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1581 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1582 HeapFree( GetProcessHeap(), 0, bmp );
1583 return 0;
1587 /***********************************************************************
1588 * D3DKMTCreateDCFromMemory (GDI32.@)
1590 NTSTATUS WINAPI D3DKMTCreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1592 const struct d3dddi_format_info
1594 D3DDDIFORMAT format;
1595 unsigned int bit_count;
1596 DWORD compression;
1597 unsigned int palette_size;
1598 DWORD mask_r, mask_g, mask_b;
1599 } *format = NULL;
1600 BITMAPOBJ *bmp = NULL;
1601 HBITMAP bitmap;
1602 unsigned int i;
1603 HDC dc;
1605 static const struct d3dddi_format_info format_info[] =
1607 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1608 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1609 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1610 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1611 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1612 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1613 { D3DDDIFMT_A4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1614 { D3DDDIFMT_X4R4G4B4, 16, BI_BITFIELDS, 0, 0x00000f00, 0x000000f0, 0x0000000f },
1615 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1618 if (!desc) return STATUS_INVALID_PARAMETER;
1620 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1621 desc->pMemory, desc->Format, desc->Width, desc->Height,
1622 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1624 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1626 for (i = 0; i < ARRAY_SIZE( format_info ); ++i)
1628 if (format_info[i].format == desc->Format)
1630 format = &format_info[i];
1631 break;
1634 if (!format) return STATUS_INVALID_PARAMETER;
1636 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1637 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1638 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1640 if (!desc->hDeviceDc || !(dc = CreateCompatibleDC( desc->hDeviceDc ))) return STATUS_INVALID_PARAMETER;
1642 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) goto error;
1644 bmp->dib.dsBm.bmWidth = desc->Width;
1645 bmp->dib.dsBm.bmHeight = desc->Height;
1646 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1647 bmp->dib.dsBm.bmPlanes = 1;
1648 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1649 bmp->dib.dsBm.bmBits = desc->pMemory;
1651 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1652 bmp->dib.dsBmih.biWidth = desc->Width;
1653 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1654 bmp->dib.dsBmih.biPlanes = 1;
1655 bmp->dib.dsBmih.biBitCount = format->bit_count;
1656 bmp->dib.dsBmih.biCompression = format->compression;
1657 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1658 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1660 bmp->dib.dsBitfields[0] = format->mask_r;
1661 bmp->dib.dsBitfields[1] = format->mask_g;
1662 bmp->dib.dsBitfields[2] = format->mask_b;
1664 if (format->palette_size)
1666 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0, format->palette_size * sizeof(*bmp->color_table) )))
1667 goto error;
1668 if (desc->pColorTable)
1670 for (i = 0; i < format->palette_size; ++i)
1672 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1673 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1674 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1675 bmp->color_table[i].rgbReserved = 0;
1678 else
1680 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1681 format->palette_size * sizeof(*bmp->color_table) );
1685 if (!(bitmap = alloc_gdi_handle( &bmp->obj, OBJ_BITMAP, &dib_funcs ))) goto error;
1687 desc->hDc = dc;
1688 desc->hBitmap = bitmap;
1689 NtGdiSelectBitmap( dc, bitmap );
1690 return STATUS_SUCCESS;
1692 error:
1693 if (bmp) HeapFree( GetProcessHeap(), 0, bmp->color_table );
1694 HeapFree( GetProcessHeap(), 0, bmp );
1695 DeleteDC( dc );
1696 return STATUS_INVALID_PARAMETER;
1700 /***********************************************************************
1701 * D3DKMTDestroyDCFromMemory (GDI32.@)
1703 NTSTATUS WINAPI D3DKMTDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1705 if (!desc) return STATUS_INVALID_PARAMETER;
1707 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1709 if (GetObjectType( desc->hDc ) != OBJ_MEMDC ||
1710 GetObjectType( desc->hBitmap ) != OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1711 DeleteObject( desc->hBitmap );
1712 DeleteDC( desc->hDc );
1714 return STATUS_SUCCESS;
1718 /***********************************************************************
1719 * DIB_GetObject
1721 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1723 INT ret = 0;
1724 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1726 if (!bmp) return 0;
1728 if (!buffer) ret = sizeof(BITMAP);
1729 else if (count >= sizeof(DIBSECTION))
1731 DIBSECTION *dib = buffer;
1732 *dib = bmp->dib;
1733 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1734 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1735 ret = sizeof(DIBSECTION);
1737 else if (count >= sizeof(BITMAP))
1739 BITMAP *bitmap = buffer;
1740 *bitmap = bmp->dib.dsBm;
1741 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1742 ret = sizeof(BITMAP);
1745 GDI_ReleaseObj( handle );
1746 return ret;
1750 /***********************************************************************
1751 * DIB_DeleteObject
1753 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1755 BITMAPOBJ *bmp;
1757 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1759 if (bmp->dib.dshSection)
1761 SYSTEM_INFO SystemInfo;
1762 GetSystemInfo( &SystemInfo );
1763 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1764 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1766 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1768 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1769 HeapFree( GetProcessHeap(), 0, bmp );
1770 return TRUE;