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