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