gdi32: Store vis_rect in DC_ATTR.
[wine.git] / dlls / gdi32 / bitmap.c
blob8866ec0af8abf79e20d886d163cc16c1a973dcbd
1 /*
2 * GDI bitmap objects
4 * Copyright 1993 Alexandre Julliard
5 * 1998 Huw D M Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "ntgdi_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
35 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
36 static BOOL BITMAP_DeleteObject( HGDIOBJ handle );
38 static const struct gdi_obj_funcs bitmap_funcs =
40 BITMAP_GetObject, /* pGetObjectW */
41 NULL, /* pUnrealizeObject */
42 BITMAP_DeleteObject /* pDeleteObject */
46 /******************************************************************************
47 * CreateCompatibleBitmap [GDI32.@]
49 * Creates a bitmap compatible with the DC.
51 * PARAMS
52 * hdc [I] Handle to device context
53 * width [I] Width of bitmap
54 * height [I] Height of bitmap
56 * RETURNS
57 * Success: Handle to bitmap
58 * Failure: 0
60 HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, INT width, INT height)
62 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
63 BITMAPINFO *bi = (BITMAPINFO *)buffer;
64 DIBSECTION dib;
66 TRACE("(%p,%d,%d)\n", hdc, width, height);
68 if (GetObjectType( hdc ) != OBJ_MEMDC)
69 return CreateBitmap( width, height,
70 GetDeviceCaps(hdc, PLANES), GetDeviceCaps(hdc, BITSPIXEL), NULL );
72 switch (GetObjectW( GetCurrentObject( hdc, OBJ_BITMAP ), sizeof(dib), &dib ))
74 case sizeof(BITMAP): /* A device-dependent bitmap is selected in the DC */
75 return CreateBitmap( width, height, dib.dsBm.bmPlanes, dib.dsBm.bmBitsPixel, NULL );
77 case sizeof(DIBSECTION): /* A DIB section is selected in the DC */
78 bi->bmiHeader = dib.dsBmih;
79 bi->bmiHeader.biWidth = width;
80 bi->bmiHeader.biHeight = height;
81 if (dib.dsBmih.biCompression == BI_BITFIELDS) /* copy the color masks */
82 memcpy(bi->bmiColors, dib.dsBitfields, sizeof(dib.dsBitfields));
83 else if (dib.dsBmih.biBitCount <= 8) /* copy the color table */
84 GetDIBColorTable(hdc, 0, 256, bi->bmiColors);
85 return CreateDIBSection( hdc, bi, DIB_RGB_COLORS, NULL, NULL, 0 );
87 default:
88 return 0;
93 /******************************************************************************
94 * NtGdiCreateBitmap (win32u.@)
96 * Creates a bitmap with the specified info.
98 HBITMAP WINAPI NtGdiCreateBitmap( INT width, INT height, UINT planes,
99 UINT bpp, const void *bits )
101 BITMAPOBJ *bmpobj;
102 HBITMAP hbitmap;
103 INT dib_stride;
104 SIZE_T size;
106 if (width > 0x7ffffff || height > 0x7ffffff)
108 SetLastError( ERROR_INVALID_PARAMETER );
109 return 0;
112 if (!width || !height)
113 return 0;
115 if (height < 0)
116 height = -height;
117 if (width < 0)
118 width = -width;
120 if (planes != 1)
122 FIXME("planes = %d\n", planes);
123 SetLastError( ERROR_INVALID_PARAMETER );
124 return NULL;
127 /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
128 if(bpp == 1) bpp = 1;
129 else if(bpp <= 4) bpp = 4;
130 else if(bpp <= 8) bpp = 8;
131 else if(bpp <= 16) bpp = 16;
132 else if(bpp <= 24) bpp = 24;
133 else if(bpp <= 32) bpp = 32;
134 else
136 WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bpp);
137 SetLastError(ERROR_INVALID_PARAMETER);
138 return NULL;
141 dib_stride = get_dib_stride( width, bpp );
142 size = dib_stride * height;
143 /* Check for overflow (dib_stride itself must be ok because of the constraint on bm.bmWidth above). */
144 if (dib_stride != size / height)
146 SetLastError( ERROR_INVALID_PARAMETER );
147 return 0;
150 /* Create the BITMAPOBJ */
151 if (!(bmpobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmpobj) )))
153 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
154 return 0;
157 bmpobj->dib.dsBm.bmType = 0;
158 bmpobj->dib.dsBm.bmWidth = width;
159 bmpobj->dib.dsBm.bmHeight = height;
160 bmpobj->dib.dsBm.bmWidthBytes = get_bitmap_stride( width, bpp );
161 bmpobj->dib.dsBm.bmPlanes = planes;
162 bmpobj->dib.dsBm.bmBitsPixel = bpp;
163 bmpobj->dib.dsBm.bmBits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
164 if (!bmpobj->dib.dsBm.bmBits)
166 HeapFree( GetProcessHeap(), 0, bmpobj );
167 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
168 return 0;
171 if (!(hbitmap = alloc_gdi_handle( &bmpobj->obj, NTGDI_OBJ_BITMAP, &bitmap_funcs )))
173 HeapFree( GetProcessHeap(), 0, bmpobj->dib.dsBm.bmBits );
174 HeapFree( GetProcessHeap(), 0, bmpobj );
175 return 0;
178 if (bits)
179 NtGdiSetBitmapBits( hbitmap, height * bmpobj->dib.dsBm.bmWidthBytes, bits );
181 TRACE("%dx%d, bpp %d planes %d: returning %p\n", width, height, bpp, planes, hbitmap);
182 return hbitmap;
186 /***********************************************************************
187 * NtGdiGetBitmapBits (win32u.@)
189 * Copies bitmap bits of bitmap to buffer.
191 * RETURNS
192 * Success: Number of bytes copied
193 * Failure: 0
195 LONG WINAPI NtGdiGetBitmapBits(
196 HBITMAP hbitmap, /* [in] Handle to bitmap */
197 LONG count, /* [in] Number of bytes to copy */
198 LPVOID bits) /* [out] Pointer to buffer to receive bits */
200 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
201 BITMAPINFO *info = (BITMAPINFO *)buffer;
202 struct gdi_image_bits src_bits;
203 struct bitblt_coords src;
204 int dst_stride, max, ret;
205 BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP );
207 if (!bmp) return 0;
209 dst_stride = get_bitmap_stride( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmBitsPixel );
210 ret = max = dst_stride * bmp->dib.dsBm.bmHeight;
211 if (!bits) goto done;
212 if (count < 0 || count > max) count = max;
213 ret = count;
215 src.visrect.left = 0;
216 src.visrect.right = bmp->dib.dsBm.bmWidth;
217 src.visrect.top = 0;
218 src.visrect.bottom = (count + dst_stride - 1) / dst_stride;
219 src.x = src.y = 0;
220 src.width = src.visrect.right - src.visrect.left;
221 src.height = src.visrect.bottom - src.visrect.top;
223 if (!get_image_from_bitmap( bmp, info, &src_bits, &src ))
225 const char *src_ptr = src_bits.ptr;
226 int src_stride = info->bmiHeader.biSizeImage / abs( info->bmiHeader.biHeight );
228 /* GetBitmapBits returns 16-bit aligned data */
230 if (info->bmiHeader.biHeight > 0)
232 src_ptr += (info->bmiHeader.biHeight - 1) * src_stride;
233 src_stride = -src_stride;
235 src_ptr += src.visrect.top * src_stride;
237 if (src_stride == dst_stride) memcpy( bits, src_ptr, count );
238 else while (count > 0)
240 memcpy( bits, src_ptr, min( count, dst_stride ) );
241 src_ptr += src_stride;
242 bits = (char *)bits + dst_stride;
243 count -= dst_stride;
245 if (src_bits.free) src_bits.free( &src_bits );
247 else ret = 0;
249 done:
250 GDI_ReleaseObj( hbitmap );
251 return ret;
255 /******************************************************************************
256 * NtGdiSetBitmapBits (win32u.@)
258 * Sets bits of color data for a bitmap.
260 * RETURNS
261 * Success: Number of bytes used in setting the bitmap bits
262 * Failure: 0
264 LONG WINAPI NtGdiSetBitmapBits(
265 HBITMAP hbitmap, /* [in] Handle to bitmap */
266 LONG count, /* [in] Number of bytes in bitmap array */
267 LPCVOID bits) /* [in] Address of array with bitmap bits */
269 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
270 BITMAPINFO *info = (BITMAPINFO *)buffer;
271 BITMAPOBJ *bmp;
272 DWORD err;
273 int i, src_stride, dst_stride;
274 struct bitblt_coords src, dst;
275 struct gdi_image_bits src_bits;
276 HRGN clip = NULL;
278 if (!bits) return 0;
280 bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP );
281 if (!bmp) return 0;
283 if (count < 0) {
284 WARN("(%d): Negative number of bytes passed???\n", count );
285 count = -count;
288 src_stride = get_bitmap_stride( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmBitsPixel );
289 count = min( count, src_stride * bmp->dib.dsBm.bmHeight );
291 dst_stride = get_dib_stride( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmBitsPixel );
293 src.visrect.left = src.x = 0;
294 src.visrect.top = src.y = 0;
295 src.visrect.right = src.width = bmp->dib.dsBm.bmWidth;
296 src.visrect.bottom = src.height = (count + src_stride - 1 ) / src_stride;
297 dst = src;
299 if (count % src_stride)
301 HRGN last_row;
302 int extra_pixels = ((count % src_stride) << 3) / bmp->dib.dsBm.bmBitsPixel;
304 if ((count % src_stride << 3) % bmp->dib.dsBm.bmBitsPixel)
305 FIXME( "Unhandled partial pixel\n" );
306 clip = NtGdiCreateRectRgn( src.visrect.left, src.visrect.top,
307 src.visrect.right, src.visrect.bottom - 1 );
308 last_row = NtGdiCreateRectRgn( src.visrect.left, src.visrect.bottom - 1,
309 src.visrect.left + extra_pixels, src.visrect.bottom );
310 NtGdiCombineRgn( clip, clip, last_row, RGN_OR );
311 DeleteObject( last_row );
314 TRACE("(%p, %d, %p) %dx%d %d bpp fetched height: %d\n",
315 hbitmap, count, bits, bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmHeight,
316 bmp->dib.dsBm.bmBitsPixel, src.height );
318 if (src_stride == dst_stride)
320 src_bits.ptr = (void *)bits;
321 src_bits.is_copy = FALSE;
322 src_bits.free = NULL;
324 else
326 if (!(src_bits.ptr = HeapAlloc( GetProcessHeap(), 0, dst.height * dst_stride )))
328 GDI_ReleaseObj( hbitmap );
329 return 0;
331 src_bits.is_copy = TRUE;
332 src_bits.free = free_heap_bits;
333 for (i = 0; i < count / src_stride; i++)
334 memcpy( (char *)src_bits.ptr + i * dst_stride, (char *)bits + i * src_stride, src_stride );
335 if (count % src_stride)
336 memcpy( (char *)src_bits.ptr + i * dst_stride, (char *)bits + i * src_stride, count % src_stride );
339 /* query the color info */
340 info->bmiHeader.biSize = sizeof(info->bmiHeader);
341 info->bmiHeader.biPlanes = 1;
342 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
343 info->bmiHeader.biCompression = BI_RGB;
344 info->bmiHeader.biXPelsPerMeter = 0;
345 info->bmiHeader.biYPelsPerMeter = 0;
346 info->bmiHeader.biClrUsed = 0;
347 info->bmiHeader.biClrImportant = 0;
348 info->bmiHeader.biWidth = 0;
349 info->bmiHeader.biHeight = 0;
350 info->bmiHeader.biSizeImage = 0;
351 err = put_image_into_bitmap( bmp, 0, info, NULL, NULL, NULL );
353 if (!err || err == ERROR_BAD_FORMAT)
355 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
356 info->bmiHeader.biHeight = -dst.height;
357 info->bmiHeader.biSizeImage = dst.height * dst_stride;
358 err = put_image_into_bitmap( bmp, clip, info, &src_bits, &src, &dst );
360 if (err) count = 0;
362 if (clip) DeleteObject( clip );
363 if (src_bits.free) src_bits.free( &src_bits );
364 GDI_ReleaseObj( hbitmap );
365 return count;
369 /***********************************************************************
370 * NtGdiSelectBitmap (win32u.@)
372 HGDIOBJ WINAPI NtGdiSelectBitmap( HDC hdc, HGDIOBJ handle )
374 HGDIOBJ ret;
375 BITMAPOBJ *bitmap;
376 DC *dc;
377 PHYSDEV physdev;
379 if (!(dc = get_dc_ptr( hdc ))) return 0;
381 if (GetObjectType( hdc ) != OBJ_MEMDC)
383 ret = 0;
384 goto done;
386 ret = dc->hBitmap;
387 if (handle == dc->hBitmap) goto done; /* nothing to do */
389 if (!(bitmap = GDI_GetObjPtr( handle, NTGDI_OBJ_BITMAP )))
391 ret = 0;
392 goto done;
395 if (handle != GetStockObject(DEFAULT_BITMAP) && GDI_get_ref_count( handle ))
397 WARN( "Bitmap already selected in another DC\n" );
398 GDI_ReleaseObj( handle );
399 ret = 0;
400 goto done;
403 if (!is_bitmapobj_dib( bitmap ) &&
404 bitmap->dib.dsBm.bmBitsPixel != 1 &&
405 bitmap->dib.dsBm.bmBitsPixel != GetDeviceCaps( hdc, BITSPIXEL ))
407 WARN( "Wrong format bitmap %u bpp\n", bitmap->dib.dsBm.bmBitsPixel );
408 GDI_ReleaseObj( handle );
409 ret = 0;
410 goto done;
413 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
414 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
416 GDI_ReleaseObj( handle );
417 ret = 0;
419 else
421 dc->hBitmap = handle;
422 GDI_inc_ref_count( handle );
423 dc->dirty = 0;
424 dc->attr->vis_rect.left = 0;
425 dc->attr->vis_rect.top = 0;
426 dc->attr->vis_rect.right = bitmap->dib.dsBm.bmWidth;
427 dc->attr->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
428 dc->device_rect = dc->attr->vis_rect;
429 GDI_ReleaseObj( handle );
430 DC_InitDC( dc );
431 GDI_dec_ref_count( ret );
434 done:
435 release_dc_ptr( dc );
436 return ret;
440 /***********************************************************************
441 * BITMAP_DeleteObject
443 static BOOL BITMAP_DeleteObject( HGDIOBJ handle )
445 BITMAPOBJ *bmp = free_gdi_handle( handle );
447 if (!bmp) return FALSE;
448 HeapFree( GetProcessHeap(), 0, bmp->dib.dsBm.bmBits );
449 HeapFree( GetProcessHeap(), 0, bmp );
450 return TRUE;
454 /***********************************************************************
455 * BITMAP_GetObject
457 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
459 INT ret = 0;
460 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, NTGDI_OBJ_BITMAP );
462 if (!bmp) return 0;
464 if (!buffer) ret = sizeof(BITMAP);
465 else if (count >= sizeof(BITMAP))
467 BITMAP *bitmap = buffer;
468 *bitmap = bmp->dib.dsBm;
469 bitmap->bmBits = NULL;
470 ret = sizeof(BITMAP);
472 GDI_ReleaseObj( handle );
473 return ret;
477 /******************************************************************************
478 * NtGdiGetBitmapDimension (win32u.@)
480 * Retrieves dimensions of a bitmap.
482 * RETURNS
483 * Success: TRUE
484 * Failure: FALSE
486 BOOL WINAPI NtGdiGetBitmapDimension(
487 HBITMAP hbitmap, /* [in] Handle to bitmap */
488 LPSIZE size) /* [out] Address of struct receiving dimensions */
490 BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP );
491 if (!bmp) return FALSE;
492 *size = bmp->size;
493 GDI_ReleaseObj( hbitmap );
494 return TRUE;
498 /******************************************************************************
499 * NtGdiSetBitmapDimension (win32u.@)
501 * Assigns dimensions to a bitmap.
502 * MSDN says that this function will fail if hbitmap is a handle created by
503 * CreateDIBSection, but that's not true on Windows 2000.
505 * RETURNS
506 * Success: TRUE
507 * Failure: FALSE
509 BOOL WINAPI NtGdiSetBitmapDimension(
510 HBITMAP hbitmap, /* [in] Handle to bitmap */
511 INT x, /* [in] Bitmap width */
512 INT y, /* [in] Bitmap height */
513 LPSIZE prevSize) /* [out] Address of structure for orig dims */
515 BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, NTGDI_OBJ_BITMAP );
516 if (!bmp) return FALSE;
517 if (prevSize) *prevSize = bmp->size;
518 bmp->size.cx = x;
519 bmp->size.cy = y;
520 GDI_ReleaseObj( hbitmap );
521 return TRUE;