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