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