ole32: Rightmost spelling fix.
[wine.git] / dlls / gdi32 / dib.c
blobad2bf4f2d90f1cd187e737d253eaac7c72953dfe
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 LPtoDP( dc->hSelf, (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)
585 COLORREF color = GetBkColor( dev->hdc );
586 dst_info->bmiColors[0].rgbRed = GetRValue( color );
587 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
588 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
589 dst_info->bmiColors[0].rgbReserved = 0;
590 dst_info->bmiHeader.biClrUsed = 1;
592 else
594 memcpy( dst_info->bmiColors, src_info->bmiColors, 2 * sizeof(dst_info->bmiColors[0]) );
595 dst_info->bmiHeader.biClrUsed = 2;
599 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
601 /* get rid of the fake 1-bpp table */
602 dst_info->bmiHeader.biClrUsed = dst_colors;
603 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
607 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
609 copy_bitmapinfo( src_info, dst_info );
610 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
611 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
613 if (err) ret = 0;
615 done:
616 if (src_bits.free) src_bits.free( &src_bits );
617 if (clip) DeleteObject( clip );
618 return ret;
621 /***********************************************************************
622 * StretchDIBits (GDI32.@)
624 INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
625 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
626 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
627 DWORD rop )
629 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
630 BITMAPINFO *info = (BITMAPINFO *)buffer;
631 PHYSDEV physdev;
632 DC *dc;
633 INT ret = 0;
635 if (!bits) return 0;
636 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
638 SetLastError( ERROR_INVALID_PARAMETER );
639 return 0;
642 if ((dc = get_dc_ptr( hdc )))
644 update_dc( dc );
645 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
646 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
647 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
648 release_dc_ptr( dc );
650 return ret;
654 /******************************************************************************
655 * SetDIBits [GDI32.@]
657 * Sets pixels in a bitmap using colors from DIB.
659 * PARAMS
660 * hdc [I] Handle to device context
661 * hbitmap [I] Handle to bitmap
662 * startscan [I] Starting scan line
663 * lines [I] Number of scan lines
664 * bits [I] Array of bitmap bits
665 * info [I] Address of structure with data
666 * coloruse [I] Type of color indexes to use
668 * RETURNS
669 * Success: Number of scan lines copied
670 * Failure: 0
672 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
673 UINT lines, LPCVOID bits, const BITMAPINFO *info,
674 UINT coloruse )
676 BITMAPOBJ *bitmap;
677 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
678 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
679 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
680 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
681 INT result = 0;
682 DWORD err;
683 struct gdi_image_bits src_bits;
684 struct bitblt_coords src, dst;
685 INT src_to_dst_offset;
686 HRGN clip = 0;
688 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
690 SetLastError( ERROR_INVALID_PARAMETER );
691 return 0;
693 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
695 DWORD *masks = (DWORD *)src_info->bmiColors;
696 if (!masks[0] || !masks[1] || !masks[2])
698 SetLastError( ERROR_INVALID_PARAMETER );
699 return 0;
703 src_bits.ptr = (void *)bits;
704 src_bits.is_copy = FALSE;
705 src_bits.free = NULL;
706 src_bits.param = NULL;
708 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
710 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
712 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
714 if (lines == 0) goto done;
715 else lines = src_info->bmiHeader.biHeight;
716 startscan = 0;
718 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
721 dst.visrect.left = 0;
722 dst.visrect.top = 0;
723 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
724 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
726 src.visrect.left = 0;
727 src.visrect.top = 0;
728 src.visrect.right = src_info->bmiHeader.biWidth;
729 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
731 if (src_info->bmiHeader.biHeight > 0)
733 src_to_dst_offset = -startscan;
734 lines = min( lines, src.visrect.bottom - startscan );
735 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
737 else
739 src_to_dst_offset = src.visrect.bottom - lines - startscan;
740 /* Unlike the bottom-up case, Windows doesn't limit lines. */
741 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
744 result = lines;
746 offset_rect( &src.visrect, 0, src_to_dst_offset );
747 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
748 src.visrect = dst.visrect;
749 offset_rect( &src.visrect, 0, -src_to_dst_offset );
751 src.x = src.visrect.left;
752 src.y = src.visrect.top;
753 src.width = src.visrect.right - src.visrect.left;
754 src.height = src.visrect.bottom - src.visrect.top;
756 dst.x = dst.visrect.left;
757 dst.y = dst.visrect.top;
758 dst.width = dst.visrect.right - dst.visrect.left;
759 dst.height = dst.visrect.bottom - dst.visrect.top;
761 copy_bitmapinfo( dst_info, src_info );
763 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
764 if (err == ERROR_BAD_FORMAT)
766 err = convert_bits( src_info, &src, dst_info, &src_bits );
767 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
769 if(err) result = 0;
771 done:
772 if (src_bits.free) src_bits.free( &src_bits );
773 if (clip) DeleteObject( clip );
774 GDI_ReleaseObj( hbitmap );
775 return result;
779 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
780 INT x_src, INT y_src, UINT startscan, UINT lines,
781 const void *bits, BITMAPINFO *src_info, UINT coloruse )
783 DC *dc = get_nulldrv_dc( dev );
784 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
785 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
786 struct bitblt_coords src, dst;
787 struct gdi_image_bits src_bits;
788 HRGN clip = 0;
789 DWORD err;
790 UINT height;
791 BOOL top_down;
792 POINT pt;
793 RECT rect;
795 top_down = (src_info->bmiHeader.biHeight < 0);
796 height = abs( src_info->bmiHeader.biHeight );
798 src_bits.ptr = (void *)bits;
799 src_bits.is_copy = FALSE;
800 src_bits.free = NULL;
802 if (!lines) return 0;
803 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
805 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
807 startscan = 0;
808 lines = height;
809 src_info->bmiHeader.biWidth = x_src + cx;
810 src_info->bmiHeader.biHeight = y_src + cy;
811 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
812 src.x = x_src;
813 src.y = 0;
814 src.width = cx;
815 src.height = cy;
816 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
818 else
820 if (startscan >= height) return 0;
821 if (!top_down && lines > height - startscan) lines = height - startscan;
823 /* map src to top-down coordinates with startscan as origin */
824 src.x = x_src;
825 src.y = startscan + lines - (y_src + cy);
826 src.width = cx;
827 src.height = cy;
828 if (src.y > 0)
830 if (!top_down)
832 /* get rid of unnecessary lines */
833 if (src.y >= lines) return 0;
834 lines -= src.y;
835 src.y = 0;
837 else if (src.y >= lines) return lines;
839 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
842 src.visrect.left = src.x;
843 src.visrect.top = src.y;
844 src.visrect.right = src.x + cx;
845 src.visrect.bottom = src.y + cy;
846 rect.left = 0;
847 rect.top = 0;
848 rect.right = src_info->bmiHeader.biWidth;
849 rect.bottom = abs( src_info->bmiHeader.biHeight );
850 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
852 lines = 0;
853 goto done;
856 pt.x = x_dst;
857 pt.y = y_dst;
858 LPtoDP( dev->hdc, &pt, 1 );
859 dst.x = pt.x;
860 dst.y = pt.y;
861 dst.width = cx;
862 dst.height = cy;
863 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
865 rect.left = dst.x;
866 rect.top = dst.y;
867 rect.right = dst.x + cx;
868 rect.bottom = dst.y + cy;
869 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
871 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
872 intersect_rect( &rect, &src.visrect, &dst.visrect );
873 src.visrect = dst.visrect = rect;
874 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
875 if (is_rect_empty( &dst.visrect )) goto done;
876 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
878 dev = GET_DC_PHYSDEV( dc, pPutImage );
879 copy_bitmapinfo( dst_info, src_info );
880 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
881 if (err == ERROR_BAD_FORMAT)
883 err = convert_bits( src_info, &src, dst_info, &src_bits );
884 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
886 if (err) lines = 0;
888 done:
889 if (src_bits.free) src_bits.free( &src_bits );
890 if (clip) DeleteObject( clip );
891 return lines;
894 /***********************************************************************
895 * SetDIBitsToDevice (GDI32.@)
897 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
898 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
899 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
900 UINT coloruse )
902 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
903 BITMAPINFO *info = (BITMAPINFO *)buffer;
904 PHYSDEV physdev;
905 INT ret = 0;
906 DC *dc;
908 if (!bits) return 0;
909 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
911 SetLastError( ERROR_INVALID_PARAMETER );
912 return 0;
915 if ((dc = get_dc_ptr( hdc )))
917 update_dc( dc );
918 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
919 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
920 ySrc, startscan, lines, bits, info, coloruse );
921 release_dc_ptr( dc );
923 return ret;
926 /***********************************************************************
927 * SetDIBColorTable (GDI32.@)
929 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
931 DC * dc;
932 UINT result = 0;
933 BITMAPOBJ * bitmap;
935 if (!(dc = get_dc_ptr( hdc ))) return 0;
937 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
939 if (startpos < bitmap->dib.dsBmih.biClrUsed)
941 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
942 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
944 GDI_ReleaseObj( dc->hBitmap );
946 if (result) /* update colors of selected objects */
948 SetTextColor( hdc, dc->textColor );
949 SetBkColor( hdc, dc->backgroundColor );
950 SelectObject( hdc, dc->hPen );
951 SelectObject( hdc, dc->hBrush );
954 release_dc_ptr( dc );
955 return result;
959 /***********************************************************************
960 * GetDIBColorTable (GDI32.@)
962 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
964 DC * dc;
965 BITMAPOBJ *bitmap;
966 UINT result = 0;
968 if (!(dc = get_dc_ptr( hdc ))) return 0;
970 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
972 if (startpos < bitmap->dib.dsBmih.biClrUsed)
974 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
975 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
977 GDI_ReleaseObj( dc->hBitmap );
979 release_dc_ptr( dc );
980 return result;
983 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
984 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
986 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
988 BITMAPINFOHEADER header;
990 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
991 header.biWidth = bmp->dib.dsBm.bmWidth;
992 header.biHeight = bmp->dib.dsBm.bmHeight;
993 header.biPlanes = 1;
994 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
996 switch (header.biBitCount)
998 case 16:
999 case 32:
1000 header.biCompression = BI_BITFIELDS;
1001 break;
1002 default:
1003 header.biCompression = BI_RGB;
1004 break;
1007 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
1008 header.biXPelsPerMeter = 0;
1009 header.biYPelsPerMeter = 0;
1010 header.biClrUsed = 0;
1011 header.biClrImportant = 0;
1013 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
1015 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
1017 coreheader->bcWidth = header.biWidth;
1018 coreheader->bcHeight = header.biHeight;
1019 coreheader->bcPlanes = header.biPlanes;
1020 coreheader->bcBitCount = header.biBitCount;
1022 else
1023 info->bmiHeader = header;
1025 return bmp->dib.dsBm.bmHeight;
1028 /************************************************************************
1029 * copy_color_info
1031 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1033 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1035 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1037 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1039 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1040 if (coloruse == DIB_PAL_COLORS)
1041 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1042 else
1044 unsigned int i;
1045 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1047 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1048 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1049 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1053 else
1055 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1056 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1058 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1059 /* bitfields are always at bmiColors even in larger structures */
1060 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1061 else if (src->bmiHeader.biClrUsed)
1063 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1064 unsigned int size;
1066 if (coloruse == DIB_PAL_COLORS)
1067 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1068 else
1069 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1070 memcpy( colorptr, src->bmiColors, size );
1075 const RGBQUAD *get_default_color_table( int bpp )
1077 static const RGBQUAD table_1[2] =
1079 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1081 static const RGBQUAD table_4[16] =
1083 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1084 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1085 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1086 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1088 static const RGBQUAD table_8[256] =
1090 /* first and last 10 entries are the default system palette entries */
1091 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1092 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1093 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1094 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1095 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1096 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1097 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1098 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1099 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1100 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1101 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1102 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1103 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1104 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1105 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1106 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1107 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1108 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1109 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1110 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1111 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1112 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1113 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1114 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1115 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1116 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1117 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1118 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1119 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1120 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1121 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1122 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1123 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1124 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1125 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1126 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1127 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1128 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1129 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1130 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1131 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1132 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1133 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1134 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1135 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1136 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1137 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1138 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1139 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1140 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1141 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1142 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1143 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1144 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1145 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1146 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1147 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1148 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1149 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1150 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1151 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1152 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1153 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1154 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1157 switch (bpp)
1159 case 1: return table_1;
1160 case 4: return table_4;
1161 case 8: return table_8;
1162 default: return NULL;
1166 void fill_default_color_table( BITMAPINFO *info )
1168 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1169 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1170 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1173 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1175 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1176 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1177 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1178 info->bmiHeader.biPlanes = 1;
1179 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1180 info->bmiHeader.biCompression = BI_RGB;
1181 info->bmiHeader.biXPelsPerMeter = 0;
1182 info->bmiHeader.biYPelsPerMeter = 0;
1183 info->bmiHeader.biClrUsed = 0;
1184 info->bmiHeader.biClrImportant = 0;
1187 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1189 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1190 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1191 unsigned int info_size;
1193 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1195 info_size = get_dib_info_size( info, usage );
1196 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1198 memcpy( ret, info, info_size );
1199 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1200 info->bmiHeader.biSizeImage );
1202 return ret;
1205 /******************************************************************************
1206 * GetDIBits [GDI32.@]
1208 * Retrieves bits of bitmap and copies to buffer.
1210 * RETURNS
1211 * Success: Number of scan lines copied from bitmap
1212 * Failure: 0
1214 INT WINAPI GetDIBits(
1215 HDC hdc, /* [in] Handle to device context */
1216 HBITMAP hbitmap, /* [in] Handle to bitmap */
1217 UINT startscan, /* [in] First scan line to set in dest bitmap */
1218 UINT lines, /* [in] Number of scan lines to copy */
1219 LPVOID bits, /* [out] Address of array for bitmap bits */
1220 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1221 UINT coloruse) /* [in] RGB or palette index */
1223 DC * dc;
1224 BITMAPOBJ * bmp;
1225 int i, dst_to_src_offset, ret = 0;
1226 DWORD err;
1227 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1228 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1229 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1230 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1231 struct gdi_image_bits src_bits;
1232 struct bitblt_coords src, dst;
1233 BOOL empty_rect = FALSE;
1235 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1236 own copy and transfer the colour info back at the end */
1237 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1238 if (coloruse > DIB_PAL_COLORS) return 0;
1239 if (bits &&
1240 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1241 return 0;
1242 dst_info->bmiHeader.biClrUsed = 0;
1243 dst_info->bmiHeader.biClrImportant = 0;
1245 if (!(dc = get_dc_ptr( hdc )))
1247 SetLastError( ERROR_INVALID_PARAMETER );
1248 return 0;
1250 update_dc( dc );
1251 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1253 release_dc_ptr( dc );
1254 return 0;
1257 src.visrect.left = 0;
1258 src.visrect.top = 0;
1259 src.visrect.right = bmp->dib.dsBm.bmWidth;
1260 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1262 dst.visrect.left = 0;
1263 dst.visrect.top = 0;
1264 dst.visrect.right = dst_info->bmiHeader.biWidth;
1265 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1267 if (lines == 0 || startscan >= dst.visrect.bottom)
1268 bits = NULL;
1270 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1272 ret = fill_query_info( info, bmp );
1273 goto done;
1276 /* validate parameters */
1278 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1279 if (dst_info->bmiHeader.biHeight == 0) goto done;
1281 switch (dst_info->bmiHeader.biCompression)
1283 case BI_RLE4:
1284 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1285 if (dst_info->bmiHeader.biHeight < 0) goto done;
1286 if (bits) goto done; /* can't retrieve compressed bits */
1287 break;
1288 case BI_RLE8:
1289 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1290 if (dst_info->bmiHeader.biHeight < 0) goto done;
1291 if (bits) goto done; /* can't retrieve compressed bits */
1292 break;
1293 case BI_BITFIELDS:
1294 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1295 /* fall through */
1296 case BI_RGB:
1297 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1298 if (dst_info->bmiHeader.biBitCount == 1) break;
1299 if (dst_info->bmiHeader.biBitCount == 4) break;
1300 if (dst_info->bmiHeader.biBitCount == 8) break;
1301 if (dst_info->bmiHeader.biBitCount == 16) break;
1302 if (dst_info->bmiHeader.biBitCount == 24) break;
1303 if (dst_info->bmiHeader.biBitCount == 32) break;
1304 /* fall through */
1305 default:
1306 goto done;
1309 if (bits)
1311 if (dst_info->bmiHeader.biHeight > 0)
1313 dst_to_src_offset = -startscan;
1314 lines = min( lines, dst.visrect.bottom - startscan );
1315 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1317 else
1319 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1320 if (dst_to_src_offset < 0)
1322 dst_to_src_offset = 0;
1323 lines = dst.visrect.bottom - startscan;
1325 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1328 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1329 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1330 dst.visrect = src.visrect;
1331 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1333 if (dst_info->bmiHeader.biHeight > 0)
1335 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1337 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1338 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1339 memset( bits, 0, pad_bytes );
1340 bits = (char *)bits + pad_bytes;
1343 else
1345 if (dst.visrect.bottom < lines)
1347 int pad_lines = lines - dst.visrect.bottom;
1348 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1349 int pad_bytes = pad_lines * stride;
1350 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1354 if (empty_rect) bits = NULL;
1356 src.x = src.visrect.left;
1357 src.y = src.visrect.top;
1358 src.width = src.visrect.right - src.visrect.left;
1359 src.height = src.visrect.bottom - src.visrect.top;
1361 lines = src.height;
1364 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1366 if (err) goto done;
1368 /* fill out the src colour table, if it needs one */
1369 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1370 fill_default_color_table( src_info );
1372 /* if the src and dst are the same depth, copy the colour info across */
1373 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1375 switch (src_info->bmiHeader.biBitCount)
1377 case 16:
1378 if (src_info->bmiHeader.biCompression == BI_RGB)
1380 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1381 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1383 break;
1384 case 32:
1385 if (src_info->bmiHeader.biCompression == BI_RGB)
1387 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1388 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1390 break;
1392 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1393 copy_color_info( dst_info, src_info, coloruse );
1395 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1397 if( coloruse == DIB_PAL_COLORS )
1399 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1401 else
1403 fill_default_color_table( dst_info );
1407 if (bits)
1409 if(dst_info->bmiHeader.biHeight > 0)
1410 dst_info->bmiHeader.biHeight = src.height;
1411 else
1412 dst_info->bmiHeader.biHeight = -src.height;
1414 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1415 if (src_bits.free) src_bits.free( &src_bits );
1416 ret = lines;
1418 else
1419 ret = !empty_rect;
1421 if (coloruse == DIB_PAL_COLORS)
1423 WORD *index = (WORD *)dst_info->bmiColors;
1424 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1425 *index = i;
1428 copy_color_info( info, dst_info, coloruse );
1429 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1431 done:
1432 release_dc_ptr( dc );
1433 GDI_ReleaseObj( hbitmap );
1434 return ret;
1438 /***********************************************************************
1439 * CreateDIBitmap (GDI32.@)
1441 * Creates a DDB (device dependent bitmap) from a DIB.
1442 * The DDB will have the same color depth as the reference DC.
1444 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1445 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1446 UINT coloruse )
1448 BITMAPINFOHEADER info;
1449 HBITMAP handle;
1450 LONG height;
1452 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1453 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1454 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1455 if (info.biWidth < 0) return 0;
1457 /* Top-down DIBs have a negative height */
1458 height = abs( info.biHeight );
1460 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1461 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1462 info.biBitCount, info.biCompression);
1464 if (hdc == NULL)
1465 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1466 else
1467 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1469 if (handle)
1471 if (init & CBM_INIT)
1473 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1475 DeleteObject( handle );
1476 handle = 0;
1481 return handle;
1485 /***********************************************************************
1486 * CreateDIBSection (GDI32.@)
1488 HBITMAP WINAPI CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1489 VOID **bits, HANDLE section, DWORD offset)
1491 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1492 BITMAPINFO *info = (BITMAPINFO *)buffer;
1493 HBITMAP ret = 0;
1494 BITMAPOBJ *bmp;
1495 void *mapBits = NULL;
1497 if (bits) *bits = NULL;
1498 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1499 if (usage > DIB_PAL_COLORS) return 0;
1500 if (info->bmiHeader.biPlanes != 1)
1502 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1503 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1506 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1508 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1509 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1510 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1511 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1512 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1514 bmp->dib.dsBm.bmType = 0;
1515 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1516 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1517 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1518 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1519 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1520 bmp->dib.dsBmih = info->bmiHeader;
1522 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1524 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1525 goto error;
1526 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1527 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1528 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1529 goto error;
1530 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1533 /* set dsBitfields values */
1534 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1536 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1537 bmp->dib.dsBitfields[0] = 0x7c00;
1538 bmp->dib.dsBitfields[1] = 0x03e0;
1539 bmp->dib.dsBitfields[2] = 0x001f;
1541 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1543 if (usage == DIB_PAL_COLORS) goto error;
1544 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1545 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1546 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1547 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1549 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1551 /* get storage location for DIB bits */
1553 if (section)
1555 SYSTEM_INFO SystemInfo;
1556 DWORD mapOffset;
1557 INT mapSize;
1559 GetSystemInfo( &SystemInfo );
1560 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1561 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1562 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1563 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1565 else
1567 offset = 0;
1568 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1569 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1571 bmp->dib.dshSection = section;
1572 bmp->dib.dsOffset = offset;
1574 if (!bmp->dib.dsBm.bmBits) goto error;
1576 if (!(ret = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1578 if (bits) *bits = bmp->dib.dsBm.bmBits;
1579 return ret;
1581 error:
1582 if (section) UnmapViewOfFile( mapBits );
1583 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1584 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1585 HeapFree( GetProcessHeap(), 0, bmp );
1586 return 0;
1590 /***********************************************************************
1591 * D3DKMTCreateDCFromMemory (GDI32.@)
1593 NTSTATUS WINAPI D3DKMTCreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1595 const struct d3dddi_format_info
1597 D3DDDIFORMAT format;
1598 unsigned int bit_count;
1599 DWORD compression;
1600 unsigned int palette_size;
1601 DWORD mask_r, mask_g, mask_b;
1602 } *format = NULL;
1603 BITMAPOBJ *bmp = NULL;
1604 HBITMAP bitmap;
1605 unsigned int i;
1606 HDC dc;
1608 static const struct d3dddi_format_info format_info[] =
1610 { D3DDDIFMT_R8G8B8, 24, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1611 { D3DDDIFMT_A8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1612 { D3DDDIFMT_X8R8G8B8, 32, BI_RGB, 0, 0x00000000, 0x00000000, 0x00000000 },
1613 { D3DDDIFMT_R5G6B5, 16, BI_BITFIELDS, 0, 0x0000f800, 0x000007e0, 0x0000001f },
1614 { D3DDDIFMT_X1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1615 { D3DDDIFMT_A1R5G5B5, 16, BI_BITFIELDS, 0, 0x00007c00, 0x000003e0, 0x0000001f },
1616 { D3DDDIFMT_P8, 8, BI_RGB, 256, 0x00000000, 0x00000000, 0x00000000 },
1619 if (!desc) return STATUS_INVALID_PARAMETER;
1621 TRACE("memory %p, format %#x, width %u, height %u, pitch %u, device dc %p, color table %p.\n",
1622 desc->pMemory, desc->Format, desc->Width, desc->Height,
1623 desc->Pitch, desc->hDeviceDc, desc->pColorTable);
1625 if (!desc->pMemory) return STATUS_INVALID_PARAMETER;
1627 for (i = 0; i < sizeof(format_info) / sizeof(*format_info); ++i)
1629 if (format_info[i].format == desc->Format)
1631 format = &format_info[i];
1632 break;
1635 if (!format) return STATUS_INVALID_PARAMETER;
1637 if (desc->Width > (UINT_MAX & ~3) / (format->bit_count / 8) ||
1638 !desc->Pitch || desc->Pitch < get_dib_stride( desc->Width, format->bit_count ) ||
1639 !desc->Height || desc->Height > UINT_MAX / desc->Pitch) return STATUS_INVALID_PARAMETER;
1641 if (!desc->hDeviceDc || !(dc = CreateCompatibleDC( desc->hDeviceDc ))) return STATUS_INVALID_PARAMETER;
1643 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) goto error;
1645 bmp->dib.dsBm.bmWidth = desc->Width;
1646 bmp->dib.dsBm.bmHeight = desc->Height;
1647 bmp->dib.dsBm.bmWidthBytes = desc->Pitch;
1648 bmp->dib.dsBm.bmPlanes = 1;
1649 bmp->dib.dsBm.bmBitsPixel = format->bit_count;
1650 bmp->dib.dsBm.bmBits = desc->pMemory;
1652 bmp->dib.dsBmih.biSize = sizeof(bmp->dib.dsBmih);
1653 bmp->dib.dsBmih.biWidth = desc->Width;
1654 bmp->dib.dsBmih.biHeight = -(LONG)desc->Height;
1655 bmp->dib.dsBmih.biPlanes = 1;
1656 bmp->dib.dsBmih.biBitCount = format->bit_count;
1657 bmp->dib.dsBmih.biCompression = format->compression;
1658 bmp->dib.dsBmih.biClrUsed = format->palette_size;
1659 bmp->dib.dsBmih.biClrImportant = format->palette_size;
1661 bmp->dib.dsBitfields[0] = format->mask_r;
1662 bmp->dib.dsBitfields[1] = format->mask_g;
1663 bmp->dib.dsBitfields[2] = format->mask_b;
1665 if (format->palette_size)
1667 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0, format->palette_size * sizeof(*bmp->color_table) )))
1668 goto error;
1669 if (desc->pColorTable)
1671 for (i = 0; i < format->palette_size; ++i)
1673 bmp->color_table[i].rgbRed = desc->pColorTable[i].peRed;
1674 bmp->color_table[i].rgbGreen = desc->pColorTable[i].peGreen;
1675 bmp->color_table[i].rgbBlue = desc->pColorTable[i].peBlue;
1676 bmp->color_table[i].rgbReserved = 0;
1679 else
1681 memcpy( bmp->color_table, get_default_color_table( format->bit_count ),
1682 format->palette_size * sizeof(*bmp->color_table) );
1686 if (!(bitmap = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1688 desc->hDc = dc;
1689 desc->hBitmap = bitmap;
1690 SelectObject( dc, bitmap );
1691 return STATUS_SUCCESS;
1693 error:
1694 if (bmp) HeapFree( GetProcessHeap(), 0, bmp->color_table );
1695 HeapFree( GetProcessHeap(), 0, bmp );
1696 DeleteDC( dc );
1697 return STATUS_INVALID_PARAMETER;
1701 /***********************************************************************
1702 * D3DKMTDestroyDCFromMemory (GDI32.@)
1704 NTSTATUS WINAPI D3DKMTDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1706 if (!desc) return STATUS_INVALID_PARAMETER;
1708 TRACE("dc %p, bitmap %p.\n", desc->hDc, desc->hBitmap);
1710 if (GetObjectType( desc->hDc ) != OBJ_MEMDC ||
1711 GetObjectType( desc->hBitmap ) != OBJ_BITMAP) return STATUS_INVALID_PARAMETER;
1712 DeleteObject( desc->hBitmap );
1713 DeleteDC( desc->hDc );
1715 return STATUS_SUCCESS;
1719 /***********************************************************************
1720 * DIB_SelectObject
1722 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1724 HGDIOBJ ret;
1725 BITMAPOBJ *bitmap;
1726 DC *dc;
1727 PHYSDEV physdev;
1729 if (!(dc = get_dc_ptr( hdc ))) return 0;
1731 if (GetObjectType( hdc ) != OBJ_MEMDC)
1733 ret = 0;
1734 goto done;
1736 ret = dc->hBitmap;
1737 if (handle == dc->hBitmap) goto done; /* nothing to do */
1739 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1741 ret = 0;
1742 goto done;
1745 if (GDI_get_ref_count( handle ))
1747 WARN( "Bitmap already selected in another DC\n" );
1748 GDI_ReleaseObj( handle );
1749 ret = 0;
1750 goto done;
1753 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1754 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1756 GDI_ReleaseObj( handle );
1757 ret = 0;
1759 else
1761 dc->hBitmap = handle;
1762 GDI_inc_ref_count( handle );
1763 dc->dirty = 0;
1764 dc->vis_rect.left = 0;
1765 dc->vis_rect.top = 0;
1766 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1767 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1768 dc->device_rect = dc->vis_rect;
1769 GDI_ReleaseObj( handle );
1770 DC_InitDC( dc );
1771 GDI_dec_ref_count( ret );
1774 done:
1775 release_dc_ptr( dc );
1776 return ret;
1780 /***********************************************************************
1781 * DIB_GetObject
1783 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1785 INT ret = 0;
1786 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1788 if (!bmp) return 0;
1790 if (!buffer) ret = sizeof(BITMAP);
1791 else if (count >= sizeof(DIBSECTION))
1793 DIBSECTION *dib = buffer;
1794 *dib = bmp->dib;
1795 dib->dsBm.bmWidthBytes = get_dib_stride( dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel );
1796 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1797 ret = sizeof(DIBSECTION);
1799 else if (count >= sizeof(BITMAP))
1801 BITMAP *bitmap = buffer;
1802 *bitmap = bmp->dib.dsBm;
1803 bitmap->bmWidthBytes = get_dib_stride( bitmap->bmWidth, bitmap->bmBitsPixel );
1804 ret = sizeof(BITMAP);
1807 GDI_ReleaseObj( handle );
1808 return ret;
1812 /***********************************************************************
1813 * DIB_DeleteObject
1815 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1817 BITMAPOBJ *bmp;
1819 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1821 if (bmp->dib.dshSection)
1823 SYSTEM_INFO SystemInfo;
1824 GetSystemInfo( &SystemInfo );
1825 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1826 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1828 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1830 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1831 return HeapFree( GetProcessHeap(), 0, bmp );