gdi32: Add a null driver entry point for PatBlt.
[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 LONG CDECL nulldrv_GetBitmapBits( HBITMAP bitmap, void *bits, LONG size )
54 {
55     BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
56
57     if (bmp->bitmap.bmBits) memcpy( bits, bmp->bitmap.bmBits, size );
58     else memset( bits, 0, size );
59     GDI_ReleaseObj( bitmap );
60     return size;
61 }
62
63 LONG CDECL nulldrv_SetBitmapBits( HBITMAP bitmap, const void *bits, LONG size )
64 {
65     BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
66
67     if (!bmp->bitmap.bmBits)
68     {
69         LONG total = bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes;  /* alloc enough for entire bitmap */
70         if (!(bmp->bitmap.bmBits = HeapAlloc( GetProcessHeap(), 0, total )))
71         {
72             GDI_ReleaseObj( bitmap );
73             return 0;
74         }
75         if (size < total) memset( (char *)bmp->bitmap.bmBits + size, 0, total - size );
76     }
77     memcpy( bmp->bitmap.bmBits, bits, size );
78     GDI_ReleaseObj( bitmap );
79     return size;
80 }
81
82 INT CDECL nulldrv_GetDIBits( PHYSDEV dev, HBITMAP bitmap, UINT start, UINT lines, LPVOID bits,
83                              BITMAPINFO *info, UINT coloruse )
84 {
85     /* FIXME: transfer bits from bmp->bitmap.bmBits */
86     return 0;
87 }
88
89 INT CDECL nulldrv_SetDIBits( PHYSDEV dev, HBITMAP bitmap, UINT start, UINT lines,
90                              const void *bits, const BITMAPINFO *info, UINT coloruse )
91 {
92     /* FIXME: transfer bits to bmp->bitmap.bmBits */
93     return 0;
94 }
95
96 /***********************************************************************
97  *           BITMAP_GetWidthBytes
98  *
99  * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
100  * data.
101  */
102 INT BITMAP_GetWidthBytes( INT bmWidth, INT bpp )
103 {
104     switch(bpp)
105     {
106     case 1:
107         return 2 * ((bmWidth+15) >> 4);
108
109     case 24:
110         bmWidth *= 3; /* fall through */
111     case 8:
112         return bmWidth + (bmWidth & 1);
113
114     case 32:
115         return bmWidth * 4;
116
117     case 16:
118     case 15:
119         return bmWidth * 2;
120
121     case 4:
122         return 2 * ((bmWidth+3) >> 2);
123
124     default:
125         WARN("Unknown depth %d, please report.\n", bpp );
126     }
127     return -1;
128 }
129
130
131 /******************************************************************************
132  * CreateBitmap [GDI32.@]
133  *
134  * Creates a bitmap with the specified info.
135  *
136  * PARAMS
137  *    width  [I] bitmap width
138  *    height [I] bitmap height
139  *    planes [I] Number of color planes
140  *    bpp    [I] Number of bits to identify a color
141  *    bits   [I] Pointer to array containing color data
142  *
143  * RETURNS
144  *    Success: Handle to bitmap
145  *    Failure: 0
146  */
147 HBITMAP WINAPI CreateBitmap( INT width, INT height, UINT planes,
148                              UINT bpp, LPCVOID bits )
149 {
150     BITMAP bm;
151
152     bm.bmType = 0;
153     bm.bmWidth = width;
154     bm.bmHeight = height;
155     bm.bmWidthBytes = BITMAP_GetWidthBytes( width, bpp );
156     bm.bmPlanes = planes;
157     bm.bmBitsPixel = bpp;
158     bm.bmBits = (LPVOID)bits;
159
160     return CreateBitmapIndirect( &bm );
161 }
162
163 /******************************************************************************
164  * CreateCompatibleBitmap [GDI32.@]
165  *
166  * Creates a bitmap compatible with the DC.
167  *
168  * PARAMS
169  *    hdc    [I] Handle to device context
170  *    width  [I] Width of bitmap
171  *    height [I] Height of bitmap
172  *
173  * RETURNS
174  *    Success: Handle to bitmap
175  *    Failure: 0
176  */
177 HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, INT width, INT height)
178 {
179     HBITMAP hbmpRet = 0;
180
181     TRACE("(%p,%d,%d) =\n", hdc, width, height);
182
183     if (GetObjectType( hdc ) != OBJ_MEMDC)
184     {
185         hbmpRet = CreateBitmap(width, height,
186                                GetDeviceCaps(hdc, PLANES),
187                                GetDeviceCaps(hdc, BITSPIXEL),
188                                NULL);
189     }
190     else  /* Memory DC */
191     {
192         DIBSECTION dib;
193         HBITMAP bitmap = GetCurrentObject( hdc, OBJ_BITMAP );
194         INT size = GetObjectW( bitmap, sizeof(dib), &dib );
195
196         if (!size) return 0;
197
198         if (size == sizeof(BITMAP))
199         {
200             /* A device-dependent bitmap is selected in the DC */
201             hbmpRet = CreateBitmap(width, height,
202                                    dib.dsBm.bmPlanes,
203                                    dib.dsBm.bmBitsPixel,
204                                    NULL);
205         }
206         else
207         {
208             /* A DIB section is selected in the DC */
209             BITMAPINFO *bi;
210             void *bits;
211
212             /* Allocate memory for a BITMAPINFOHEADER structure and a
213                color table. The maximum number of colors in a color table
214                is 256 which corresponds to a bitmap with depth 8.
215                Bitmaps with higher depths don't have color tables. */
216             bi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
217
218             if (bi)
219             {
220                 bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);
221                 bi->bmiHeader.biWidth         = width;
222                 bi->bmiHeader.biHeight        = height;
223                 bi->bmiHeader.biPlanes        = dib.dsBmih.biPlanes;
224                 bi->bmiHeader.biBitCount      = dib.dsBmih.biBitCount;
225                 bi->bmiHeader.biCompression   = dib.dsBmih.biCompression;
226                 bi->bmiHeader.biSizeImage     = 0;
227                 bi->bmiHeader.biXPelsPerMeter = dib.dsBmih.biXPelsPerMeter;
228                 bi->bmiHeader.biYPelsPerMeter = dib.dsBmih.biYPelsPerMeter;
229                 bi->bmiHeader.biClrUsed       = dib.dsBmih.biClrUsed;
230                 bi->bmiHeader.biClrImportant  = dib.dsBmih.biClrImportant;
231
232                 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
233                 {
234                     /* Copy the color masks */
235                     CopyMemory(bi->bmiColors, dib.dsBitfields, 3 * sizeof(DWORD));
236                 }
237                 else if (bi->bmiHeader.biBitCount <= 8)
238                 {
239                     /* Copy the color table */
240                     GetDIBColorTable(hdc, 0, 256, bi->bmiColors);
241                 }
242
243                 hbmpRet = CreateDIBSection(hdc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
244                 HeapFree(GetProcessHeap(), 0, bi);
245             }
246         }
247     }
248
249     TRACE("\t\t%p\n", hbmpRet);
250     return hbmpRet;
251 }
252
253
254 /******************************************************************************
255  * CreateBitmapIndirect [GDI32.@]
256  *
257  * Creates a bitmap with the specified info.
258  *
259  * PARAMS
260  *  bmp [I] Pointer to the bitmap info describing the bitmap
261  *
262  * RETURNS
263  *    Success: Handle to bitmap
264  *    Failure: NULL. Use GetLastError() to determine the cause.
265  *
266  * NOTES
267  *  If a width or height of 0 are given, a 1x1 monochrome bitmap is returned.
268  */
269 HBITMAP WINAPI CreateBitmapIndirect( const BITMAP *bmp )
270 {
271     BITMAP bm;
272     BITMAPOBJ *bmpobj;
273     HBITMAP hbitmap;
274
275     if (!bmp || bmp->bmType)
276     {
277         SetLastError( ERROR_INVALID_PARAMETER );
278         return NULL;
279     }
280
281     if (bmp->bmWidth > 0x7ffffff || bmp->bmHeight > 0x7ffffff)
282     {
283         SetLastError( ERROR_INVALID_PARAMETER );
284         return 0;
285     }
286
287     bm = *bmp;
288
289     if (!bm.bmWidth || !bm.bmHeight)
290     {
291         return GetStockObject( DEFAULT_BITMAP );
292     }
293     else
294     {
295         if (bm.bmHeight < 0)
296             bm.bmHeight = -bm.bmHeight;
297         if (bm.bmWidth < 0)
298             bm.bmWidth = -bm.bmWidth;
299     }
300
301     if (bm.bmPlanes != 1)
302     {
303         FIXME("planes = %d\n", bm.bmPlanes);
304         SetLastError( ERROR_INVALID_PARAMETER );
305         return NULL;
306     }
307
308     /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
309     if(bm.bmBitsPixel == 1)         bm.bmBitsPixel = 1;
310     else if(bm.bmBitsPixel <= 4)    bm.bmBitsPixel = 4;
311     else if(bm.bmBitsPixel <= 8)    bm.bmBitsPixel = 8;
312     else if(bm.bmBitsPixel <= 16)   bm.bmBitsPixel = 16;
313     else if(bm.bmBitsPixel <= 24)   bm.bmBitsPixel = 24;
314     else if(bm.bmBitsPixel <= 32)   bm.bmBitsPixel = 32;
315     else {
316         WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bm.bmBitsPixel);
317         SetLastError(ERROR_INVALID_PARAMETER);
318         return NULL;
319     }
320
321     /* Windows ignores the provided bm.bmWidthBytes */
322     bm.bmWidthBytes = BITMAP_GetWidthBytes( bm.bmWidth, bm.bmBitsPixel );
323     /* XP doesn't allow to create bitmaps larger than 128 Mb */
324     if (bm.bmHeight > 128 * 1024 * 1024 / bm.bmWidthBytes)
325     {
326         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
327         return 0;
328     }
329
330     /* Create the BITMAPOBJ */
331     if (!(bmpobj = HeapAlloc( GetProcessHeap(), 0, sizeof(*bmpobj) )))
332     {
333         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
334         return 0;
335     }
336
337     bmpobj->size.cx = 0;
338     bmpobj->size.cy = 0;
339     bmpobj->bitmap = bm;
340     bmpobj->bitmap.bmBits = NULL;
341     bmpobj->funcs = &null_driver;
342     bmpobj->dib = NULL;
343     bmpobj->color_table = NULL;
344     bmpobj->nb_colors = 0;
345
346     if (!(hbitmap = alloc_gdi_handle( &bmpobj->header, OBJ_BITMAP, &bitmap_funcs )))
347     {
348         HeapFree( GetProcessHeap(), 0, bmpobj );
349         return 0;
350     }
351
352     if (bm.bmBits)
353         SetBitmapBits( hbitmap, bm.bmHeight * bm.bmWidthBytes, bm.bmBits );
354
355     TRACE("%dx%d, %d colors returning %p\n", bm.bmWidth, bm.bmHeight,
356           1 << (bm.bmPlanes * bm.bmBitsPixel), hbitmap);
357
358     return hbitmap;
359 }
360
361
362 /***********************************************************************
363  * GetBitmapBits [GDI32.@]
364  *
365  * Copies bitmap bits of bitmap to buffer.
366  *
367  * RETURNS
368  *    Success: Number of bytes copied
369  *    Failure: 0
370  */
371 LONG WINAPI GetBitmapBits(
372     HBITMAP hbitmap, /* [in]  Handle to bitmap */
373     LONG count,        /* [in]  Number of bytes to copy */
374     LPVOID bits)       /* [out] Pointer to buffer to receive bits */
375 {
376     BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
377     LONG height, ret;
378
379     if (!bmp) return 0;
380
381     if (bmp->dib)  /* simply copy the bits from the DIB */
382     {
383         DIBSECTION *dib = bmp->dib;
384         const char *src = dib->dsBm.bmBits;
385         INT width_bytes = BITMAP_GetWidthBytes(dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel);
386         LONG max = width_bytes * bmp->bitmap.bmHeight;
387
388         if (!bits)
389         {
390             ret = max;
391             goto done;
392         }
393
394         if (count > max) count = max;
395         ret = count;
396
397         /* GetBitmapBits returns not 32-bit aligned data */
398
399         if (bmp->dib->dsBmih.biHeight >= 0)  /* not top-down, need to flip contents vertically */
400         {
401             src += dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight;
402             while (count > 0)
403             {
404                 src -= dib->dsBm.bmWidthBytes;
405                 memcpy( bits, src, min( count, width_bytes ) );
406                 bits = (char *)bits + width_bytes;
407                 count -= width_bytes;
408             }
409         }
410         else
411         {
412             while (count > 0)
413             {
414                 memcpy( bits, src, min( count, width_bytes ) );
415                 src += dib->dsBm.bmWidthBytes;
416                 bits = (char *)bits + width_bytes;
417                 count -= width_bytes;
418             }
419         }
420         goto done;
421     }
422
423     /* If the bits vector is null, the function should return the read size */
424     if(bits == NULL)
425     {
426         ret = bmp->bitmap.bmWidthBytes * bmp->bitmap.bmHeight;
427         goto done;
428     }
429
430     if (count < 0) {
431         WARN("(%d): Negative number of bytes passed???\n", count );
432         count = -count;
433     }
434
435     /* Only get entire lines */
436     height = count / bmp->bitmap.bmWidthBytes;
437     if (height > bmp->bitmap.bmHeight) height = bmp->bitmap.bmHeight;
438     count = height * bmp->bitmap.bmWidthBytes;
439     if (count == 0)
440       {
441         WARN("Less than one entire line requested\n");
442         ret = 0;
443         goto done;
444       }
445
446
447     TRACE("(%p, %d, %p) %dx%d %d colors fetched height: %d\n",
448           hbitmap, count, bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
449           1 << bmp->bitmap.bmBitsPixel, height );
450
451     ret = bmp->funcs->pGetBitmapBits( hbitmap, bits, count );
452  done:
453     GDI_ReleaseObj( hbitmap );
454     return ret;
455 }
456
457
458 /******************************************************************************
459  * SetBitmapBits [GDI32.@]
460  *
461  * Sets bits of color data for a bitmap.
462  *
463  * RETURNS
464  *    Success: Number of bytes used in setting the bitmap bits
465  *    Failure: 0
466  */
467 LONG WINAPI SetBitmapBits(
468     HBITMAP hbitmap, /* [in] Handle to bitmap */
469     LONG count,        /* [in] Number of bytes in bitmap array */
470     LPCVOID bits)      /* [in] Address of array with bitmap bits */
471 {
472     BITMAPOBJ *bmp;
473     LONG height, ret;
474
475     if (!bits) return 0;
476
477     bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
478     if (!bmp) return 0;
479
480     if (count < 0) {
481         WARN("(%d): Negative number of bytes passed???\n", count );
482         count = -count;
483     }
484
485     if (bmp->dib)  /* simply copy the bits into the DIB */
486     {
487         DIBSECTION *dib = bmp->dib;
488         char *dest = dib->dsBm.bmBits;
489         LONG max = dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight;
490         if (count > max) count = max;
491         ret = count;
492
493         if (bmp->dib->dsBmih.biHeight >= 0)  /* not top-down, need to flip contents vertically */
494         {
495             dest += dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight;
496             while (count > 0)
497             {
498                 dest -= dib->dsBm.bmWidthBytes;
499                 memcpy( dest, bits, min( count, dib->dsBm.bmWidthBytes ) );
500                 bits = (const char *)bits + dib->dsBm.bmWidthBytes;
501                 count -= dib->dsBm.bmWidthBytes;
502             }
503         }
504         else memcpy( dest, bits, count );
505
506         GDI_ReleaseObj( hbitmap );
507         return ret;
508     }
509
510     /* Only get entire lines */
511     height = count / bmp->bitmap.bmWidthBytes;
512     if (height > bmp->bitmap.bmHeight) height = bmp->bitmap.bmHeight;
513     count = height * bmp->bitmap.bmWidthBytes;
514
515     TRACE("(%p, %d, %p) %dx%d %d colors fetched height: %d\n",
516           hbitmap, count, bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
517           1 << bmp->bitmap.bmBitsPixel, height );
518
519     ret = bmp->funcs->pSetBitmapBits( hbitmap, bits, count );
520     GDI_ReleaseObj( hbitmap );
521     return ret;
522 }
523
524 /**********************************************************************
525  *              BITMAP_CopyBitmap
526  *
527  */
528 HBITMAP BITMAP_CopyBitmap(HBITMAP hbitmap)
529 {
530     HBITMAP res;
531     DIBSECTION dib;
532     BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
533
534     if (!bmp) return 0;
535     if (bmp->dib)
536     {
537         void *bits;
538         BITMAPINFO *bi;
539         HDC dc;
540
541         dib = *bmp->dib;
542         GDI_ReleaseObj( hbitmap );
543         dc = CreateCompatibleDC( NULL );
544
545         if (!dc) return 0;
546         if (!(bi = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ))))
547         {
548             DeleteDC( dc );
549             return 0;
550         }
551         bi->bmiHeader = dib.dsBmih;
552
553         /* Get the color table or the color masks */
554         GetDIBits( dc, hbitmap, 0, 0, NULL, bi, DIB_RGB_COLORS );
555         bi->bmiHeader.biHeight = dib.dsBmih.biHeight;
556
557         res = CreateDIBSection( dc, bi, DIB_RGB_COLORS, &bits, NULL, 0 );
558         if (res) SetDIBits( dc, res, 0, dib.dsBm.bmHeight, dib.dsBm.bmBits, bi, DIB_RGB_COLORS );
559         HeapFree( GetProcessHeap(), 0, bi );
560         DeleteDC( dc );
561         return res;
562     }
563     dib.dsBm = bmp->bitmap;
564     dib.dsBm.bmBits = NULL;
565     GDI_ReleaseObj( hbitmap );
566
567     res = CreateBitmapIndirect( &dib.dsBm );
568     if(res) {
569         char *buf = HeapAlloc( GetProcessHeap(), 0, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight );
570         GetBitmapBits (hbitmap, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight, buf);
571         SetBitmapBits (res, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight, buf);
572         HeapFree( GetProcessHeap(), 0, buf );
573     }
574     return res;
575 }
576
577
578 /***********************************************************************
579  *           BITMAP_SetOwnerDC
580  *
581  * Set the type of DC that owns the bitmap. This is used when the
582  * bitmap is selected into a device to initialize the bitmap function
583  * table.
584  */
585 BOOL BITMAP_SetOwnerDC( HBITMAP hbitmap, PHYSDEV physdev )
586 {
587     BITMAPOBJ *bitmap;
588     BOOL ret = TRUE;
589
590     /* never set the owner of the stock bitmap since it can be selected in multiple DCs */
591     if (hbitmap == GetStockObject(DEFAULT_BITMAP)) return TRUE;
592
593     if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return FALSE;
594
595     if (bitmap->funcs != physdev->funcs)
596     {
597         /* we can only change from the null driver to some other driver */
598         if (bitmap->funcs == &null_driver)
599         {
600             if (physdev->funcs->pCreateBitmap)
601             {
602                 ret = physdev->funcs->pCreateBitmap( physdev, hbitmap, bitmap->bitmap.bmBits );
603                 if (ret) bitmap->funcs = physdev->funcs;
604             }
605             else
606             {
607                 WARN( "Trying to select bitmap %p in DC that doesn't support it\n", hbitmap );
608                 ret = FALSE;
609             }
610         }
611         else
612         {
613             FIXME( "Trying to select bitmap %p in different DC type\n", hbitmap );
614             ret = FALSE;
615         }
616     }
617     GDI_ReleaseObj( hbitmap );
618     return ret;
619 }
620
621
622 /***********************************************************************
623  *           BITMAP_SelectObject
624  */
625 static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, HDC hdc )
626 {
627     HGDIOBJ ret;
628     BITMAPOBJ *bitmap;
629     DC *dc;
630     PHYSDEV physdev;
631
632     if (!(dc = get_dc_ptr( hdc ))) return 0;
633
634     if (GetObjectType( hdc ) != OBJ_MEMDC)
635     {
636         ret = 0;
637         goto done;
638     }
639     ret = dc->hBitmap;
640     if (handle == dc->hBitmap) goto done;  /* nothing to do */
641
642     if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
643     {
644         ret = 0;
645         goto done;
646     }
647
648     if (bitmap->header.selcount && (handle != GetStockObject(DEFAULT_BITMAP)))
649     {
650         WARN( "Bitmap already selected in another DC\n" );
651         GDI_ReleaseObj( handle );
652         ret = 0;
653         goto done;
654     }
655
656     physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
657
658     if (!BITMAP_SetOwnerDC( handle, physdev ))
659     {
660         GDI_ReleaseObj( handle );
661         ret = 0;
662         goto done;
663     }
664     if (!physdev->funcs->pSelectBitmap( physdev, handle ))
665     {
666         GDI_ReleaseObj( handle );
667         ret = 0;
668     }
669     else
670     {
671         dc->hBitmap = handle;
672         GDI_inc_ref_count( handle );
673         dc->dirty = 0;
674         dc->vis_rect.left   = 0;
675         dc->vis_rect.top    = 0;
676         dc->vis_rect.right  = bitmap->bitmap.bmWidth;
677         dc->vis_rect.bottom = bitmap->bitmap.bmHeight;
678         SetRectRgn( dc->hVisRgn, 0, 0, bitmap->bitmap.bmWidth, bitmap->bitmap.bmHeight);
679         GDI_ReleaseObj( handle );
680         DC_InitDC( dc );
681         GDI_dec_ref_count( ret );
682     }
683
684  done:
685     release_dc_ptr( dc );
686     return ret;
687 }
688
689
690 /***********************************************************************
691  *           BITMAP_DeleteObject
692  */
693 static BOOL BITMAP_DeleteObject( HGDIOBJ handle )
694 {
695     const DC_FUNCTIONS *funcs;
696     BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
697
698     if (!bmp) return FALSE;
699     funcs = bmp->funcs;
700     GDI_ReleaseObj( handle );
701
702     funcs->pDeleteBitmap( handle );
703
704     if (!(bmp = free_gdi_handle( handle ))) return FALSE;
705
706     HeapFree( GetProcessHeap(), 0, bmp->bitmap.bmBits );
707
708     if (bmp->dib)
709     {
710         DIBSECTION *dib = bmp->dib;
711
712         if (dib->dsBm.bmBits)
713         {
714             if (dib->dshSection)
715             {
716                 SYSTEM_INFO SystemInfo;
717                 GetSystemInfo( &SystemInfo );
718                 UnmapViewOfFile( (char *)dib->dsBm.bmBits -
719                                  (dib->dsOffset % SystemInfo.dwAllocationGranularity) );
720             }
721             else if (!dib->dsOffset)
722                 VirtualFree(dib->dsBm.bmBits, 0L, MEM_RELEASE );
723         }
724         HeapFree(GetProcessHeap(), 0, dib);
725         HeapFree(GetProcessHeap(), 0, bmp->color_table);
726     }
727     return HeapFree( GetProcessHeap(), 0, bmp );
728 }
729
730
731 /***********************************************************************
732  *           BITMAP_GetObject
733  */
734 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
735 {
736     INT ret;
737     BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
738
739     if (!bmp) return 0;
740
741     if (!buffer) ret = sizeof(BITMAP);
742     else if (count < sizeof(BITMAP)) ret = 0;
743     else if (bmp->dib)
744     {
745         if (count >= sizeof(DIBSECTION))
746         {
747             DIBSECTION *dib = buffer;
748             *dib = *bmp->dib;
749             dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
750             ret = sizeof(DIBSECTION);
751         }
752         else /* if (count >= sizeof(BITMAP)) */
753         {
754             DIBSECTION *dib = bmp->dib;
755             memcpy( buffer, &dib->dsBm, sizeof(BITMAP) );
756             ret = sizeof(BITMAP);
757         }
758     }
759     else
760     {
761         memcpy( buffer, &bmp->bitmap, sizeof(BITMAP) );
762         ((BITMAP *) buffer)->bmBits = NULL;
763         ret = sizeof(BITMAP);
764     }
765     GDI_ReleaseObj( handle );
766     return ret;
767 }
768
769
770 /******************************************************************************
771  * CreateDiscardableBitmap [GDI32.@]
772  *
773  * Creates a discardable bitmap.
774  *
775  * RETURNS
776  *    Success: Handle to bitmap
777  *    Failure: NULL
778  */
779 HBITMAP WINAPI CreateDiscardableBitmap(
780     HDC hdc,    /* [in] Handle to device context */
781     INT width,  /* [in] Bitmap width */
782     INT height) /* [in] Bitmap height */
783 {
784     return CreateCompatibleBitmap( hdc, width, height );
785 }
786
787
788 /******************************************************************************
789  * GetBitmapDimensionEx [GDI32.@]
790  *
791  * Retrieves dimensions of a bitmap.
792  *
793  * RETURNS
794  *    Success: TRUE
795  *    Failure: FALSE
796  */
797 BOOL WINAPI GetBitmapDimensionEx(
798     HBITMAP hbitmap, /* [in]  Handle to bitmap */
799     LPSIZE size)     /* [out] Address of struct receiving dimensions */
800 {
801     BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
802     if (!bmp) return FALSE;
803     *size = bmp->size;
804     GDI_ReleaseObj( hbitmap );
805     return TRUE;
806 }
807
808
809 /******************************************************************************
810  * SetBitmapDimensionEx [GDI32.@]
811  *
812  * Assigns dimensions to a bitmap.
813  * MSDN says that this function will fail if hbitmap is a handle created by
814  * CreateDIBSection, but that's not true on Windows 2000.
815  *
816  * RETURNS
817  *    Success: TRUE
818  *    Failure: FALSE
819  */
820 BOOL WINAPI SetBitmapDimensionEx(
821     HBITMAP hbitmap, /* [in]  Handle to bitmap */
822     INT x,           /* [in]  Bitmap width */
823     INT y,           /* [in]  Bitmap height */
824     LPSIZE prevSize) /* [out] Address of structure for orig dims */
825 {
826     BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
827     if (!bmp) return FALSE;
828     if (prevSize) *prevSize = bmp->size;
829     bmp->size.cx = x;
830     bmp->size.cy = y;
831     GDI_ReleaseObj( hbitmap );
832     return TRUE;
833 }