[WIN32K]
[reactos.git] / subsystems / win32 / win32k / objects / bitmaps.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <win32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 LONG APIENTRY
26 IntSetBitmapBits(
27 PSURFACE psurf,
28 DWORD Bytes,
29 IN PBYTE Bits)
30 {
31 /* Don't copy more bytes than the buffer has */
32 Bytes = min(Bytes, psurf->SurfObj.cjBits);
33
34 RtlCopyMemory(psurf->SurfObj.pvBits, Bits, Bytes);
35
36 return Bytes;
37 }
38
39 void
40 NTAPI
41 UnsafeSetBitmapBits(
42 PSURFACE psurf,
43 IN ULONG cjBits,
44 IN PVOID pvBits)
45 {
46 PUCHAR pjDst, pjSrc;
47 LONG lDeltaDst, lDeltaSrc;
48 ULONG nWidth, nHeight, cBitsPixel;
49
50 nWidth = psurf->SurfObj.sizlBitmap.cx;
51 nHeight = psurf->SurfObj.sizlBitmap.cy;
52 cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
53
54 /* Get pointers */
55 pjDst = psurf->SurfObj.pvScan0;
56 pjSrc = pvBits;
57 lDeltaDst = psurf->SurfObj.lDelta;
58 lDeltaSrc = BITMAP_GetWidthBytes(nWidth, cBitsPixel);
59
60 while (nHeight--)
61 {
62 /* Copy one line */
63 memcpy(pjDst, pjSrc, lDeltaSrc);
64 pjSrc += lDeltaSrc;
65 pjDst += lDeltaDst;
66 }
67
68 }
69
70 HBITMAP
71 APIENTRY
72 GreCreateBitmapEx(
73 IN INT nWidth,
74 IN INT nHeight,
75 IN ULONG cjWidthBytes,
76 IN ULONG iFormat,
77 IN USHORT fjBitmap,
78 IN ULONG cjSizeImage,
79 IN OPTIONAL PVOID pvBits)
80 {
81 PSURFACE psurf;
82 SURFOBJ *pso;
83 HBITMAP hbmp;
84 PVOID pvCompressedBits;
85 SIZEL sizl;
86 FLONG fl = 0;
87
88 /* Verify format */
89 if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
90
91 /* Allocate a surface */
92 psurf = SURFACE_AllocSurface(STYPE_BITMAP, nWidth, nHeight, iFormat);
93 if (!psurf)
94 {
95 DPRINT1("SURFACE_AllocSurface failed.\n");
96 return NULL;
97 }
98
99 /* Get the handle for the bitmap and the surfobj */
100 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
101 pso = &psurf->SurfObj;
102
103 /* The infamous RLE hack */
104 if (iFormat == BMF_4RLE)
105 {
106 sizl.cx = nWidth; sizl.cy = nHeight;
107 pvCompressedBits = pvBits;
108 pvBits = EngAllocMem(FL_ZERO_MEMORY, pso->cjBits, TAG_DIB);
109 Decompress4bpp(sizl, pvCompressedBits, pvBits, pso->lDelta);
110 fl |= BMF_RLE_HACK;
111 }
112 else if (iFormat == BMF_8RLE)
113 {
114 sizl.cx = nWidth; sizl.cy = nHeight;
115 pvCompressedBits = pvBits;
116 pvBits = EngAllocMem(FL_ZERO_MEMORY, pso->cjBits, TAG_DIB);
117 Decompress8bpp(sizl, pvCompressedBits, pvBits, pso->lDelta);
118 fl |= BMF_RLE_HACK;
119 }
120
121 /* Set the bitmap bits */
122 if (!SURFACE_bSetBitmapBits(psurf, fjBitmap, cjWidthBytes, pvBits))
123 {
124 /* Bail out if that failed */
125 DPRINT1("SURFACE_bSetBitmapBits failed.\n");
126 SURFACE_FreeSurfaceByHandle(hbmp);
127 return NULL;
128 }
129
130 /* Mark as API bitmap */
131 psurf->flags |= API_BITMAP;
132
133 /* Unlock the surface and return */
134 SURFACE_UnlockSurface(psurf);
135 return hbmp;
136 }
137
138 HBITMAP
139 APIENTRY
140 GreCreateBitmap(
141 IN INT nWidth,
142 IN INT nHeight,
143 IN UINT cPlanes,
144 IN UINT cBitsPixel,
145 IN OPTIONAL PVOID pvBits)
146 {
147 /* Call the extended function */
148 return GreCreateBitmapEx(nWidth,
149 nHeight,
150 0, /* auto width */
151 BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
152 0, /* no bitmap flags */
153 0, /* auto size */
154 pvBits);
155 }
156
157 HBITMAP
158 APIENTRY
159 NtGdiCreateBitmap(
160 IN INT nWidth,
161 IN INT nHeight,
162 IN UINT cPlanes,
163 IN UINT cBitsPixel,
164 IN OPTIONAL LPBYTE pUnsafeBits)
165 {
166 PSURFACE psurf;
167 SURFOBJ *pso;
168 HBITMAP hbmp;
169 FLONG fl = 0;
170 ULONG cjWidthBytes, iFormat;
171
172 /* NOTE: Windows also doesn't store nr. of planes separately! */
173 cBitsPixel = BITMAP_GetRealBitsPixel(cBitsPixel * cPlanes);
174
175 /* Calculate bitmap format */
176 iFormat = BitmapFormat(cBitsPixel, BI_RGB);
177
178 /* Check parameters */
179 if (iFormat == 0 || nWidth <= 0 || nWidth >= 0x8000000 || nHeight <= 0)
180 {
181 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
182 nWidth, nHeight, cBitsPixel);
183 EngSetLastError(ERROR_INVALID_PARAMETER);
184 return NULL;
185 }
186
187 /* Make sure that cjBits will not overflow */
188 cjWidthBytes = DIB_GetDIBWidthBytes(nWidth, cBitsPixel);
189 if ((ULONGLONG)cjWidthBytes * nHeight >= 0x100000000ULL)
190 {
191 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
192 nWidth, nHeight, cBitsPixel);
193 EngSetLastError(ERROR_INVALID_PARAMETER);
194 return NULL;
195 }
196
197 /* Allocate a surface */
198 psurf = SURFACE_AllocSurface(STYPE_BITMAP, nWidth, nHeight, iFormat);
199 if (!psurf)
200 {
201 DPRINT1("SURFACE_AllocSurface failed.\n");
202 EngSetLastError(ERROR_OUTOFMEMORY);
203 return NULL;
204 }
205
206 /* Get the handle for the bitmap and the surfobj */
207 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
208 pso = &psurf->SurfObj;
209
210 /* Allocate the bitmap bits */
211 if (!SURFACE_bSetBitmapBits(psurf, fl, 0, NULL))
212 {
213 /* Bail out if that failed */
214 DPRINT1("SURFACE_bSetBitmapBits failed.\n");
215 SURFACE_FreeSurfaceByHandle(hbmp);
216 return NULL;
217 }
218
219 if (pUnsafeBits)
220 {
221 _SEH2_TRY
222 {
223 ProbeForRead(pUnsafeBits, cjWidthBytes * nHeight, 1);
224 UnsafeSetBitmapBits(psurf, 0, pUnsafeBits);
225 }
226 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
227 {
228 SURFACE_FreeSurfaceByHandle(hbmp);
229 _SEH2_YIELD(return NULL;)
230 }
231 _SEH2_END
232 }
233
234 /* Mark as API bitmap */
235 psurf->flags |= API_BITMAP;
236
237 /* Unlock the surface and return */
238 SURFACE_UnlockSurface(psurf);
239 return hbmp;
240 }
241
242
243 HBITMAP FASTCALL
244 IntCreateCompatibleBitmap(
245 PDC Dc,
246 INT Width,
247 INT Height)
248 {
249 HBITMAP Bmp = NULL;
250
251 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
252 if (0 == Width || 0 == Height)
253 {
254 Bmp = NtGdiGetStockObject(DEFAULT_BITMAP);
255 }
256 else
257 {
258 if (Dc->dctype != DC_TYPE_MEMORY)
259 {
260 PSURFACE psurf;
261 SIZEL size;
262
263 size.cx = abs(Width);
264 size.cy = abs(Height);
265 Bmp = GreCreateBitmap(abs(Width),
266 abs(Height),
267 1,
268 Dc->ppdev->gdiinfo.cBitsPixel,
269 NULL);
270 psurf = SURFACE_LockSurface(Bmp);
271 ASSERT(psurf);
272 /* Set palette */
273 psurf->ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
274 /* Set flags */
275 psurf->flags = API_BITMAP;
276 psurf->hdc = NULL; // Fixme
277 SURFACE_UnlockSurface(psurf);
278 }
279 else
280 {
281 DIBSECTION dibs;
282 INT Count;
283 PSURFACE psurf = Dc->dclevel.pSurface;
284 Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
285
286 if (Count)
287 {
288 if (Count == sizeof(BITMAP))
289 {
290 SIZEL size;
291 PSURFACE psurfBmp;
292 size.cx = abs(Width);
293 size.cy = abs(Height);
294 Bmp = GreCreateBitmap(abs(Width),
295 abs(Height),
296 1,
297 dibs.dsBm.bmBitsPixel,
298 NULL);
299 psurfBmp = SURFACE_LockSurface(Bmp);
300 ASSERT(psurfBmp);
301 /* Assign palette */
302 psurfBmp->ppal = psurf->ppal;
303 GDIOBJ_IncrementShareCount((POBJ)psurf->ppal);
304 /* Set flags */
305 psurfBmp->flags = API_BITMAP;
306 psurfBmp->hdc = NULL; // Fixme
307 SURFACE_UnlockSurface(psurfBmp);
308 }
309 else
310 {
311 /* A DIB section is selected in the DC */
312 BITMAPV5INFO bi;
313 PVOID Bits;
314
315 RtlZeroMemory(&bi.bmiHeader, sizeof(bi.bmiHeader));
316 bi.bmiHeader.bV5Size = sizeof(bi.bmiHeader);
317 bi.bmiHeader.bV5Width = Width;
318 bi.bmiHeader.bV5Height = Height;
319 bi.bmiHeader.bV5Planes = dibs.dsBmih.biPlanes;
320 bi.bmiHeader.bV5BitCount = dibs.dsBmih.biBitCount;
321 bi.bmiHeader.bV5Compression = dibs.dsBmih.biCompression;
322 bi.bmiHeader.bV5SizeImage = 0;
323 bi.bmiHeader.bV5XPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
324 bi.bmiHeader.bV5YPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
325 bi.bmiHeader.bV5ClrUsed = dibs.dsBmih.biClrUsed;
326 bi.bmiHeader.bV5ClrImportant = dibs.dsBmih.biClrImportant;
327
328 if (bi.bmiHeader.bV5Compression == BI_BITFIELDS)
329 {
330 /* Copy the color masks */
331 bi.bmiHeader.bV5RedMask = dibs.dsBitfields[0];
332 bi.bmiHeader.bV5GreenMask = dibs.dsBitfields[1];
333 bi.bmiHeader.bV5BlueMask = dibs.dsBitfields[2];
334 }
335 else if (bi.bmiHeader.bV5BitCount <= 8)
336 {
337 /* Copy the color table */
338 UINT Index;
339 PPALETTE PalGDI;
340
341 if (!psurf->ppal)
342 {
343 SetLastWin32Error(ERROR_INVALID_HANDLE);
344 return 0;
345 }
346
347 PalGDI = PALETTE_LockPalette(psurf->ppal->BaseObject.hHmgr);
348
349 for (Index = 0;
350 Index < 256 && Index < PalGDI->NumColors;
351 Index++)
352 {
353 bi.bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
354 bi.bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
355 bi.bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
356 bi.bmiColors[Index].rgbReserved = 0;
357 }
358 PALETTE_UnlockPalette(PalGDI);
359
360 Bmp = DIB_CreateDIBSection(Dc,
361 &bi,
362 DIB_RGB_COLORS,
363 &Bits,
364 NULL,
365 0,
366 0);
367 return Bmp;
368 }
369 }
370 }
371 }
372 }
373 return Bmp;
374 }
375
376 HBITMAP APIENTRY
377 NtGdiCreateCompatibleBitmap(
378 HDC hDC,
379 INT Width,
380 INT Height)
381 {
382 HBITMAP Bmp;
383 PDC Dc;
384
385 if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
386 {
387 SetLastWin32Error(ERROR_INVALID_PARAMETER);
388 return NULL;
389 }
390
391 if (!hDC)
392 return GreCreateBitmap(Width, Height, 1, 1, 0);
393
394 Dc = DC_LockDc(hDC);
395
396 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
397 hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
398
399 if (NULL == Dc)
400 {
401 SetLastWin32Error(ERROR_INVALID_HANDLE);
402 return NULL;
403 }
404
405 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
406
407 DPRINT("\t\t%04x\n", Bmp);
408 DC_UnlockDc(Dc);
409 return Bmp;
410 }
411
412 BOOL APIENTRY
413 NtGdiGetBitmapDimension(
414 HBITMAP hBitmap,
415 LPSIZE Dimension)
416 {
417 PSURFACE psurfBmp;
418 BOOL Ret = TRUE;
419
420 if (hBitmap == NULL)
421 return FALSE;
422
423 psurfBmp = SURFACE_LockSurface(hBitmap);
424 if (psurfBmp == NULL)
425 {
426 SetLastWin32Error(ERROR_INVALID_HANDLE);
427 return FALSE;
428 }
429
430 _SEH2_TRY
431 {
432 ProbeForWrite(Dimension, sizeof(SIZE), 1);
433 *Dimension = psurfBmp->sizlDim;
434 }
435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
436 {
437 Ret = FALSE;
438 }
439 _SEH2_END
440
441 SURFACE_UnlockSurface(psurfBmp);
442
443 return Ret;
444 }
445
446 COLORREF APIENTRY
447 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
448 {
449 PDC dc = NULL;
450 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
451 BOOL bInRect = FALSE;
452 SURFACE *psurf;
453 SURFOBJ *pso;
454 PPALETTE ppal;
455 EXLATEOBJ exlo;
456 HBITMAP hBmpTmp;
457
458 dc = DC_LockDc(hDC);
459
460 if (!dc)
461 {
462 SetLastWin32Error(ERROR_INVALID_HANDLE);
463 return Result;
464 }
465
466 if (dc->dctype == DC_TYPE_INFO)
467 {
468 DC_UnlockDc(dc);
469 return Result;
470 }
471
472 XPos += dc->ptlDCOrig.x;
473 YPos += dc->ptlDCOrig.y;
474 if (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos))
475 {
476 bInRect = TRUE;
477 psurf = dc->dclevel.pSurface;
478 if (psurf)
479 {
480 pso = &psurf->SurfObj;
481 if (psurf->ppal)
482 {
483 ppal = psurf->ppal;
484 GDIOBJ_IncrementShareCount(&ppal->BaseObject);
485 }
486 else
487 ppal = PALETTE_ShareLockPalette(dc->ppdev->devinfo.hpalDefault);
488
489 if (psurf->SurfObj.iBitmapFormat == BMF_1BPP && !psurf->hSecure)
490 {
491 /* FIXME: palette should be gpalMono already ! */
492 EXLATEOBJ_vInitialize(&exlo, &gpalMono, &gpalRGB, 0, 0xffffff, 0);
493 }
494 else
495 {
496 EXLATEOBJ_vInitialize(&exlo, ppal, &gpalRGB, 0, 0xffffff, 0);
497 }
498
499 // check if this DC has a DIB behind it...
500 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
501 {
502 ASSERT(pso->lDelta);
503 Result = XLATEOBJ_iXlate(&exlo.xlo,
504 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
505 }
506
507 EXLATEOBJ_vCleanup(&exlo);
508 PALETTE_ShareUnlockPalette(ppal);
509 }
510 }
511 DC_UnlockDc(dc);
512
513 // if Result is still CLR_INVALID, then the "quick" method above didn't work
514 if (bInRect && Result == CLR_INVALID)
515 {
516 // FIXME: create a 1x1 32BPP DIB, and blit to it
517 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
518 if (hDCTmp)
519 {
520 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
521 BITMAPINFO bi;
522 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
523 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
524 bi.bmiHeader.biWidth,
525 bi.bmiHeader.biHeight,
526 0,
527 NULL,
528 &bi,
529 DIB_RGB_COLORS,
530 bi.bmiHeader.biBitCount,
531 bi.bmiHeader.biSizeImage,
532 0,
533 0);
534
535 //HBITMAP hBmpTmp = GreCreateBitmap(1, 1, 1, 32, NULL);
536 if (hBmpTmp)
537 {
538 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
539 if (hBmpOld)
540 {
541 PSURFACE psurf;
542
543 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
544 NtGdiSelectBitmap(hDCTmp, hBmpOld);
545
546 // our bitmap is no longer selected, so we can access it's stuff...
547 psurf = SURFACE_LockSurface(hBmpTmp);
548 if (psurf)
549 {
550 // Dont you need to convert something here?
551 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
552 SURFACE_UnlockSurface(psurf);
553 }
554 }
555 GreDeleteObject(hBmpTmp);
556 }
557 NtGdiDeleteObjectApp(hDCTmp);
558 }
559 }
560
561 return Result;
562 }
563
564
565 LONG APIENTRY
566 IntGetBitmapBits(
567 PSURFACE psurf,
568 DWORD Bytes,
569 OUT PBYTE Bits)
570 {
571 LONG ret;
572
573 ASSERT(Bits);
574
575 /* Don't copy more bytes than the buffer has */
576 Bytes = min(Bytes, psurf->SurfObj.cjBits);
577
578 #if 0
579 /* FIXME: Call DDI CopyBits here if available */
580 if (psurf->DDBitmap)
581 {
582 DPRINT("Calling device specific BitmapBits\n");
583 if (psurf->DDBitmap->funcs->pBitmapBits)
584 {
585 ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
586 bits,
587 count,
588 DDB_GET);
589 }
590 else
591 {
592 ERR_(bitmap)("BitmapBits == NULL??\n");
593 ret = 0;
594 }
595 }
596 else
597 #endif
598 {
599 RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
600 ret = Bytes;
601 }
602 return ret;
603 }
604
605 LONG APIENTRY
606 NtGdiGetBitmapBits(
607 HBITMAP hBitmap,
608 ULONG Bytes,
609 OUT OPTIONAL PBYTE pUnsafeBits)
610 {
611 PSURFACE psurf;
612 LONG bmSize, ret;
613
614 if (pUnsafeBits != NULL && Bytes == 0)
615 {
616 return 0;
617 }
618
619 psurf = SURFACE_LockSurface(hBitmap);
620 if (!psurf)
621 {
622 SetLastWin32Error(ERROR_INVALID_HANDLE);
623 return 0;
624 }
625
626 bmSize = BITMAP_GetWidthBytes(psurf->SurfObj.sizlBitmap.cx,
627 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
628 abs(psurf->SurfObj.sizlBitmap.cy);
629
630 /* If the bits vector is null, the function should return the read size */
631 if (pUnsafeBits == NULL)
632 {
633 SURFACE_UnlockSurface(psurf);
634 return bmSize;
635 }
636
637 /* Don't copy more bytes than the buffer has */
638 Bytes = min(Bytes, bmSize);
639
640 // FIXME: use MmSecureVirtualMemory
641 _SEH2_TRY
642 {
643 ProbeForWrite(pUnsafeBits, Bytes, 1);
644 ret = IntGetBitmapBits(psurf, Bytes, pUnsafeBits);
645 }
646 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
647 {
648 ret = 0;
649 }
650 _SEH2_END
651
652 SURFACE_UnlockSurface(psurf);
653
654 return ret;
655 }
656
657
658 LONG APIENTRY
659 NtGdiSetBitmapBits(
660 HBITMAP hBitmap,
661 DWORD Bytes,
662 IN PBYTE pUnsafeBits)
663 {
664 LONG ret;
665 PSURFACE psurf;
666
667 if (pUnsafeBits == NULL || Bytes == 0)
668 {
669 return 0;
670 }
671
672 psurf = SURFACE_LockSurface(hBitmap);
673 if (psurf == NULL)
674 {
675 SetLastWin32Error(ERROR_INVALID_HANDLE);
676 return 0;
677 }
678
679 _SEH2_TRY
680 {
681 ProbeForRead(pUnsafeBits, Bytes, 1);
682 UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
683 ret = 1;
684 }
685 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
686 {
687 ret = 0;
688 }
689 _SEH2_END
690
691 SURFACE_UnlockSurface(psurf);
692
693 return ret;
694 }
695
696 BOOL APIENTRY
697 NtGdiSetBitmapDimension(
698 HBITMAP hBitmap,
699 INT Width,
700 INT Height,
701 LPSIZE Size)
702 {
703 PSURFACE psurf;
704 BOOL Ret = TRUE;
705
706 if (hBitmap == NULL)
707 return FALSE;
708
709 psurf = SURFACE_LockSurface(hBitmap);
710 if (psurf == NULL)
711 {
712 SetLastWin32Error(ERROR_INVALID_HANDLE);
713 return FALSE;
714 }
715
716 if (Size)
717 {
718 _SEH2_TRY
719 {
720 ProbeForWrite(Size, sizeof(SIZE), 1);
721 *Size = psurf->sizlDim;
722 }
723 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
724 {
725 Ret = FALSE;
726 }
727 _SEH2_END
728 }
729
730 /* The dimension is changed even if writing the old value failed */
731 psurf->sizlDim.cx = Width;
732 psurf->sizlDim.cy = Height;
733
734 SURFACE_UnlockSurface(psurf);
735
736 return Ret;
737 }
738
739 VOID IntHandleSpecialColorType(HDC hDC, COLORREF* Color)
740 {
741 PDC pdc = NULL;
742 RGBQUAD quad;
743 PALETTEENTRY palEntry;
744 UINT index;
745
746 switch (*Color >> 24)
747 {
748 case 0x10: /* DIBINDEX */
749 if (IntGetDIBColorTable(hDC, LOWORD(*Color), 1, &quad) == 1)
750 {
751 *Color = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
752 }
753 else
754 {
755 /* Out of color table bounds - use black */
756 *Color = RGB(0, 0, 0);
757 }
758 break;
759 case 0x02: /* PALETTERGB */
760 pdc = DC_LockDc(hDC);
761 if (pdc->dclevel.hpal != NtGdiGetStockObject(DEFAULT_PALETTE))
762 {
763 index = NtGdiGetNearestPaletteIndex(pdc->dclevel.hpal, *Color);
764 IntGetPaletteEntries(pdc->dclevel.hpal, index, 1, &palEntry);
765 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
766 }
767 else
768 {
769 /* Use the pure color */
770 *Color = *Color & 0x00FFFFFF;
771 }
772 DC_UnlockDc(pdc);
773 break;
774 case 0x01: /* PALETTEINDEX */
775 pdc = DC_LockDc(hDC);
776 if (IntGetPaletteEntries(pdc->dclevel.hpal, LOWORD(*Color), 1, &palEntry) == 1)
777 {
778 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
779 }
780 else
781 {
782 /* Index does not exist, use zero index */
783 IntGetPaletteEntries(pdc->dclevel.hpal, 0, 1, &palEntry);
784 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
785 }
786 DC_UnlockDc(pdc);
787 break;
788 default:
789 DPRINT("Unsupported color type %d passed\n", *Color >> 24);
790 break;
791 }
792 }
793
794 BOOL APIENTRY
795 GdiSetPixelV(
796 HDC hDC,
797 INT X,
798 INT Y,
799 COLORREF Color)
800 {
801 HBRUSH hBrush;
802 HGDIOBJ OldBrush;
803
804 if ((Color & 0xFF000000) != 0)
805 {
806 IntHandleSpecialColorType(hDC, &Color);
807 }
808
809 hBrush = NtGdiCreateSolidBrush(Color, NULL);
810 if (hBrush == NULL)
811 return FALSE;
812
813 OldBrush = NtGdiSelectBrush(hDC, hBrush);
814 if (OldBrush == NULL)
815 {
816 GreDeleteObject(hBrush);
817 return FALSE;
818 }
819
820 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
821 NtGdiSelectBrush(hDC, OldBrush);
822 GreDeleteObject(hBrush);
823
824 return TRUE;
825 }
826
827 COLORREF APIENTRY
828 NtGdiSetPixel(
829 HDC hDC,
830 INT X,
831 INT Y,
832 COLORREF Color)
833 {
834 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
835
836 if (GdiSetPixelV(hDC,X,Y,Color))
837 {
838 Color = NtGdiGetPixel(hDC,X,Y);
839 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
840 return Color;
841 }
842
843 Color = (COLORREF)CLR_INVALID;
844 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
845 return Color;
846 }
847
848
849 /* Internal Functions */
850
851 UINT FASTCALL
852 BITMAP_GetRealBitsPixel(UINT nBitsPixel)
853 {
854 if (nBitsPixel <= 1)
855 return 1;
856 if (nBitsPixel <= 4)
857 return 4;
858 if (nBitsPixel <= 8)
859 return 8;
860 if (nBitsPixel <= 16)
861 return 16;
862 if (nBitsPixel <= 24)
863 return 24;
864 if (nBitsPixel <= 32)
865 return 32;
866
867 return 0;
868 }
869
870 INT FASTCALL
871 BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
872 {
873 #if 0
874 switch (bpp)
875 {
876 case 1:
877 return 2 * ((bmWidth+15) >> 4);
878
879 case 24:
880 bmWidth *= 3; /* fall through */
881 case 8:
882 return bmWidth + (bmWidth & 1);
883
884 case 32:
885 return bmWidth * 4;
886
887 case 16:
888 case 15:
889 return bmWidth * 2;
890
891 case 4:
892 return 2 * ((bmWidth+3) >> 2);
893
894 default:
895 DPRINT ("stub");
896 }
897
898 return -1;
899 #endif
900
901 return ((bmWidth * bpp + 15) & ~15) >> 3;
902 }
903
904 HBITMAP FASTCALL
905 BITMAP_CopyBitmap(HBITMAP hBitmap)
906 {
907 HBITMAP res;
908 BITMAP bm;
909 SURFACE *Bitmap, *resBitmap;
910 SIZEL Size;
911
912 if (hBitmap == NULL)
913 {
914 return 0;
915 }
916
917 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
918 if (Bitmap == NULL)
919 {
920 return 0;
921 }
922
923 BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
924 bm.bmBits = NULL;
925 if (Bitmap->SurfObj.lDelta >= 0)
926 bm.bmHeight = -bm.bmHeight;
927
928 Size.cx = abs(bm.bmWidth);
929 Size.cy = abs(bm.bmHeight);
930 res = GreCreateBitmap(abs(bm.bmWidth),
931 abs(bm.bmHeight),
932 1,
933 bm.bmBitsPixel,
934 NULL);
935
936 if (res)
937 {
938 PBYTE buf;
939
940 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
941 if (resBitmap)
942 {
943 buf = ExAllocatePoolWithTag(PagedPool,
944 bm.bmWidthBytes * abs(bm.bmHeight),
945 TAG_BITMAP);
946 if (buf == NULL)
947 {
948 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
949 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
950 GreDeleteObject(res);
951 return 0;
952 }
953 IntGetBitmapBits(Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
954 IntSetBitmapBits(resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
955 ExFreePoolWithTag(buf,TAG_BITMAP);
956 resBitmap->flags = Bitmap->flags;
957 /* Copy palette */
958 if (Bitmap->ppal)
959 {
960 resBitmap->ppal = Bitmap->ppal ;
961 GDIOBJ_IncrementShareCount(&Bitmap->ppal->BaseObject);
962 }
963 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
964 }
965 else
966 {
967 GreDeleteObject(res);
968 res = NULL;
969 }
970 }
971
972 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
973
974 return res;
975 }
976
977 INT APIENTRY
978 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
979 {
980 PBITMAP pBitmap;
981
982 if (!buffer) return sizeof(BITMAP);
983 if ((UINT)Count < sizeof(BITMAP)) return 0;
984
985 /* always fill a basic BITMAP structure */
986 pBitmap = buffer;
987 pBitmap->bmType = 0;
988 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
989 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
990 pBitmap->bmWidthBytes = abs(psurf->SurfObj.lDelta);
991 pBitmap->bmPlanes = 1;
992 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
993
994 /* Check for DIB section */
995 if (psurf->hSecure)
996 {
997 /* Set bmBits in this case */
998 pBitmap->bmBits = psurf->SurfObj.pvBits;
999
1000 if (Count >= sizeof(DIBSECTION))
1001 {
1002 /* Fill rest of DIBSECTION */
1003 PDIBSECTION pds = buffer;
1004
1005 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
1006 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
1007 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
1008 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
1009 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
1010 switch (psurf->SurfObj.iBitmapFormat)
1011 {
1012 /* FIXME: What about BI_BITFIELDS? */
1013 case BMF_1BPP:
1014 case BMF_4BPP:
1015 case BMF_8BPP:
1016 case BMF_16BPP:
1017 case BMF_24BPP:
1018 case BMF_32BPP:
1019 pds->dsBmih.biCompression = BI_RGB;
1020 break;
1021 case BMF_4RLE:
1022 pds->dsBmih.biCompression = BI_RLE4;
1023 break;
1024 case BMF_8RLE:
1025 pds->dsBmih.biCompression = BI_RLE8;
1026 break;
1027 case BMF_JPEG:
1028 pds->dsBmih.biCompression = BI_JPEG;
1029 break;
1030 case BMF_PNG:
1031 pds->dsBmih.biCompression = BI_PNG;
1032 break;
1033 }
1034 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
1035 pds->dsBmih.biXPelsPerMeter = 0;
1036 pds->dsBmih.biYPelsPerMeter = 0;
1037 pds->dsBmih.biClrUsed = psurf->biClrUsed;
1038 pds->dsBmih.biClrImportant = psurf->biClrImportant;
1039 pds->dsBitfields[0] = psurf->dsBitfields[0];
1040 pds->dsBitfields[1] = psurf->dsBitfields[1];
1041 pds->dsBitfields[2] = psurf->dsBitfields[2];
1042 pds->dshSection = psurf->hDIBSection;
1043 pds->dsOffset = psurf->dwOffset;
1044
1045 return sizeof(DIBSECTION);
1046 }
1047 }
1048 else
1049 {
1050 /* not set according to wine test, confirmed in win2k */
1051 pBitmap->bmBits = NULL;
1052 }
1053
1054 return sizeof(BITMAP);
1055 }
1056
1057 /*
1058 * @implemented
1059 */
1060 HDC
1061 APIENTRY
1062 NtGdiGetDCforBitmap(
1063 IN HBITMAP hsurf)
1064 {
1065 HDC hdc = NULL;
1066 PSURFACE psurf = SURFACE_LockSurface(hsurf);
1067 if (psurf)
1068 {
1069 hdc = psurf->hdc;
1070 SURFACE_UnlockSurface(psurf);
1071 }
1072 return hdc;
1073 }
1074
1075 /* EOF */