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