- Use absolute value of width in NtGdiCreateBitmap.
[reactos.git] / reactos / subsys / 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: bitmaps.c,v 1.81 2004/11/21 10:55:29 navaraf Exp $ */
20 #include <w32k.h>
21
22 #define IN_RECT(r,x,y) \
23 ( \
24 (x) >= (r).left && \
25 (y) >= (r).top && \
26 (x) < (r).right && \
27 (y) < (r).bottom \
28 )
29
30 BOOL STDCALL
31 NtGdiBitBlt(
32 HDC hDCDest,
33 INT XDest,
34 INT YDest,
35 INT Width,
36 INT Height,
37 HDC hDCSrc,
38 INT XSrc,
39 INT YSrc,
40 DWORD ROP)
41 {
42 PDC DCDest = NULL;
43 PDC DCSrc = NULL;
44 BITMAPOBJ *BitmapDest, *BitmapSrc;
45 RECTL DestRect;
46 POINTL SourcePoint, BrushOrigin;
47 BOOL Status;
48 XLATEOBJ *XlateObj = NULL;
49 HPALETTE SourcePalette = 0, DestPalette = 0;
50 PGDIBRUSHOBJ BrushObj;
51 GDIBRUSHINST BrushInst;
52 BOOL UsesSource = ROP_USES_SOURCE(ROP);
53 BOOL UsesPattern = ROP_USES_PATTERN(ROP);
54
55 DCDest = DC_LockDc(hDCDest);
56 if (NULL == DCDest)
57 {
58 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
59 SetLastWin32Error(ERROR_INVALID_HANDLE);
60 return FALSE;
61 }
62
63 if (UsesSource)
64 {
65 if (hDCSrc != hDCDest)
66 {
67 DCSrc = DC_LockDc(hDCSrc);
68 if (NULL == DCSrc)
69 {
70 DC_UnlockDc(hDCDest);
71 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
72 SetLastWin32Error(ERROR_INVALID_HANDLE);
73 return FALSE;
74 }
75 }
76 else
77 {
78 DCSrc = DCDest;
79 }
80 }
81 else
82 {
83 DCSrc = NULL;
84 }
85
86 /* Offset the destination and source by the origin of their DCs. */
87 XDest += DCDest->w.DCOrgX;
88 YDest += DCDest->w.DCOrgY;
89 if (UsesSource)
90 {
91 XSrc += DCSrc->w.DCOrgX;
92 YSrc += DCSrc->w.DCOrgY;
93 }
94
95 DestRect.left = XDest;
96 DestRect.top = YDest;
97 DestRect.right = XDest+Width;
98 DestRect.bottom = YDest+Height;
99
100 SourcePoint.x = XSrc;
101 SourcePoint.y = YSrc;
102
103 BrushOrigin.x = 0;
104 BrushOrigin.y = 0;
105
106 /* Determine surfaces to be used in the bitblt */
107 BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
108 if (UsesSource)
109 {
110 if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
111 BitmapSrc = BitmapDest;
112 else
113 BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
114 }
115 else
116 {
117 BitmapSrc = NULL;
118 }
119
120 if (UsesPattern)
121 {
122 BrushObj = BRUSHOBJ_LockBrush(DCDest->w.hBrush);
123 if (NULL == BrushObj)
124 {
125 if (UsesSource && hDCSrc != hDCDest)
126 {
127 DC_UnlockDc(hDCSrc);
128 }
129 DC_UnlockDc(hDCDest);
130 SetLastWin32Error(ERROR_INVALID_HANDLE);
131 return FALSE;
132 }
133 BrushOrigin = BrushObj->ptOrigin;
134 IntGdiInitBrushInstance(&BrushInst, BrushObj, DCDest->XlateBrush);
135 }
136 else
137 {
138 BrushObj = NULL;
139 }
140
141 /* Create the XLATEOBJ. */
142 if (UsesSource)
143 {
144 if (DCDest->w.hPalette != 0)
145 DestPalette = DCDest->w.hPalette;
146
147 if (DCSrc->w.hPalette != 0)
148 SourcePalette = DCSrc->w.hPalette;
149
150 /* KB41464 details how to convert between mono and color */
151 if (DCDest->w.bitsPerPixel == DCSrc->w.bitsPerPixel == 1)
152 {
153 XlateObj = NULL;
154 }
155 else
156 {
157 if (DCDest->w.bitsPerPixel == 1)
158 {
159 XlateObj = IntEngCreateMonoXlate(0, DestPalette, SourcePalette, DCSrc->w.backgroundColor);
160 }
161 else if (DCSrc->w.bitsPerPixel == 1)
162 {
163 XlateObj = IntEngCreateSrcMonoXlate(DestPalette, DCSrc->w.backgroundColor, DCSrc->w.textColor);
164 }
165 else
166 {
167 XlateObj = IntEngCreateXlate(0, 0, DestPalette, SourcePalette);
168 }
169 if (NULL == XlateObj)
170 {
171 if (UsesSource && hDCSrc != hDCDest)
172 {
173 DC_UnlockDc(hDCSrc);
174 }
175 DC_UnlockDc(hDCDest);
176 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
177 return FALSE;
178 }
179 }
180 }
181
182 /* Perform the bitblt operation */
183 Status = IntEngBitBlt(BitmapDest, BitmapSrc, NULL, DCDest->CombinedClip, XlateObj,
184 &DestRect, &SourcePoint, NULL, BrushObj ? &BrushInst.BrushObject : NULL, &BrushOrigin, ROP);
185
186 if (UsesSource && XlateObj != NULL)
187 EngDeleteXlate(XlateObj);
188 BITMAPOBJ_UnlockBitmap(DCDest->w.hBitmap);
189 if (UsesSource && DCSrc->w.hBitmap != DCDest->w.hBitmap)
190 {
191 BITMAPOBJ_UnlockBitmap(DCSrc->w.hBitmap);
192 }
193 if (UsesPattern)
194 {
195 BRUSHOBJ_UnlockBrush(DCDest->w.hBrush);
196 }
197 if (UsesSource && hDCSrc != hDCDest)
198 {
199 DC_UnlockDc(hDCSrc);
200 }
201 DC_UnlockDc(hDCDest);
202
203 return Status;
204 }
205
206 BOOL STDCALL
207 NtGdiTransparentBlt(
208 HDC hdcDst,
209 INT xDst,
210 INT yDst,
211 INT cxDst,
212 INT cyDst,
213 HDC hdcSrc,
214 INT xSrc,
215 INT ySrc,
216 INT cxSrc,
217 INT cySrc,
218 COLORREF TransColor)
219 {
220 PDC DCDest, DCSrc;
221 RECTL rcDest, rcSrc;
222 BITMAPOBJ *BitmapDest, *BitmapSrc;
223 XLATEOBJ *XlateObj;
224 HPALETTE SourcePalette = 0, DestPalette = 0;
225 PPALGDI PalDestGDI, PalSourceGDI;
226 USHORT PalDestMode, PalSrcMode;
227 ULONG TransparentColor = 0;
228 BOOL Ret = FALSE;
229
230 if(!(DCDest = DC_LockDc(hdcDst)))
231 {
232 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);
233 SetLastWin32Error(ERROR_INVALID_HANDLE);
234 return FALSE;
235 }
236
237 if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))
238 {
239 DC_UnlockDc(hdcDst);
240 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);
241 SetLastWin32Error(ERROR_INVALID_HANDLE);
242 return FALSE;
243 }
244 if(hdcDst == hdcSrc)
245 {
246 DCSrc = DCDest;
247 }
248
249 /* Offset positions */
250 xDst += DCDest->w.DCOrgX;
251 yDst += DCDest->w.DCOrgY;
252 xSrc += DCSrc->w.DCOrgX;
253 ySrc += DCSrc->w.DCOrgY;
254
255 if(DCDest->w.hPalette)
256 DestPalette = DCDest->w.hPalette;
257
258 if(DCSrc->w.hPalette)
259 SourcePalette = DCSrc->w.hPalette;
260
261 if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))
262 {
263 DC_UnlockDc(hdcSrc);
264 DC_UnlockDc(hdcDst);
265 SetLastWin32Error(ERROR_INVALID_HANDLE);
266 return FALSE;
267 }
268 if((DestPalette != SourcePalette) && !(PalDestGDI = PALETTE_LockPalette(DestPalette)))
269 {
270 PALETTE_UnlockPalette(SourcePalette);
271 DC_UnlockDc(hdcSrc);
272 DC_UnlockDc(hdcDst);
273 SetLastWin32Error(ERROR_INVALID_HANDLE);
274 return FALSE;
275 }
276 if(DestPalette != SourcePalette)
277 {
278 PalDestMode = PalDestGDI->Mode;
279 PalSrcMode = PalSourceGDI->Mode;
280 PALETTE_UnlockPalette(DestPalette);
281 }
282 else
283 {
284 PalDestMode = PalSrcMode = PalSourceGDI->Mode;
285 }
286 PALETTE_UnlockPalette(SourcePalette);
287
288 /* Translate Transparent (RGB) Color to the source palette */
289 if((XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalSrcMode, PAL_RGB, SourcePalette, NULL)))
290 {
291 TransparentColor = XLATEOBJ_iXlate(XlateObj, (ULONG)TransColor);
292 EngDeleteXlate(XlateObj);
293 }
294
295 /* Create the XLATE object to convert colors between source and destination */
296 XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalDestMode, PalSrcMode, DestPalette, SourcePalette);
297
298 BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
299 ASSERT(BitmapDest);
300 BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
301 ASSERT(BitmapSrc);
302
303 rcDest.left = xDst;
304 rcDest.top = yDst;
305 rcDest.right = rcDest.left + cxDst;
306 rcDest.bottom = rcDest.top + cyDst;
307 rcSrc.left = xSrc;
308 rcSrc.top = ySrc;
309 rcSrc.right = rcSrc.left + cxSrc;
310 rcSrc.bottom = rcSrc.top + cySrc;
311
312 if((cxDst != cxSrc) || (cyDst != cySrc))
313 {
314 DPRINT1("TransparentBlt() does not support stretching at the moment!\n");
315 goto done;
316 }
317
318 Ret = IntEngTransparentBlt(BitmapDest, BitmapSrc, DCDest->CombinedClip, XlateObj, &rcDest, &rcSrc,
319 TransparentColor, 0);
320
321 done:
322 BITMAPOBJ_UnlockBitmap(DCDest->w.hBitmap);
323 BITMAPOBJ_UnlockBitmap(DCSrc->w.hBitmap);
324 DC_UnlockDc(hdcSrc);
325 if(hdcDst != hdcSrc)
326 {
327 DC_UnlockDc(hdcDst);
328 }
329 if(XlateObj)
330 {
331 EngDeleteXlate(XlateObj);
332 }
333 return Ret;
334 }
335
336 HBITMAP STDCALL
337 NtGdiCreateBitmap(
338 INT Width,
339 INT Height,
340 UINT Planes,
341 UINT BitsPerPel,
342 CONST VOID *Bits)
343 {
344 PBITMAPOBJ bmp;
345 HBITMAP hBitmap;
346 SIZEL Size;
347
348 /* NOTE: Windows also doesn't store nr. of planes separately! */
349 BitsPerPel = (BYTE)BitsPerPel * (BYTE)Planes;
350
351 /* Check parameters */
352 if (!Height || !Width)
353 {
354 Size.cx = Size.cy = 1;
355 }
356 else
357 {
358 Size.cx = abs(Width);
359 Size.cy = abs(Height);
360 }
361
362 /* Create the bitmap object. */
363 hBitmap = IntCreateBitmap(Size, BITMAPOBJ_GetWidthBytes(Width, BitsPerPel),
364 BitmapFormat(BitsPerPel, BI_RGB),
365 (Height > 0 ? 0 : BMF_TOPDOWN) |
366 (Bits == NULL ? 0 : BMF_NOZEROINIT), NULL);
367 if (!hBitmap)
368 {
369 DPRINT("NtGdiCreateBitmap: IntCreateBitmap returned 0\n");
370 return 0;
371 }
372
373 DPRINT("NtGdiCreateBitmap:%dx%d, %d BPP colors returning %08x\n",
374 Size.cx, Size.cy, BitsPerPel, hBitmap);
375
376 bmp = BITMAPOBJ_LockBitmap( hBitmap );
377 bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
378 BITMAPOBJ_UnlockBitmap( hBitmap );
379
380 /*
381 * NOTE: It's ugly practice, but we are using the object even
382 * after unlocking. Since the handle is currently known only
383 * to us it should be safe.
384 */
385
386 if (Bits != NULL)
387 {
388 NtGdiSetBitmapBits(hBitmap, bmp->SurfObj.cjBits, Bits);
389 }
390
391 return hBitmap;
392 }
393
394 BOOL FASTCALL
395 Bitmap_InternalDelete( PBITMAPOBJ pBmp )
396 {
397 ASSERT( pBmp );
398
399 if (pBmp->SurfObj.pvBits != NULL &&
400 (pBmp->flFlags & BITMAPOBJ_IS_APIBITMAP))
401 {
402 if (pBmp->dib == NULL)
403 {
404 ExFreePool(pBmp->SurfObj.pvBits);
405 }
406 else
407 {
408 EngFreeUserMem(pBmp->SurfObj.pvBits);
409 }
410 }
411
412 return TRUE;
413 }
414
415
416 HBITMAP FASTCALL
417 IntCreateCompatibleBitmap(
418 PDC Dc,
419 INT Width,
420 INT Height)
421 {
422 HBITMAP Bmp;
423
424 Bmp = NULL;
425
426 if ((Width >= 0x10000) || (Height >= 0x10000))
427 {
428 DPRINT1("got bad width %d or height %d, please look for reason\n", Width, Height);
429 return NULL;
430 }
431
432 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
433 if (0 == Width || 0 == Height)
434 {
435 Bmp = NtGdiCreateBitmap (1, 1, 1, 1, NULL);
436 }
437 else
438 {
439 Bmp = NtGdiCreateBitmap(Width, Height, 1, Dc->w.bitsPerPixel, NULL);
440 }
441
442 return Bmp;
443 }
444
445 HBITMAP STDCALL
446 NtGdiCreateCompatibleBitmap(
447 HDC hDC,
448 INT Width,
449 INT Height)
450 {
451 HBITMAP Bmp;
452 PDC Dc;
453
454 Dc = DC_LockDc(hDC);
455
456 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n", hDC, Width, Height, Dc->w.bitsPerPixel);
457
458 if (NULL == Dc)
459 {
460 SetLastWin32Error(ERROR_INVALID_HANDLE);
461 return NULL;
462 }
463
464 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
465
466 DPRINT ("\t\t%04x\n", Bmp);
467 DC_UnlockDc(hDC);
468 return Bmp;
469 }
470
471 HBITMAP STDCALL
472 NtGdiCreateBitmapIndirect(CONST BITMAP *BM)
473 {
474 return NtGdiCreateBitmap (BM->bmWidth,
475 BM->bmHeight,
476 BM->bmPlanes,
477 BM->bmBitsPixel,
478 BM->bmBits);
479 }
480
481 HBITMAP STDCALL
482 NtGdiCreateDiscardableBitmap(
483 HDC hDC,
484 INT Width,
485 INT Height)
486 {
487 /* FIXME: this probably should do something else */
488 return NtGdiCreateCompatibleBitmap(hDC, Width, Height);
489 }
490
491 BOOL STDCALL
492 NtGdiExtFloodFill(
493 HDC hDC,
494 INT XStart,
495 INT YStart,
496 COLORREF Color,
497 UINT FillType)
498 {
499 UNIMPLEMENTED;
500 return FALSE;
501 }
502
503 BOOL STDCALL
504 NtGdiFloodFill(
505 HDC hDC,
506 INT XStart,
507 INT YStart,
508 COLORREF Fill)
509 {
510 return NtGdiExtFloodFill(hDC, XStart, YStart, Fill, FLOODFILLBORDER );
511 }
512
513 BOOL STDCALL
514 NtGdiGetBitmapDimensionEx(
515 HBITMAP hBitmap,
516 LPSIZE Dimension)
517 {
518 PBITMAPOBJ bmp;
519
520 bmp = BITMAPOBJ_LockBitmap(hBitmap);
521 if (bmp == NULL)
522 {
523 return FALSE;
524 }
525
526 *Dimension = bmp->dimension;
527
528 BITMAPOBJ_UnlockBitmap(hBitmap);
529
530 return TRUE;
531 }
532
533 COLORREF STDCALL
534 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
535 {
536 PDC dc = NULL;
537 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
538 BOOL bInRect = FALSE;
539 BITMAPOBJ *BitmapObject;
540 SURFOBJ *SurfaceObject;
541 HPALETTE Pal = 0;
542 XLATEOBJ *XlateObj;
543
544 dc = DC_LockDc (hDC);
545
546 if ( !dc )
547 {
548 SetLastWin32Error(ERROR_INVALID_HANDLE);
549 return Result;
550 }
551 XPos += dc->w.DCOrgX;
552 YPos += dc->w.DCOrgY;
553 if ( IN_RECT(dc->CombinedClip->rclBounds,XPos,YPos) )
554 {
555 bInRect = TRUE;
556 BitmapObject = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
557 SurfaceObject = &BitmapObject->SurfObj;
558 if ( BitmapObject )
559 {
560 if ( dc->w.hPalette != 0 )
561 Pal = dc->w.hPalette;
562 /* FIXME: Verify if it shouldn't be PAL_BGR! */
563 XlateObj = (XLATEOBJ*)IntEngCreateXlate ( PAL_RGB, 0, NULL, Pal );
564 if ( XlateObj )
565 {
566 // check if this DC has a DIB behind it...
567 if ( SurfaceObject->pvScan0 ) // STYPE_BITMAP == SurfaceObject->iType
568 {
569 ASSERT ( SurfaceObject->lDelta );
570 Result = XLATEOBJ_iXlate(XlateObj,
571 DibFunctionsForBitmapFormat[SurfaceObject->iBitmapFormat].DIB_GetPixel ( SurfaceObject, XPos, YPos ) );
572 }
573 EngDeleteXlate(XlateObj);
574 }
575 }
576 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
577 }
578 DC_UnlockDc(hDC);
579
580 // if Result is still CLR_INVALID, then the "quick" method above didn't work
581 if ( bInRect && Result == CLR_INVALID )
582 {
583 // FIXME: create a 1x1 32BPP DIB, and blit to it
584 HDC hDCTmp = NtGdiCreateCompatableDC(hDC);
585 if ( hDCTmp )
586 {
587 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
588 BITMAPINFO bi;
589 RtlMoveMemory ( &(bi.bmiHeader), &bih, sizeof(bih) );
590 HBITMAP hBmpTmp = NtGdiCreateDIBitmap ( hDC, &bi.bmiHeader, 0, NULL, &bi, DIB_RGB_COLORS );
591 //HBITMAP hBmpTmp = NtGdiCreateBitmap ( 1, 1, 1, 32, NULL);
592 if ( hBmpTmp )
593 {
594 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectObject ( hDCTmp, hBmpTmp );
595 if ( hBmpOld )
596 {
597 PBITMAPOBJ bmpobj;
598
599 NtGdiBitBlt ( hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY );
600 NtGdiSelectObject ( hDCTmp, hBmpOld );
601
602 // our bitmap is no longer selected, so we can access it's stuff...
603 bmpobj = BITMAPOBJ_LockBitmap ( hBmpTmp );
604 if ( bmpobj )
605 {
606 Result = *(COLORREF*)bmpobj->SurfObj.pvScan0;
607 BITMAPOBJ_UnlockBitmap ( hBmpTmp );
608 }
609 }
610 NtGdiDeleteObject ( hBmpTmp );
611 }
612 NtGdiDeleteDC ( hDCTmp );
613 }
614 }
615
616 return Result;
617 }
618
619 /***********************************************************************
620 * MaskBlt
621 * Ported from WINE by sedwards 11-4-03
622 *
623 * Someone thought it would be faster to do it here and then switch back
624 * to GDI32. I dunno. Write a test and let me know.
625 */
626
627 static inline BYTE
628 SwapROP3_SrcDst(BYTE bRop3)
629 {
630 return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);
631 }
632
633 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
634 #define BKGND_ROP3(ROP4) (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])
635 #define DSTCOPY 0x00AA0029
636 #define DSTERASE 0x00220326 /* dest = dest & (~src) : DSna */
637
638 BOOL STDCALL
639 NtGdiMaskBlt (
640 HDC hdcDest, INT nXDest, INT nYDest,
641 INT nWidth, INT nHeight, HDC hdcSrc,
642 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
643 INT xMask, INT yMask, DWORD dwRop)
644 {
645 HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;
646 HDC hDCMask, hDC1, hDC2;
647 static const DWORD ROP3Table[256] =
648 {
649 0x00000042, 0x00010289,
650 0x00020C89, 0x000300AA,
651 0x00040C88, 0x000500A9,
652 0x00060865, 0x000702C5,
653 0x00080F08, 0x00090245,
654 0x000A0329, 0x000B0B2A,
655 0x000C0324, 0x000D0B25,
656 0x000E08A5, 0x000F0001,
657 0x00100C85, 0x001100A6,
658 0x00120868, 0x001302C8,
659 0x00140869, 0x001502C9,
660 0x00165CCA, 0x00171D54,
661 0x00180D59, 0x00191CC8,
662 0x001A06C5, 0x001B0768,
663 0x001C06CA, 0x001D0766,
664 0x001E01A5, 0x001F0385,
665 0x00200F09, 0x00210248,
666 0x00220326, 0x00230B24,
667 0x00240D55, 0x00251CC5,
668 0x002606C8, 0x00271868,
669 0x00280369, 0x002916CA,
670 0x002A0CC9, 0x002B1D58,
671 0x002C0784, 0x002D060A,
672 0x002E064A, 0x002F0E2A,
673 0x0030032A, 0x00310B28,
674 0x00320688, 0x00330008,
675 0x003406C4, 0x00351864,
676 0x003601A8, 0x00370388,
677 0x0038078A, 0x00390604,
678 0x003A0644, 0x003B0E24,
679 0x003C004A, 0x003D18A4,
680 0x003E1B24, 0x003F00EA,
681 0x00400F0A, 0x00410249,
682 0x00420D5D, 0x00431CC4,
683 0x00440328, 0x00450B29,
684 0x004606C6, 0x0047076A,
685 0x00480368, 0x004916C5,
686 0x004A0789, 0x004B0605,
687 0x004C0CC8, 0x004D1954,
688 0x004E0645, 0x004F0E25,
689 0x00500325, 0x00510B26,
690 0x005206C9, 0x00530764,
691 0x005408A9, 0x00550009,
692 0x005601A9, 0x00570389,
693 0x00580785, 0x00590609,
694 0x005A0049, 0x005B18A9,
695 0x005C0649, 0x005D0E29,
696 0x005E1B29, 0x005F00E9,
697 0x00600365, 0x006116C6,
698 0x00620786, 0x00630608,
699 0x00640788, 0x00650606,
700 0x00660046, 0x006718A8,
701 0x006858A6, 0x00690145,
702 0x006A01E9, 0x006B178A,
703 0x006C01E8, 0x006D1785,
704 0x006E1E28, 0x006F0C65,
705 0x00700CC5, 0x00711D5C,
706 0x00720648, 0x00730E28,
707 0x00740646, 0x00750E26,
708 0x00761B28, 0x007700E6,
709 0x007801E5, 0x00791786,
710 0x007A1E29, 0x007B0C68,
711 0x007C1E24, 0x007D0C69,
712 0x007E0955, 0x007F03C9,
713 0x008003E9, 0x00810975,
714 0x00820C49, 0x00831E04,
715 0x00840C48, 0x00851E05,
716 0x008617A6, 0x008701C5,
717 0x008800C6, 0x00891B08,
718 0x008A0E06, 0x008B0666,
719 0x008C0E08, 0x008D0668,
720 0x008E1D7C, 0x008F0CE5,
721 0x00900C45, 0x00911E08,
722 0x009217A9, 0x009301C4,
723 0x009417AA, 0x009501C9,
724 0x00960169, 0x0097588A,
725 0x00981888, 0x00990066,
726 0x009A0709, 0x009B07A8,
727 0x009C0704, 0x009D07A6,
728 0x009E16E6, 0x009F0345,
729 0x00A000C9, 0x00A11B05,
730 0x00A20E09, 0x00A30669,
731 0x00A41885, 0x00A50065,
732 0x00A60706, 0x00A707A5,
733 0x00A803A9, 0x00A90189,
734 0x00AA0029, 0x00AB0889,
735 0x00AC0744, 0x00AD06E9,
736 0x00AE0B06, 0x00AF0229,
737 0x00B00E05, 0x00B10665,
738 0x00B21974, 0x00B30CE8,
739 0x00B4070A, 0x00B507A9,
740 0x00B616E9, 0x00B70348,
741 0x00B8074A, 0x00B906E6,
742 0x00BA0B09, 0x00BB0226,
743 0x00BC1CE4, 0x00BD0D7D,
744 0x00BE0269, 0x00BF08C9,
745 0x00C000CA, 0x00C11B04,
746 0x00C21884, 0x00C3006A,
747 0x00C40E04, 0x00C50664,
748 0x00C60708, 0x00C707AA,
749 0x00C803A8, 0x00C90184,
750 0x00CA0749, 0x00CB06E4,
751 0x00CC0020, 0x00CD0888,
752 0x00CE0B08, 0x00CF0224,
753 0x00D00E0A, 0x00D1066A,
754 0x00D20705, 0x00D307A4,
755 0x00D41D78, 0x00D50CE9,
756 0x00D616EA, 0x00D70349,
757 0x00D80745, 0x00D906E8,
758 0x00DA1CE9, 0x00DB0D75,
759 0x00DC0B04, 0x00DD0228,
760 0x00DE0268, 0x00DF08C8,
761 0x00E003A5, 0x00E10185,
762 0x00E20746, 0x00E306EA,
763 0x00E40748, 0x00E506E5,
764 0x00E61CE8, 0x00E70D79,
765 0x00E81D74, 0x00E95CE6,
766 0x00EA02E9, 0x00EB0849,
767 0x00EC02E8, 0x00ED0848,
768 0x00EE0086, 0x00EF0A08,
769 0x00F00021, 0x00F10885,
770 0x00F20B05, 0x00F3022A,
771 0x00F40B0A, 0x00F50225,
772 0x00F60265, 0x00F708C5,
773 0x00F802E5, 0x00F90845,
774 0x00FA0089, 0x00FB0A09,
775 0x00FC008A, 0x00FD0A0A,
776 0x00FE02A9, 0x00FF0062,
777 };
778
779 if (!hbmMask)
780 return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
781
782 /* 1. make mask bitmap's dc */
783 hDCMask = NtGdiCreateCompatableDC(hdcDest);
784 hOldMaskBitmap = (HBITMAP)NtGdiSelectObject(hDCMask, hbmMask);
785
786 /* 2. make masked Background bitmap */
787
788 /* 2.1 make bitmap */
789 hDC1 = NtGdiCreateCompatableDC(hdcDest);
790 hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
791 hOldBitmap2 = (HBITMAP)NtGdiSelectObject(hDC1, hBitmap2);
792
793 /* 2.2 draw dest bitmap and mask */
794 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
795 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop));
796 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE);
797
798 /* 3. make masked Foreground bitmap */
799
800 /* 3.1 make bitmap */
801 hDC2 = NtGdiCreateCompatableDC(hdcDest);
802 hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
803 hOldBitmap3 = (HBITMAP)NtGdiSelectObject(hDC2, hBitmap3);
804
805 /* 3.2 draw src bitmap and mask */
806 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
807 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
808 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND);
809
810 /* 4. combine two bitmap and copy it to hdcDest */
811 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT);
812 NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY);
813
814 /* 5. restore all object */
815 NtGdiSelectObject(hDCMask, hOldMaskBitmap);
816 NtGdiSelectObject(hDC1, hOldBitmap2);
817 NtGdiSelectObject(hDC2, hOldBitmap3);
818
819 /* 6. delete all temp object */
820 NtGdiDeleteObject(hBitmap2);
821 NtGdiDeleteObject(hBitmap3);
822
823 NtGdiDeleteDC(hDC1);
824 NtGdiDeleteDC(hDC2);
825 NtGdiDeleteDC(hDCMask);
826
827 return TRUE;
828 }
829
830 BOOL STDCALL
831 NtGdiPlgBlt(
832 HDC hDCDest,
833 CONST POINT *Point,
834 HDC hDCSrc,
835 INT XSrc,
836 INT YSrc,
837 INT Width,
838 INT Height,
839 HBITMAP hMaskBitmap,
840 INT xMask,
841 INT yMask)
842 {
843 UNIMPLEMENTED;
844 return FALSE;
845 }
846
847 LONG STDCALL
848 NtGdiSetBitmapBits(
849 HBITMAP hBitmap,
850 DWORD Bytes,
851 CONST VOID *Bits)
852 {
853 LONG height, ret;
854 PBITMAPOBJ bmp;
855
856 bmp = BITMAPOBJ_LockBitmap(hBitmap);
857 if (bmp == NULL || Bits == NULL)
858 {
859 return 0;
860 }
861
862 if (Bytes < 0)
863 {
864 DPRINT ("(%ld): Negative number of bytes passed???\n", Bytes );
865 Bytes = -Bytes;
866 }
867
868 /* Only get entire lines */
869 height = Bytes / abs(bmp->SurfObj.lDelta);
870 if (height > bmp->SurfObj.sizlBitmap.cx)
871 {
872 height = bmp->SurfObj.sizlBitmap.cx;
873 }
874 Bytes = height * abs(bmp->SurfObj.lDelta);
875 DPRINT ("(%08x, bytes:%ld, bits:%p) %dx%d %d colors fetched height: %ld\n",
876 hBitmap,
877 Bytes,
878 Bits,
879 bmp->SurfObj.sizlBitmap.cx,
880 bmp->SurfObj.sizlBitmap.cy,
881 1 << BitsPerFormat(bmp->SurfObj.iBitmapFormat),
882 height);
883
884 #if 0
885 /* FIXME: call DDI specific function here if available */
886 if(bmp->DDBitmap)
887 {
888 DPRINT ("Calling device specific BitmapBits\n");
889 if (bmp->DDBitmap->funcs->pBitmapBits)
890 {
891 ret = bmp->DDBitmap->funcs->pBitmapBits(hBitmap, (void *) Bits, Bytes, DDB_SET);
892 }
893 else
894 {
895 DPRINT ("BitmapBits == NULL??\n");
896 ret = 0;
897 }
898 }
899 else
900 #endif
901 {
902 memcpy(bmp->SurfObj.pvBits, Bits, Bytes);
903 ret = Bytes;
904 }
905
906 BITMAPOBJ_UnlockBitmap(hBitmap);
907
908 return ret;
909 }
910
911 BOOL STDCALL
912 NtGdiSetBitmapDimensionEx(
913 HBITMAP hBitmap,
914 INT Width,
915 INT Height,
916 LPSIZE Size)
917 {
918 PBITMAPOBJ bmp;
919
920 bmp = BITMAPOBJ_LockBitmap(hBitmap);
921 if (bmp == NULL)
922 {
923 return FALSE;
924 }
925
926 if (Size)
927 {
928 *Size = bmp->dimension;
929 }
930 bmp->dimension.cx = Width;
931 bmp->dimension.cy = Height;
932
933 BITMAPOBJ_UnlockBitmap (hBitmap);
934
935 return TRUE;
936 }
937
938 COLORREF STDCALL
939 NtGdiSetPixel(
940 HDC hDC,
941 INT X,
942 INT Y,
943 COLORREF Color)
944 {
945 COLORREF cr = NtGdiGetPixel(hDC,X,Y);
946 if(cr != CLR_INVALID && NtGdiSetPixelV(hDC,X,Y,Color))
947 {
948 return(cr);
949 }
950 return ((COLORREF) -1);
951 }
952
953 BOOL STDCALL
954 NtGdiSetPixelV(
955 HDC hDC,
956 INT X,
957 INT Y,
958 COLORREF Color)
959 {
960 HBRUSH NewBrush = NtGdiCreateSolidBrush(Color);
961 HGDIOBJ OldBrush;
962
963 if (NewBrush == NULL)
964 return(FALSE);
965 OldBrush = NtGdiSelectObject(hDC, NewBrush);
966 if (OldBrush == NULL)
967 {
968 NtGdiDeleteObject(NewBrush);
969 return(FALSE);
970 }
971 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
972 NtGdiSelectObject(hDC, OldBrush);
973 NtGdiDeleteObject(NewBrush);
974 return TRUE;
975 }
976
977 BOOL STDCALL
978 NtGdiStretchBlt(
979 HDC hDCDest,
980 INT XOriginDest,
981 INT YOriginDest,
982 INT WidthDest,
983 INT HeightDest,
984 HDC hDCSrc,
985 INT XOriginSrc,
986 INT YOriginSrc,
987 INT WidthSrc,
988 INT HeightSrc,
989 DWORD ROP)
990 {
991 PDC DCDest = NULL;
992 PDC DCSrc = NULL;
993 BITMAPOBJ *BitmapDest, *BitmapSrc;
994 RECTL DestRect;
995 RECTL SourceRect;
996 BOOL Status;
997 XLATEOBJ *XlateObj = NULL;
998 HPALETTE SourcePalette = 0, DestPalette = 0;
999 PGDIBRUSHOBJ BrushObj;
1000 BOOL UsesSource = ((ROP & 0xCC0000) >> 2) != (ROP & 0x330000);
1001 BOOL UsesPattern = ((ROP & 0xF00000) >> 4) != (ROP & 0x0F0000);
1002
1003 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
1004 {
1005 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1006 return FALSE;
1007 }
1008 DCDest = DC_LockDc(hDCDest);
1009 if (NULL == DCDest)
1010 {
1011 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);
1012 SetLastWin32Error(ERROR_INVALID_HANDLE);
1013 return FALSE;
1014 }
1015
1016 if (UsesSource)
1017 {
1018 if (hDCSrc != hDCDest)
1019 {
1020 DCSrc = DC_LockDc(hDCSrc);
1021 if (NULL == DCSrc)
1022 {
1023 DC_UnlockDc(hDCDest);
1024 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);
1025 SetLastWin32Error(ERROR_INVALID_HANDLE);
1026 return FALSE;
1027 }
1028 }
1029 else
1030 {
1031 DCSrc = DCDest;
1032 }
1033 }
1034 else
1035 {
1036 DCSrc = NULL;
1037 }
1038
1039 /* Offset the destination and source by the origin of their DCs. */
1040 XOriginDest += DCDest->w.DCOrgX;
1041 YOriginDest += DCDest->w.DCOrgY;
1042 if (UsesSource)
1043 {
1044 XOriginSrc += DCSrc->w.DCOrgX;
1045 YOriginSrc += DCSrc->w.DCOrgY;
1046 }
1047
1048 DestRect.left = XOriginDest;
1049 DestRect.top = YOriginDest;
1050 DestRect.right = XOriginDest+WidthDest;
1051 DestRect.bottom = YOriginDest+HeightDest;
1052
1053 SourceRect.left = XOriginSrc;
1054 SourceRect.top = YOriginSrc;
1055 SourceRect.right = XOriginSrc+WidthSrc;
1056 SourceRect.bottom = YOriginSrc+HeightSrc;
1057
1058 /* Determine surfaces to be used in the bitblt */
1059 BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
1060 if (UsesSource)
1061 {
1062 if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
1063 BitmapSrc = BitmapDest;
1064 else
1065 BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
1066 }
1067 else
1068 {
1069 BitmapSrc = NULL;
1070 }
1071
1072 if (UsesPattern)
1073 {
1074 BrushObj = BRUSHOBJ_LockBrush(DCDest->w.hBrush);
1075 if (NULL == BrushObj)
1076 {
1077 if (UsesSource && hDCSrc != hDCDest)
1078 {
1079 DC_UnlockDc(hDCSrc);
1080 }
1081 DC_UnlockDc(hDCDest);
1082 SetLastWin32Error(ERROR_INVALID_HANDLE);
1083 return FALSE;
1084 }
1085 }
1086 else
1087 {
1088 BrushObj = NULL;
1089 }
1090
1091 /* Create the XLATEOBJ. */
1092 if (UsesSource)
1093 {
1094 if (DCDest->w.hPalette != 0)
1095 DestPalette = DCDest->w.hPalette;
1096
1097 if (DCSrc->w.hPalette != 0)
1098 SourcePalette = DCSrc->w.hPalette;
1099
1100 /* FIXME: Use the same logic for create XLATEOBJ as in NtGdiBitBlt. */
1101 XlateObj = (XLATEOBJ*)IntEngCreateXlate(0, 0, DestPalette, SourcePalette);
1102 if (NULL == XlateObj)
1103 {
1104 if (UsesSource && hDCSrc != hDCDest)
1105 {
1106 DC_UnlockDc(hDCSrc);
1107 }
1108 DC_UnlockDc(hDCDest);
1109 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
1110 return FALSE;
1111 }
1112 }
1113
1114 /* Perform the bitblt operation */
1115 Status = IntEngStretchBlt(BitmapDest, BitmapSrc, NULL, DCDest->CombinedClip,
1116 XlateObj, &DestRect, &SourceRect, NULL, NULL, NULL, COLORONCOLOR);
1117
1118 if (UsesSource)
1119 EngDeleteXlate(XlateObj);
1120 BITMAPOBJ_UnlockBitmap(DCDest->w.hBitmap);
1121 if (UsesSource && DCSrc->w.hBitmap != DCDest->w.hBitmap)
1122 {
1123 BITMAPOBJ_UnlockBitmap(DCSrc->w.hBitmap);
1124 }
1125 if (UsesPattern)
1126 {
1127 BRUSHOBJ_UnlockBrush(DCDest->w.hBrush);
1128 }
1129 if (UsesSource && hDCSrc != hDCDest)
1130 {
1131 DC_UnlockDc(hDCSrc);
1132 }
1133 DC_UnlockDc(hDCDest);
1134
1135 return Status;
1136 }
1137
1138 /* Internal Functions */
1139
1140 INT FASTCALL
1141 BITMAPOBJ_GetWidthBytes (INT bmWidth, INT bpp)
1142 {
1143 #if 0
1144 switch(bpp)
1145 {
1146 case 1:
1147 return 2 * ((bmWidth+15) >> 4);
1148
1149 case 24:
1150 bmWidth *= 3; /* fall through */
1151 case 8:
1152 return bmWidth + (bmWidth & 1);
1153
1154 case 32:
1155 return bmWidth * 4;
1156
1157 case 16:
1158 case 15:
1159 return bmWidth * 2;
1160
1161 case 4:
1162 return 2 * ((bmWidth+3) >> 2);
1163
1164 default:
1165 DPRINT ("stub");
1166 }
1167
1168 return -1;
1169 #endif
1170
1171 return ((bmWidth * bpp + 15) & ~15) >> 3;
1172 }
1173
1174 HBITMAP FASTCALL
1175 BITMAPOBJ_CopyBitmap(HBITMAP hBitmap)
1176 {
1177 HBITMAP res;
1178 BITMAP bm;
1179
1180 if (IntGdiGetObject(hBitmap, sizeof(BITMAP), &bm) == 0)
1181 {
1182 return 0;
1183 }
1184 bm.bmBits = NULL;
1185 res = NtGdiCreateBitmapIndirect(&bm);
1186 if(res)
1187 {
1188 char *buf;
1189
1190 buf = ExAllocatePoolWithTag (PagedPool, bm.bmWidthBytes * bm.bmHeight, TAG_BITMAP);
1191 NtGdiGetBitmapBits (hBitmap, bm.bmWidthBytes * bm.bmHeight, buf);
1192 NtGdiSetBitmapBits (res, bm.bmWidthBytes * bm.bmHeight, buf);
1193 ExFreePool (buf);
1194 }
1195
1196 return res;
1197 }
1198
1199 INT STDCALL
1200 BITMAP_GetObject(BITMAPOBJ * bmp, INT count, LPVOID buffer)
1201 {
1202 if(bmp->dib)
1203 {
1204 if(count < (INT) sizeof(DIBSECTION))
1205 {
1206 if (count > (INT) sizeof(BITMAP)) count = sizeof(BITMAP);
1207 }
1208 else
1209 {
1210 if (count > (INT) sizeof(DIBSECTION)) count = sizeof(DIBSECTION);
1211 }
1212 memcpy(buffer, bmp->dib, count);
1213 return count;
1214 }
1215 else
1216 {
1217 BITMAP Bitmap;
1218 if (count > (INT) sizeof(BITMAP)) count = sizeof(BITMAP);
1219 Bitmap.bmType = 0;
1220 Bitmap.bmWidth = bmp->SurfObj.sizlBitmap.cx;
1221 Bitmap.bmHeight = bmp->SurfObj.sizlBitmap.cy;
1222 Bitmap.bmWidthBytes = abs(bmp->SurfObj.lDelta);
1223 Bitmap.bmPlanes = 1;
1224 Bitmap.bmBitsPixel = BitsPerFormat(bmp->SurfObj.iBitmapFormat);
1225 Bitmap.bmBits = bmp->SurfObj.pvBits;
1226 memcpy(buffer, &Bitmap, count);
1227 return count;
1228 }
1229 }
1230 /* EOF */