gdi32: Avoid redundant computation of the gradient bounding rectangle.
[wine/multimedia.git] / dlls / gdi32 / dib.c
blobd8d283e1823fb89d3aaaa3b14b34ef13d43a6f44
1 /*
2 * GDI device-independent bitmaps
4 * Copyright 1993,1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 Important information:
24 * Current Windows versions support two different DIB structures:
26 - BITMAPCOREINFO / BITMAPCOREHEADER (legacy structures; used in OS/2)
27 - BITMAPINFO / BITMAPINFOHEADER
29 Most Windows API functions taking a BITMAPINFO* / BITMAPINFOHEADER* also
30 accept the old "core" structures, and so must WINE.
31 You can distinguish them by looking at the first member (bcSize/biSize).
34 * The palettes are stored in different formats:
36 - BITMAPCOREINFO: Array of RGBTRIPLE
37 - BITMAPINFO: Array of RGBQUAD
40 * There are even more DIB headers, but they all extend BITMAPINFOHEADER:
42 - BITMAPV4HEADER: Introduced in Windows 95 / NT 4.0
43 - BITMAPV5HEADER: Introduced in Windows 98 / 2000
45 If biCompression is BI_BITFIELDS, the color masks are at the same position
46 in all the headers (they start at bmiColors of BITMAPINFOHEADER), because
47 the new headers have structure members for the masks.
50 * You should never access the color table using the bmiColors member,
51 because the passed structure may have one of the extended headers
52 mentioned above. Use this to calculate the location:
54 BITMAPINFO* info;
55 void* colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
58 * More information:
59 Search for "Bitmap Structures" in MSDN
62 #include <stdarg.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <assert.h>
67 #include "windef.h"
68 #include "winbase.h"
69 #include "gdi_private.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
75 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc );
76 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
77 static BOOL DIB_DeleteObject( HGDIOBJ handle );
79 static const struct gdi_obj_funcs dib_funcs =
81 DIB_SelectObject, /* pSelectObject */
82 DIB_GetObject, /* pGetObjectA */
83 DIB_GetObject, /* pGetObjectW */
84 NULL, /* pUnrealizeObject */
85 DIB_DeleteObject /* pDeleteObject */
88 /***********************************************************************
89 * bitmap_info_size
91 * Return the size of the bitmap info structure including color table.
93 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
95 unsigned int colors, size, masks = 0;
97 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
99 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
100 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
101 return sizeof(BITMAPCOREHEADER) + colors *
102 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
104 else /* assume BITMAPINFOHEADER */
106 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
107 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
108 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
109 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
110 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
114 /*******************************************************************************************
115 * Verify that the DIB parameters are valid.
117 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
119 if (info->biWidth <= 0) return FALSE;
120 if (info->biHeight == 0) return FALSE;
122 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
124 if (info->biHeight < 0) return FALSE;
125 if (!info->biSizeImage) return FALSE;
126 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
129 if (!info->biPlanes) return FALSE;
131 switch (info->biBitCount)
133 case 1:
134 case 4:
135 case 8:
136 case 24:
137 return (info->biCompression == BI_RGB);
138 case 16:
139 case 32:
140 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
141 default:
142 return FALSE;
146 /*******************************************************************************************
147 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
149 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
151 if (!info) return FALSE;
153 if (info->biSize == sizeof(BITMAPCOREHEADER))
155 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
156 dst->biWidth = core->bcWidth;
157 dst->biHeight = core->bcHeight;
158 dst->biPlanes = core->bcPlanes;
159 dst->biBitCount = core->bcBitCount;
160 dst->biCompression = BI_RGB;
161 dst->biXPelsPerMeter = 0;
162 dst->biYPelsPerMeter = 0;
163 dst->biClrUsed = 0;
164 dst->biClrImportant = 0;
166 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
168 *dst = *info;
170 else
172 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
173 return FALSE;
176 dst->biSize = sizeof(*dst);
177 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
178 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
179 return TRUE;
182 /*******************************************************************************************
183 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
185 * The resulting sanitized BITMAPINFO is guaranteed to have:
186 * - biSize set to sizeof(BITMAPINFOHEADER)
187 * - biSizeImage set to the actual image size even for non-compressed DIB
188 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
189 * - color table present only for <= 8 bpp, always starts at info->bmiColors
191 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
192 UINT coloruse, BOOL allow_compression )
194 void *src_colors;
196 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
197 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
198 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
200 src_colors = (char *)info + info->bmiHeader.biSize;
202 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
204 /* bitfields are always at bmiColors even in larger structures */
205 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
206 dst->bmiHeader.biClrUsed = 0;
208 else if (dst->bmiHeader.biBitCount <= 8)
210 unsigned int colors = dst->bmiHeader.biClrUsed;
211 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
213 if (!colors) colors = max_colors;
214 else colors = min( colors, max_colors );
216 if (coloruse == DIB_PAL_COLORS)
218 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
219 max_colors = colors;
221 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
223 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
225 else
227 unsigned int i;
228 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
229 for (i = 0; i < colors; i++)
231 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
232 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
233 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
234 dst->bmiColors[i].rgbReserved = 0;
237 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
238 dst->bmiHeader.biClrUsed = max_colors;
240 else dst->bmiHeader.biClrUsed = 0;
242 return TRUE;
245 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
247 PALETTEENTRY palEntry[256];
248 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
249 int i, colors = 1 << info->bmiHeader.biBitCount;
251 info->bmiHeader.biClrUsed = colors;
253 if (!palette) return 0;
255 memset( palEntry, 0, sizeof(palEntry) );
256 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
257 return 0;
259 for (i = 0; i < colors; i++)
261 info->bmiColors[i].rgbRed = palEntry[i].peRed;
262 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
263 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
264 info->bmiColors[i].rgbReserved = 0;
267 return colors;
270 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
272 PALETTEENTRY entries[256];
273 RGBQUAD table[256];
274 HPALETTE palette;
275 const WORD *index = (const WORD *)info->bmiColors;
276 int i, count, colors = info->bmiHeader.biClrUsed;
278 if (!colors) return TRUE;
279 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
280 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
282 for (i = 0; i < colors; i++, index++)
284 table[i].rgbRed = entries[*index % count].peRed;
285 table[i].rgbGreen = entries[*index % count].peGreen;
286 table[i].rgbBlue = entries[*index % count].peBlue;
287 table[i].rgbReserved = 0;
289 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
290 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
291 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
292 return TRUE;
295 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
297 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
298 const int bpp = info->bmiHeader.biBitCount;
300 if (height > 0)
301 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
302 else
303 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
306 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
308 int i = 0;
309 int left, right;
310 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
311 HRGN run = NULL;
312 BYTE skip, num, data;
313 BYTE *out_bits, *in_bits = bits->ptr;
315 if (clip) *clip = NULL;
317 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
319 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
320 if (!out_bits) goto fail;
322 if (clip)
324 *clip = CreateRectRgn( 0, 0, 0, 0 );
325 run = CreateRectRgn( 0, 0, 0, 0 );
326 if (!*clip || !run) goto fail;
329 x = left = right = 0;
330 y = height - 1;
332 while (i < info->bmiHeader.biSizeImage - 1)
334 num = in_bits[i];
335 data = in_bits[i + 1];
336 i += 2;
338 if (num)
340 if (x + num > width) num = width - x;
341 if (num)
343 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
344 if (info->bmiHeader.biBitCount == 8)
345 memset( out_ptr, s, num );
346 else
348 if(x & 1)
350 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
351 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
352 out_ptr++;
353 x++;
354 num--;
356 /* this will write one too many if num is odd, but that doesn't matter */
357 if (num) memset( out_ptr, s, (num + 1) / 2 );
360 x += num;
361 right = x;
363 else
365 if (data < 3)
367 if(left != right && clip)
369 SetRectRgn( run, left, y, right, y + 1 );
370 CombineRgn( *clip, run, *clip, RGN_OR );
372 switch (data)
374 case 0: /* eol */
375 left = right = x = 0;
376 y--;
377 if(y < 0) goto done;
378 break;
380 case 1: /* eod */
381 goto done;
383 case 2: /* delta */
384 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
385 x += in_bits[i];
386 if (x > width) x = width;
387 left = right = x;
388 y -= in_bits[i + 1];
389 if(y < 0) goto done;
390 i += 2;
393 else /* data bytes of data */
395 num = data;
396 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
397 if (skip > info->bmiHeader.biSizeImage - i) goto done;
398 skip = (skip + 1) & ~1;
399 if (x + num > width) num = width - x;
400 if (num)
402 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
403 if (info->bmiHeader.biBitCount == 8)
404 memcpy( out_ptr, in_bits + i, num );
405 else
407 if(x & 1)
409 const BYTE *in_ptr = in_bits + i;
410 for ( ; num; num--, x++)
412 if (x & 1)
414 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
415 out_ptr++;
417 else
418 *out_ptr = (*in_ptr++ << 4) & 0xf0;
421 else
422 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
425 x += num;
426 right = x;
427 i += skip;
432 done:
433 if (run) DeleteObject( run );
434 if (bits->free) bits->free( bits );
436 bits->ptr = out_bits;
437 bits->is_copy = TRUE;
438 bits->free = free_heap_bits;
440 return TRUE;
442 fail:
443 if (run) DeleteObject( run );
444 if (clip && *clip) DeleteObject( *clip );
445 HeapFree( GetProcessHeap(), 0, out_bits );
446 return FALSE;
451 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
452 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
453 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
455 DC *dc = get_nulldrv_dc( dev );
456 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
457 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
458 struct bitblt_coords src, dst;
459 struct gdi_image_bits src_bits;
460 DWORD err;
461 HRGN clip = NULL;
462 INT ret = 0;
463 INT height = abs( src_info->bmiHeader.biHeight );
464 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
465 RECT rect;
467 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
468 xSrc, ySrc, widthSrc, heightSrc, rop);
470 src_bits.ptr = (void*)bits;
471 src_bits.is_copy = FALSE;
472 src_bits.free = NULL;
474 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
476 rect.left = xDst;
477 rect.top = yDst;
478 rect.right = xDst + widthDst;
479 rect.bottom = yDst + heightDst;
480 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
481 dst.x = rect.left;
482 dst.y = rect.top;
483 dst.width = rect.right - rect.left;
484 dst.height = rect.bottom - rect.top;
486 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
488 dst.x += dst.width;
489 dst.width = -dst.width;
491 rop &= ~NOMIRRORBITMAP;
493 src.x = xSrc;
494 src.width = widthSrc;
495 src.y = ySrc;
496 src.height = heightSrc;
498 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
499 non_stretch_from_origin = TRUE;
501 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
503 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
504 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
507 if (rop != SRCCOPY || non_stretch_from_origin)
509 if (dst.width == 1 && src.width > 1) src.width--;
510 if (dst.height == 1 && src.height > 1) src.height--;
513 if (rop != SRCCOPY)
515 if (dst.width < 0 && dst.width == src.width)
517 /* This is off-by-one, but that's what Windows does */
518 dst.x += dst.width;
519 src.x += src.width;
520 dst.width = -dst.width;
521 src.width = -src.width;
523 if (dst.height < 0 && dst.height == src.height)
525 dst.y += dst.height;
526 src.y += src.height;
527 dst.height = -dst.height;
528 src.height = -src.height;
532 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
534 if (src.y >= height && src.y + src.height + 1 < height)
535 src.y = height - 1;
536 else if (src.y > 0 && src.y + src.height + 1 < 0)
537 src.y = -src.height - 1;
539 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
541 src.visrect.left = 0;
542 src.visrect.right = src_info->bmiHeader.biWidth;
543 src.visrect.top = 0;
544 src.visrect.bottom = height;
545 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
547 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
549 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
551 if (!intersect_vis_rectangles( &dst, &src )) goto done;
553 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
555 dev = GET_DC_PHYSDEV( dc, pPutImage );
556 copy_bitmapinfo( dst_info, src_info );
557 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
558 if (err == ERROR_BAD_FORMAT)
560 /* 1-bpp destination without a color table requires a fake 1-entry table
561 * that contains only the background color */
562 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
564 COLORREF color = GetBkColor( dev->hdc );
565 dst_info->bmiColors[0].rgbRed = GetRValue( color );
566 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
567 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
568 dst_info->bmiColors[0].rgbReserved = 0;
569 dst_info->bmiHeader.biClrUsed = 1;
572 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE )))
574 /* get rid of the fake 1-bpp table */
575 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
576 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
580 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
582 copy_bitmapinfo( src_info, dst_info );
583 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
584 if (!err) err = dev->funcs->pPutImage( dev, 0, NULL, dst_info, &src_bits, &src, &dst, rop );
586 if (err) ret = 0;
587 else if (rop == SRCCOPY) ret = height;
588 else ret = src_info->bmiHeader.biHeight;
590 done:
591 if (src_bits.free) src_bits.free( &src_bits );
592 if (clip) DeleteObject( clip );
593 return ret;
596 /***********************************************************************
597 * StretchDIBits (GDI32.@)
599 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
600 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
601 const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
603 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
604 BITMAPINFO *info = (BITMAPINFO *)buffer;
605 DC *dc;
606 INT ret = 0;
608 if (!bits) return 0;
609 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
611 SetLastError( ERROR_INVALID_PARAMETER );
612 return 0;
615 if ((dc = get_dc_ptr( hdc )))
617 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
618 update_dc( dc );
619 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
620 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
621 release_dc_ptr( dc );
623 return ret;
627 /******************************************************************************
628 * SetDIBits [GDI32.@]
630 * Sets pixels in a bitmap using colors from DIB.
632 * PARAMS
633 * hdc [I] Handle to device context
634 * hbitmap [I] Handle to bitmap
635 * startscan [I] Starting scan line
636 * lines [I] Number of scan lines
637 * bits [I] Array of bitmap bits
638 * info [I] Address of structure with data
639 * coloruse [I] Type of color indexes to use
641 * RETURNS
642 * Success: Number of scan lines copied
643 * Failure: 0
645 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
646 UINT lines, LPCVOID bits, const BITMAPINFO *info,
647 UINT coloruse )
649 BITMAPOBJ *bitmap;
650 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
651 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
652 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
653 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
654 INT result = 0;
655 DWORD err;
656 struct gdi_image_bits src_bits;
657 struct bitblt_coords src, dst;
658 INT src_to_dst_offset;
659 HRGN clip = 0;
661 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
663 SetLastError( ERROR_INVALID_PARAMETER );
664 return 0;
666 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
668 DWORD *masks = (DWORD *)src_info->bmiColors;
669 if (!masks[0] || !masks[1] || !masks[2])
671 SetLastError( ERROR_INVALID_PARAMETER );
672 return 0;
676 src_bits.ptr = (void *)bits;
677 src_bits.is_copy = FALSE;
678 src_bits.free = NULL;
679 src_bits.param = NULL;
681 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
683 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
685 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
687 if (lines == 0) goto done;
688 else lines = src_info->bmiHeader.biHeight;
689 startscan = 0;
691 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
694 dst.visrect.left = 0;
695 dst.visrect.top = 0;
696 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
697 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
699 src.visrect.left = 0;
700 src.visrect.top = 0;
701 src.visrect.right = src_info->bmiHeader.biWidth;
702 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
704 if (src_info->bmiHeader.biHeight > 0)
706 src_to_dst_offset = -startscan;
707 lines = min( lines, src.visrect.bottom - startscan );
708 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
710 else
712 src_to_dst_offset = src.visrect.bottom - lines - startscan;
713 /* Unlike the bottom-up case, Windows doesn't limit lines. */
714 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
717 result = lines;
719 offset_rect( &src.visrect, 0, src_to_dst_offset );
720 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
721 src.visrect = dst.visrect;
722 offset_rect( &src.visrect, 0, -src_to_dst_offset );
724 src.x = src.visrect.left;
725 src.y = src.visrect.top;
726 src.width = src.visrect.right - src.visrect.left;
727 src.height = src.visrect.bottom - src.visrect.top;
729 dst.x = dst.visrect.left;
730 dst.y = dst.visrect.top;
731 dst.width = dst.visrect.right - dst.visrect.left;
732 dst.height = dst.visrect.bottom - dst.visrect.top;
734 copy_bitmapinfo( dst_info, src_info );
736 err = bitmap->funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
737 if (err == ERROR_BAD_FORMAT)
739 err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
740 if (!err) err = bitmap->funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
742 if(err) result = 0;
744 done:
745 if (src_bits.free) src_bits.free( &src_bits );
746 if (clip) DeleteObject( clip );
747 GDI_ReleaseObj( hbitmap );
748 return result;
752 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
753 INT x_src, INT y_src, UINT startscan, UINT lines,
754 const void *bits, BITMAPINFO *src_info, UINT coloruse )
756 DC *dc = get_nulldrv_dc( dev );
757 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
758 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
759 struct bitblt_coords src, dst;
760 struct gdi_image_bits src_bits;
761 HRGN clip = 0;
762 DWORD err;
763 UINT height;
764 BOOL top_down;
765 POINT pt;
766 RECT rect;
768 top_down = (src_info->bmiHeader.biHeight < 0);
769 height = abs( src_info->bmiHeader.biHeight );
771 src_bits.ptr = (void *)bits;
772 src_bits.is_copy = FALSE;
773 src_bits.free = NULL;
775 if (!lines) return 0;
776 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
778 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
780 startscan = 0;
781 lines = height;
782 src_info->bmiHeader.biWidth = x_src + cx;
783 src_info->bmiHeader.biHeight = y_src + cy;
784 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
785 src.x = x_src;
786 src.y = 0;
787 src.width = cx;
788 src.height = cy;
789 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
791 else
793 if (startscan >= height) return 0;
794 if (!top_down && lines > height - startscan) lines = height - startscan;
796 /* map src to top-down coordinates with startscan as origin */
797 src.x = x_src;
798 src.y = startscan + lines - (y_src + cy);
799 src.width = cx;
800 src.height = cy;
801 if (src.y > 0)
803 if (!top_down)
805 /* get rid of unnecessary lines */
806 if (src.y >= lines) return 0;
807 lines -= src.y;
808 src.y = 0;
810 else if (src.y >= lines) return lines;
812 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
815 src.visrect.left = src.x;
816 src.visrect.top = src.y;
817 src.visrect.right = src.x + cx;
818 src.visrect.bottom = src.y + cy;
819 rect.left = 0;
820 rect.top = 0;
821 rect.right = src_info->bmiHeader.biWidth;
822 rect.bottom = abs( src_info->bmiHeader.biHeight );
823 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
825 lines = 0;
826 goto done;
829 pt.x = x_dst;
830 pt.y = y_dst;
831 LPtoDP( dev->hdc, &pt, 1 );
832 dst.x = pt.x;
833 dst.y = pt.y;
834 dst.width = cx;
835 dst.height = cy;
836 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
838 rect.left = dst.x;
839 rect.top = dst.y;
840 rect.right = dst.x + cx;
841 rect.bottom = dst.y + cy;
842 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
844 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
845 intersect_rect( &rect, &src.visrect, &dst.visrect );
846 src.visrect = dst.visrect = rect;
847 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
848 if (is_rect_empty( &dst.visrect )) goto done;
849 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
851 dev = GET_DC_PHYSDEV( dc, pPutImage );
852 copy_bitmapinfo( dst_info, src_info );
853 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
854 if (err == ERROR_BAD_FORMAT)
856 err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
857 if (!err) err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
859 if (err) lines = 0;
861 done:
862 if (src_bits.free) src_bits.free( &src_bits );
863 if (clip) DeleteObject( clip );
864 return lines;
867 /***********************************************************************
868 * SetDIBitsToDevice (GDI32.@)
870 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
871 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
872 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
873 UINT coloruse )
875 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
876 BITMAPINFO *info = (BITMAPINFO *)buffer;
877 INT ret = 0;
878 DC *dc;
880 if (!bits) return 0;
881 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
883 SetLastError( ERROR_INVALID_PARAMETER );
884 return 0;
887 if ((dc = get_dc_ptr( hdc )))
889 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
890 update_dc( dc );
891 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
892 ySrc, startscan, lines, bits, info, coloruse );
893 release_dc_ptr( dc );
895 return ret;
898 /***********************************************************************
899 * SetDIBColorTable (GDI32.@)
901 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, CONST RGBQUAD *colors )
903 DC * dc;
904 UINT result = 0;
905 BITMAPOBJ * bitmap;
907 if (!(dc = get_dc_ptr( hdc ))) return 0;
909 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
911 if (startpos < bitmap->dib.dsBmih.biClrUsed)
913 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
914 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
916 GDI_ReleaseObj( dc->hBitmap );
918 if (result) /* update colors of selected objects */
920 SetTextColor( hdc, dc->textColor );
921 SetBkColor( hdc, dc->backgroundColor );
922 SelectObject( hdc, dc->hPen );
923 SelectObject( hdc, dc->hBrush );
926 release_dc_ptr( dc );
927 return result;
931 /***********************************************************************
932 * GetDIBColorTable (GDI32.@)
934 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
936 DC * dc;
937 BITMAPOBJ *bitmap;
938 UINT result = 0;
940 if (!(dc = get_dc_ptr( hdc ))) return 0;
942 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
944 if (startpos < bitmap->dib.dsBmih.biClrUsed)
946 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
947 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
949 GDI_ReleaseObj( dc->hBitmap );
951 release_dc_ptr( dc );
952 return result;
955 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
956 static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f};
957 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
959 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
961 BITMAPINFOHEADER header;
963 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
964 header.biWidth = bmp->dib.dsBm.bmWidth;
965 header.biHeight = bmp->dib.dsBm.bmHeight;
966 header.biPlanes = 1;
967 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
969 switch (header.biBitCount)
971 case 16:
972 case 32:
973 header.biCompression = BI_BITFIELDS;
974 break;
975 default:
976 header.biCompression = BI_RGB;
977 break;
980 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
981 header.biXPelsPerMeter = 0;
982 header.biYPelsPerMeter = 0;
983 header.biClrUsed = 0;
984 header.biClrImportant = 0;
986 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
988 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
990 coreheader->bcWidth = header.biWidth;
991 coreheader->bcHeight = header.biHeight;
992 coreheader->bcPlanes = header.biPlanes;
993 coreheader->bcBitCount = header.biBitCount;
995 else
996 info->bmiHeader = header;
998 return bmp->dib.dsBm.bmHeight;
1001 /************************************************************************
1002 * copy_color_info
1004 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1006 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1008 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1010 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1012 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1013 if (coloruse == DIB_PAL_COLORS)
1014 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1015 else
1017 unsigned int i;
1018 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1020 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1021 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1022 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1026 else
1028 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1029 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1031 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1032 /* bitfields are always at bmiColors even in larger structures */
1033 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1034 else if (src->bmiHeader.biClrUsed)
1036 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1037 unsigned int size;
1039 if (coloruse == DIB_PAL_COLORS)
1040 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1041 else
1042 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1043 memcpy( colorptr, src->bmiColors, size );
1048 const RGBQUAD *get_default_color_table( int bpp )
1050 static const RGBQUAD table_1[2] =
1052 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1054 static const RGBQUAD table_4[16] =
1056 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1057 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1058 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1059 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1061 static const RGBQUAD table_8[256] =
1063 /* first and last 10 entries are the default system palette entries */
1064 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1065 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1066 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1067 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1068 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1069 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1070 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1071 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1072 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1073 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1074 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1075 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1076 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1077 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1078 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1079 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1080 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1081 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1082 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1083 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1084 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1085 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1086 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1087 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1088 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1089 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1090 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1091 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1092 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1093 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1094 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1095 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1096 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1097 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1098 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1099 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1100 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1101 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1102 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1103 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1104 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1105 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1106 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1107 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1108 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1109 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1110 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1111 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1112 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1113 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1114 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1115 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1116 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1117 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1118 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1119 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1120 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1121 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1122 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1123 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1124 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1125 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1126 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1127 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1130 switch (bpp)
1132 case 1: return table_1;
1133 case 4: return table_4;
1134 case 8: return table_8;
1135 default: return NULL;
1139 void fill_default_color_table( BITMAPINFO *info )
1141 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1142 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1143 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1146 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1148 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1149 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1150 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1151 info->bmiHeader.biPlanes = 1;
1152 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1153 info->bmiHeader.biCompression = BI_RGB;
1154 info->bmiHeader.biXPelsPerMeter = 0;
1155 info->bmiHeader.biYPelsPerMeter = 0;
1156 info->bmiHeader.biClrUsed = 0;
1157 info->bmiHeader.biClrImportant = 0;
1160 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1162 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1163 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1164 unsigned int info_size;
1166 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1168 info_size = get_dib_info_size( info, usage );
1169 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1171 memcpy( ret, info, info_size );
1172 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1173 info->bmiHeader.biSizeImage );
1175 return ret;
1178 /******************************************************************************
1179 * GetDIBits [GDI32.@]
1181 * Retrieves bits of bitmap and copies to buffer.
1183 * RETURNS
1184 * Success: Number of scan lines copied from bitmap
1185 * Failure: 0
1187 INT WINAPI GetDIBits(
1188 HDC hdc, /* [in] Handle to device context */
1189 HBITMAP hbitmap, /* [in] Handle to bitmap */
1190 UINT startscan, /* [in] First scan line to set in dest bitmap */
1191 UINT lines, /* [in] Number of scan lines to copy */
1192 LPVOID bits, /* [out] Address of array for bitmap bits */
1193 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1194 UINT coloruse) /* [in] RGB or palette index */
1196 DC * dc;
1197 BITMAPOBJ * bmp;
1198 int i, dst_to_src_offset, ret = 0;
1199 DWORD err;
1200 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1201 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1202 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1203 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1204 struct gdi_image_bits src_bits;
1205 struct bitblt_coords src, dst;
1206 BOOL empty_rect = FALSE;
1208 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1209 own copy and transfer the colour info back at the end */
1210 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1211 if (coloruse > DIB_PAL_COLORS) return 0;
1212 if (bits &&
1213 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1214 return 0;
1215 dst_info->bmiHeader.biClrUsed = 0;
1216 dst_info->bmiHeader.biClrImportant = 0;
1218 if (!(dc = get_dc_ptr( hdc )))
1220 SetLastError( ERROR_INVALID_PARAMETER );
1221 return 0;
1223 update_dc( dc );
1224 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1226 release_dc_ptr( dc );
1227 return 0;
1230 src.visrect.left = 0;
1231 src.visrect.top = 0;
1232 src.visrect.right = bmp->dib.dsBm.bmWidth;
1233 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1235 dst.visrect.left = 0;
1236 dst.visrect.top = 0;
1237 dst.visrect.right = dst_info->bmiHeader.biWidth;
1238 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1240 if (lines == 0 || startscan >= dst.visrect.bottom)
1241 bits = NULL;
1243 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1245 ret = fill_query_info( info, bmp );
1246 goto done;
1249 /* validate parameters */
1251 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1252 if (dst_info->bmiHeader.biHeight == 0) goto done;
1254 switch (dst_info->bmiHeader.biCompression)
1256 case BI_RLE4:
1257 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1258 if (dst_info->bmiHeader.biHeight < 0) goto done;
1259 if (bits) goto done; /* can't retrieve compressed bits */
1260 break;
1261 case BI_RLE8:
1262 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1263 if (dst_info->bmiHeader.biHeight < 0) goto done;
1264 if (bits) goto done; /* can't retrieve compressed bits */
1265 break;
1266 case BI_BITFIELDS:
1267 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1268 /* fall through */
1269 case BI_RGB:
1270 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1271 if (dst_info->bmiHeader.biBitCount == 1) break;
1272 if (dst_info->bmiHeader.biBitCount == 4) break;
1273 if (dst_info->bmiHeader.biBitCount == 8) break;
1274 if (dst_info->bmiHeader.biBitCount == 16) break;
1275 if (dst_info->bmiHeader.biBitCount == 24) break;
1276 if (dst_info->bmiHeader.biBitCount == 32) break;
1277 /* fall through */
1278 default:
1279 goto done;
1282 if (bits)
1284 if (dst_info->bmiHeader.biHeight > 0)
1286 dst_to_src_offset = -startscan;
1287 lines = min( lines, dst.visrect.bottom - startscan );
1288 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1290 else
1292 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1293 if (dst_to_src_offset < 0)
1295 dst_to_src_offset = 0;
1296 lines = dst.visrect.bottom - startscan;
1298 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1301 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1302 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1303 dst.visrect = src.visrect;
1304 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1306 if (dst_info->bmiHeader.biHeight > 0)
1308 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1310 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1311 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1312 memset( bits, 0, pad_bytes );
1313 bits = (char *)bits + pad_bytes;
1316 else
1318 if (dst.visrect.bottom < lines)
1320 int pad_lines = lines - dst.visrect.bottom;
1321 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1322 int pad_bytes = pad_lines * stride;
1323 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1327 if (empty_rect) bits = NULL;
1329 src.x = src.visrect.left;
1330 src.y = src.visrect.top;
1331 src.width = src.visrect.right - src.visrect.left;
1332 src.height = src.visrect.bottom - src.visrect.top;
1334 lines = src.height;
1337 err = bmp->funcs->pGetImage( NULL, hbitmap, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1339 if (err) goto done;
1341 /* fill out the src colour table, if it needs one */
1342 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1343 fill_default_color_table( src_info );
1345 /* if the src and dst are the same depth, copy the colour info across */
1346 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1348 switch (src_info->bmiHeader.biBitCount)
1350 case 16:
1351 if (src_info->bmiHeader.biCompression == BI_RGB)
1353 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1354 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1356 break;
1357 case 32:
1358 if (src_info->bmiHeader.biCompression == BI_RGB)
1360 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1361 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1363 break;
1365 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1366 copy_color_info( dst_info, src_info, coloruse );
1368 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1370 if( coloruse == DIB_PAL_COLORS )
1372 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1374 else
1376 fill_default_color_table( dst_info );
1380 if (bits)
1382 if(dst_info->bmiHeader.biHeight > 0)
1383 dst_info->bmiHeader.biHeight = src.height;
1384 else
1385 dst_info->bmiHeader.biHeight = -src.height;
1387 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits, FALSE );
1388 if (src_bits.free) src_bits.free( &src_bits );
1389 ret = lines;
1391 else
1392 ret = empty_rect ? FALSE : TRUE;
1394 if (coloruse == DIB_PAL_COLORS)
1396 WORD *index = (WORD *)dst_info->bmiColors;
1397 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1398 *index = i;
1401 copy_color_info( info, dst_info, coloruse );
1402 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1404 done:
1405 release_dc_ptr( dc );
1406 GDI_ReleaseObj( hbitmap );
1407 return ret;
1411 /***********************************************************************
1412 * CreateDIBitmap (GDI32.@)
1414 * Creates a DDB (device dependent bitmap) from a DIB.
1415 * The DDB will have the same color depth as the reference DC.
1417 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1418 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1419 UINT coloruse )
1421 BITMAPINFOHEADER info;
1422 HBITMAP handle;
1423 LONG height;
1425 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1426 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1427 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1428 if (info.biWidth < 0) return 0;
1430 /* Top-down DIBs have a negative height */
1431 height = abs( info.biHeight );
1433 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1434 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1435 info.biBitCount, info.biCompression);
1437 if (hdc == NULL)
1438 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1439 else
1440 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1442 if (handle)
1444 if (init & CBM_INIT)
1446 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1448 DeleteObject( handle );
1449 handle = 0;
1454 return handle;
1458 /***********************************************************************
1459 * CreateDIBSection (GDI32.@)
1461 HBITMAP WINAPI CreateDIBSection(HDC hdc, CONST BITMAPINFO *bmi, UINT usage,
1462 VOID **bits, HANDLE section, DWORD offset)
1464 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1465 BITMAPINFO *info = (BITMAPINFO *)buffer;
1466 HBITMAP ret = 0;
1467 BITMAPOBJ *bmp;
1468 void *mapBits = NULL;
1470 if (bits) *bits = NULL;
1471 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1472 if (usage > DIB_PAL_COLORS) return 0;
1473 if (info->bmiHeader.biPlanes != 1)
1475 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1476 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1479 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1481 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1482 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1483 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1484 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1485 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1487 bmp->dib.dsBm.bmType = 0;
1488 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1489 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1490 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1491 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1492 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1493 bmp->dib.dsBmih = info->bmiHeader;
1495 bmp->funcs = &dib_driver;
1497 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1499 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1500 goto error;
1501 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1502 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1503 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1504 goto error;
1505 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1508 /* set dsBitfields values */
1509 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1511 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1512 bmp->dib.dsBitfields[0] = 0x7c00;
1513 bmp->dib.dsBitfields[1] = 0x03e0;
1514 bmp->dib.dsBitfields[2] = 0x001f;
1516 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1518 if (usage == DIB_PAL_COLORS) goto error;
1519 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1520 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1521 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1522 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1524 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1526 /* get storage location for DIB bits */
1528 if (section)
1530 SYSTEM_INFO SystemInfo;
1531 DWORD mapOffset;
1532 INT mapSize;
1534 GetSystemInfo( &SystemInfo );
1535 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1536 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1537 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1538 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1540 else
1542 offset = 0;
1543 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1544 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1546 bmp->dib.dshSection = section;
1547 bmp->dib.dsOffset = offset;
1549 if (!bmp->dib.dsBm.bmBits) goto error;
1551 if (!(ret = alloc_gdi_handle( &bmp->header, OBJ_BITMAP, &dib_funcs ))) goto error;
1553 if (bits) *bits = bmp->dib.dsBm.bmBits;
1554 return ret;
1556 error:
1557 if (section) UnmapViewOfFile( mapBits );
1558 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1559 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1560 HeapFree( GetProcessHeap(), 0, bmp );
1561 return 0;
1565 /***********************************************************************
1566 * DIB_SelectObject
1568 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1570 HGDIOBJ ret;
1571 BITMAPOBJ *bitmap;
1572 DC *dc;
1573 PHYSDEV physdev = NULL, old_physdev = NULL, pathdev = NULL;
1575 if (!(dc = get_dc_ptr( hdc ))) return 0;
1577 if (GetObjectType( hdc ) != OBJ_MEMDC)
1579 ret = 0;
1580 goto done;
1582 ret = dc->hBitmap;
1583 if (handle == dc->hBitmap) goto done; /* nothing to do */
1585 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1587 ret = 0;
1588 goto done;
1591 if (bitmap->header.selcount)
1593 WARN( "Bitmap already selected in another DC\n" );
1594 GDI_ReleaseObj( handle );
1595 ret = 0;
1596 goto done;
1599 if (dc->physDev->funcs == &path_driver) pathdev = pop_dc_driver( &dc->physDev );
1601 old_physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1602 physdev = dc->dibdrv;
1603 if (old_physdev != dc->dibdrv)
1605 if (physdev) push_dc_driver( &dc->physDev, physdev, physdev->funcs );
1606 else
1608 if (!dib_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL )) goto done;
1609 dc->dibdrv = physdev = dc->physDev;
1613 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1615 GDI_ReleaseObj( handle );
1616 ret = 0;
1618 else
1620 dc->hBitmap = handle;
1621 GDI_inc_ref_count( handle );
1622 dc->dirty = 0;
1623 dc->vis_rect.left = 0;
1624 dc->vis_rect.top = 0;
1625 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1626 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1627 GDI_ReleaseObj( handle );
1628 DC_InitDC( dc );
1629 GDI_dec_ref_count( ret );
1632 done:
1633 if(!ret)
1635 if (old_physdev && old_physdev != dc->dibdrv) pop_dc_driver( &dc->physDev );
1637 if (pathdev) push_dc_driver( &dc->physDev, pathdev, pathdev->funcs );
1638 release_dc_ptr( dc );
1639 return ret;
1643 /***********************************************************************
1644 * DIB_GetObject
1646 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1648 INT ret = 0;
1649 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1651 if (!bmp) return 0;
1653 if (!buffer) ret = sizeof(BITMAP);
1654 else if (count >= sizeof(DIBSECTION))
1656 DIBSECTION *dib = buffer;
1657 *dib = bmp->dib;
1658 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1659 ret = sizeof(DIBSECTION);
1661 else if (count >= sizeof(BITMAP))
1663 BITMAP *bitmap = buffer;
1664 *bitmap = bmp->dib.dsBm;
1665 ret = sizeof(BITMAP);
1668 GDI_ReleaseObj( handle );
1669 return ret;
1673 /***********************************************************************
1674 * DIB_DeleteObject
1676 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1678 BITMAPOBJ *bmp;
1680 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1682 if (bmp->dib.dshSection)
1684 SYSTEM_INFO SystemInfo;
1685 GetSystemInfo( &SystemInfo );
1686 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1687 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1689 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1691 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1692 return HeapFree( GetProcessHeap(), 0, bmp );