gdi32: Forward the null driver GetImage to the DIB driver since the bits are in DIB...
[wine] / dlls / gdi32 / bitmap.c
1 /*
2  * GDI bitmap objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1998 Huw D M Davies
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "gdi_private.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
33
34
35 static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, HDC hdc );
36 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
37 static BOOL BITMAP_DeleteObject( HGDIOBJ handle );
38
39 static const struct gdi_obj_funcs bitmap_funcs =
40 {
41     BITMAP_SelectObject,  /* pSelectObject */
42     BITMAP_GetObject,     /* pGetObjectA */
43     BITMAP_GetObject,     /* pGetObjectW */
44     NULL,                 /* pUnrealizeObject */
45     BITMAP_DeleteObject   /* pDeleteObject */
46 };
47
48
49 /***********************************************************************
50  *           null driver fallback implementations
51  */
52
53 DWORD nulldrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
54                         struct gdi_image_bits *bits, struct bitblt_coords *src )
55 {
56     BITMAPOBJ *bmp;
57     DWORD ret;
58
59     if (!hbitmap) return ERROR_NOT_SUPPORTED;
60     if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return ERROR_INVALID_HANDLE;
61
62     if (bmp->bitmap.bmBits || !bits)
63     {
64         ret = dib_driver.pGetImage( 0, hbitmap, info, bits, src );
65     }
66     else if (!(ret = dib_driver.pGetImage( 0, hbitmap, info, NULL, src )))
67     {
68         info->bmiHeader.biHeight = -(src->visrect.bottom - src->visrect.top);
69         info->bmiHeader.biSizeImage = get_dib_image_size( info );
70
71         /* make the source rectangle relative to the returned bits */
72         src->y -= src->visrect.top;
73         offset_rect( &src->visrect, 0, -src->visrect.top );
74
75         /* return all-zero bits */
76         bits->ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage );
77         bits->is_copy = TRUE;
78         bits->free = free_heap_bits;
79     }
80     GDI_ReleaseObj( hbitmap );
81     return ret;
82 }
83
84 DWORD nulldrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
85                         const struct gdi_image_bits *bits, struct bitblt_coords *src,
86                         struct bitblt_coords *dst, DWORD rop )
87 {
88     BITMAPOBJ *bmp;
89
90     if (!hbitmap) return ERROR_SUCCESS;
91     if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return ERROR_INVALID_HANDLE;
92
93     if (info->bmiHeader.biPlanes != 1) goto update_format;
94     if (info->bmiHeader.biBitCount != bmp->bitmap.bmBitsPixel) goto update_format;
95     /* FIXME: check color masks */
96
97     if (bits)
98     {
99         int i, width_bytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
100         unsigned char *dst_bits, *src_bits;
101
102         if ((src->width != dst->width) || (src->height != dst->height))
103         {
104             GDI_ReleaseObj( hbitmap );
105             return ERROR_TRANSFORM_NOT_SUPPORTED;
106         }
107         if (src->visrect.left > 0 || src->visrect.right < bmp->bitmap.bmWidth ||
108             dst->visrect.left > 0 || dst->visrect.right < bmp->bitmap.bmWidth)
109         {
110             FIXME( "setting partial rows not supported\n" );
111             GDI_ReleaseObj( hbitmap );
112             return ERROR_NOT_SUPPORTED;
113         }
114         if (clip)
115         {
116             FIXME( "clip region not supported\n" );
117             GDI_ReleaseObj( hbitmap );
118             return ERROR_NOT_SUPPORTED;
119         }
120
121         if (!bmp->bitmap.bmBits &&
122             !(bmp->bitmap.bmBits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
123                                               bmp->bitmap.bmHeight * width_bytes )))
124         {
125             GDI_ReleaseObj( hbitmap );
126             return ERROR_OUTOFMEMORY;
127         }
128         dst_bits = (unsigned char *)bmp->bitmap.bmBits + dst->visrect.top * width_bytes;
129         src_bits = bits->ptr;
130         if (info->bmiHeader.biHeight > 0)
131         {
132             src_bits += (info->bmiHeader.biHeight - 1 - src->visrect.top) * width_bytes;
133             width_bytes = -width_bytes;
134         }
135         else
136             src_bits += src->visrect.top * width_bytes;
137
138         if (width_bytes != bmp->bitmap.bmWidthBytes)
139         {
140             for (i = 0; i < dst->visrect.bottom - dst->visrect.top; i++)
141             {
142                 memcpy( dst_bits, src_bits, bmp->bitmap.bmWidthBytes );
143                 src_bits += width_bytes;
144                 dst_bits += abs(width_bytes);
145             }
146         }
147         else memcpy( dst_bits, src_bits, width_bytes * (dst->visrect.bottom - dst->visrect.top) );
148     }
149     GDI_ReleaseObj( hbitmap );
150     return ERROR_SUCCESS;
151
152 update_format:
153     info->bmiHeader.biPlanes   = 1;
154     info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
155     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
156     GDI_ReleaseObj( hbitmap );
157     return ERROR_BAD_FORMAT;
158 }
159
160
161 /******************************************************************************
162  * CreateBitmap [GDI32.@]
163  *
164  * Creates a bitmap with the specified info.
165  *
166  * PARAMS
167  *    width  [I] bitmap width
168  *    height [I] bitmap height
169  *    planes [I] Number of color planes
170  *    bpp    [I] Number of bits to identify a color
171  *    bits   [I] Pointer to array containing color data
172  *
173  * RETURNS
174  *    Success: Handle to bitmap
175  *    Failure: 0
176  */
177 HBITMAP WINAPI CreateBitmap( INT width, INT height, UINT planes,
178                              UINT bpp, LPCVOID bits )
179 {
180     BITMAP bm;
181
182     bm.bmType = 0;
183     bm.bmWidth = width;
184     bm.bmHeight = height;
185     bm.bmWidthBytes = get_bitmap_stride( width, bpp );
186     bm.bmPlanes = planes;
187     bm.bmBitsPixel = bpp;
188     bm.bmBits = (LPVOID)bits;
189
190     return CreateBitmapIndirect( &bm );
191 }
192
193 /******************************************************************************
194  * CreateCompatibleBitmap [GDI32.@]
195  *
196  * Creates a bitmap compatible with the DC.
197  *
198  * PARAMS
199  *    hdc    [I] Handle to device context
200  *    width  [I] Width of bitmap
201  *    height [I] Height of bitmap
202  *
203  * RETURNS
204  *    Success: Handle to bitmap
205  *    Failure: 0
206  */
207 HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, INT width, INT height)
208 {
209     HBITMAP hbmpRet = 0;
210
211     TRACE("(%p,%d,%d) =\n", hdc, width, height);
212
213     if (GetObjectType( hdc ) != OBJ_MEMDC)
214     {
215         hbmpRet = CreateBitmap(width, height,
216                                GetDeviceCaps(hdc, PLANES),
217                                GetDeviceCaps(hdc, BITSPIXEL),
218                                NULL);
219     }
220     else  /* Memory DC */
221     {
222         DIBSECTION dib;
223         HBITMAP bitmap = GetCurrentObject( hdc, OBJ_BITMAP );
224         INT size = GetObjectW( bitmap, sizeof(dib), &dib );
225
226         if (!size) return 0;
227
228         if (size == sizeof(BITMAP))
229         {
230             /* A device-dependent bitmap is selected in the DC */
231             hbmpRet = CreateBitmap(width, height,
232                                    dib.dsBm.bmPlanes,
233                                    dib.dsBm.bmBitsPixel,
234                                    NULL);
235         }
236         else
237         {
238             /* A DIB section is selected in the DC */
239             BITMAPINFO *bi;
240             void *bits;
241
242             /* Allocate memory for a BITMAPINFOHEADER structure and a
243                color table. The maximum number of colors in a color table
244                is 256 which corresponds to a bitmap with depth 8.
245                Bitmaps with higher depths don't have color tables. */
246             bi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
247
248             if (bi)
249             {
250                 bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);
251                 bi->bmiHeader.biWidth         = width;
252                 bi->bmiHeader.biHeight        = height;
253                 bi->bmiHeader.biPlanes        = dib.dsBmih.biPlanes;
254                 bi->bmiHeader.biBitCount      = dib.dsBmih.biBitCount;
255                 bi->bmiHeader.biCompression   = dib.dsBmih.biCompression;
256                 bi->bmiHeader.biSizeImage     = 0;
257                 bi->bmiHeader.biXPelsPerMeter = dib.dsBmih.biXPelsPerMeter;
258                 bi->bmiHeader.biYPelsPerMeter = dib.dsBmih.biYPelsPerMeter;
259                 bi->bmiHeader.biClrUsed       = dib.dsBmih.biClrUsed;
260                 bi->bmiHeader.biClrImportant  = dib.dsBmih.biClrImportant;
261
262                 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
263                 {
264                     /* Copy the color masks */
265                     CopyMemory(bi->bmiColors, dib.dsBitfields, 3 * sizeof(DWORD));
266                 }
267                 else if (bi->bmiHeader.biBitCount <= 8)
268                 {
269                     /* Copy the color table */
270                     GetDIBColorTable(hdc, 0, 256, bi->bmiColors);
271                 }
272
273                 hbmpRet = CreateDIBSection(hdc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
274                 HeapFree(GetProcessHeap(), 0, bi);
275             }
276         }
277     }
278
279     TRACE("\t\t%p\n", hbmpRet);
280     return hbmpRet;
281 }
282
283
284 /******************************************************************************
285  * CreateBitmapIndirect [GDI32.@]
286  *
287  * Creates a bitmap with the specified info.
288  *
289  * PARAMS
290  *  bmp [I] Pointer to the bitmap info describing the bitmap
291  *
292  * RETURNS
293  *    Success: Handle to bitmap
294  *    Failure: NULL. Use GetLastError() to determine the cause.
295  *
296  * NOTES
297  *  If a width or height of 0 are given, a 1x1 monochrome bitmap is returned.
298  */
299 HBITMAP WINAPI CreateBitmapIndirect( const BITMAP *bmp )
300 {
301     BITMAP bm;
302     BITMAPOBJ *bmpobj;
303     HBITMAP hbitmap;
304
305     if (!bmp || bmp->bmType)
306     {
307         SetLastError( ERROR_INVALID_PARAMETER );
308         return NULL;
309     }
310
311     if (bmp->bmWidth > 0x7ffffff || bmp->bmHeight > 0x7ffffff)
312     {
313         SetLastError( ERROR_INVALID_PARAMETER );
314         return 0;
315     }
316
317     bm = *bmp;
318
319     if (!bm.bmWidth || !bm.bmHeight)
320     {
321         return GetStockObject( DEFAULT_BITMAP );
322     }
323     else
324     {
325         if (bm.bmHeight < 0)
326             bm.bmHeight = -bm.bmHeight;
327         if (bm.bmWidth < 0)
328             bm.bmWidth = -bm.bmWidth;
329     }
330
331     if (bm.bmPlanes != 1)
332     {
333         FIXME("planes = %d\n", bm.bmPlanes);
334         SetLastError( ERROR_INVALID_PARAMETER );
335         return NULL;
336     }
337
338     /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
339     if(bm.bmBitsPixel == 1)         bm.bmBitsPixel = 1;
340     else if(bm.bmBitsPixel <= 4)    bm.bmBitsPixel = 4;
341     else if(bm.bmBitsPixel <= 8)    bm.bmBitsPixel = 8;
342     else if(bm.bmBitsPixel <= 16)   bm.bmBitsPixel = 16;
343     else if(bm.bmBitsPixel <= 24)   bm.bmBitsPixel = 24;
344     else if(bm.bmBitsPixel <= 32)   bm.bmBitsPixel = 32;
345     else {
346         WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bm.bmBitsPixel);
347         SetLastError(ERROR_INVALID_PARAMETER);
348         return NULL;
349     }
350
351     /* Windows ignores the provided bm.bmWidthBytes */
352     bm.bmWidthBytes = get_bitmap_stride( bm.bmWidth, bm.bmBitsPixel );
353     /* XP doesn't allow to create bitmaps larger than 128 Mb */
354     if (bm.bmHeight > 128 * 1024 * 1024 / bm.bmWidthBytes)
355     {
356         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
357         return 0;
358     }
359
360     /* Create the BITMAPOBJ */
361     if (!(bmpobj = HeapAlloc( GetProcessHeap(), 0, sizeof(*bmpobj) )))
362     {
363         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
364         return 0;
365     }
366
367     bmpobj->size.cx = 0;
368     bmpobj->size.cy = 0;
369     bmpobj->bitmap = bm;
370     bmpobj->bitmap.bmBits = NULL;
371     bmpobj->funcs = &null_driver;
372     bmpobj->dib = NULL;
373     bmpobj->color_table = NULL;
374     bmpobj->nb_colors = 0;
375
376     if (!(hbitmap = alloc_gdi_handle( &bmpobj->header, OBJ_BITMAP, &bitmap_funcs )))
377     {
378         HeapFree( GetProcessHeap(), 0, bmpobj );
379         return 0;
380     }
381
382     if (bm.bmBits)
383         SetBitmapBits( hbitmap, bm.bmHeight * bm.bmWidthBytes, bm.bmBits );
384
385     TRACE("%dx%d, %d colors returning %p\n", bm.bmWidth, bm.bmHeight,
386           1 << (bm.bmPlanes * bm.bmBitsPixel), hbitmap);
387
388     return hbitmap;
389 }
390
391
392 /* convenience wrapper for GetImage to retrieve the full contents of a bitmap */
393 BOOL get_bitmap_image( HBITMAP hbitmap, BITMAPINFO *info, struct gdi_image_bits *bits )
394 {
395     struct bitblt_coords src;
396     BOOL ret = FALSE;
397     BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
398
399     if (bmp)
400     {
401         src.visrect.left   = src.x = 0;
402         src.visrect.top    = src.y = 0;
403         src.visrect.right  = src.width = bmp->bitmap.bmWidth;
404         src.visrect.bottom = src.height = bmp->bitmap.bmHeight;
405         ret = !bmp->funcs->pGetImage( NULL, hbitmap, info, bits, &src );
406         GDI_ReleaseObj( hbitmap );
407     }
408     return ret;
409 }
410
411
412 /***********************************************************************
413  * GetBitmapBits [GDI32.@]
414  *
415  * Copies bitmap bits of bitmap to buffer.
416  *
417  * RETURNS
418  *    Success: Number of bytes copied
419  *    Failure: 0
420  */
421 LONG WINAPI GetBitmapBits(
422     HBITMAP hbitmap, /* [in]  Handle to bitmap */
423     LONG count,        /* [in]  Number of bytes to copy */
424     LPVOID bits)       /* [out] Pointer to buffer to receive bits */
425 {
426     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
427     BITMAPINFO *info = (BITMAPINFO *)buffer;
428     struct gdi_image_bits src_bits;
429     struct bitblt_coords src;
430     int dst_stride, max, ret;
431     BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
432     const struct gdi_dc_funcs *funcs;
433
434     if (!bmp) return 0;
435     funcs = get_bitmap_funcs( bmp );
436
437     if (bmp->dib) dst_stride = get_bitmap_stride( bmp->dib->dsBmih.biWidth, bmp->dib->dsBmih.biBitCount );
438     else dst_stride = get_bitmap_stride( bmp->bitmap.bmWidth, bmp->bitmap.bmBitsPixel );
439
440     ret = max = dst_stride * bmp->bitmap.bmHeight;
441     if (!bits) goto done;
442     if (count > max) count = max;
443     ret = count;
444
445     src.visrect.left = 0;
446     src.visrect.right = bmp->bitmap.bmWidth;
447     src.visrect.top = 0;
448     src.visrect.bottom = (count + dst_stride - 1) / dst_stride;
449     src.x = src.y = 0;
450     src.width = src.visrect.right - src.visrect.left;
451     src.height = src.visrect.bottom - src.visrect.top;
452
453     if (!funcs->pGetImage( NULL, hbitmap, info, &src_bits, &src ))
454     {
455         const char *src_ptr = src_bits.ptr;
456         int src_stride = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
457
458         /* GetBitmapBits returns 16-bit aligned data */
459
460         if (info->bmiHeader.biHeight > 0)
461         {
462             src_ptr += (info->bmiHeader.biHeight - 1) * src_stride;
463             src_stride = -src_stride;
464         }
465         src_ptr += src.visrect.top * src_stride;
466
467         if (src_stride == dst_stride) memcpy( bits, src_ptr, count );
468         else while (count > 0)
469         {
470             memcpy( bits, src_ptr, min( count, dst_stride ) );
471             src_ptr += src_stride;
472             bits = (char *)bits + dst_stride;
473             count -= dst_stride;
474         }
475         if (src_bits.free) src_bits.free( &src_bits );
476     }
477     else ret = 0;
478
479 done:
480     GDI_ReleaseObj( hbitmap );
481     return ret;
482 }
483
484
485 /******************************************************************************
486  * SetBitmapBits [GDI32.@]
487  *
488  * Sets bits of color data for a bitmap.
489  *
490  * RETURNS
491  *    Success: Number of bytes used in setting the bitmap bits
492  *    Failure: 0
493  */
494 LONG WINAPI SetBitmapBits(
495     HBITMAP hbitmap, /* [in] Handle to bitmap */
496     LONG count,        /* [in] Number of bytes in bitmap array */
497     LPCVOID bits)      /* [in] Address of array with bitmap bits */
498 {
499     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
500     BITMAPINFO *info = (BITMAPINFO *)buffer;
501     BITMAPOBJ *bmp;
502     DWORD err;
503     int i, src_stride, dst_stride;
504     struct bitblt_coords src, dst;
505     struct gdi_image_bits src_bits;
506     HRGN clip = NULL;
507     const struct gdi_dc_funcs *funcs;
508
509     if (!bits) return 0;
510
511     bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
512     if (!bmp) return 0;
513
514     funcs = get_bitmap_funcs( bmp );
515
516     if (count < 0) {
517         WARN("(%d): Negative number of bytes passed???\n", count );
518         count = -count;
519     }
520
521     if (bmp->dib) src_stride = get_bitmap_stride( bmp->dib->dsBmih.biWidth, bmp->dib->dsBmih.biBitCount );
522     else src_stride = get_bitmap_stride( bmp->bitmap.bmWidth, bmp->bitmap.bmBitsPixel );
523     count = min( count, src_stride * bmp->bitmap.bmHeight );
524
525     dst_stride = get_dib_stride( bmp->bitmap.bmWidth, bmp->bitmap.bmBitsPixel );
526
527     src.visrect.left   = src.x = 0;
528     src.visrect.top    = src.y = 0;
529     src.visrect.right  = src.width = bmp->bitmap.bmWidth;
530     src.visrect.bottom = src.height = (count + src_stride - 1 ) / src_stride;
531     dst = src;
532
533     if (count % src_stride)
534     {
535         HRGN last_row;
536         int extra_pixels = ((count % src_stride) << 3) / bmp->bitmap.bmBitsPixel;
537
538         if ((count % src_stride << 3) % bmp->bitmap.bmBitsPixel)
539             FIXME( "Unhandled partial pixel\n" );
540         clip = CreateRectRgn( src.visrect.left, src.visrect.top,
541                               src.visrect.right, src.visrect.bottom - 1 );
542         last_row = CreateRectRgn( src.visrect.left, src.visrect.bottom - 1,
543                                   src.visrect.left + extra_pixels, src.visrect.bottom );
544         CombineRgn( clip, clip, last_row, RGN_OR );
545         DeleteObject( last_row );
546     }
547
548     TRACE("(%p, %d, %p) %dx%d %d bpp fetched height: %d\n",
549           hbitmap, count, bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
550           bmp->bitmap.bmBitsPixel, src.height );
551
552     if (src_stride == dst_stride)
553     {
554         src_bits.ptr = (void *)bits;
555         src_bits.is_copy = FALSE;
556         src_bits.free = NULL;
557     }
558     else
559     {
560         if (!(src_bits.ptr = HeapAlloc( GetProcessHeap(), 0, dst.height * dst_stride )))
561         {
562             GDI_ReleaseObj( hbitmap );
563             return 0;
564         }
565         src_bits.is_copy = TRUE;
566         src_bits.free = free_heap_bits;
567         for (i = 0; i < count / src_stride; i++)
568             memcpy( (char *)src_bits.ptr + i * dst_stride, (char *)bits + i * src_stride, src_stride );
569         if (count % src_stride)
570             memcpy( (char *)src_bits.ptr + i * dst_stride, (char *)bits + i * src_stride, count % src_stride );
571     }
572
573     /* query the color info */
574     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
575     info->bmiHeader.biPlanes        = 1;
576     info->bmiHeader.biBitCount      = bmp->bitmap.bmBitsPixel;
577     info->bmiHeader.biCompression   = BI_RGB;
578     info->bmiHeader.biXPelsPerMeter = 0;
579     info->bmiHeader.biYPelsPerMeter = 0;
580     info->bmiHeader.biClrUsed       = 0;
581     info->bmiHeader.biClrImportant  = 0;
582     info->bmiHeader.biWidth         = 0;
583     info->bmiHeader.biHeight        = 0;
584     info->bmiHeader.biSizeImage     = 0;
585     err = funcs->pPutImage( NULL, hbitmap, 0, info, NULL, NULL, NULL, SRCCOPY );
586
587     if (!err || err == ERROR_BAD_FORMAT)
588     {
589         info->bmiHeader.biPlanes        = 1;
590         info->bmiHeader.biBitCount      = bmp->bitmap.bmBitsPixel;
591         info->bmiHeader.biWidth         = bmp->bitmap.bmWidth;
592         info->bmiHeader.biHeight        = -dst.height;
593         info->bmiHeader.biSizeImage     = dst.height * dst_stride;
594         err = funcs->pPutImage( NULL, hbitmap, clip, info, &src_bits, &src, &dst, SRCCOPY );
595     }
596     if (err) count = 0;
597
598     if (clip) DeleteObject( clip );
599     if (src_bits.free) src_bits.free( &src_bits );
600     GDI_ReleaseObj( hbitmap );
601     return count;
602 }
603
604 /**********************************************************************
605  *              BITMAP_CopyBitmap
606  *
607  */
608 HBITMAP BITMAP_CopyBitmap(HBITMAP hbitmap)
609 {
610     HBITMAP res;
611     DIBSECTION dib;
612     BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
613
614     if (!bmp) return 0;
615     if (bmp->dib)
616     {
617         void *bits;
618         BITMAPINFO *bi;
619         HDC dc;
620
621         dib = *bmp->dib;
622         GDI_ReleaseObj( hbitmap );
623         dc = CreateCompatibleDC( NULL );
624
625         if (!dc) return 0;
626         if (!(bi = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ))))
627         {
628             DeleteDC( dc );
629             return 0;
630         }
631         bi->bmiHeader = dib.dsBmih;
632
633         /* Get the color table or the color masks */
634         GetDIBits( dc, hbitmap, 0, 0, NULL, bi, DIB_RGB_COLORS );
635         bi->bmiHeader.biHeight = dib.dsBmih.biHeight;
636
637         res = CreateDIBSection( dc, bi, DIB_RGB_COLORS, &bits, NULL, 0 );
638         if (res) SetDIBits( dc, res, 0, dib.dsBm.bmHeight, dib.dsBm.bmBits, bi, DIB_RGB_COLORS );
639         HeapFree( GetProcessHeap(), 0, bi );
640         DeleteDC( dc );
641         return res;
642     }
643     dib.dsBm = bmp->bitmap;
644     dib.dsBm.bmBits = NULL;
645     GDI_ReleaseObj( hbitmap );
646
647     res = CreateBitmapIndirect( &dib.dsBm );
648     if(res) {
649         char *buf = HeapAlloc( GetProcessHeap(), 0, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight );
650         GetBitmapBits (hbitmap, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight, buf);
651         SetBitmapBits (res, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight, buf);
652         HeapFree( GetProcessHeap(), 0, buf );
653     }
654     return res;
655 }
656
657
658 static void set_initial_bitmap_bits( HBITMAP hbitmap, BITMAPOBJ *bmp )
659 {
660     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
661     BITMAPINFO *info = (BITMAPINFO *)buffer;
662     DWORD err;
663     int width_bytes;
664     struct bitblt_coords src, dst;
665     struct gdi_image_bits bits;
666
667     if (!bmp->bitmap.bmBits) return;
668     if (bmp->funcs->pPutImage == nulldrv_PutImage) return;
669
670     width_bytes = get_dib_stride( bmp->bitmap.bmWidth, bmp->bitmap.bmBitsPixel );
671
672     src.visrect.left   = src.x = 0;
673     src.visrect.top    = src.y = 0;
674     src.visrect.right  = src.width = bmp->bitmap.bmWidth;
675     src.visrect.bottom = src.height = bmp->bitmap.bmHeight;
676     dst = src;
677
678     bits.ptr = bmp->bitmap.bmBits;
679     bits.is_copy = TRUE;
680     bits.free = free_heap_bits;
681     bmp->bitmap.bmBits = NULL;
682
683     /* query the color info */
684     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
685     info->bmiHeader.biPlanes        = 1;
686     info->bmiHeader.biBitCount      = bmp->bitmap.bmBitsPixel;
687     info->bmiHeader.biCompression   = BI_RGB;
688     info->bmiHeader.biXPelsPerMeter = 0;
689     info->bmiHeader.biYPelsPerMeter = 0;
690     info->bmiHeader.biClrUsed       = 0;
691     info->bmiHeader.biClrImportant  = 0;
692     info->bmiHeader.biWidth         = 0;
693     info->bmiHeader.biHeight        = 0;
694     info->bmiHeader.biSizeImage     = 0;
695     err = bmp->funcs->pPutImage( NULL, hbitmap, 0, info, NULL, NULL, NULL, SRCCOPY );
696
697     if (!err || err == ERROR_BAD_FORMAT)
698     {
699         info->bmiHeader.biPlanes    = 1;
700         info->bmiHeader.biBitCount  = bmp->bitmap.bmBitsPixel;
701         info->bmiHeader.biWidth     = bmp->bitmap.bmWidth;
702         info->bmiHeader.biHeight    = -dst.height;
703         info->bmiHeader.biSizeImage = dst.height * width_bytes;
704         bmp->funcs->pPutImage( NULL, hbitmap, 0, info, &bits, &src, &dst, SRCCOPY );
705     }
706
707     if (bits.free) bits.free( &bits );
708 }
709
710 /***********************************************************************
711  *           BITMAP_SetOwnerDC
712  *
713  * Set the type of DC that owns the bitmap. This is used when the
714  * bitmap is selected into a device to initialize the bitmap function
715  * table.
716  */
717 BOOL BITMAP_SetOwnerDC( HBITMAP hbitmap, PHYSDEV physdev )
718 {
719     BITMAPOBJ *bitmap;
720     BOOL ret = TRUE;
721
722     /* never set the owner of the stock bitmap since it can be selected in multiple DCs */
723     if (hbitmap == GetStockObject(DEFAULT_BITMAP)) return TRUE;
724
725     if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return FALSE;
726
727     if (!bitmap->dib && bitmap->funcs != physdev->funcs)
728     {
729         /* we can only change from the null driver to some other driver */
730         if (bitmap->funcs == &null_driver)
731         {
732             if (physdev->funcs->pCreateBitmap)
733             {
734                 ret = physdev->funcs->pCreateBitmap( physdev, hbitmap );
735                 if (ret)
736                 {
737                     bitmap->funcs = physdev->funcs;
738                     set_initial_bitmap_bits( hbitmap, bitmap );
739                 }
740             }
741             else
742             {
743                 WARN( "Trying to select bitmap %p in DC that doesn't support it\n", hbitmap );
744                 ret = FALSE;
745             }
746         }
747         else
748         {
749             FIXME( "Trying to select bitmap %p in different DC type\n", hbitmap );
750             ret = FALSE;
751         }
752     }
753     GDI_ReleaseObj( hbitmap );
754     return ret;
755 }
756
757
758 /***********************************************************************
759  *           BITMAP_SelectObject
760  */
761 static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, HDC hdc )
762 {
763     HGDIOBJ ret;
764     BITMAPOBJ *bitmap;
765     DC *dc;
766     PHYSDEV physdev = NULL, old_physdev = NULL;
767
768     if (!(dc = get_dc_ptr( hdc ))) return 0;
769
770     if (GetObjectType( hdc ) != OBJ_MEMDC)
771     {
772         ret = 0;
773         goto done;
774     }
775     ret = dc->hBitmap;
776     if (handle == dc->hBitmap) goto done;  /* nothing to do */
777
778     if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
779     {
780         ret = 0;
781         goto done;
782     }
783
784     if (bitmap->header.selcount && (handle != GetStockObject(DEFAULT_BITMAP)))
785     {
786         WARN( "Bitmap already selected in another DC\n" );
787         GDI_ReleaseObj( handle );
788         ret = 0;
789         goto done;
790     }
791
792     old_physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
793     if(old_physdev == &dc->dibdrv.dev)
794         pop_dc_driver( dc, old_physdev );
795
796     if(bitmap->dib)
797     {
798         physdev = &dc->dibdrv.dev;
799         push_dc_driver( dc, physdev, physdev->funcs );
800     }
801     else
802         physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
803
804     if (!BITMAP_SetOwnerDC( handle, physdev ))
805     {
806         GDI_ReleaseObj( handle );
807         ret = 0;
808         goto done;
809     }
810     if (!physdev->funcs->pSelectBitmap( physdev, handle ))
811     {
812         GDI_ReleaseObj( handle );
813         ret = 0;
814     }
815     else
816     {
817         dc->hBitmap = handle;
818         GDI_inc_ref_count( handle );
819         dc->dirty = 0;
820         dc->vis_rect.left   = 0;
821         dc->vis_rect.top    = 0;
822         dc->vis_rect.right  = bitmap->bitmap.bmWidth;
823         dc->vis_rect.bottom = bitmap->bitmap.bmHeight;
824         SetRectRgn( dc->hVisRgn, 0, 0, bitmap->bitmap.bmWidth, bitmap->bitmap.bmHeight);
825         GDI_ReleaseObj( handle );
826         DC_InitDC( dc );
827         GDI_dec_ref_count( ret );
828     }
829
830  done:
831     if(!ret)
832     {
833         if(physdev == &dc->dibdrv.dev) pop_dc_driver( dc, physdev );
834         if(old_physdev == &dc->dibdrv.dev) push_dc_driver( dc, old_physdev, old_physdev->funcs );
835     }
836     release_dc_ptr( dc );
837     return ret;
838 }
839
840
841 /***********************************************************************
842  *           BITMAP_DeleteObject
843  */
844 static BOOL BITMAP_DeleteObject( HGDIOBJ handle )
845 {
846     const DC_FUNCTIONS *funcs;
847     BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
848
849     if (!bmp) return FALSE;
850     funcs = bmp->funcs;
851     GDI_ReleaseObj( handle );
852
853     funcs->pDeleteBitmap( handle );
854
855     if (!(bmp = free_gdi_handle( handle ))) return FALSE;
856
857     HeapFree( GetProcessHeap(), 0, bmp->bitmap.bmBits );
858
859     if (bmp->dib)
860     {
861         DIBSECTION *dib = bmp->dib;
862
863         if (dib->dsBm.bmBits)
864         {
865             if (dib->dshSection)
866             {
867                 SYSTEM_INFO SystemInfo;
868                 GetSystemInfo( &SystemInfo );
869                 UnmapViewOfFile( (char *)dib->dsBm.bmBits -
870                                  (dib->dsOffset % SystemInfo.dwAllocationGranularity) );
871             }
872             else if (!dib->dsOffset)
873                 VirtualFree(dib->dsBm.bmBits, 0L, MEM_RELEASE );
874         }
875         HeapFree(GetProcessHeap(), 0, dib);
876         HeapFree(GetProcessHeap(), 0, bmp->color_table);
877     }
878     return HeapFree( GetProcessHeap(), 0, bmp );
879 }
880
881
882 /***********************************************************************
883  *           BITMAP_GetObject
884  */
885 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
886 {
887     INT ret;
888     BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
889
890     if (!bmp) return 0;
891
892     if (!buffer) ret = sizeof(BITMAP);
893     else if (count < sizeof(BITMAP)) ret = 0;
894     else if (bmp->dib)
895     {
896         if (count >= sizeof(DIBSECTION))
897         {
898             DIBSECTION *dib = buffer;
899             *dib = *bmp->dib;
900             dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
901             ret = sizeof(DIBSECTION);
902         }
903         else /* if (count >= sizeof(BITMAP)) */
904         {
905             DIBSECTION *dib = bmp->dib;
906             memcpy( buffer, &dib->dsBm, sizeof(BITMAP) );
907             ret = sizeof(BITMAP);
908         }
909     }
910     else
911     {
912         memcpy( buffer, &bmp->bitmap, sizeof(BITMAP) );
913         ((BITMAP *) buffer)->bmBits = NULL;
914         ret = sizeof(BITMAP);
915     }
916     GDI_ReleaseObj( handle );
917     return ret;
918 }
919
920
921 /******************************************************************************
922  * CreateDiscardableBitmap [GDI32.@]
923  *
924  * Creates a discardable bitmap.
925  *
926  * RETURNS
927  *    Success: Handle to bitmap
928  *    Failure: NULL
929  */
930 HBITMAP WINAPI CreateDiscardableBitmap(
931     HDC hdc,    /* [in] Handle to device context */
932     INT width,  /* [in] Bitmap width */
933     INT height) /* [in] Bitmap height */
934 {
935     return CreateCompatibleBitmap( hdc, width, height );
936 }
937
938
939 /******************************************************************************
940  * GetBitmapDimensionEx [GDI32.@]
941  *
942  * Retrieves dimensions of a bitmap.
943  *
944  * RETURNS
945  *    Success: TRUE
946  *    Failure: FALSE
947  */
948 BOOL WINAPI GetBitmapDimensionEx(
949     HBITMAP hbitmap, /* [in]  Handle to bitmap */
950     LPSIZE size)     /* [out] Address of struct receiving dimensions */
951 {
952     BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
953     if (!bmp) return FALSE;
954     *size = bmp->size;
955     GDI_ReleaseObj( hbitmap );
956     return TRUE;
957 }
958
959
960 /******************************************************************************
961  * SetBitmapDimensionEx [GDI32.@]
962  *
963  * Assigns dimensions to a bitmap.
964  * MSDN says that this function will fail if hbitmap is a handle created by
965  * CreateDIBSection, but that's not true on Windows 2000.
966  *
967  * RETURNS
968  *    Success: TRUE
969  *    Failure: FALSE
970  */
971 BOOL WINAPI SetBitmapDimensionEx(
972     HBITMAP hbitmap, /* [in]  Handle to bitmap */
973     INT x,           /* [in]  Bitmap width */
974     INT y,           /* [in]  Bitmap height */
975     LPSIZE prevSize) /* [out] Address of structure for orig dims */
976 {
977     BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
978     if (!bmp) return FALSE;
979     if (prevSize) *prevSize = bmp->size;
980     bmp->size.cx = x;
981     bmp->size.cy = y;
982     GDI_ReleaseObj( hbitmap );
983     return TRUE;
984 }