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