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