[WIN32SS]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / bitmaps.c
1 /*
2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bitmap functions
5 * FILE: subsys/win32k/objects/bitmaps.c
6 * PROGRAMER: Timo Kreuzer <timo.kreuzer@reactos.org>
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 void
15 NTAPI
16 UnsafeSetBitmapBits(
17 PSURFACE psurf,
18 IN ULONG cjBits,
19 IN PVOID pvBits)
20 {
21 PUCHAR pjDst, pjSrc;
22 LONG lDeltaDst, lDeltaSrc;
23 ULONG nWidth, nHeight, cBitsPixel;
24
25 nWidth = psurf->SurfObj.sizlBitmap.cx;
26 nHeight = psurf->SurfObj.sizlBitmap.cy;
27 cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
28
29 /* Get pointers */
30 pjDst = psurf->SurfObj.pvScan0;
31 pjSrc = pvBits;
32 lDeltaDst = psurf->SurfObj.lDelta;
33 lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
34
35 while (nHeight--)
36 {
37 /* Copy one line */
38 memcpy(pjDst, pjSrc, lDeltaSrc);
39 pjSrc += lDeltaSrc;
40 pjDst += lDeltaDst;
41 }
42
43 }
44
45 HBITMAP
46 NTAPI
47 GreCreateBitmapEx(
48 _In_ ULONG nWidth,
49 _In_ ULONG nHeight,
50 _In_ ULONG cjWidthBytes,
51 _In_ ULONG iFormat,
52 _In_ USHORT fjBitmap,
53 _In_ ULONG cjSizeImage,
54 _In_opt_ PVOID pvBits,
55 _In_ FLONG flags)
56 {
57 PSURFACE psurf;
58 HBITMAP hbmp;
59
60 /* Verify format */
61 if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
62
63 /* Allocate a surface */
64 psurf = SURFACE_AllocSurface(STYPE_BITMAP, nWidth, nHeight, iFormat);
65 if (!psurf)
66 {
67 DPRINT1("SURFACE_AllocSurface failed.\n");
68 return NULL;
69 }
70
71 /* Get the handle for the bitmap */
72 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
73
74 /* The infamous RLE hack */
75 if (iFormat == BMF_4RLE || iFormat == BMF_8RLE)
76 {
77 PVOID pvCompressedBits;
78 SIZEL sizl;
79 LONG lDelta;
80
81 sizl.cx = nWidth;
82 sizl.cy = nHeight;
83 lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);
84
85 pvCompressedBits = pvBits;
86 pvBits = EngAllocMem(FL_ZERO_MEMORY, lDelta * nHeight, TAG_DIB);
87 if (!pvBits)
88 {
89 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
90 GDIOBJ_vDeleteObject(&psurf->BaseObject);
91 return NULL;
92 }
93 DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat);
94 fjBitmap |= BMF_RLE_HACK;
95
96 iFormat = iFormat == BMF_4RLE ? BMF_4BPP : BMF_8BPP;
97 psurf->SurfObj.iBitmapFormat = iFormat;
98 }
99
100 /* Mark as API bitmap */
101 psurf->flags |= (flags | API_BITMAP);
102
103 /* Set the bitmap bits */
104 if (!SURFACE_bSetBitmapBits(psurf, fjBitmap, cjWidthBytes, pvBits))
105 {
106 /* Bail out if that failed */
107 DPRINT1("SURFACE_bSetBitmapBits failed.\n");
108 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
109 GDIOBJ_vDeleteObject(&psurf->BaseObject);
110 return NULL;
111 }
112
113 /* Unlock the surface and return */
114 SURFACE_UnlockSurface(psurf);
115 return hbmp;
116 }
117
118 /* Creates a DDB surface,
119 * as in CreateCompatibleBitmap or CreateBitmap.
120 * Note that each scanline must be 32bit aligned!
121 */
122 HBITMAP
123 NTAPI
124 GreCreateBitmap(
125 _In_ ULONG nWidth,
126 _In_ ULONG nHeight,
127 _In_ ULONG cPlanes,
128 _In_ ULONG cBitsPixel,
129 _In_opt_ PVOID pvBits)
130 {
131 /* Call the extended function */
132 return GreCreateBitmapEx(nWidth,
133 nHeight,
134 0, /* Auto width */
135 BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
136 0, /* No bitmap flags */
137 0, /* Auto size */
138 pvBits,
139 DDB_SURFACE /* DDB */);
140 }
141
142 HBITMAP
143 APIENTRY
144 NtGdiCreateBitmap(
145 IN INT nWidth,
146 IN INT nHeight,
147 IN UINT cPlanes,
148 IN UINT cBitsPixel,
149 IN OPTIONAL LPBYTE pUnsafeBits)
150 {
151 HBITMAP hbmp;
152 ULONG cRealBpp, cjWidthBytes, iFormat;
153 ULONGLONG cjSize;
154
155 /* Calculate bitmap format and real bits per pixel. */
156 iFormat = BitmapFormat(cBitsPixel * cPlanes, BI_RGB);
157 cRealBpp = gajBitsPerFormat[iFormat];
158
159 /* Calculate width and image size in bytes */
160 cjWidthBytes = WIDTH_BYTES_ALIGN16(nWidth, cRealBpp);
161 cjSize = (ULONGLONG)cjWidthBytes * nHeight;
162
163 /* Check parameters (possible overflow of cjSize!) */
164 if ((iFormat == 0) || (nWidth <= 0) || (nWidth >= 0x8000000) || (nHeight <= 0) ||
165 (cBitsPixel > 32) || (cPlanes > 32) || (cjSize >= 0x100000000ULL))
166 {
167 DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%d, Planes=%d\n",
168 nWidth, nHeight, cBitsPixel, cPlanes);
169 EngSetLastError(ERROR_INVALID_PARAMETER);
170 return NULL;
171 }
172
173 /* Call internal function. */
174 hbmp = GreCreateBitmapEx(nWidth, nHeight, 0, iFormat, 0, 0, NULL, DDB_SURFACE);
175
176 if (pUnsafeBits && hbmp)
177 {
178 PSURFACE psurf = SURFACE_ShareLockSurface(hbmp);
179 _SEH2_TRY
180 {
181 ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1);
182 UnsafeSetBitmapBits(psurf, 0, pUnsafeBits);
183 }
184 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
185 {
186 GDIOBJ_vDeleteObject(&psurf->BaseObject);
187 _SEH2_YIELD(return NULL;)
188 }
189 _SEH2_END
190
191 SURFACE_ShareUnlockSurface(psurf);
192 }
193
194 return hbmp;
195 }
196
197
198 HBITMAP FASTCALL
199 IntCreateCompatibleBitmap(
200 PDC Dc,
201 INT Width,
202 INT Height)
203 {
204 HBITMAP Bmp = NULL;
205
206 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
207 if (0 == Width || 0 == Height)
208 {
209 return NtGdiGetStockObject(DEFAULT_BITMAP);
210 }
211
212 if (Dc->dctype != DC_TYPE_MEMORY)
213 {
214 PSURFACE psurf;
215
216 Bmp = GreCreateBitmap(abs(Width),
217 abs(Height),
218 1,
219 Dc->ppdev->gdiinfo.cBitsPixel,
220 NULL);
221 psurf = SURFACE_ShareLockSurface(Bmp);
222 ASSERT(psurf);
223 /* Set palette */
224 psurf->ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
225 /* Set flags */
226 psurf->flags = API_BITMAP;
227 psurf->hdc = NULL; // FIXME:
228 SURFACE_ShareUnlockSurface(psurf);
229 }
230 else
231 {
232 DIBSECTION dibs;
233 INT Count;
234 PSURFACE psurf = Dc->dclevel.pSurface;
235 Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
236
237 if (Count == sizeof(BITMAP))
238 {
239 PSURFACE psurfBmp;
240
241 Bmp = GreCreateBitmap(abs(Width),
242 abs(Height),
243 1,
244 dibs.dsBm.bmBitsPixel,
245 NULL);
246 psurfBmp = SURFACE_ShareLockSurface(Bmp);
247 ASSERT(psurfBmp);
248 /* Assign palette */
249 psurfBmp->ppal = psurf->ppal;
250 GDIOBJ_vReferenceObjectByPointer((POBJ)psurf->ppal);
251 /* Set flags */
252 psurfBmp->flags = API_BITMAP;
253 psurfBmp->hdc = NULL; // FIXME:
254 SURFACE_ShareUnlockSurface(psurfBmp);
255 }
256 else if (Count == sizeof(DIBSECTION))
257 {
258 /* A DIB section is selected in the DC */
259 BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
260 PVOID Bits;
261 BITMAPINFO* bi = (BITMAPINFO*)buf;
262
263 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
264 bi->bmiHeader.biWidth = Width;
265 bi->bmiHeader.biHeight = Height;
266 bi->bmiHeader.biPlanes = dibs.dsBmih.biPlanes;
267 bi->bmiHeader.biBitCount = dibs.dsBmih.biBitCount;
268 bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
269 bi->bmiHeader.biSizeImage = 0;
270 bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
271 bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
272 bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
273 bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
274
275 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
276 {
277 /* Copy the color masks */
278 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
279 }
280 else if (bi->bmiHeader.biBitCount <= 8)
281 {
282 /* Copy the color table */
283 UINT Index;
284 PPALETTE PalGDI;
285
286 if (!psurf->ppal)
287 {
288 EngSetLastError(ERROR_INVALID_HANDLE);
289 return 0;
290 }
291
292 PalGDI = psurf->ppal;
293
294 for (Index = 0;
295 Index < 256 && Index < PalGDI->NumColors;
296 Index++)
297 {
298 bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
299 bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
300 bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
301 bi->bmiColors[Index].rgbReserved = 0;
302 }
303 }
304
305 Bmp = DIB_CreateDIBSection(Dc,
306 bi,
307 DIB_RGB_COLORS,
308 &Bits,
309 NULL,
310 0,
311 0);
312 return Bmp;
313 }
314 }
315 return Bmp;
316 }
317
318 HBITMAP APIENTRY
319 NtGdiCreateCompatibleBitmap(
320 HDC hDC,
321 INT Width,
322 INT Height)
323 {
324 HBITMAP Bmp;
325 PDC Dc;
326
327 if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
328 {
329 EngSetLastError(ERROR_INVALID_PARAMETER);
330 return NULL;
331 }
332
333 if (!hDC)
334 return GreCreateBitmap(Width, Height, 1, 1, 0);
335
336 Dc = DC_LockDc(hDC);
337
338 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
339 hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
340
341 if (NULL == Dc)
342 {
343 EngSetLastError(ERROR_INVALID_HANDLE);
344 return NULL;
345 }
346
347 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
348
349 DPRINT("\t\t%04x\n", Bmp);
350 DC_UnlockDc(Dc);
351 return Bmp;
352 }
353
354 BOOL APIENTRY
355 NtGdiGetBitmapDimension(
356 HBITMAP hBitmap,
357 LPSIZE Dimension)
358 {
359 PSURFACE psurfBmp;
360 BOOL Ret = TRUE;
361
362 if (hBitmap == NULL)
363 return FALSE;
364
365 psurfBmp = SURFACE_ShareLockSurface(hBitmap);
366 if (psurfBmp == NULL)
367 {
368 EngSetLastError(ERROR_INVALID_HANDLE);
369 return FALSE;
370 }
371
372 _SEH2_TRY
373 {
374 ProbeForWrite(Dimension, sizeof(SIZE), 1);
375 *Dimension = psurfBmp->sizlDim;
376 }
377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
378 {
379 Ret = FALSE;
380 }
381 _SEH2_END
382
383 SURFACE_ShareUnlockSurface(psurfBmp);
384
385 return Ret;
386 }
387
388 COLORREF APIENTRY
389 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
390 {
391 PDC dc = NULL;
392 COLORREF Result = (COLORREF)CLR_INVALID; // Default to failure
393 BOOL bInRect = FALSE;
394 SURFACE *psurf;
395 SURFOBJ *pso;
396 EXLATEOBJ exlo;
397 HBITMAP hBmpTmp;
398
399 dc = DC_LockDc(hDC);
400
401 if (!dc)
402 {
403 EngSetLastError(ERROR_INVALID_HANDLE);
404 return Result;
405 }
406
407 if (dc->dctype == DC_TYPE_INFO)
408 {
409 DC_UnlockDc(dc);
410 return Result;
411 }
412
413 XPos += dc->ptlDCOrig.x;
414 YPos += dc->ptlDCOrig.y;
415 if ((dc->rosdc.CombinedClip == NULL) ||
416 (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos)))
417 {
418 bInRect = TRUE;
419 psurf = dc->dclevel.pSurface;
420 if (psurf)
421 {
422 pso = &psurf->SurfObj;
423 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, &gpalRGB, 0, 0xffffff, 0);
424 // Check if this DC has a DIB behind it...
425 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
426 {
427 ASSERT(pso->lDelta);
428 Result = XLATEOBJ_iXlate(&exlo.xlo,
429 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
430 }
431
432 EXLATEOBJ_vCleanup(&exlo);
433 }
434 }
435 DC_UnlockDc(dc);
436
437 // If Result is still CLR_INVALID, then the "quick" method above didn't work
438 if (bInRect && Result == CLR_INVALID)
439 {
440 // FIXME: create a 1x1 32BPP DIB, and blit to it
441 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
442 if (hDCTmp)
443 {
444 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
445 BITMAPINFO bi;
446 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
447 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
448 bi.bmiHeader.biWidth,
449 bi.bmiHeader.biHeight,
450 0,
451 NULL,
452 &bi,
453 DIB_RGB_COLORS,
454 bi.bmiHeader.biBitCount,
455 bi.bmiHeader.biSizeImage,
456 0,
457 0);
458
459 //HBITMAP hBmpTmp = GreCreateBitmap(1, 1, 1, 32, NULL);
460 if (hBmpTmp)
461 {
462 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
463 if (hBmpOld)
464 {
465 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
466 NtGdiSelectBitmap(hDCTmp, hBmpOld);
467
468 // Our bitmap is no longer selected, so we can access it's stuff...
469 psurf = SURFACE_ShareLockSurface(hBmpTmp);
470 if (psurf)
471 {
472 // Dont you need to convert something here?
473 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
474 SURFACE_ShareUnlockSurface(psurf);
475 }
476 }
477 GreDeleteObject(hBmpTmp);
478 }
479 NtGdiDeleteObjectApp(hDCTmp);
480 }
481 }
482
483 return Result;
484 }
485
486 VOID
487 FASTCALL
488 UnsafeGetBitmapBits(
489 PSURFACE psurf,
490 DWORD Bytes,
491 OUT PBYTE pvBits)
492 {
493 PUCHAR pjDst, pjSrc;
494 LONG lDeltaDst, lDeltaSrc;
495 ULONG nWidth, nHeight, cBitsPixel;
496
497 nWidth = psurf->SurfObj.sizlBitmap.cx;
498 nHeight = psurf->SurfObj.sizlBitmap.cy;
499 cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
500
501 /* Get pointers */
502 pjSrc = psurf->SurfObj.pvScan0;
503 pjDst = pvBits;
504 lDeltaSrc = psurf->SurfObj.lDelta;
505 lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
506
507 while (nHeight--)
508 {
509 /* Copy one line */
510 RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
511 pjSrc += lDeltaSrc;
512 pjDst += lDeltaDst;
513 }
514 }
515
516 LONG
517 APIENTRY
518 NtGdiGetBitmapBits(
519 HBITMAP hBitmap,
520 ULONG cjBuffer,
521 OUT OPTIONAL PBYTE pUnsafeBits)
522 {
523 PSURFACE psurf;
524 ULONG cjSize;
525 LONG ret;
526
527 /* Check parameters */
528 if (pUnsafeBits != NULL && cjBuffer == 0)
529 {
530 return 0;
531 }
532
533 /* Lock the bitmap */
534 psurf = SURFACE_ShareLockSurface(hBitmap);
535 if (!psurf)
536 {
537 EngSetLastError(ERROR_INVALID_HANDLE);
538 return 0;
539 }
540
541 /* Calculate the size of the bitmap in bytes */
542 cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx,
543 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
544 abs(psurf->SurfObj.sizlBitmap.cy);
545
546 /* If the bits vector is null, the function should return the read size */
547 if (pUnsafeBits == NULL)
548 {
549 SURFACE_ShareUnlockSurface(psurf);
550 return cjSize;
551 }
552
553 /* Don't copy more bytes than the buffer has */
554 cjBuffer = min(cjBuffer, cjSize);
555
556 // FIXME: Use MmSecureVirtualMemory
557 _SEH2_TRY
558 {
559 ProbeForWrite(pUnsafeBits, cjBuffer, 1);
560 UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
561 ret = cjBuffer;
562 }
563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
564 {
565 ret = 0;
566 }
567 _SEH2_END
568
569 SURFACE_ShareUnlockSurface(psurf);
570
571 return ret;
572 }
573
574
575 LONG APIENTRY
576 NtGdiSetBitmapBits(
577 HBITMAP hBitmap,
578 DWORD Bytes,
579 IN PBYTE pUnsafeBits)
580 {
581 LONG ret;
582 PSURFACE psurf;
583
584 if (pUnsafeBits == NULL || Bytes == 0)
585 {
586 return 0;
587 }
588
589 psurf = SURFACE_ShareLockSurface(hBitmap);
590 if (psurf == NULL)
591 {
592 EngSetLastError(ERROR_INVALID_HANDLE);
593 return 0;
594 }
595
596 _SEH2_TRY
597 {
598 ProbeForRead(pUnsafeBits, Bytes, 1);
599 UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
600 ret = 1;
601 }
602 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
603 {
604 ret = 0;
605 }
606 _SEH2_END
607
608 SURFACE_ShareUnlockSurface(psurf);
609
610 return ret;
611 }
612
613 BOOL APIENTRY
614 NtGdiSetBitmapDimension(
615 HBITMAP hBitmap,
616 INT Width,
617 INT Height,
618 LPSIZE Size)
619 {
620 PSURFACE psurf;
621 BOOL Ret = TRUE;
622
623 if (hBitmap == NULL)
624 return FALSE;
625
626 psurf = SURFACE_ShareLockSurface(hBitmap);
627 if (psurf == NULL)
628 {
629 EngSetLastError(ERROR_INVALID_HANDLE);
630 return FALSE;
631 }
632
633 if (Size)
634 {
635 _SEH2_TRY
636 {
637 ProbeForWrite(Size, sizeof(SIZE), 1);
638 *Size = psurf->sizlDim;
639 }
640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
641 {
642 Ret = FALSE;
643 }
644 _SEH2_END
645 }
646
647 /* The dimension is changed even if writing the old value failed */
648 psurf->sizlDim.cx = Width;
649 psurf->sizlDim.cy = Height;
650
651 SURFACE_ShareUnlockSurface(psurf);
652
653 return Ret;
654 }
655
656 VOID IntHandleSpecialColorType(HDC hDC, COLORREF* Color)
657 {
658 PDC pdc = NULL;
659 RGBQUAD quad;
660 PALETTEENTRY palEntry;
661 UINT index;
662
663 switch (*Color >> 24)
664 {
665 case 0x10: /* DIBINDEX */
666 if (IntGetDIBColorTable(hDC, LOWORD(*Color), 1, &quad) == 1)
667 {
668 *Color = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
669 }
670 else
671 {
672 /* Out of color table bounds - use black */
673 *Color = RGB(0, 0, 0);
674 }
675 break;
676 case 0x02: /* PALETTERGB */
677 pdc = DC_LockDc(hDC);
678 if (pdc->dclevel.hpal != NtGdiGetStockObject(DEFAULT_PALETTE))
679 {
680 index = NtGdiGetNearestPaletteIndex(pdc->dclevel.hpal, *Color);
681 IntGetPaletteEntries(pdc->dclevel.hpal, index, 1, &palEntry);
682 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
683 }
684 else
685 {
686 /* Use the pure color */
687 *Color = *Color & 0x00FFFFFF;
688 }
689 DC_UnlockDc(pdc);
690 break;
691 case 0x01: /* PALETTEINDEX */
692 pdc = DC_LockDc(hDC);
693 if (IntGetPaletteEntries(pdc->dclevel.hpal, LOWORD(*Color), 1, &palEntry) == 1)
694 {
695 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
696 }
697 else
698 {
699 /* Index does not exist, use zero index */
700 IntGetPaletteEntries(pdc->dclevel.hpal, 0, 1, &palEntry);
701 *Color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
702 }
703 DC_UnlockDc(pdc);
704 break;
705 default:
706 DPRINT("Unsupported color type %d passed\n", *Color >> 24);
707 break;
708 }
709 }
710
711 BOOL APIENTRY
712 GdiSetPixelV(
713 HDC hDC,
714 INT X,
715 INT Y,
716 COLORREF Color)
717 {
718 HBRUSH hBrush;
719 HGDIOBJ OldBrush;
720
721 if ((Color & 0xFF000000) != 0)
722 {
723 IntHandleSpecialColorType(hDC, &Color);
724 }
725
726 hBrush = NtGdiCreateSolidBrush(Color, NULL);
727 if (hBrush == NULL)
728 return FALSE;
729
730 OldBrush = NtGdiSelectBrush(hDC, hBrush);
731 if (OldBrush == NULL)
732 {
733 GreDeleteObject(hBrush);
734 return FALSE;
735 }
736
737 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
738 NtGdiSelectBrush(hDC, OldBrush);
739 GreDeleteObject(hBrush);
740
741 return TRUE;
742 }
743
744 COLORREF APIENTRY
745 NtGdiSetPixel(
746 HDC hDC,
747 INT X,
748 INT Y,
749 COLORREF Color)
750 {
751 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
752
753 if (GdiSetPixelV(hDC,X,Y,Color))
754 {
755 Color = NtGdiGetPixel(hDC,X,Y);
756 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
757 return Color;
758 }
759
760 Color = (COLORREF)CLR_INVALID;
761 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
762 return Color;
763 }
764
765
766 /* Internal Functions */
767
768 HBITMAP
769 FASTCALL
770 BITMAP_CopyBitmap(HBITMAP hBitmap)
771 {
772 HBITMAP hbmNew;
773 SURFACE *psurfSrc, *psurfNew;
774
775 /* Fail, if no source bitmap is given */
776 if (hBitmap == NULL) return 0;
777
778 /* Lock the source bitmap */
779 psurfSrc = SURFACE_ShareLockSurface(hBitmap);
780 if (psurfSrc == NULL)
781 {
782 return 0;
783 }
784
785 /* Allocate a new bitmap with the same dimensions as the source bmp */
786 hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
787 psurfSrc->SurfObj.sizlBitmap.cy,
788 abs(psurfSrc->SurfObj.lDelta),
789 psurfSrc->SurfObj.iBitmapFormat,
790 psurfSrc->SurfObj.fjBitmap,
791 psurfSrc->SurfObj.cjBits,
792 NULL,
793 psurfSrc->flags);
794
795 if (hbmNew)
796 {
797 /* Lock the new bitmap */
798 psurfNew = SURFACE_ShareLockSurface(hbmNew);
799 if (psurfNew)
800 {
801 /* Copy the bitmap bits to the new bitmap buffer */
802 RtlCopyMemory(psurfNew->SurfObj.pvBits,
803 psurfSrc->SurfObj.pvBits,
804 psurfNew->SurfObj.cjBits);
805
806 /* Dereference the new bitmaps palette, we will use a different */
807 GDIOBJ_vDereferenceObject(&psurfNew->ppal->BaseObject);
808
809 /* Reference the palette of the source bitmap and use it */
810 GDIOBJ_vReferenceObjectByPointer(&psurfSrc->ppal->BaseObject);
811 psurfNew->ppal = psurfSrc->ppal;
812
813 /* Unlock the new surface */
814 SURFACE_ShareUnlockSurface(psurfNew);
815 }
816 else
817 {
818 /* Failed to lock the bitmap, shouldn't happen */
819 GreDeleteObject(hbmNew);
820 hbmNew = NULL;
821 }
822 }
823
824 /* Unlock the source bitmap and return the handle of the new bitmap */
825 SURFACE_ShareUnlockSurface(psurfSrc);
826 return hbmNew;
827 }
828
829 INT APIENTRY
830 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
831 {
832 PBITMAP pBitmap;
833
834 if (!buffer) return sizeof(BITMAP);
835 if ((UINT)Count < sizeof(BITMAP)) return 0;
836
837 /* Always fill a basic BITMAP structure */
838 pBitmap = buffer;
839 pBitmap->bmType = 0;
840 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
841 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
842 pBitmap->bmPlanes = 1;
843 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
844 pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
845
846 /* Check for DIB section */
847 if (psurf->hSecure)
848 {
849 /* Set bmBits in this case */
850 pBitmap->bmBits = psurf->SurfObj.pvBits;
851 /* DIBs data are 32 bits aligned */
852 pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
853
854 if (Count >= sizeof(DIBSECTION))
855 {
856 /* Fill rest of DIBSECTION */
857 PDIBSECTION pds = buffer;
858
859 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
860 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
861 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
862 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
863 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
864
865 switch (psurf->SurfObj.iBitmapFormat)
866 {
867 case BMF_1BPP:
868 case BMF_4BPP:
869 case BMF_8BPP:
870 pds->dsBmih.biCompression = BI_RGB;
871 break;
872
873 case BMF_16BPP:
874 if (psurf->ppal->flFlags & PAL_RGB16_555)
875 pds->dsBmih.biCompression = BI_RGB;
876 else
877 pds->dsBmih.biCompression = BI_BITFIELDS;
878 break;
879
880 case BMF_24BPP:
881 case BMF_32BPP:
882 /* 24/32bpp BI_RGB is actually BGR format */
883 if (psurf->ppal->flFlags & PAL_BGR)
884 pds->dsBmih.biCompression = BI_RGB;
885 else
886 pds->dsBmih.biCompression = BI_BITFIELDS;
887 break;
888
889 case BMF_4RLE:
890 pds->dsBmih.biCompression = BI_RLE4;
891 break;
892 case BMF_8RLE:
893 pds->dsBmih.biCompression = BI_RLE8;
894 break;
895 case BMF_JPEG:
896 pds->dsBmih.biCompression = BI_JPEG;
897 break;
898 case BMF_PNG:
899 pds->dsBmih.biCompression = BI_PNG;
900 break;
901 default:
902 ASSERT(FALSE); /* This shouldn't happen */
903 }
904
905 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
906 pds->dsBmih.biXPelsPerMeter = 0;
907 pds->dsBmih.biYPelsPerMeter = 0;
908 pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
909 pds->dsBmih.biClrImportant = psurf->biClrImportant;
910 pds->dsBitfields[0] = psurf->ppal->RedMask;
911 pds->dsBitfields[1] = psurf->ppal->GreenMask;
912 pds->dsBitfields[2] = psurf->ppal->BlueMask;
913 pds->dshSection = psurf->hDIBSection;
914 pds->dsOffset = psurf->dwOffset;
915
916 return sizeof(DIBSECTION);
917 }
918 }
919 else
920 {
921 /* Not set according to wine test, confirmed in win2k */
922 pBitmap->bmBits = NULL;
923 }
924
925 return sizeof(BITMAP);
926 }
927
928 /*
929 * @implemented
930 */
931 HDC
932 APIENTRY
933 NtGdiGetDCforBitmap(
934 IN HBITMAP hsurf)
935 {
936 HDC hdc = NULL;
937 PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
938 if (psurf)
939 {
940 hdc = psurf->hdc;
941 SURFACE_ShareUnlockSurface(psurf);
942 }
943 return hdc;
944 }
945
946
947 /* EOF */