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