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