e6049570d2974c0ad325e4b92bfedcd8aadf377e
[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 BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
313 PVOID Bits;
314 BITMAPINFO* bi = (BITMAPINFO*)buf;
315
316 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
317 bi->bmiHeader.biWidth = Width;
318 bi->bmiHeader.biHeight = Height;
319 bi->bmiHeader.biPlanes = dibs.dsBmih.biPlanes;
320 bi->bmiHeader.biBitCount = dibs.dsBmih.biBitCount;
321 bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
322 bi->bmiHeader.biSizeImage = 0;
323 bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
324 bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
325 bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
326 bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
327
328 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
329 {
330 /* Copy the color masks */
331 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
332 }
333 else if (bi->bmiHeader.biBitCount <= 8)
334 {
335 /* Copy the color table */
336 UINT Index;
337 PPALETTE PalGDI;
338
339 if (!psurf->ppal)
340 {
341 SetLastWin32Error(ERROR_INVALID_HANDLE);
342 return 0;
343 }
344
345 PalGDI = PALETTE_LockPalette(psurf->ppal->BaseObject.hHmgr);
346
347 for (Index = 0;
348 Index < 256 && Index < PalGDI->NumColors;
349 Index++)
350 {
351 bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
352 bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
353 bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
354 bi->bmiColors[Index].rgbReserved = 0;
355 }
356 PALETTE_UnlockPalette(PalGDI);
357
358 Bmp = DIB_CreateDIBSection(Dc,
359 bi,
360 DIB_RGB_COLORS,
361 &Bits,
362 NULL,
363 0,
364 0);
365 return Bmp;
366 }
367 }
368 }
369 }
370 }
371 return Bmp;
372 }
373
374 HBITMAP APIENTRY
375 NtGdiCreateCompatibleBitmap(
376 HDC hDC,
377 INT Width,
378 INT Height)
379 {
380 HBITMAP Bmp;
381 PDC Dc;
382
383 if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
384 {
385 SetLastWin32Error(ERROR_INVALID_PARAMETER);
386 return NULL;
387 }
388
389 if (!hDC)
390 return GreCreateBitmap(Width, Height, 1, 1, 0);
391
392 Dc = DC_LockDc(hDC);
393
394 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
395 hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
396
397 if (NULL == Dc)
398 {
399 SetLastWin32Error(ERROR_INVALID_HANDLE);
400 return NULL;
401 }
402
403 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
404
405 DPRINT("\t\t%04x\n", Bmp);
406 DC_UnlockDc(Dc);
407 return Bmp;
408 }
409
410 BOOL APIENTRY
411 NtGdiGetBitmapDimension(
412 HBITMAP hBitmap,
413 LPSIZE Dimension)
414 {
415 PSURFACE psurfBmp;
416 BOOL Ret = TRUE;
417
418 if (hBitmap == NULL)
419 return FALSE;
420
421 psurfBmp = SURFACE_LockSurface(hBitmap);
422 if (psurfBmp == NULL)
423 {
424 SetLastWin32Error(ERROR_INVALID_HANDLE);
425 return FALSE;
426 }
427
428 _SEH2_TRY
429 {
430 ProbeForWrite(Dimension, sizeof(SIZE), 1);
431 *Dimension = psurfBmp->sizlDim;
432 }
433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
434 {
435 Ret = FALSE;
436 }
437 _SEH2_END
438
439 SURFACE_UnlockSurface(psurfBmp);
440
441 return Ret;
442 }
443
444 COLORREF APIENTRY
445 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
446 {
447 PDC dc = NULL;
448 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
449 BOOL bInRect = FALSE;
450 SURFACE *psurf;
451 SURFOBJ *pso;
452 PPALETTE ppal;
453 EXLATEOBJ exlo;
454 HBITMAP hBmpTmp;
455
456 dc = DC_LockDc(hDC);
457
458 if (!dc)
459 {
460 SetLastWin32Error(ERROR_INVALID_HANDLE);
461 return Result;
462 }
463
464 if (dc->dctype == DC_TYPE_INFO)
465 {
466 DC_UnlockDc(dc);
467 return Result;
468 }
469
470 XPos += dc->ptlDCOrig.x;
471 YPos += dc->ptlDCOrig.y;
472 if (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos))
473 {
474 bInRect = TRUE;
475 psurf = dc->dclevel.pSurface;
476 if (psurf)
477 {
478 pso = &psurf->SurfObj;
479 if (psurf->ppal)
480 {
481 ppal = psurf->ppal;
482 GDIOBJ_IncrementShareCount(&ppal->BaseObject);
483 }
484 else
485 ppal = PALETTE_ShareLockPalette(dc->ppdev->devinfo.hpalDefault);
486
487 if (psurf->SurfObj.iBitmapFormat == BMF_1BPP && !psurf->hSecure)
488 {
489 /* FIXME: palette should be gpalMono already ! */
490 EXLATEOBJ_vInitialize(&exlo, &gpalMono, &gpalRGB, 0, 0xffffff, 0);
491 }
492 else
493 {
494 EXLATEOBJ_vInitialize(&exlo, ppal, &gpalRGB, 0, 0xffffff, 0);
495 }
496
497 // check if this DC has a DIB behind it...
498 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
499 {
500 ASSERT(pso->lDelta);
501 Result = XLATEOBJ_iXlate(&exlo.xlo,
502 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
503 }
504
505 EXLATEOBJ_vCleanup(&exlo);
506 PALETTE_ShareUnlockPalette(ppal);
507 }
508 }
509 DC_UnlockDc(dc);
510
511 // if Result is still CLR_INVALID, then the "quick" method above didn't work
512 if (bInRect && Result == CLR_INVALID)
513 {
514 // FIXME: create a 1x1 32BPP DIB, and blit to it
515 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
516 if (hDCTmp)
517 {
518 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
519 BITMAPINFO bi;
520 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
521 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
522 bi.bmiHeader.biWidth,
523 bi.bmiHeader.biHeight,
524 0,
525 NULL,
526 &bi,
527 DIB_RGB_COLORS,
528 bi.bmiHeader.biBitCount,
529 bi.bmiHeader.biSizeImage,
530 0,
531 0);
532
533 //HBITMAP hBmpTmp = GreCreateBitmap(1, 1, 1, 32, NULL);
534 if (hBmpTmp)
535 {
536 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
537 if (hBmpOld)
538 {
539 PSURFACE psurf;
540
541 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
542 NtGdiSelectBitmap(hDCTmp, hBmpOld);
543
544 // our bitmap is no longer selected, so we can access it's stuff...
545 psurf = SURFACE_LockSurface(hBmpTmp);
546 if (psurf)
547 {
548 // Dont you need to convert something here?
549 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
550 SURFACE_UnlockSurface(psurf);
551 }
552 }
553 GreDeleteObject(hBmpTmp);
554 }
555 NtGdiDeleteObjectApp(hDCTmp);
556 }
557 }
558
559 return Result;
560 }
561
562
563 LONG APIENTRY
564 IntGetBitmapBits(
565 PSURFACE psurf,
566 DWORD Bytes,
567 OUT PBYTE Bits)
568 {
569 LONG ret;
570
571 ASSERT(Bits);
572
573 /* Don't copy more bytes than the buffer has */
574 Bytes = min(Bytes, psurf->SurfObj.cjBits);
575
576 #if 0
577 /* FIXME: Call DDI CopyBits here if available */
578 if (psurf->DDBitmap)
579 {
580 DPRINT("Calling device specific BitmapBits\n");
581 if (psurf->DDBitmap->funcs->pBitmapBits)
582 {
583 ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
584 bits,
585 count,
586 DDB_GET);
587 }
588 else
589 {
590 ERR_(bitmap)("BitmapBits == NULL??\n");
591 ret = 0;
592 }
593 }
594 else
595 #endif
596 {
597 RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
598 ret = Bytes;
599 }
600 return ret;
601 }
602
603 LONG APIENTRY
604 NtGdiGetBitmapBits(
605 HBITMAP hBitmap,
606 ULONG Bytes,
607 OUT OPTIONAL PBYTE pUnsafeBits)
608 {
609 PSURFACE psurf;
610 LONG bmSize, ret;
611
612 if (pUnsafeBits != NULL && Bytes == 0)
613 {
614 return 0;
615 }
616
617 psurf = SURFACE_LockSurface(hBitmap);
618 if (!psurf)
619 {
620 SetLastWin32Error(ERROR_INVALID_HANDLE);
621 return 0;
622 }
623
624 bmSize = BITMAP_GetWidthBytes(psurf->SurfObj.sizlBitmap.cx,
625 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
626 abs(psurf->SurfObj.sizlBitmap.cy);
627
628 /* If the bits vector is null, the function should return the read size */
629 if (pUnsafeBits == NULL)
630 {
631 SURFACE_UnlockSurface(psurf);
632 return bmSize;
633 }
634
635 /* Don't copy more bytes than the buffer has */
636 Bytes = min(Bytes, bmSize);
637
638 // FIXME: use MmSecureVirtualMemory
639 _SEH2_TRY
640 {
641 ProbeForWrite(pUnsafeBits, Bytes, 1);
642 ret = IntGetBitmapBits(psurf, Bytes, pUnsafeBits);
643 }
644 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
645 {
646 ret = 0;
647 }
648 _SEH2_END
649
650 SURFACE_UnlockSurface(psurf);
651
652 return ret;
653 }
654
655
656 LONG APIENTRY
657 NtGdiSetBitmapBits(
658 HBITMAP hBitmap,
659 DWORD Bytes,
660 IN PBYTE pUnsafeBits)
661 {
662 LONG ret;
663 PSURFACE psurf;
664
665 if (pUnsafeBits == NULL || Bytes == 0)
666 {
667 return 0;
668 }
669
670 psurf = SURFACE_LockSurface(hBitmap);
671 if (psurf == NULL)
672 {
673 SetLastWin32Error(ERROR_INVALID_HANDLE);
674 return 0;
675 }
676
677 _SEH2_TRY
678 {
679 ProbeForRead(pUnsafeBits, Bytes, 1);
680 UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
681 ret = 1;
682 }
683 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
684 {
685 ret = 0;
686 }
687 _SEH2_END
688
689 SURFACE_UnlockSurface(psurf);
690
691 return ret;
692 }
693
694 BOOL APIENTRY
695 NtGdiSetBitmapDimension(
696 HBITMAP hBitmap,
697 INT Width,
698 INT Height,
699 LPSIZE Size)
700 {
701 PSURFACE psurf;
702 BOOL Ret = TRUE;
703
704 if (hBitmap == NULL)
705 return FALSE;
706
707 psurf = SURFACE_LockSurface(hBitmap);
708 if (psurf == NULL)
709 {
710 SetLastWin32Error(ERROR_INVALID_HANDLE);
711 return FALSE;
712 }
713
714 if (Size)
715 {
716 _SEH2_TRY
717 {
718 ProbeForWrite(Size, sizeof(SIZE), 1);
719 *Size = psurf->sizlDim;
720 }
721 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
722 {
723 Ret = FALSE;
724 }
725 _SEH2_END
726 }
727
728 /* The dimension is changed even if writing the old value failed */
729 psurf->sizlDim.cx = Width;
730 psurf->sizlDim.cy = Height;
731
732 SURFACE_UnlockSurface(psurf);
733
734 return Ret;
735 }
736
737 VOID IntHandleSpecialColorType(HDC hDC, COLORREF* Color)
738 {
739 PDC pdc = NULL;
740 RGBQUAD quad;
741 PALETTEENTRY palEntry;
742 UINT index;
743
744 switch (*Color >> 24)
745 {
746 case 0x10: /* DIBINDEX */
747 if (IntGetDIBColorTable(hDC, LOWORD(*Color), 1, &quad) == 1)
748 {
749 *Color = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
750 }
751 else
752 {
753 /* Out of color table bounds - use black */
754 *Color = RGB(0, 0, 0);
755 }
756 break;
757 case 0x02: /* PALETTERGB */
758 pdc = DC_LockDc(hDC);
759 if (pdc->dclevel.hpal != NtGdiGetStockObject(DEFAULT_PALETTE))
760 {
761 index = NtGdiGetNearestPaletteIndex(pdc->dclevel.hpal, *Color);
762 IntGetPaletteEntries(pdc->dclevel.hpal, index, 1, &palEntry);
763 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
764 }
765 else
766 {
767 /* Use the pure color */
768 *Color = *Color & 0x00FFFFFF;
769 }
770 DC_UnlockDc(pdc);
771 break;
772 case 0x01: /* PALETTEINDEX */
773 pdc = DC_LockDc(hDC);
774 if (IntGetPaletteEntries(pdc->dclevel.hpal, LOWORD(*Color), 1, &palEntry) == 1)
775 {
776 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
777 }
778 else
779 {
780 /* Index does not exist, use zero index */
781 IntGetPaletteEntries(pdc->dclevel.hpal, 0, 1, &palEntry);
782 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
783 }
784 DC_UnlockDc(pdc);
785 break;
786 default:
787 DPRINT("Unsupported color type %d passed\n", *Color >> 24);
788 break;
789 }
790 }
791
792 BOOL APIENTRY
793 GdiSetPixelV(
794 HDC hDC,
795 INT X,
796 INT Y,
797 COLORREF Color)
798 {
799 HBRUSH hBrush;
800 HGDIOBJ OldBrush;
801
802 if ((Color & 0xFF000000) != 0)
803 {
804 IntHandleSpecialColorType(hDC, &Color);
805 }
806
807 hBrush = NtGdiCreateSolidBrush(Color, NULL);
808 if (hBrush == NULL)
809 return FALSE;
810
811 OldBrush = NtGdiSelectBrush(hDC, hBrush);
812 if (OldBrush == NULL)
813 {
814 GreDeleteObject(hBrush);
815 return FALSE;
816 }
817
818 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
819 NtGdiSelectBrush(hDC, OldBrush);
820 GreDeleteObject(hBrush);
821
822 return TRUE;
823 }
824
825 COLORREF APIENTRY
826 NtGdiSetPixel(
827 HDC hDC,
828 INT X,
829 INT Y,
830 COLORREF Color)
831 {
832 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
833
834 if (GdiSetPixelV(hDC,X,Y,Color))
835 {
836 Color = NtGdiGetPixel(hDC,X,Y);
837 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
838 return Color;
839 }
840
841 Color = (COLORREF)CLR_INVALID;
842 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
843 return Color;
844 }
845
846
847 /* Internal Functions */
848
849 UINT FASTCALL
850 BITMAP_GetRealBitsPixel(UINT nBitsPixel)
851 {
852 if (nBitsPixel <= 1)
853 return 1;
854 if (nBitsPixel <= 4)
855 return 4;
856 if (nBitsPixel <= 8)
857 return 8;
858 if (nBitsPixel <= 16)
859 return 16;
860 if (nBitsPixel <= 24)
861 return 24;
862 if (nBitsPixel <= 32)
863 return 32;
864
865 return 0;
866 }
867
868 INT FASTCALL
869 BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
870 {
871 #if 0
872 switch (bpp)
873 {
874 case 1:
875 return 2 * ((bmWidth+15) >> 4);
876
877 case 24:
878 bmWidth *= 3; /* fall through */
879 case 8:
880 return bmWidth + (bmWidth & 1);
881
882 case 32:
883 return bmWidth * 4;
884
885 case 16:
886 case 15:
887 return bmWidth * 2;
888
889 case 4:
890 return 2 * ((bmWidth+3) >> 2);
891
892 default:
893 DPRINT ("stub");
894 }
895
896 return -1;
897 #endif
898
899 return ((bmWidth * bpp + 15) & ~15) >> 3;
900 }
901
902 HBITMAP FASTCALL
903 BITMAP_CopyBitmap(HBITMAP hBitmap)
904 {
905 HBITMAP res;
906 BITMAP bm;
907 SURFACE *Bitmap, *resBitmap;
908 SIZEL Size;
909
910 if (hBitmap == NULL)
911 {
912 return 0;
913 }
914
915 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
916 if (Bitmap == NULL)
917 {
918 return 0;
919 }
920
921 BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
922 bm.bmBits = NULL;
923 if (Bitmap->SurfObj.lDelta >= 0)
924 bm.bmHeight = -bm.bmHeight;
925
926 Size.cx = abs(bm.bmWidth);
927 Size.cy = abs(bm.bmHeight);
928 res = GreCreateBitmap(abs(bm.bmWidth),
929 abs(bm.bmHeight),
930 1,
931 bm.bmBitsPixel,
932 NULL);
933
934 if (res)
935 {
936 PBYTE buf;
937
938 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
939 if (resBitmap)
940 {
941 buf = ExAllocatePoolWithTag(PagedPool,
942 bm.bmWidthBytes * abs(bm.bmHeight),
943 TAG_BITMAP);
944 if (buf == NULL)
945 {
946 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
947 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
948 GreDeleteObject(res);
949 return 0;
950 }
951 IntGetBitmapBits(Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
952 IntSetBitmapBits(resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
953 ExFreePoolWithTag(buf,TAG_BITMAP);
954 resBitmap->flags = Bitmap->flags;
955 /* Copy palette */
956 if (Bitmap->ppal)
957 {
958 resBitmap->ppal = Bitmap->ppal ;
959 GDIOBJ_IncrementShareCount(&Bitmap->ppal->BaseObject);
960 }
961 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
962 }
963 else
964 {
965 GreDeleteObject(res);
966 res = NULL;
967 }
968 }
969
970 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
971
972 return res;
973 }
974
975 INT APIENTRY
976 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
977 {
978 PBITMAP pBitmap;
979
980 if (!buffer) return sizeof(BITMAP);
981 if ((UINT)Count < sizeof(BITMAP)) return 0;
982
983 /* always fill a basic BITMAP structure */
984 pBitmap = buffer;
985 pBitmap->bmType = 0;
986 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
987 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
988 pBitmap->bmWidthBytes = abs(psurf->SurfObj.lDelta);
989 pBitmap->bmPlanes = 1;
990 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
991
992 /* Check for DIB section */
993 if (psurf->hSecure)
994 {
995 /* Set bmBits in this case */
996 pBitmap->bmBits = psurf->SurfObj.pvBits;
997
998 if (Count >= sizeof(DIBSECTION))
999 {
1000 /* Fill rest of DIBSECTION */
1001 PDIBSECTION pds = buffer;
1002
1003 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
1004 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
1005 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
1006 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
1007 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
1008 switch (psurf->SurfObj.iBitmapFormat)
1009 {
1010 /* FIXME: What about BI_BITFIELDS? */
1011 case BMF_1BPP:
1012 case BMF_4BPP:
1013 case BMF_8BPP:
1014 case BMF_16BPP:
1015 case BMF_24BPP:
1016 case BMF_32BPP:
1017 pds->dsBmih.biCompression = BI_RGB;
1018 break;
1019 case BMF_4RLE:
1020 pds->dsBmih.biCompression = BI_RLE4;
1021 break;
1022 case BMF_8RLE:
1023 pds->dsBmih.biCompression = BI_RLE8;
1024 break;
1025 case BMF_JPEG:
1026 pds->dsBmih.biCompression = BI_JPEG;
1027 break;
1028 case BMF_PNG:
1029 pds->dsBmih.biCompression = BI_PNG;
1030 break;
1031 }
1032 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
1033 pds->dsBmih.biXPelsPerMeter = 0;
1034 pds->dsBmih.biYPelsPerMeter = 0;
1035 pds->dsBmih.biClrUsed = psurf->biClrUsed;
1036 pds->dsBmih.biClrImportant = psurf->biClrImportant;
1037 pds->dsBitfields[0] = psurf->dsBitfields[0];
1038 pds->dsBitfields[1] = psurf->dsBitfields[1];
1039 pds->dsBitfields[2] = psurf->dsBitfields[2];
1040 pds->dshSection = psurf->hDIBSection;
1041 pds->dsOffset = psurf->dwOffset;
1042
1043 return sizeof(DIBSECTION);
1044 }
1045 }
1046 else
1047 {
1048 /* not set according to wine test, confirmed in win2k */
1049 pBitmap->bmBits = NULL;
1050 }
1051
1052 return sizeof(BITMAP);
1053 }
1054
1055 /*
1056 * @implemented
1057 */
1058 HDC
1059 APIENTRY
1060 NtGdiGetDCforBitmap(
1061 IN HBITMAP hsurf)
1062 {
1063 HDC hdc = NULL;
1064 PSURFACE psurf = SURFACE_LockSurface(hsurf);
1065 if (psurf)
1066 {
1067 hdc = psurf->hdc;
1068 SURFACE_UnlockSurface(psurf);
1069 }
1070 return hdc;
1071 }
1072
1073 /* EOF */