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