wininet: Use return value of sprintf() instead of calling strlen() and simplify code.
[wine.git] / dlls / gdi32 / dib.c
blob585d2ac0d48378243cc5a946688832a595c897d4
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( const 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;
453 return TRUE;
455 fail:
456 if (run) DeleteObject( run );
457 if (clip && *clip) DeleteObject( *clip );
458 HeapFree( GetProcessHeap(), 0, out_bits );
459 return FALSE;
464 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
465 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
466 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
468 DC *dc = get_nulldrv_dc( dev );
469 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
470 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
471 struct bitblt_coords src, dst;
472 struct gdi_image_bits src_bits;
473 DWORD err;
474 HRGN clip = NULL;
475 INT ret = 0;
476 INT height = abs( src_info->bmiHeader.biHeight );
477 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
478 RECT rect;
480 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
481 xSrc, ySrc, widthSrc, heightSrc, rop);
483 src_bits.ptr = (void*)bits;
484 src_bits.is_copy = FALSE;
485 src_bits.free = NULL;
487 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
489 rect.left = xDst;
490 rect.top = yDst;
491 rect.right = xDst + widthDst;
492 rect.bottom = yDst + heightDst;
493 lp_to_dp( dc, (POINT *)&rect, 2 );
494 dst.x = rect.left;
495 dst.y = rect.top;
496 dst.width = rect.right - rect.left;
497 dst.height = rect.bottom - rect.top;
499 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
501 dst.x += dst.width;
502 dst.width = -dst.width;
504 rop &= ~NOMIRRORBITMAP;
506 src.x = xSrc;
507 src.width = widthSrc;
508 src.y = ySrc;
509 src.height = heightSrc;
511 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
512 non_stretch_from_origin = TRUE;
514 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
516 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
517 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
520 if (rop != SRCCOPY || non_stretch_from_origin)
522 if (dst.width == 1 && src.width > 1) src.width--;
523 if (dst.height == 1 && src.height > 1) src.height--;
526 if (rop != SRCCOPY)
528 if (dst.width < 0 && dst.width == src.width)
530 /* This is off-by-one, but that's what Windows does */
531 dst.x += dst.width;
532 src.x += src.width;
533 dst.width = -dst.width;
534 src.width = -src.width;
536 if (dst.height < 0 && dst.height == src.height)
538 dst.y += dst.height;
539 src.y += src.height;
540 dst.height = -dst.height;
541 src.height = -src.height;
545 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
547 if (src.y >= height && src.y + src.height + 1 < height)
548 src.y = height - 1;
549 else if (src.y > 0 && src.y + src.height + 1 < 0)
550 src.y = -src.height - 1;
552 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
554 src.visrect.left = 0;
555 src.visrect.right = src_info->bmiHeader.biWidth;
556 src.visrect.top = 0;
557 src.visrect.bottom = height;
558 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
560 if (rop == SRCCOPY) ret = height;
561 else ret = src_info->bmiHeader.biHeight;
563 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
565 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
567 if (!intersect_vis_rectangles( &dst, &src )) goto done;
569 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
571 dev = GET_DC_PHYSDEV( dc, pPutImage );
572 copy_bitmapinfo( dst_info, src_info );
573 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
574 if (err == ERROR_BAD_FORMAT)
576 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
578 /* 1-bpp destination without a color table requires a fake 1-entry table
579 * that contains only the background color; except with a 1-bpp source,
580 * in which case it uses the source colors */
581 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
583 if (src_info->bmiHeader.biBitCount > 1)
584 get_mono_dc_colors( dc, dst_info, 1 );
585 else
587 memcpy( dst_info->bmiColors, src_info->bmiColors, 2 * sizeof(dst_info->bmiColors[0]) );
588 dst_info->bmiHeader.biClrUsed = 2;
592 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
594 /* get rid of the fake 1-bpp table */
595 dst_info->bmiHeader.biClrUsed = dst_colors;
596 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
600 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
602 copy_bitmapinfo( src_info, dst_info );
603 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, dc->stretchBltMode );
604 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
606 if (err) ret = 0;
608 done:
609 if (src_bits.free) src_bits.free( &src_bits );
610 if (clip) DeleteObject( clip );
611 return ret;
614 /***********************************************************************
615 * StretchDIBits (GDI32.@)
617 INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
618 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
619 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
620 DWORD rop )
622 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
623 BITMAPINFO *info = (BITMAPINFO *)buffer;
624 PHYSDEV physdev;
625 DC *dc;
626 INT ret = 0;
628 if (!bits) return 0;
629 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
631 SetLastError( ERROR_INVALID_PARAMETER );
632 return 0;
635 if ((dc = get_dc_ptr( hdc )))
637 update_dc( dc );
638 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
639 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
640 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
641 release_dc_ptr( dc );
643 return ret;
647 /******************************************************************************
648 * SetDIBits [GDI32.@]
650 * Sets pixels in a bitmap using colors from DIB.
652 * PARAMS
653 * hdc [I] Handle to device context
654 * hbitmap [I] Handle to bitmap
655 * startscan [I] Starting scan line
656 * lines [I] Number of scan lines
657 * bits [I] Array of bitmap bits
658 * info [I] Address of structure with data
659 * coloruse [I] Type of color indexes to use
661 * RETURNS
662 * Success: Number of scan lines copied
663 * Failure: 0
665 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
666 UINT lines, LPCVOID bits, const BITMAPINFO *info,
667 UINT coloruse )
669 BITMAPOBJ *bitmap;
670 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
671 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
672 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
673 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
674 INT result = 0;
675 DWORD err;
676 struct gdi_image_bits src_bits;
677 struct bitblt_coords src, dst;
678 INT src_to_dst_offset;
679 HRGN clip = 0;
681 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
683 SetLastError( ERROR_INVALID_PARAMETER );
684 return 0;
686 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
688 DWORD *masks = (DWORD *)src_info->bmiColors;
689 if (!masks[0] || !masks[1] || !masks[2])
691 SetLastError( ERROR_INVALID_PARAMETER );
692 return 0;
696 src_bits.ptr = (void *)bits;
697 src_bits.is_copy = FALSE;
698 src_bits.free = NULL;
699 src_bits.param = NULL;
701 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
703 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
705 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
707 if (lines == 0) goto done;
708 else lines = src_info->bmiHeader.biHeight;
709 startscan = 0;
711 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
714 dst.visrect.left = 0;
715 dst.visrect.top = 0;
716 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
717 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
719 src.visrect.left = 0;
720 src.visrect.top = 0;
721 src.visrect.right = src_info->bmiHeader.biWidth;
722 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
724 if (src_info->bmiHeader.biHeight > 0)
726 src_to_dst_offset = -startscan;
727 lines = min( lines, src.visrect.bottom - startscan );
728 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
730 else
732 src_to_dst_offset = src.visrect.bottom - lines - startscan;
733 /* Unlike the bottom-up case, Windows doesn't limit lines. */
734 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
737 result = lines;
739 offset_rect( &src.visrect, 0, src_to_dst_offset );
740 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
741 src.visrect = dst.visrect;
742 offset_rect( &src.visrect, 0, -src_to_dst_offset );
744 src.x = src.visrect.left;
745 src.y = src.visrect.top;
746 src.width = src.visrect.right - src.visrect.left;
747 src.height = src.visrect.bottom - src.visrect.top;
749 dst.x = dst.visrect.left;
750 dst.y = dst.visrect.top;
751 dst.width = dst.visrect.right - dst.visrect.left;
752 dst.height = dst.visrect.bottom - dst.visrect.top;
754 copy_bitmapinfo( dst_info, src_info );
756 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
757 if (err == ERROR_BAD_FORMAT)
759 err = convert_bits( src_info, &src, dst_info, &src_bits );
760 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
762 if(err) result = 0;
764 done:
765 if (src_bits.free) src_bits.free( &src_bits );
766 if (clip) DeleteObject( clip );
767 GDI_ReleaseObj( hbitmap );
768 return result;
772 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
773 INT x_src, INT y_src, UINT startscan, UINT lines,
774 const void *bits, BITMAPINFO *src_info, UINT coloruse )
776 DC *dc = get_nulldrv_dc( dev );
777 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
778 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
779 struct bitblt_coords src, dst;
780 struct gdi_image_bits src_bits;
781 HRGN clip = 0;
782 DWORD err;
783 UINT height;
784 BOOL top_down;
785 POINT pt;
786 RECT rect;
788 top_down = (src_info->bmiHeader.biHeight < 0);
789 height = abs( src_info->bmiHeader.biHeight );
791 src_bits.ptr = (void *)bits;
792 src_bits.is_copy = FALSE;
793 src_bits.free = NULL;
795 if (!lines) return 0;
796 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
798 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
800 startscan = 0;
801 lines = height;
802 src_info->bmiHeader.biWidth = x_src + cx;
803 src_info->bmiHeader.biHeight = y_src + cy;
804 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
805 src.x = x_src;
806 src.y = 0;
807 src.width = cx;
808 src.height = cy;
809 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
811 else
813 if (startscan >= height) return 0;
814 if (!top_down && lines > height - startscan) lines = height - startscan;
816 /* map src to top-down coordinates with startscan as origin */
817 src.x = x_src;
818 src.y = startscan + lines - (y_src + cy);
819 src.width = cx;
820 src.height = cy;
821 if (src.y > 0)
823 if (!top_down)
825 /* get rid of unnecessary lines */
826 if (src.y >= lines) return 0;
827 lines -= src.y;
828 src.y = 0;
830 else if (src.y >= lines) return lines;
832 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
835 src.visrect.left = src.x;
836 src.visrect.top = src.y;
837 src.visrect.right = src.x + cx;
838 src.visrect.bottom = src.y + cy;
839 rect.left = 0;
840 rect.top = 0;
841 rect.right = src_info->bmiHeader.biWidth;
842 rect.bottom = abs( src_info->bmiHeader.biHeight );
843 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
845 lines = 0;
846 goto done;
849 pt.x = x_dst;
850 pt.y = y_dst;
851 lp_to_dp( dc, &pt, 1 );
852 dst.x = pt.x;
853 dst.y = pt.y;
854 dst.width = cx;
855 dst.height = cy;
856 if (dc->layout & LAYOUT_RTL) dst.x -= cx - 1;
858 rect.left = dst.x;
859 rect.top = dst.y;
860 rect.right = dst.x + cx;
861 rect.bottom = dst.y + cy;
862 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
864 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
865 intersect_rect( &rect, &src.visrect, &dst.visrect );
866 src.visrect = dst.visrect = rect;
867 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
868 if (is_rect_empty( &dst.visrect )) goto done;
869 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
871 dev = GET_DC_PHYSDEV( dc, pPutImage );
872 copy_bitmapinfo( dst_info, src_info );
873 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
874 if (err == ERROR_BAD_FORMAT)
876 err = convert_bits( src_info, &src, dst_info, &src_bits );
877 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
879 if (err) lines = 0;
881 done:
882 if (src_bits.free) src_bits.free( &src_bits );
883 if (clip) DeleteObject( clip );
884 return lines;
887 /***********************************************************************
888 * SetDIBitsToDevice (GDI32.@)
890 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
891 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
892 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
893 UINT coloruse )
895 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
896 BITMAPINFO *info = (BITMAPINFO *)buffer;
897 PHYSDEV physdev;
898 INT ret = 0;
899 DC *dc;
901 if (!bits) return 0;
902 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
904 SetLastError( ERROR_INVALID_PARAMETER );
905 return 0;
908 if ((dc = get_dc_ptr( hdc )))
910 update_dc( dc );
911 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
912 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
913 ySrc, startscan, lines, bits, info, coloruse );
914 release_dc_ptr( dc );
916 return ret;
919 /***********************************************************************
920 * SetDIBColorTable (GDI32.@)
922 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
924 DC * dc;
925 UINT result = 0;
926 BITMAPOBJ * bitmap;
928 if (!(dc = get_dc_ptr( hdc ))) return 0;
930 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
932 if (startpos < bitmap->dib.dsBmih.biClrUsed)
934 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
935 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
937 GDI_ReleaseObj( dc->hBitmap );
939 if (result) /* update colors of selected objects */
941 SetTextColor( hdc, dc->textColor );
942 SetBkColor( hdc, dc->backgroundColor );
943 SelectObject( hdc, dc->hPen );
944 SelectObject( 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;
1049 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1051 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1052 /* bitfields are always at bmiColors even in larger structures */
1053 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1054 else if (src->bmiHeader.biClrUsed)
1056 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1057 unsigned int size;
1059 if (coloruse == DIB_PAL_COLORS)
1060 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1061 else
1062 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1063 memcpy( colorptr, src->bmiColors, size );
1068 const RGBQUAD *get_default_color_table( int bpp )
1070 static const RGBQUAD table_1[2] =
1072 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1074 static const RGBQUAD table_4[16] =
1076 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1077 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1078 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1079 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1081 static const RGBQUAD table_8[256] =
1083 /* first and last 10 entries are the default system palette entries */
1084 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1085 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1086 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1087 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1088 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1089 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1090 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1091 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1092 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1093 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1094 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1095 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1096 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1097 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1098 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1099 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1100 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1101 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1102 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1103 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1104 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1105 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1106 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1107 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1108 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1109 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1110 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1111 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1112 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1113 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1114 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1115 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1116 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1117 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1118 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1119 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1120 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1121 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1122 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1123 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1124 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1125 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1126 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1127 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1128 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1129 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1130 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1131 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1132 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1133 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1134 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1135 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1136 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1137 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1138 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1139 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1140 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1141 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1142 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1143 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1144 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1145 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1146 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1147 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1150 switch (bpp)
1152 case 1: return table_1;
1153 case 4: return table_4;
1154 case 8: return table_8;
1155 default: return NULL;
1159 void fill_default_color_table( BITMAPINFO *info )
1161 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1162 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1163 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1166 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1168 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1169 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1170 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1171 info->bmiHeader.biPlanes = 1;
1172 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1173 info->bmiHeader.biCompression = BI_RGB;
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 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 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1386 copy_color_info( dst_info, src_info, coloruse );
1388 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1390 if( coloruse == DIB_PAL_COLORS )
1392 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1394 else
1396 fill_default_color_table( dst_info );
1400 if (bits)
1402 if(dst_info->bmiHeader.biHeight > 0)
1403 dst_info->bmiHeader.biHeight = src.height;
1404 else
1405 dst_info->bmiHeader.biHeight = -src.height;
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)) info->bmiHeader.biClrUsed = 0;
1424 done:
1425 release_dc_ptr( dc );
1426 GDI_ReleaseObj( hbitmap );
1427 return ret;
1431 /***********************************************************************
1432 * CreateDIBitmap (GDI32.@)
1434 * Creates a DDB (device dependent bitmap) from a DIB.
1435 * The DDB will have the same color depth as the reference DC.
1437 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1438 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1439 UINT coloruse )
1441 BITMAPINFOHEADER info;
1442 HBITMAP handle;
1443 LONG height;
1445 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1446 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1447 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1448 if (info.biWidth < 0) return 0;
1450 /* Top-down DIBs have a negative height */
1451 height = abs( info.biHeight );
1453 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1454 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1455 info.biBitCount, info.biCompression);
1457 if (hdc == NULL)
1458 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1459 else
1460 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1462 if (handle)
1464 if (init & CBM_INIT)
1466 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1468 DeleteObject( handle );
1469 handle = 0;
1474 return handle;
1478 /***********************************************************************
1479 * CreateDIBSection (GDI32.@)
1481 HBITMAP WINAPI DECLSPEC_HOTPATCH CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1482 void **bits, HANDLE section, DWORD offset)
1484 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1485 BITMAPINFO *info = (BITMAPINFO *)buffer;
1486 HBITMAP ret = 0;
1487 BITMAPOBJ *bmp;
1488 void *mapBits = NULL;
1490 if (bits) *bits = NULL;
1491 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1492 if (usage > DIB_PAL_COLORS) return 0;
1493 if (info->bmiHeader.biPlanes != 1)
1495 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1496 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1499 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1501 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1502 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1503 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1504 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1505 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1507 bmp->dib.dsBm.bmType = 0;
1508 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1509 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1510 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1511 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1512 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1513 bmp->dib.dsBmih = info->bmiHeader;
1515 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1517 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1518 goto error;
1519 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1520 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1521 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1522 goto error;
1523 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1526 /* set dsBitfields values */
1527 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1529 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1530 bmp->dib.dsBitfields[0] = 0x7c00;
1531 bmp->dib.dsBitfields[1] = 0x03e0;
1532 bmp->dib.dsBitfields[2] = 0x001f;
1534 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1536 if (usage == DIB_PAL_COLORS) goto error;
1537 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1538 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1539 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1540 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1542 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1544 /* get storage location for DIB bits */
1546 if (section)
1548 SYSTEM_INFO SystemInfo;
1549 DWORD mapOffset;
1550 INT mapSize;
1552 GetSystemInfo( &SystemInfo );
1553 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1554 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1555 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1556 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1558 else
1560 offset = 0;
1561 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1562 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1564 bmp->dib.dshSection = section;
1565 bmp->dib.dsOffset = offset;
1567 if (!bmp->dib.dsBm.bmBits) goto error;
1569 if (!(ret = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1571 if (bits) *bits = bmp->dib.dsBm.bmBits;
1572 return ret;
1574 error:
1575 if (section) UnmapViewOfFile( mapBits );
1576 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1577 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1578 HeapFree( GetProcessHeap(), 0, bmp );
1579 return 0;
1583 /***********************************************************************
1584 * D3DKMTCreateDCFromMemory (GDI32.@)
1586 NTSTATUS WINAPI D3DKMTCreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1588 const struct d3dddi_format_info
1590 D3DDDIFORMAT format;
1591 unsigned int bit_count;
1592 DWORD compression;
1593 unsigned int palette_size;
1594 DWORD mask_r, mask_g, mask_b;
1595 } *format = NULL;
1596 BITMAPOBJ *bmp = NULL;
1597 HBITMAP bitmap;
1598 unsigned int i;
1599 HDC dc;
1601 static const struct d3dddi_format_info format_info[] =
1603 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1604 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1605 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1606 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1607 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1608 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1609 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1612 if (!desc) return STATUS_INVALID_PARAMETER;
1614 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1615 desc->pMemory, desc->Format, desc->Width, desc->Height,
1616 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1618 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1620 for (i = 0; i < sizeof(format_info) / sizeof(*format_info); ++i)
1622 if (format_info[i].format == desc->Format)
1624 format = &format_info[i];
1625 break;
1628 if (!format) return STATUS_INVALID_PARAMETER;
1630 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1631 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1632 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1634 if (!desc->hDeviceDc || !(dc = CreateCompatibleDC( desc->hDeviceDc ))) return STATUS_INVALID_PARAMETER;
1636 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) goto error;
1638 bmp->dib.dsBm.bmWidth = desc->Width;
1639 bmp->dib.dsBm.bmHeight = desc->Height;
1640 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1641 bmp->dib.dsBm.bmPlanes = 1;
1642 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1643 bmp->dib.dsBm.bmBits = desc->pMemory;
1645 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1646 bmp->dib.dsBmih.biWidth = desc->Width;
1647 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1648 bmp->dib.dsBmih.biPlanes = 1;
1649 bmp->dib.dsBmih.biBitCount = format->bit_count;
1650 bmp->dib.dsBmih.biCompression = format->compression;
1651 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1652 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1654 bmp->dib.dsBitfields[0] = format->mask_r;
1655 bmp->dib.dsBitfields[1] = format->mask_g;
1656 bmp->dib.dsBitfields[2] = format->mask_b;
1658 if (format->palette_size)
1660 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0, format->palette_size * sizeof(*bmp->color_table) )))
1661 goto error;
1662 if (desc->pColorTable)
1664 for (i = 0; i < format->palette_size; ++i)
1666 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1667 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1668 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1669 bmp->color_table[i].rgbReserved = 0;
1672 else
1674 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1675 format->palette_size * sizeof(*bmp->color_table) );
1679 if (!(bitmap = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1681 desc->hDc = dc;
1682 desc->hBitmap = bitmap;
1683 SelectObject( dc, bitmap );
1684 return STATUS_SUCCESS;
1686 error:
1687 if (bmp) HeapFree( GetProcessHeap(), 0, bmp->color_table );
1688 HeapFree( GetProcessHeap(), 0, bmp );
1689 DeleteDC( dc );
1690 return STATUS_INVALID_PARAMETER;
1694 /***********************************************************************
1695 * D3DKMTDestroyDCFromMemory (GDI32.@)
1697 NTSTATUS WINAPI D3DKMTDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1699 if (!desc) return STATUS_INVALID_PARAMETER;
1701 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1703 if (GetObjectType( desc->hDc ) != OBJ_MEMDC ||
1704 GetObjectType( desc->hBitmap ) != OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1705 DeleteObject( desc->hBitmap );
1706 DeleteDC( desc->hDc );
1708 return STATUS_SUCCESS;
1712 /***********************************************************************
1713 * DIB_SelectObject
1715 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1717 HGDIOBJ ret;
1718 BITMAPOBJ *bitmap;
1719 DC *dc;
1720 PHYSDEV physdev;
1722 if (!(dc = get_dc_ptr( hdc ))) return 0;
1724 if (GetObjectType( hdc ) != OBJ_MEMDC)
1726 ret = 0;
1727 goto done;
1729 ret = dc->hBitmap;
1730 if (handle == dc->hBitmap) goto done; /* nothing to do */
1732 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1734 ret = 0;
1735 goto done;
1738 if (GDI_get_ref_count( handle ))
1740 WARN( "Bitmap already selected in another DC\n" );
1741 GDI_ReleaseObj( handle );
1742 ret = 0;
1743 goto done;
1746 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1747 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1749 GDI_ReleaseObj( handle );
1750 ret = 0;
1752 else
1754 dc->hBitmap = handle;
1755 GDI_inc_ref_count( handle );
1756 dc->dirty = 0;
1757 dc->vis_rect.left = 0;
1758 dc->vis_rect.top = 0;
1759 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1760 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1761 dc->device_rect = dc->vis_rect;
1762 GDI_ReleaseObj( handle );
1763 DC_InitDC( dc );
1764 GDI_dec_ref_count( ret );
1767 done:
1768 release_dc_ptr( dc );
1769 return ret;
1773 /***********************************************************************
1774 * DIB_GetObject
1776 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1778 INT ret = 0;
1779 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1781 if (!bmp) return 0;
1783 if (!buffer) ret = sizeof(BITMAP);
1784 else if (count >= sizeof(DIBSECTION))
1786 DIBSECTION *dib = buffer;
1787 *dib = bmp->dib;
1788 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1789 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1790 ret = sizeof(DIBSECTION);
1792 else if (count >= sizeof(BITMAP))
1794 BITMAP *bitmap = buffer;
1795 *bitmap = bmp->dib.dsBm;
1796 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1797 ret = sizeof(BITMAP);
1800 GDI_ReleaseObj( handle );
1801 return ret;
1805 /***********************************************************************
1806 * DIB_DeleteObject
1808 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1810 BITMAPOBJ *bmp;
1812 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1814 if (bmp->dib.dshSection)
1816 SYSTEM_INFO SystemInfo;
1817 GetSystemInfo( &SystemInfo );
1818 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1819 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1821 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1823 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1824 return HeapFree( GetProcessHeap(), 0, bmp );