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