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