xref: /reactos/win32ss/gdi/ntgdi/bitmaps.c (revision 090ccb3d)
1 /*
2  * COPYRIGHT:        GNU GPL, See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          Bitmap functions
5  * FILE:             win32ss/gdi/ntgdi/bitmaps.c
6  * PROGRAMERS:       Timo Kreuzer <timo.kreuzer@reactos.org>
7  *                   Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
8  */
9 
10 #include <win32k.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 BOOL
16 NTAPI
GreSetBitmapOwner(_In_ HBITMAP hbmp,_In_ ULONG ulOwner)17 GreSetBitmapOwner(
18     _In_ HBITMAP hbmp,
19     _In_ ULONG ulOwner)
20 {
21     /* Check if we have the correct object type */
22     if (GDI_HANDLE_GET_TYPE(hbmp) != GDILoObjType_LO_BITMAP_TYPE)
23     {
24         DPRINT1("Incorrect type for hbmp: %p\n", hbmp);
25         return FALSE;
26     }
27 
28     /// FIXME: this is a hack and doesn't handle a race condition properly.
29     /// It needs to be done in GDIOBJ_vSetObjectOwner atomically.
30 
31     /* Check if we set public or none */
32     if ((ulOwner == GDI_OBJ_HMGR_PUBLIC) ||
33         (ulOwner == GDI_OBJ_HMGR_NONE))
34     {
35         /* Only allow this for owned objects */
36         if (GreGetObjectOwner(hbmp) != GDI_OBJ_HMGR_POWNED)
37         {
38             DPRINT1("Cannot change owner for non-powned hbmp\n");
39             return FALSE;
40         }
41     }
42 
43     return GreSetObjectOwner(hbmp, ulOwner);
44 }
45 
46 LONG
47 NTAPI
UnsafeSetBitmapBits(_Inout_ PSURFACE psurf,_In_ ULONG cjBits,_In_ const VOID * pvBits)48 UnsafeSetBitmapBits(
49     _Inout_ PSURFACE psurf,
50     _In_ ULONG cjBits,
51     _In_ const VOID *pvBits)
52 {
53     PUCHAR pjDst;
54     const UCHAR *pjSrc;
55     LONG lDeltaDst, lDeltaSrc, lDeltaDstAbs;
56     ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
57 
58     NT_ASSERT(psurf->flags & API_BITMAP);
59     NT_ASSERT(psurf->SurfObj.iBitmapFormat <= BMF_32BPP);
60 
61     nWidth = psurf->SurfObj.sizlBitmap.cx;
62     nHeight = psurf->SurfObj.sizlBitmap.cy;
63     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
64 
65     pjDst = psurf->SurfObj.pvScan0;
66     pjSrc = pvBits;
67     lDeltaDst = psurf->SurfObj.lDelta;
68     lDeltaDstAbs = labs(lDeltaDst);
69     lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
70     NT_ASSERT(lDeltaSrc <= lDeltaDstAbs);
71 
72     cbDst = lDeltaDstAbs * nHeight;
73     cbSrc = lDeltaSrc * nHeight;
74     cjBits = min(cjBits, cbSrc);
75 
76     iSrc = iDst = 0;
77     for (Y = 0; Y < nHeight; Y++)
78     {
79         if (iSrc + lDeltaSrc > cjBits || iDst + lDeltaDstAbs > cbDst)
80         {
81             LONG lDelta = min(cjBits - iSrc, cbDst - iDst);
82             NT_ASSERT(lDelta >= 0);
83             RtlCopyMemory(pjDst, pjSrc, lDelta);
84             iSrc += lDelta;
85             break;
86         }
87 
88         /* Copy one line */
89         RtlCopyMemory(pjDst, pjSrc, lDeltaSrc);
90         pjSrc += lDeltaSrc;
91         pjDst += lDeltaDst;
92         iSrc += lDeltaSrc;
93         iDst += lDeltaDstAbs;
94     }
95 
96     return iSrc;
97 }
98 
99 HBITMAP
100 NTAPI
GreCreateBitmapEx(_In_ ULONG nWidth,_In_ ULONG nHeight,_In_ ULONG cjWidthBytes,_In_ ULONG iFormat,_In_ USHORT fjBitmap,_In_ ULONG cjSizeImage,_In_opt_ PVOID pvBits,_In_ FLONG flags)101 GreCreateBitmapEx(
102     _In_ ULONG nWidth,
103     _In_ ULONG nHeight,
104     _In_ ULONG cjWidthBytes,
105     _In_ ULONG iFormat,
106     _In_ USHORT fjBitmap,
107     _In_ ULONG cjSizeImage,
108     _In_opt_ PVOID pvBits,
109     _In_ FLONG flags)
110 {
111     PSURFACE psurf;
112     HBITMAP hbmp;
113     PVOID pvCompressedBits = NULL;
114 
115     /* Verify format */
116     if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
117 
118     /* The infamous RLE hack */
119     if ((iFormat == BMF_4RLE) || (iFormat == BMF_8RLE))
120     {
121         pvCompressedBits = pvBits;
122         pvBits = NULL;
123         iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
124     }
125 
126     /* Allocate a surface */
127     psurf = SURFACE_AllocSurface(STYPE_BITMAP,
128                                  nWidth,
129                                  nHeight,
130                                  iFormat,
131                                  fjBitmap,
132                                  cjWidthBytes,
133                                  pvCompressedBits ? 0 : cjSizeImage,
134                                  pvBits);
135     if (!psurf)
136     {
137         DPRINT1("SURFACE_AllocSurface failed.\n");
138         return NULL;
139     }
140 
141     /* The infamous RLE hack */
142     if (pvCompressedBits)
143     {
144         SIZEL sizl;
145         LONG lDelta;
146 
147         sizl.cx = nWidth;
148         sizl.cy = nHeight;
149         lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);
150 
151         pvBits = psurf->SurfObj.pvBits;
152         DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat, cjSizeImage);
153     }
154 
155     /* Get the handle for the bitmap */
156     hbmp = (HBITMAP)psurf->SurfObj.hsurf;
157 
158     /* Mark as API bitmap */
159     psurf->flags |= (flags | API_BITMAP);
160 
161     /* Unlock the surface and return */
162     SURFACE_UnlockSurface(psurf);
163     return hbmp;
164 }
165 
166 /* Creates a DDB surface,
167  * as in CreateCompatibleBitmap or CreateBitmap.
168  * Note that each scanline must be 32bit aligned!
169  */
170 HBITMAP
171 NTAPI
GreCreateBitmap(_In_ ULONG nWidth,_In_ ULONG nHeight,_In_ ULONG cPlanes,_In_ ULONG cBitsPixel,_In_opt_ PVOID pvBits)172 GreCreateBitmap(
173     _In_ ULONG nWidth,
174     _In_ ULONG nHeight,
175     _In_ ULONG cPlanes,
176     _In_ ULONG cBitsPixel,
177     _In_opt_ PVOID pvBits)
178 {
179     /* Call the extended function */
180     return GreCreateBitmapEx(nWidth,
181                              nHeight,
182                              0, /* Auto width */
183                              BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
184                              0, /* No bitmap flags */
185                              0, /* Auto size */
186                              pvBits,
187                              DDB_SURFACE /* DDB */);
188 }
189 
190 HBITMAP
191 APIENTRY
NtGdiCreateBitmap(IN INT nWidth,IN INT nHeight,IN UINT cPlanes,IN UINT cBitsPixel,IN OPTIONAL LPBYTE pUnsafeBits)192 NtGdiCreateBitmap(
193     IN INT nWidth,
194     IN INT nHeight,
195     IN UINT cPlanes,
196     IN UINT cBitsPixel,
197     IN OPTIONAL LPBYTE pUnsafeBits)
198 {
199     HBITMAP hbmp;
200     ULONG cRealBpp, cjWidthBytes, iFormat;
201     ULONGLONG cjSize;
202     PSURFACE psurf;
203 
204     /* Calculate bitmap format and real bits per pixel. */
205     iFormat = BitmapFormat(cBitsPixel * cPlanes, BI_RGB);
206     cRealBpp = gajBitsPerFormat[iFormat];
207 
208     /* Calculate width and image size in bytes */
209     cjWidthBytes = WIDTH_BYTES_ALIGN16(nWidth, cRealBpp);
210     cjSize = (ULONGLONG)cjWidthBytes * nHeight;
211 
212     /* Check parameters (possible overflow of cjSize!) */
213     if ((iFormat == 0) || (nWidth <= 0) || (nWidth >= 0x8000000) || (nHeight <= 0) ||
214         (cBitsPixel > 32) || (cPlanes > 32) || (cjSize >= 0x100000000ULL))
215     {
216         DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
217                 nWidth, nHeight, cBitsPixel, cPlanes);
218         EngSetLastError(ERROR_INVALID_PARAMETER);
219         return NULL;
220     }
221 
222     /* Allocate the surface (but don't set the bits) */
223     psurf = SURFACE_AllocSurface(STYPE_BITMAP,
224                                  nWidth,
225                                  nHeight,
226                                  iFormat,
227                                  0,
228                                  0,
229                                  0,
230                                  NULL);
231     if (!psurf)
232     {
233         DPRINT1("SURFACE_AllocSurface failed.\n");
234         return NULL;
235     }
236 
237     /* Mark as API and DDB bitmap */
238     psurf->flags |= (API_BITMAP | DDB_SURFACE);
239 
240     /* Check if we have bits to set */
241     if (pUnsafeBits)
242     {
243         /* Protect with SEH and copy the bits */
244         _SEH2_TRY
245         {
246             ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1);
247             UnsafeSetBitmapBits(psurf, cjSize, pUnsafeBits);
248         }
249         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
250         {
251             GDIOBJ_vDeleteObject(&psurf->BaseObject);
252             _SEH2_YIELD(return NULL;)
253         }
254         _SEH2_END
255     }
256     else
257     {
258         /* Zero the bits */
259         RtlZeroMemory(psurf->SurfObj.pvBits, psurf->SurfObj.cjBits);
260     }
261 
262     /* Get the handle for the bitmap */
263     hbmp = (HBITMAP)psurf->SurfObj.hsurf;
264 
265     /* Unlock the surface */
266     SURFACE_UnlockSurface(psurf);
267 
268     return hbmp;
269 }
270 
271 
272 HBITMAP FASTCALL
IntCreateCompatibleBitmap(PDC Dc,INT Width,INT Height,UINT Planes,UINT Bpp)273 IntCreateCompatibleBitmap(
274     PDC Dc,
275     INT Width,
276     INT Height,
277     UINT Planes,
278     UINT Bpp)
279 {
280     HBITMAP Bmp = NULL;
281     PPALETTE ppal;
282 
283     /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
284     if (0 == Width || 0 == Height)
285     {
286         return NtGdiGetStockObject(DEFAULT_BITMAP);
287     }
288 
289     if (Dc->dctype != DCTYPE_MEMORY)
290     {
291         PSURFACE psurf;
292 
293         Bmp = GreCreateBitmap(abs(Width),
294                               abs(Height),
295                               Planes ? Planes : 1,
296                               Bpp ? Bpp : Dc->ppdev->gdiinfo.cBitsPixel,
297                               NULL);
298         if (Bmp == NULL)
299         {
300             DPRINT1("Failed to allocate a bitmap!\n");
301             return NULL;
302         }
303 
304         psurf = SURFACE_ShareLockSurface(Bmp);
305         ASSERT(psurf);
306 
307         /* Dereference old palette and set new palette */
308         ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
309         ASSERT(ppal);
310         SURFACE_vSetPalette(psurf, ppal);
311         PALETTE_ShareUnlockPalette(ppal);
312 
313         /* Set flags */
314         psurf->flags = API_BITMAP;
315         psurf->hdc = NULL; // FIXME:
316         psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
317         SURFACE_ShareUnlockSurface(psurf);
318     }
319     else
320     {
321         DIBSECTION dibs;
322         INT Count;
323         PSURFACE psurf = Dc->dclevel.pSurface;
324         if(!psurf) psurf = psurfDefaultBitmap;
325         Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
326 
327         if (Count == sizeof(BITMAP))
328         {
329             PSURFACE psurfBmp;
330 
331             Bmp = GreCreateBitmap(abs(Width),
332                           abs(Height),
333                           Planes ? Planes : 1,
334                           Bpp ? Bpp : dibs.dsBm.bmBitsPixel,
335                           NULL);
336             if (Bmp == NULL)
337             {
338                 DPRINT1("Failed to allocate a bitmap!\n");
339                 return NULL;
340             }
341             psurfBmp = SURFACE_ShareLockSurface(Bmp);
342             ASSERT(psurfBmp);
343 
344             /* Dereference old palette and set new palette */
345             SURFACE_vSetPalette(psurfBmp, psurf->ppal);
346 
347             /* Set flags */
348             psurfBmp->flags = API_BITMAP;
349             psurfBmp->hdc = NULL; // FIXME:
350             psurfBmp->SurfObj.hdev = (HDEV)Dc->ppdev;
351             SURFACE_ShareUnlockSurface(psurfBmp);
352         }
353         else if (Count == sizeof(DIBSECTION))
354         {
355             /* A DIB section is selected in the DC */
356             BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
357             PVOID Bits;
358             BITMAPINFO* bi = (BITMAPINFO*)buf;
359 
360             bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);
361             bi->bmiHeader.biWidth         = Width;
362             bi->bmiHeader.biHeight        = Height;
363             bi->bmiHeader.biPlanes        = Planes ? Planes : dibs.dsBmih.biPlanes;
364             bi->bmiHeader.biBitCount      = Bpp ? Bpp : dibs.dsBmih.biBitCount;
365             bi->bmiHeader.biCompression   = dibs.dsBmih.biCompression;
366             bi->bmiHeader.biSizeImage     = 0;
367             bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
368             bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
369             bi->bmiHeader.biClrUsed       = dibs.dsBmih.biClrUsed;
370             bi->bmiHeader.biClrImportant  = dibs.dsBmih.biClrImportant;
371 
372             if (bi->bmiHeader.biCompression == BI_BITFIELDS)
373             {
374                 /* Copy the color masks */
375                 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
376             }
377             else if (bi->bmiHeader.biBitCount <= 8)
378             {
379                 /* Copy the color table */
380                 UINT Index;
381                 PPALETTE PalGDI;
382 
383                 if (!psurf->ppal)
384                 {
385                     EngSetLastError(ERROR_INVALID_HANDLE);
386                     return 0;
387                 }
388 
389                 PalGDI = psurf->ppal;
390 
391                 for (Index = 0;
392                         Index < 256 && Index < PalGDI->NumColors;
393                         Index++)
394                 {
395                     bi->bmiColors[Index].rgbRed   = PalGDI->IndexedColors[Index].peRed;
396                     bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
397                     bi->bmiColors[Index].rgbBlue  = PalGDI->IndexedColors[Index].peBlue;
398                     bi->bmiColors[Index].rgbReserved = 0;
399                 }
400             }
401 
402             Bmp = DIB_CreateDIBSection(Dc,
403                                        bi,
404                                        DIB_RGB_COLORS,
405                                        &Bits,
406                                        NULL,
407                                        0,
408                                        0);
409             return Bmp;
410         }
411     }
412     return Bmp;
413 }
414 
415 HBITMAP APIENTRY
NtGdiCreateCompatibleBitmap(HDC hDC,INT Width,INT Height)416 NtGdiCreateCompatibleBitmap(
417     HDC hDC,
418     INT Width,
419     INT Height)
420 {
421     HBITMAP Bmp;
422     PDC Dc;
423 
424     /* Check parameters */
425     if ((Width <= 0) || (Height <= 0) || ((Width * Height) > 0x3FFFFFFF))
426     {
427         EngSetLastError(ERROR_INVALID_PARAMETER);
428         return NULL;
429     }
430 
431     if (!hDC)
432         return GreCreateBitmap(Width, Height, 1, 1, 0);
433 
434     Dc = DC_LockDc(hDC);
435 
436     DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
437            hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
438 
439     if (NULL == Dc)
440     {
441         EngSetLastError(ERROR_INVALID_HANDLE);
442         return NULL;
443     }
444 
445     Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0);
446 
447     DC_UnlockDc(Dc);
448     return Bmp;
449 }
450 
451 BOOL
452 NTAPI
GreGetBitmapDimension(_In_ HBITMAP hBitmap,_Out_ LPSIZE psizDim)453 GreGetBitmapDimension(
454     _In_ HBITMAP hBitmap,
455     _Out_ LPSIZE psizDim)
456 {
457     PSURFACE psurfBmp;
458 
459     if (hBitmap == NULL)
460         return FALSE;
461 
462     /* Lock the bitmap */
463     psurfBmp = SURFACE_ShareLockSurface(hBitmap);
464     if (psurfBmp == NULL)
465     {
466         EngSetLastError(ERROR_INVALID_HANDLE);
467         return FALSE;
468     }
469 
470     *psizDim = psurfBmp->sizlDim;
471 
472     /* Unlock the bitmap */
473     SURFACE_ShareUnlockSurface(psurfBmp);
474 
475     return TRUE;
476 }
477 
478 BOOL
479 APIENTRY
NtGdiGetBitmapDimension(HBITMAP hBitmap,LPSIZE psizDim)480 NtGdiGetBitmapDimension(
481     HBITMAP hBitmap,
482     LPSIZE psizDim)
483 {
484     SIZE dim;
485 
486     if (!GreGetBitmapDimension(hBitmap, &dim))
487         return FALSE;
488 
489     /* Use SEH to copy the data to the caller */
490     _SEH2_TRY
491     {
492         ProbeForWrite(psizDim, sizeof(*psizDim), 1);
493         *psizDim = dim;
494     }
495     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
496     {
497         _SEH2_YIELD(return FALSE);
498     }
499     _SEH2_END
500 
501     return TRUE;
502 }
503 
504 
505 LONG
506 FASTCALL
UnsafeGetBitmapBits(PSURFACE psurf,DWORD Bytes,OUT PBYTE pvBits)507 UnsafeGetBitmapBits(
508     PSURFACE psurf,
509     DWORD Bytes,
510     OUT PBYTE pvBits)
511 {
512     PUCHAR pjDst, pjSrc;
513     LONG lDeltaDst, lDeltaSrc, lDeltaSrcAbs;
514     ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
515 
516     nWidth = psurf->SurfObj.sizlBitmap.cx;
517     nHeight = psurf->SurfObj.sizlBitmap.cy;
518     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
519 
520     /* Get pointers */
521     pjSrc = psurf->SurfObj.pvScan0;
522     pjDst = pvBits;
523     lDeltaSrc = psurf->SurfObj.lDelta;
524     lDeltaSrcAbs = labs(lDeltaSrc);
525     lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
526     NT_ASSERT(lDeltaSrcAbs >= lDeltaDst);
527 
528     cbSrc = nHeight * lDeltaSrcAbs;
529     cbDst = nHeight * lDeltaDst;
530     Bytes = min(Bytes, cbDst);
531 
532     iSrc = iDst = 0;
533     for (Y = 0; Y < nHeight; Y++)
534     {
535         if (iSrc + lDeltaSrcAbs > cbSrc || iDst + lDeltaDst > Bytes)
536         {
537             LONG lDelta = min(cbSrc - iSrc, Bytes - iDst);
538             NT_ASSERT(lDelta >= 0);
539             RtlCopyMemory(pjDst, pjSrc, lDelta);
540             iDst += lDelta;
541             break;
542         }
543 
544         /* Copy one line */
545         RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
546         pjSrc += lDeltaSrc;
547         pjDst += lDeltaDst;
548         iSrc += lDeltaSrcAbs;
549         iDst += lDeltaDst;
550     }
551 
552     return iDst;
553 }
554 
555 LONG
556 APIENTRY
NtGdiGetBitmapBits(HBITMAP hBitmap,ULONG cjBuffer,OUT OPTIONAL PBYTE pUnsafeBits)557 NtGdiGetBitmapBits(
558     HBITMAP hBitmap,
559     ULONG cjBuffer,
560     OUT OPTIONAL PBYTE pUnsafeBits)
561 {
562     PSURFACE psurf;
563     ULONG cjSize;
564     LONG ret;
565 
566     /* Check parameters */
567     if (pUnsafeBits != NULL && cjBuffer == 0)
568     {
569         return 0;
570     }
571 
572     /* Lock the bitmap */
573     psurf = SURFACE_ShareLockSurface(hBitmap);
574     if (!psurf)
575     {
576         EngSetLastError(ERROR_INVALID_HANDLE);
577         return 0;
578     }
579 
580     /* Calculate the size of the bitmap in bytes */
581     cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx,
582                 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
583                 psurf->SurfObj.sizlBitmap.cy;
584 
585     /* If the bits vector is null, the function should return the read size */
586     if (pUnsafeBits == NULL)
587     {
588         SURFACE_ShareUnlockSurface(psurf);
589         return cjSize;
590     }
591 
592     /* Don't copy more bytes than the buffer has */
593     cjBuffer = min(cjBuffer, cjSize);
594 
595     // FIXME: Use MmSecureVirtualMemory
596     _SEH2_TRY
597     {
598         ProbeForWrite(pUnsafeBits, cjBuffer, 1);
599         ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
600     }
601     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
602     {
603         ret = 0;
604     }
605     _SEH2_END
606 
607     SURFACE_ShareUnlockSurface(psurf);
608 
609     return ret;
610 }
611 
612 
613 LONG APIENTRY
NtGdiSetBitmapBits(HBITMAP hBitmap,DWORD Bytes,IN PBYTE pUnsafeBits)614 NtGdiSetBitmapBits(
615     HBITMAP hBitmap,
616     DWORD Bytes,
617     IN PBYTE pUnsafeBits)
618 {
619     LONG ret;
620     PSURFACE psurf;
621 
622     if (pUnsafeBits == NULL || Bytes == 0)
623     {
624         return 0;
625     }
626 
627     if (GDI_HANDLE_IS_STOCKOBJ(hBitmap))
628     {
629         return 0;
630     }
631 
632     psurf = SURFACE_ShareLockSurface(hBitmap);
633     if (psurf == NULL)
634     {
635         EngSetLastError(ERROR_INVALID_HANDLE);
636         return 0;
637     }
638 
639     if (((psurf->flags & API_BITMAP) == 0) ||
640         (psurf->SurfObj.iBitmapFormat > BMF_32BPP))
641     {
642         DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
643                 psurf->SurfObj.iBitmapFormat,
644                 psurf->flags);
645         EngSetLastError(ERROR_INVALID_HANDLE);
646         SURFACE_ShareUnlockSurface(psurf);
647         return 0;
648     }
649 
650     _SEH2_TRY
651     {
652         /* NOTE: Win2k3 doesn't check WORD alignment here. */
653         ProbeForWrite(pUnsafeBits, Bytes, 1);
654         ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
655     }
656     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
657     {
658         ret = 0;
659     }
660     _SEH2_END
661 
662     SURFACE_ShareUnlockSurface(psurf);
663 
664     return ret;
665 }
666 
667 BOOL APIENTRY
NtGdiSetBitmapDimension(HBITMAP hBitmap,INT Width,INT Height,LPSIZE Size)668 NtGdiSetBitmapDimension(
669     HBITMAP hBitmap,
670     INT Width,
671     INT Height,
672     LPSIZE Size)
673 {
674     PSURFACE psurf;
675     BOOL Ret = TRUE;
676 
677     if (hBitmap == NULL)
678         return FALSE;
679 
680     psurf = SURFACE_ShareLockSurface(hBitmap);
681     if (psurf == NULL)
682     {
683         EngSetLastError(ERROR_INVALID_HANDLE);
684         return FALSE;
685     }
686 
687     if (Size)
688     {
689         _SEH2_TRY
690         {
691             ProbeForWrite(Size, sizeof(SIZE), 1);
692             *Size = psurf->sizlDim;
693         }
694         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
695         {
696             Ret = FALSE;
697         }
698         _SEH2_END
699     }
700 
701     /* The dimension is changed even if writing the old value failed */
702     psurf->sizlDim.cx = Width;
703     psurf->sizlDim.cy = Height;
704 
705     SURFACE_ShareUnlockSurface(psurf);
706 
707     return Ret;
708 }
709 
710 /*  Internal Functions  */
711 
712 HBITMAP
713 FASTCALL
BITMAP_CopyBitmap(HBITMAP hBitmap)714 BITMAP_CopyBitmap(HBITMAP hBitmap)
715 {
716     HBITMAP hbmNew;
717     SURFACE *psurfSrc, *psurfNew;
718 
719     /* Fail, if no source bitmap is given */
720     if (hBitmap == NULL) return 0;
721 
722     /* Lock the source bitmap */
723     psurfSrc = SURFACE_ShareLockSurface(hBitmap);
724     if (psurfSrc == NULL)
725     {
726         return 0;
727     }
728 
729     /* Allocate a new bitmap with the same dimensions as the source bmp */
730     hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
731                                psurfSrc->SurfObj.sizlBitmap.cy,
732                                abs(psurfSrc->SurfObj.lDelta),
733                                psurfSrc->SurfObj.iBitmapFormat,
734                                psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN,
735                                psurfSrc->SurfObj.cjBits,
736                                NULL,
737                                psurfSrc->flags);
738 
739     if (hbmNew)
740     {
741         /* Lock the new bitmap */
742         psurfNew = SURFACE_ShareLockSurface(hbmNew);
743         if (psurfNew)
744         {
745             /* Copy the bitmap bits to the new bitmap buffer */
746             RtlCopyMemory(psurfNew->SurfObj.pvBits,
747                           psurfSrc->SurfObj.pvBits,
748                           psurfNew->SurfObj.cjBits);
749 
750 
751             /* Reference the palette of the source bitmap and use it */
752             SURFACE_vSetPalette(psurfNew, psurfSrc->ppal);
753 
754             /* Unlock the new surface */
755             SURFACE_ShareUnlockSurface(psurfNew);
756         }
757         else
758         {
759             /* Failed to lock the bitmap, shouldn't happen */
760             GreDeleteObject(hbmNew);
761             hbmNew = NULL;
762         }
763     }
764 
765     /* Unlock the source bitmap and return the handle of the new bitmap */
766     SURFACE_ShareUnlockSurface(psurfSrc);
767     return hbmNew;
768 }
769 
770 INT APIENTRY
BITMAP_GetObject(SURFACE * psurf,INT Count,LPVOID buffer)771 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
772 {
773     PBITMAP pBitmap;
774 
775     if (!buffer) return sizeof(BITMAP);
776     if ((UINT)Count < sizeof(BITMAP)) return 0;
777 
778     /* Always fill a basic BITMAP structure */
779     pBitmap = buffer;
780     pBitmap->bmType = 0;
781     pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
782     pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
783     pBitmap->bmPlanes = 1;
784     pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
785     pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
786 
787     /* Check for DIB section */
788     if (psurf->hSecure)
789     {
790         /* Set bmBits in this case */
791         pBitmap->bmBits = psurf->SurfObj.pvBits;
792         /* DIBs data are 32 bits aligned */
793         pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
794 
795         if (Count >= sizeof(DIBSECTION))
796         {
797             /* Fill rest of DIBSECTION */
798             PDIBSECTION pds = buffer;
799 
800             pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
801             pds->dsBmih.biWidth = pds->dsBm.bmWidth;
802             pds->dsBmih.biHeight = pds->dsBm.bmHeight;
803             pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
804             pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
805 
806             switch (psurf->SurfObj.iBitmapFormat)
807             {
808                 case BMF_1BPP:
809                 case BMF_4BPP:
810                 case BMF_8BPP:
811                    pds->dsBmih.biCompression = BI_RGB;
812                    break;
813 
814                 case BMF_16BPP:
815                     if (psurf->ppal->flFlags & PAL_RGB16_555)
816                         pds->dsBmih.biCompression = BI_RGB;
817                     else
818                         pds->dsBmih.biCompression = BI_BITFIELDS;
819                     break;
820 
821                 case BMF_24BPP:
822                 case BMF_32BPP:
823                     /* 24/32bpp BI_RGB is actually BGR format */
824                     if (psurf->ppal->flFlags & PAL_BGR)
825                         pds->dsBmih.biCompression = BI_RGB;
826                     else
827                         pds->dsBmih.biCompression = BI_BITFIELDS;
828                     break;
829 
830                 case BMF_4RLE:
831                    pds->dsBmih.biCompression = BI_RLE4;
832                    break;
833                 case BMF_8RLE:
834                    pds->dsBmih.biCompression = BI_RLE8;
835                    break;
836                 case BMF_JPEG:
837                    pds->dsBmih.biCompression = BI_JPEG;
838                    break;
839                 case BMF_PNG:
840                    pds->dsBmih.biCompression = BI_PNG;
841                    break;
842                 default:
843                     ASSERT(FALSE); /* This shouldn't happen */
844             }
845 
846             pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
847             pds->dsBmih.biXPelsPerMeter = 0;
848             pds->dsBmih.biYPelsPerMeter = 0;
849             pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
850             pds->dsBmih.biClrImportant = psurf->biClrImportant;
851             pds->dsBitfields[0] = psurf->ppal->RedMask;
852             pds->dsBitfields[1] = psurf->ppal->GreenMask;
853             pds->dsBitfields[2] = psurf->ppal->BlueMask;
854             pds->dshSection = psurf->hDIBSection;
855             pds->dsOffset = psurf->dwOffset;
856 
857             return sizeof(DIBSECTION);
858         }
859     }
860     else
861     {
862         /* Not set according to wine test, confirmed in win2k */
863         pBitmap->bmBits = NULL;
864     }
865 
866     return sizeof(BITMAP);
867 }
868 
869 /*
870  * @implemented
871  */
872 HDC
873 APIENTRY
NtGdiGetDCforBitmap(IN HBITMAP hsurf)874 NtGdiGetDCforBitmap(
875     IN HBITMAP hsurf)
876 {
877     HDC hdc = NULL;
878     PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
879     if (psurf)
880     {
881         hdc = psurf->hdc;
882         SURFACE_ShareUnlockSurface(psurf);
883     }
884     return hdc;
885 }
886 
887 
888 /* EOF */
889