Jeffrey Morlan (mrnobo1024 at yahoo.com) - Fix ModifyWorldTransform multiplies. See...
[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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$ */
20
21 #include <w32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 #define IN_RECT(r,x,y) \
27 ( \
28 (x) >= (r).left && \
29 (y) >= (r).top && \
30 (x) < (r).right && \
31 (y) < (r).bottom \
32 )
33
34 HBITMAP STDCALL
35 IntGdiCreateBitmap(
36 INT Width,
37 INT Height,
38 UINT Planes,
39 UINT BitsPixel,
40 IN OPTIONAL LPBYTE pBits)
41 {
42 HBITMAP hBitmap;
43 SIZEL Size;
44 LONG WidthBytes;
45
46 /* NOTE: Windows also doesn't store nr. of planes separately! */
47 BitsPixel = BITMAPOBJ_GetRealBitsPixel(BitsPixel * Planes);
48
49 /* Check parameters */
50 if (BitsPixel == 0 || Width < 0)
51 {
52 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n", Width, Height, BitsPixel);
53 SetLastWin32Error(ERROR_INVALID_PARAMETER);
54 return 0;
55 }
56
57 WidthBytes = BITMAPOBJ_GetWidthBytes(Width, Planes * BitsPixel);
58
59 Size.cx = abs(Width);
60 Size.cy = abs(Height);
61
62 /* Create the bitmap object. */
63 hBitmap = IntCreateBitmap(Size, WidthBytes,
64 BitmapFormat(BitsPixel, BI_RGB),
65 (Height < 0 ? BMF_TOPDOWN : 0) |
66 (NULL == pBits ? 0 : BMF_NOZEROINIT), NULL);
67 if (!hBitmap)
68 {
69 DPRINT("IntGdiCreateBitmap: returned 0\n");
70 return 0;
71 }
72
73 PBITMAPOBJ bmp = BITMAPOBJ_LockBitmap( hBitmap );
74 if (bmp == NULL)
75 {
76 NtGdiDeleteObject(hBitmap);
77 return NULL;
78 }
79
80 bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
81 bmp->hDC = NULL; // Fixme
82
83 if (NULL != pBits)
84 {
85 IntSetBitmapBits(bmp, bmp->SurfObj.cjBits, pBits);
86 }
87
88 BITMAPOBJ_UnlockBitmap( bmp );
89
90 DPRINT("IntGdiCreateBitmap : %dx%d, %d BPP colors, topdown %d, returning %08x\n",
91 Size.cx, Size.cy, BitsPixel, (Height < 0 ? 1 : 0), hBitmap);
92
93 return hBitmap;
94 }
95
96
97 HBITMAP STDCALL
98 NtGdiCreateBitmap(
99 INT Width,
100 INT Height,
101 UINT Planes,
102 UINT BitsPixel,
103 IN OPTIONAL LPBYTE pUnsafeBits)
104 {
105 HBITMAP hBitmap;
106
107 _SEH_TRY
108 {
109 if (pUnsafeBits)
110 {
111 UINT cjBits = BITMAPOBJ_GetWidthBytes(Width, BitsPixel) * abs(Height);
112 ProbeForRead(pUnsafeBits, cjBits, 1);
113 }
114
115 hBitmap = IntGdiCreateBitmap(Width, Height, Planes, BitsPixel, pUnsafeBits);
116
117 }
118 _SEH_HANDLE
119 {
120 hBitmap = 0;
121 }
122 _SEH_END
123
124 return hBitmap;
125 }
126
127 BOOL INTERNAL_CALL
128 BITMAP_Cleanup(PVOID ObjectBody)
129 {
130 PBITMAPOBJ pBmp = (PBITMAPOBJ)ObjectBody;
131 if (pBmp->SurfObj.pvBits != NULL &&
132 (pBmp->flFlags & BITMAPOBJ_IS_APIBITMAP))
133 {
134 if (pBmp->dib == NULL)
135 {
136 if (pBmp->SurfObj.pvBits != NULL)
137 ExFreePool(pBmp->SurfObj.pvBits);
138 }
139 else
140 {
141 if (pBmp->SurfObj.pvBits != NULL)
142 EngFreeUserMem(pBmp->SurfObj.pvBits);
143 }
144 if (pBmp->hDIBPalette != NULL)
145 {
146 NtGdiDeleteObject(pBmp->hDIBPalette);
147 }
148 }
149
150 if (NULL != pBmp->BitsLock)
151 {
152 ExFreePoolWithTag(pBmp->BitsLock, TAG_BITMAPOBJ);
153 pBmp->BitsLock = NULL;
154 }
155
156 return TRUE;
157 }
158
159
160 HBITMAP FASTCALL
161 IntCreateCompatibleBitmap(
162 PDC Dc,
163 INT Width,
164 INT Height)
165 {
166 HBITMAP Bmp;
167
168 Bmp = NULL;
169
170 if ((Width >= 0x10000) || (Height >= 0x10000))
171 {
172 DPRINT1("got bad width %d or height %d, please look for reason\n", Width, Height);
173 return NULL;
174 }
175
176 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
177 if (0 == Width || 0 == Height)
178 {
179 Bmp = IntGdiCreateBitmap (1, 1, 1, 1, NULL);
180 }
181 else
182 {
183 Bmp = IntGdiCreateBitmap(abs(Width), abs(Height), 1, Dc->w.bitsPerPixel, NULL);
184 }
185
186 return Bmp;
187 }
188
189 HBITMAP STDCALL
190 NtGdiCreateCompatibleBitmap(
191 HDC hDC,
192 INT Width,
193 INT Height)
194 {
195 HBITMAP Bmp;
196 PDC Dc;
197
198 Dc = DC_LockDc(hDC);
199
200 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n", hDC, Width, Height, Dc->w.bitsPerPixel);
201
202 if (NULL == Dc)
203 {
204 SetLastWin32Error(ERROR_INVALID_HANDLE);
205 return NULL;
206 }
207
208 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
209
210 DPRINT ("\t\t%04x\n", Bmp);
211 DC_UnlockDc(Dc);
212 return Bmp;
213 }
214
215 BOOL STDCALL
216 NtGdiGetBitmapDimension(
217 HBITMAP hBitmap,
218 LPSIZE Dimension)
219 {
220 PBITMAPOBJ bmp;
221
222 bmp = BITMAPOBJ_LockBitmap(hBitmap);
223 if (bmp == NULL)
224 {
225 return FALSE;
226 }
227
228 *Dimension = bmp->dimension;
229
230 BITMAPOBJ_UnlockBitmap(bmp);
231
232 return TRUE;
233 }
234
235 COLORREF STDCALL
236 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
237 {
238 PDC dc = NULL;
239 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
240 BOOL bInRect = FALSE;
241 BITMAPOBJ *BitmapObject;
242 SURFOBJ *SurfaceObject;
243 HPALETTE Pal = 0;
244 XLATEOBJ *XlateObj;
245 HBITMAP hBmpTmp;
246
247 dc = DC_LockDc (hDC);
248
249 if ( !dc )
250 {
251 SetLastWin32Error(ERROR_INVALID_HANDLE);
252 return Result;
253 }
254 if (dc->DC_Type == DC_TYPE_INFO)
255 {
256 DC_UnlockDc(dc);
257 return Result;
258 }
259 XPos += dc->ptlDCOrig.x;
260 YPos += dc->ptlDCOrig.y;
261 if ( IN_RECT(dc->CombinedClip->rclBounds,XPos,YPos) )
262 {
263 bInRect = TRUE;
264 BitmapObject = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
265 SurfaceObject = &BitmapObject->SurfObj;
266 if ( BitmapObject )
267 {
268 Pal = BitmapObject->hDIBPalette;
269 if (!Pal) Pal = pPrimarySurface->DevInfo.hpalDefault;
270
271 /* FIXME: Verify if it shouldn't be PAL_BGR! */
272 XlateObj = (XLATEOBJ*)IntEngCreateXlate ( PAL_RGB, 0, NULL, Pal );
273 if ( XlateObj )
274 {
275 // check if this DC has a DIB behind it...
276 if ( SurfaceObject->pvScan0 ) // STYPE_BITMAP == SurfaceObject->iType
277 {
278 ASSERT ( SurfaceObject->lDelta );
279 Result = XLATEOBJ_iXlate(XlateObj,
280 DibFunctionsForBitmapFormat[SurfaceObject->iBitmapFormat].DIB_GetPixel ( SurfaceObject, XPos, YPos ) );
281 }
282 EngDeleteXlate(XlateObj);
283 }
284 BITMAPOBJ_UnlockBitmap(BitmapObject);
285 }
286 }
287 DC_UnlockDc(dc);
288
289 // if Result is still CLR_INVALID, then the "quick" method above didn't work
290 if ( bInRect && Result == CLR_INVALID )
291 {
292 // FIXME: create a 1x1 32BPP DIB, and blit to it
293 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
294 if ( hDCTmp )
295 {
296 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
297 BITMAPINFO bi;
298 RtlMoveMemory ( &(bi.bmiHeader), &bih, sizeof(bih) );
299 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
300 bi.bmiHeader.biWidth,
301 bi.bmiHeader.biHeight,
302 0,
303 NULL,
304 &bi,
305 DIB_RGB_COLORS,
306 bi.bmiHeader.biBitCount,
307 bi.bmiHeader.biSizeImage,
308 0,
309 0);
310
311 //HBITMAP hBmpTmp = IntGdiCreateBitmap ( 1, 1, 1, 32, NULL);
312 if ( hBmpTmp )
313 {
314 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap ( hDCTmp, hBmpTmp );
315 if ( hBmpOld )
316 {
317 PBITMAPOBJ bmpobj;
318
319 NtGdiBitBlt ( hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0 );
320 NtGdiSelectBitmap ( hDCTmp, hBmpOld );
321
322 // our bitmap is no longer selected, so we can access it's stuff...
323 bmpobj = BITMAPOBJ_LockBitmap ( hBmpTmp );
324 if ( bmpobj )
325 {
326 Result = *(COLORREF*)bmpobj->SurfObj.pvScan0;
327 BITMAPOBJ_UnlockBitmap ( bmpobj );
328 }
329 }
330 NtGdiDeleteObject ( hBmpTmp );
331 }
332 NtGdiDeleteObjectApp ( hDCTmp );
333 }
334 }
335
336 return Result;
337 }
338
339
340 LONG STDCALL
341 IntGetBitmapBits(
342 PBITMAPOBJ bmp,
343 DWORD Bytes,
344 OUT PBYTE Bits)
345 {
346 LONG ret;
347
348 ASSERT(Bits);
349
350 /* Don't copy more bytes than the buffer has */
351 Bytes = min(Bytes, bmp->SurfObj.cjBits);
352
353 #if 0
354 /* FIXME: Call DDI CopyBits here if available */
355 if(bmp->DDBitmap)
356 {
357 DPRINT("Calling device specific BitmapBits\n");
358 if(bmp->DDBitmap->funcs->pBitmapBits)
359 {
360 ret = bmp->DDBitmap->funcs->pBitmapBits(hbitmap, bits, count, DDB_GET);
361 }
362 else
363 {
364 ERR_(bitmap)("BitmapBits == NULL??\n");
365 ret = 0;
366 }
367 }
368 else
369 #endif
370 {
371 RtlCopyMemory(Bits, bmp->SurfObj.pvBits, Bytes);
372 ret = Bytes;
373 }
374 return ret;
375 }
376
377 LONG STDCALL
378 NtGdiGetBitmapBits(HBITMAP hBitmap,
379 ULONG Bytes,
380 OUT OPTIONAL PBYTE pUnsafeBits)
381 {
382 PBITMAPOBJ bmp;
383 LONG ret;
384
385 if (pUnsafeBits != NULL && Bytes == 0)
386 {
387 return 0;
388 }
389
390 bmp = BITMAPOBJ_LockBitmap (hBitmap);
391 if (!bmp)
392 {
393 SetLastWin32Error(ERROR_INVALID_HANDLE);
394 return 0;
395 }
396
397 /* If the bits vector is null, the function should return the read size */
398 if (pUnsafeBits == NULL)
399 {
400 ret = bmp->SurfObj.cjBits;
401 BITMAPOBJ_UnlockBitmap (bmp);
402 return ret;
403 }
404
405 /* Don't copy more bytes than the buffer has */
406 Bytes = min(Bytes, bmp->SurfObj.cjBits);
407
408 _SEH_TRY
409 {
410 ProbeForWrite(pUnsafeBits, Bytes, 1);
411 ret = IntGetBitmapBits(bmp, Bytes, pUnsafeBits);
412 }
413 _SEH_HANDLE
414 {
415 ret = 0;
416 }
417 _SEH_END
418
419 BITMAPOBJ_UnlockBitmap (bmp);
420
421 return ret;
422 }
423
424
425 LONG STDCALL
426 IntSetBitmapBits(
427 PBITMAPOBJ bmp,
428 DWORD Bytes,
429 IN PBYTE Bits)
430 {
431 LONG ret;
432
433 /* Don't copy more bytes than the buffer has */
434 Bytes = min(Bytes, bmp->SurfObj.cjBits);
435
436 #if 0
437 /* FIXME: call DDI specific function here if available */
438 if(bmp->DDBitmap)
439 {
440 DPRINT ("Calling device specific BitmapBits\n");
441 if (bmp->DDBitmap->funcs->pBitmapBits)
442 {
443 ret = bmp->DDBitmap->funcs->pBitmapBits(hBitmap, (void *) Bits, Bytes, DDB_SET);
444 }
445 else
446 {
447 DPRINT ("BitmapBits == NULL??\n");
448 ret = 0;
449 }
450 }
451 else
452 #endif
453 {
454 RtlCopyMemory(bmp->SurfObj.pvBits, Bits, Bytes);
455 ret = Bytes;
456 }
457
458 return ret;
459 }
460
461
462 LONG STDCALL
463 NtGdiSetBitmapBits(
464 HBITMAP hBitmap,
465 DWORD Bytes,
466 IN PBYTE pUnsafeBits)
467 {
468 LONG ret;
469 PBITMAPOBJ bmp;
470
471 if (pUnsafeBits == NULL || Bytes == 0)
472 {
473 return 0;
474 }
475
476 bmp = BITMAPOBJ_LockBitmap(hBitmap);
477 if (bmp == NULL)
478 {
479 SetLastWin32Error(ERROR_INVALID_HANDLE);
480 return 0;
481 }
482
483 _SEH_TRY
484 {
485 ProbeForRead(pUnsafeBits, Bytes, 1);
486 ret = IntSetBitmapBits(bmp, Bytes, pUnsafeBits);
487 }
488 _SEH_HANDLE
489 {
490 ret = 0;
491 }
492 _SEH_END
493
494 BITMAPOBJ_UnlockBitmap(bmp);
495
496 return ret;
497 }
498
499 BOOL STDCALL
500 NtGdiSetBitmapDimension(
501 HBITMAP hBitmap,
502 INT Width,
503 INT Height,
504 LPSIZE Size)
505 {
506 PBITMAPOBJ bmp;
507
508 bmp = BITMAPOBJ_LockBitmap(hBitmap);
509 if (bmp == NULL)
510 {
511 return FALSE;
512 }
513
514 if (Size)
515 {
516 *Size = bmp->dimension;
517 }
518 bmp->dimension.cx = Width;
519 bmp->dimension.cy = Height;
520
521 BITMAPOBJ_UnlockBitmap (bmp);
522
523 return TRUE;
524 }
525
526 BOOL STDCALL
527 GdiSetPixelV(
528 HDC hDC,
529 INT X,
530 INT Y,
531 COLORREF Color)
532 {
533 HBRUSH NewBrush = NtGdiCreateSolidBrush(Color, NULL);
534 HGDIOBJ OldBrush;
535
536 if (NewBrush == NULL)
537 return(FALSE);
538 OldBrush = NtGdiSelectBrush(hDC, NewBrush);
539 if (OldBrush == NULL)
540 {
541 NtGdiDeleteObject(NewBrush);
542 return(FALSE);
543 }
544 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
545 NtGdiSelectBrush(hDC, OldBrush);
546 NtGdiDeleteObject(NewBrush);
547 return TRUE;
548 }
549
550 COLORREF STDCALL
551 NtGdiSetPixel(
552 HDC hDC,
553 INT X,
554 INT Y,
555 COLORREF Color)
556 {
557 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
558
559 if (GdiSetPixelV(hDC,X,Y,Color))
560 {
561 Color = NtGdiGetPixel(hDC,X,Y);
562 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
563 return Color;
564 }
565
566 Color = ((COLORREF) CLR_INVALID);
567 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
568 return Color;
569 }
570
571
572 /* Internal Functions */
573
574 INT FASTCALL
575 BITMAPOBJ_GetRealBitsPixel(INT nBitsPixel)
576 {
577 if (nBitsPixel < 0)
578 return 0;
579 if (nBitsPixel <= 1)
580 return 1;
581 if (nBitsPixel <= 2)
582 return 2;
583 if (nBitsPixel <= 4)
584 return 4;
585 if (nBitsPixel <= 8)
586 return 8;
587 if (nBitsPixel <= 16)
588 return 16;
589 if (nBitsPixel <= 24)
590 return 24;
591 if (nBitsPixel <= 32)
592 return 32;
593
594 return 0;
595 }
596
597 INT FASTCALL
598 BITMAPOBJ_GetWidthBytes (INT bmWidth, INT bpp)
599 {
600 #if 0
601 switch(bpp)
602 {
603 case 1:
604 return 2 * ((bmWidth+15) >> 4);
605
606 case 24:
607 bmWidth *= 3; /* fall through */
608 case 8:
609 return bmWidth + (bmWidth & 1);
610
611 case 32:
612 return bmWidth * 4;
613
614 case 16:
615 case 15:
616 return bmWidth * 2;
617
618 case 4:
619 return 2 * ((bmWidth+3) >> 2);
620
621 default:
622 DPRINT ("stub");
623 }
624
625 return -1;
626 #endif
627
628 return ((bmWidth * bpp + 15) & ~15) >> 3;
629 }
630
631 HBITMAP FASTCALL
632 BITMAPOBJ_CopyBitmap(HBITMAP hBitmap)
633 {
634 HBITMAP res;
635 BITMAP bm;
636 BITMAPOBJ *Bitmap, *resBitmap;
637 SIZEL Size;
638
639 if (hBitmap == NULL)
640 {
641 return 0;
642 }
643
644 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
645 if (Bitmap == NULL)
646 {
647 return 0;
648 }
649
650 BITMAP_GetObject(Bitmap, sizeof(BITMAP), &bm);
651 bm.bmBits = NULL;
652 if (Bitmap->SurfObj.lDelta >= 0)
653 bm.bmHeight = -bm.bmHeight;
654
655 Size.cx = abs(bm.bmWidth);
656 Size.cy = abs(bm.bmHeight);
657 res = IntCreateBitmap(Size,
658 bm.bmWidthBytes,
659 BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
660 (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
661 NULL);
662
663 if(res)
664 {
665 PBYTE buf;
666
667 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
668 if (resBitmap)
669 {
670 buf = ExAllocatePoolWithTag (PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
671 if (buf == NULL)
672 {
673 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
674 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
675 NtGdiDeleteObject(res);
676 return 0;
677 }
678 IntGetBitmapBits (Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
679 IntSetBitmapBits (resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
680 ExFreePool (buf);
681 resBitmap->flFlags = Bitmap->flFlags;
682 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
683 }
684 else
685 {
686 NtGdiDeleteObject(res);
687 res = NULL;
688 }
689 }
690
691 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
692
693 return res;
694 }
695
696 INT STDCALL
697 BITMAP_GetObject(BITMAPOBJ * bmp, INT Count, LPVOID buffer)
698 {
699 if ((UINT)Count < sizeof(BITMAP)) return 0;
700
701 if(bmp->dib)
702 {
703 if((UINT)Count < sizeof(DIBSECTION))
704 {
705 Count = sizeof(BITMAP);
706 }
707 else
708 {
709 Count = sizeof(DIBSECTION);
710 }
711 if (buffer)
712 {
713 memcpy(buffer, bmp->dib, Count);
714 }
715 return Count;
716 }
717 else
718 {
719 Count = sizeof(BITMAP);
720 if (buffer)
721 {
722 BITMAP Bitmap;
723
724 Count = sizeof(BITMAP);
725 Bitmap.bmType = 0;
726 Bitmap.bmWidth = bmp->SurfObj.sizlBitmap.cx;
727 Bitmap.bmHeight = bmp->SurfObj.sizlBitmap.cy;
728 Bitmap.bmWidthBytes = abs(bmp->SurfObj.lDelta);
729 Bitmap.bmPlanes = 1;
730 Bitmap.bmBitsPixel = BitsPerFormat(bmp->SurfObj.iBitmapFormat);
731 //Bitmap.bmBits = bmp->SurfObj.pvBits;
732 Bitmap.bmBits = NULL; /* not set accoring wine test confirm in win2k */
733 memcpy(buffer, &Bitmap, Count);
734 }
735 return Count;
736 }
737 }
738
739 /*
740 * @implemented
741 */
742 HDC
743 APIENTRY
744 NtGdiGetDCforBitmap(
745 IN HBITMAP hsurf)
746 {
747 HDC hDC = NULL;
748 PBITMAPOBJ bmp = BITMAPOBJ_LockBitmap( hsurf );
749 hDC = bmp->hDC;
750 BITMAPOBJ_UnlockBitmap( bmp );
751 return hDC;
752 }
753
754
755 /* EOF */