1d8de81e35cca80f589d893c3596a6231c0c6e0b
[reactos.git] / subsystems / win32 / win32k / objects / bitblt.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 /* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */
20
21 #include <w32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26
27
28 BOOL APIENTRY
29 NtGdiAlphaBlend(
30 HDC hDCDest,
31 LONG XOriginDest,
32 LONG YOriginDest,
33 LONG WidthDest,
34 LONG HeightDest,
35 HDC hDCSrc,
36 LONG XOriginSrc,
37 LONG YOriginSrc,
38 LONG WidthSrc,
39 LONG HeightSrc,
40 BLENDFUNCTION BlendFunc,
41 HANDLE hcmXform)
42 {
43 PDC DCDest;
44 PDC DCSrc;
45 HDC ahDC[2];
46 PGDIOBJ apObj[2];
47 SURFACE *BitmapDest, *BitmapSrc;
48 RECTL DestRect, SourceRect;
49 BOOL bResult;
50 EXLATEOBJ exlo;
51 BLENDOBJ BlendObj;
52 BlendObj.BlendFunction = BlendFunc;
53
54 if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0)
55 {
56 SetLastWin32Error(ERROR_INVALID_PARAMETER);
57 return FALSE;
58 }
59
60 DPRINT("Locking DCs\n");
61 ahDC[0] = hDCDest;
62 ahDC[1] = hDCSrc ;
63 GDIOBJ_LockMultipleObjs(2, ahDC, apObj);
64 DCDest = apObj[0];
65 DCSrc = apObj[1];
66
67 if ((NULL == DCDest) || (NULL == DCSrc))
68 {
69 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hDCDest, hDCSrc);
70 SetLastWin32Error(ERROR_INVALID_HANDLE);
71 if(DCSrc) GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
72 if(DCDest) GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
73 return FALSE;
74 }
75
76 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
77 {
78 GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
79 GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
80 /* Yes, Windows really returns TRUE in this case */
81 return TRUE;
82 }
83
84 DestRect.left = XOriginDest;
85 DestRect.top = YOriginDest;
86 DestRect.right = XOriginDest + WidthDest;
87 DestRect.bottom = YOriginDest + HeightDest;
88 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
89
90 DestRect.left += DCDest->ptlDCOrig.x;
91 DestRect.top += DCDest->ptlDCOrig.y;
92 DestRect.right += DCDest->ptlDCOrig.x;
93 DestRect.bottom += DCDest->ptlDCOrig.y;
94
95 SourceRect.left = XOriginSrc;
96 SourceRect.top = YOriginSrc;
97 SourceRect.right = XOriginSrc + WidthSrc;
98 SourceRect.bottom = YOriginSrc + HeightSrc;
99 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
100
101 SourceRect.left += DCSrc->ptlDCOrig.x;
102 SourceRect.top += DCSrc->ptlDCOrig.y;
103 SourceRect.right += DCSrc->ptlDCOrig.x;
104 SourceRect.bottom += DCSrc->ptlDCOrig.y;
105
106 if (!DestRect.right ||
107 !DestRect.bottom ||
108 !SourceRect.right ||
109 !SourceRect.bottom)
110 {
111 GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
112 GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
113 return TRUE;
114 }
115
116 /* Prepare DCs for blit */
117 DPRINT("Preparing DCs for blit\n");
118 DC_vPrepareDCsForBlit(DCDest, DestRect, DCSrc, SourceRect);
119
120 /* Determine surfaces to be used in the bitblt */
121 BitmapDest = DCDest->dclevel.pSurface;
122 if (!BitmapDest)
123 {
124 bResult = FALSE ;
125 goto leave ;
126 }
127
128 BitmapSrc = DCSrc->dclevel.pSurface;
129 if (!BitmapSrc)
130 {
131 bResult = FALSE;
132 goto leave;
133 }
134
135 /* Create the XLATEOBJ. */
136 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
137
138 /* Perform the alpha blend operation */
139 DPRINT("Performing the alpha Blend\n");
140 bResult = IntEngAlphaBlend(&BitmapDest->SurfObj,
141 &BitmapSrc->SurfObj,
142 DCDest->rosdc.CombinedClip,
143 &exlo.xlo,
144 &DestRect,
145 &SourceRect,
146 &BlendObj);
147
148 EXLATEOBJ_vCleanup(&exlo);
149 leave :
150 DPRINT("Finishing blit\n");
151 DC_vFinishBlit(DCDest, DCSrc);
152 GDIOBJ_UnlockObjByPtr(&DCSrc->BaseObject);
153 GDIOBJ_UnlockObjByPtr(&DCDest->BaseObject);
154
155 return bResult;
156 }
157
158 BOOL APIENTRY
159 NtGdiBitBlt(
160 HDC hDCDest,
161 INT XDest,
162 INT YDest,
163 INT Width,
164 INT Height,
165 HDC hDCSrc,
166 INT XSrc,
167 INT YSrc,
168 DWORD ROP,
169 IN DWORD crBackColor,
170 IN FLONG fl)
171 {
172 PDC DCDest;
173 PDC DCSrc = NULL;
174 PDC_ATTR pdcattr = NULL;
175 SURFACE *BitmapDest, *BitmapSrc = NULL;
176 RECTL DestRect;
177 POINTL SourcePoint;
178 BOOL Status = FALSE;
179 EXLATEOBJ exlo;
180 XLATEOBJ *XlateObj = NULL;
181 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
182
183 DCDest = DC_LockDc(hDCDest);
184 if (NULL == DCDest)
185 {
186 DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
187 return FALSE;
188 }
189
190 if (DCDest->dctype == DC_TYPE_INFO)
191 {
192 DC_UnlockDc(DCDest);
193 /* Yes, Windows really returns TRUE in this case */
194 return TRUE;
195 }
196
197 if (UsesSource)
198 {
199 if (hDCSrc != hDCDest)
200 {
201 DCSrc = DC_LockDc(hDCSrc);
202 if (NULL == DCSrc)
203 {
204 DC_UnlockDc(DCDest);
205 DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
206 return FALSE;
207 }
208 if (DCSrc->dctype == DC_TYPE_INFO)
209 {
210 DC_UnlockDc(DCSrc);
211 DC_UnlockDc(DCDest);
212 /* Yes, Windows really returns TRUE in this case */
213 return TRUE;
214 }
215 }
216 else
217 {
218 DCSrc = DCDest;
219 }
220 }
221
222 pdcattr = DCDest->pdcattr;
223
224 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
225 DC_vUpdateFillBrush(DCDest);
226
227 DestRect.left = XDest;
228 DestRect.top = YDest;
229 DestRect.right = XDest+Width;
230 DestRect.bottom = YDest+Height;
231 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
232
233 DestRect.left += DCDest->ptlDCOrig.x;
234 DestRect.top += DCDest->ptlDCOrig.y;
235 DestRect.right += DCDest->ptlDCOrig.x;
236 DestRect.bottom += DCDest->ptlDCOrig.y;
237
238 SourcePoint.x = XSrc;
239 SourcePoint.y = YSrc;
240
241 if (UsesSource)
242 {
243 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
244
245 SourcePoint.x += DCSrc->ptlDCOrig.x;
246 SourcePoint.y += DCSrc->ptlDCOrig.y;
247 }
248
249 /* Determine surfaces to be used in the bitblt */
250 BitmapDest = DCDest->dclevel.pSurface;
251 if (!BitmapDest)
252 goto cleanup;
253
254 if (UsesSource)
255 {
256 {
257 BitmapSrc = DCSrc->dclevel.pSurface;
258 if (!BitmapSrc)
259 goto cleanup;
260 }
261 }
262
263 /* Create the XLATEOBJ. */
264 if (UsesSource)
265 {
266 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
267 XlateObj = &exlo.xlo;
268 }
269
270 /* Perform the bitblt operation */
271 Status = IntEngBitBlt(&BitmapDest->SurfObj,
272 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
273 NULL,
274 DCDest->rosdc.CombinedClip,
275 XlateObj,
276 &DestRect,
277 &SourcePoint,
278 NULL,
279 &DCDest->eboFill.BrushObject,
280 &DCDest->dclevel.pbrFill->ptOrigin,
281 ROP3_TO_ROP4(ROP));
282
283 cleanup:
284 if (UsesSource)
285 EXLATEOBJ_vCleanup(&exlo);
286 if (UsesSource && hDCSrc != hDCDest)
287 {
288 DC_UnlockDc(DCSrc);
289 }
290 DC_UnlockDc(DCDest);
291
292 return Status;
293 }
294
295 BOOL APIENTRY
296 NtGdiTransparentBlt(
297 HDC hdcDst,
298 INT xDst,
299 INT yDst,
300 INT cxDst,
301 INT cyDst,
302 HDC hdcSrc,
303 INT xSrc,
304 INT ySrc,
305 INT cxSrc,
306 INT cySrc,
307 COLORREF TransColor)
308 {
309 PDC DCDest, DCSrc;
310 RECTL rcDest, rcSrc;
311 SURFACE *BitmapDest, *BitmapSrc = NULL;
312 HPALETTE SourcePalette = 0, DestPalette = 0;
313 PPALETTE PalDestGDI, PalSourceGDI;
314 USHORT PalDestMode, PalSrcMode;
315 ULONG TransparentColor = 0;
316 BOOL Ret = FALSE;
317 EXLATEOBJ exlo;
318
319 if(!(DCDest = DC_LockDc(hdcDst)))
320 {
321 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);
322 SetLastWin32Error(ERROR_INVALID_HANDLE);
323 return FALSE;
324 }
325 if (DCDest->dctype == DC_TYPE_INFO)
326 {
327 DC_UnlockDc(DCDest);
328 /* Yes, Windows really returns TRUE in this case */
329 return TRUE;
330 }
331
332 if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))
333 {
334 DC_UnlockDc(DCDest);
335 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);
336 SetLastWin32Error(ERROR_INVALID_HANDLE);
337 return FALSE;
338 }
339
340 if(hdcDst == hdcSrc)
341 {
342 DCSrc = DCDest;
343 }
344
345 if (DCSrc->dctype == DC_TYPE_INFO)
346 {
347 DC_UnlockDc(DCSrc);
348 if(hdcDst != hdcSrc)
349 {
350 DC_UnlockDc(DCDest);
351 }
352 /* Yes, Windows really returns TRUE in this case */
353 return TRUE;
354 }
355
356 BitmapDest = DCDest->dclevel.pSurface;
357 if (!BitmapDest)
358 {
359 goto done;
360 }
361
362 BitmapSrc = DCSrc->dclevel.pSurface;
363 if (!BitmapSrc)
364 {
365 goto done;
366 }
367
368 DestPalette = BitmapDest->hDIBPalette;
369 if (!DestPalette) DestPalette = pPrimarySurface->devinfo.hpalDefault;
370
371 SourcePalette = BitmapSrc->hDIBPalette;
372 if (!SourcePalette) SourcePalette = pPrimarySurface->devinfo.hpalDefault;
373
374 if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))
375 {
376 SetLastWin32Error(ERROR_INVALID_HANDLE);
377 goto done;
378 }
379 PalSrcMode = PalSourceGDI->Mode;
380 PALETTE_UnlockPalette(PalSourceGDI);
381
382 if(DestPalette != SourcePalette)
383 {
384 if (!(PalDestGDI = PALETTE_LockPalette(DestPalette)))
385 {
386 SetLastWin32Error(ERROR_INVALID_HANDLE);
387 goto done;
388 }
389 PalDestMode = PalDestGDI->Mode;
390 PALETTE_UnlockPalette(PalDestGDI);
391 }
392 else
393 {
394 PalDestMode = PalSrcMode;
395 PalDestGDI = PalSourceGDI;
396 }
397
398 /* Translate Transparent (RGB) Color to the source palette */
399 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, PalSourceGDI, 0, 0, 0);
400 TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor);
401 EXLATEOBJ_vCleanup(&exlo);
402
403 EXLATEOBJ_vInitialize(&exlo, PalSourceGDI, PalDestGDI, 0, 0, 0);
404
405 rcDest.left = xDst;
406 rcDest.top = yDst;
407 rcDest.right = rcDest.left + cxDst;
408 rcDest.bottom = rcDest.top + cyDst;
409 IntLPtoDP(DCDest, (LPPOINT)&rcDest, 2);
410
411 rcDest.left += DCDest->ptlDCOrig.x;
412 rcDest.top += DCDest->ptlDCOrig.y;
413 rcDest.right += DCDest->ptlDCOrig.x;
414 rcDest.bottom += DCDest->ptlDCOrig.y;
415
416 rcSrc.left = xSrc;
417 rcSrc.top = ySrc;
418 rcSrc.right = rcSrc.left + cxSrc;
419 rcSrc.bottom = rcSrc.top + cySrc;
420 IntLPtoDP(DCSrc, (LPPOINT)&rcSrc, 2);
421
422 rcSrc.left += DCSrc->ptlDCOrig.x;
423 rcSrc.top += DCSrc->ptlDCOrig.y;
424 rcSrc.right += DCSrc->ptlDCOrig.x;
425 rcSrc.bottom += DCSrc->ptlDCOrig.y;
426
427 Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
428 DCDest->rosdc.CombinedClip, &exlo.xlo, &rcDest, &rcSrc,
429 TransparentColor, 0);
430
431 done:
432 DC_UnlockDc(DCSrc);
433 if(hdcDst != hdcSrc)
434 {
435 DC_UnlockDc(DCDest);
436 }
437 EXLATEOBJ_vCleanup(&exlo);
438 return Ret;
439 }
440
441 /***********************************************************************
442 * MaskBlt
443 * Ported from WINE by sedwards 11-4-03
444 *
445 * Someone thought it would be faster to do it here and then switch back
446 * to GDI32. I dunno. Write a test and let me know.
447 * A. It should be in here!
448 */
449
450 static __inline BYTE
451 SwapROP3_SrcDst(BYTE bRop3)
452 {
453 return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);
454 }
455
456 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
457 #define BKGND_ROP3(ROP4) (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])
458 #define DSTCOPY 0x00AA0029
459 #define DSTERASE 0x00220326 /* dest = dest & (~src) : DSna */
460
461 BOOL APIENTRY
462 NtGdiMaskBlt(
463 HDC hdcDest,
464 INT nXDest,
465 INT nYDest,
466 INT nWidth,
467 INT nHeight,
468 HDC hdcSrc,
469 INT nXSrc,
470 INT nYSrc,
471 HBITMAP hbmMask,
472 INT xMask,
473 INT yMask,
474 DWORD dwRop,
475 IN DWORD crBackColor)
476 {
477 HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;
478 HDC hDCMask, hDC1, hDC2;
479 static const DWORD ROP3Table[256] =
480 {
481 0x00000042, 0x00010289,
482 0x00020C89, 0x000300AA,
483 0x00040C88, 0x000500A9,
484 0x00060865, 0x000702C5,
485 0x00080F08, 0x00090245,
486 0x000A0329, 0x000B0B2A,
487 0x000C0324, 0x000D0B25,
488 0x000E08A5, 0x000F0001,
489 0x00100C85, 0x001100A6,
490 0x00120868, 0x001302C8,
491 0x00140869, 0x001502C9,
492 0x00165CCA, 0x00171D54,
493 0x00180D59, 0x00191CC8,
494 0x001A06C5, 0x001B0768,
495 0x001C06CA, 0x001D0766,
496 0x001E01A5, 0x001F0385,
497 0x00200F09, 0x00210248,
498 0x00220326, 0x00230B24,
499 0x00240D55, 0x00251CC5,
500 0x002606C8, 0x00271868,
501 0x00280369, 0x002916CA,
502 0x002A0CC9, 0x002B1D58,
503 0x002C0784, 0x002D060A,
504 0x002E064A, 0x002F0E2A,
505 0x0030032A, 0x00310B28,
506 0x00320688, 0x00330008,
507 0x003406C4, 0x00351864,
508 0x003601A8, 0x00370388,
509 0x0038078A, 0x00390604,
510 0x003A0644, 0x003B0E24,
511 0x003C004A, 0x003D18A4,
512 0x003E1B24, 0x003F00EA,
513 0x00400F0A, 0x00410249,
514 0x00420D5D, 0x00431CC4,
515 0x00440328, 0x00450B29,
516 0x004606C6, 0x0047076A,
517 0x00480368, 0x004916C5,
518 0x004A0789, 0x004B0605,
519 0x004C0CC8, 0x004D1954,
520 0x004E0645, 0x004F0E25,
521 0x00500325, 0x00510B26,
522 0x005206C9, 0x00530764,
523 0x005408A9, 0x00550009,
524 0x005601A9, 0x00570389,
525 0x00580785, 0x00590609,
526 0x005A0049, 0x005B18A9,
527 0x005C0649, 0x005D0E29,
528 0x005E1B29, 0x005F00E9,
529 0x00600365, 0x006116C6,
530 0x00620786, 0x00630608,
531 0x00640788, 0x00650606,
532 0x00660046, 0x006718A8,
533 0x006858A6, 0x00690145,
534 0x006A01E9, 0x006B178A,
535 0x006C01E8, 0x006D1785,
536 0x006E1E28, 0x006F0C65,
537 0x00700CC5, 0x00711D5C,
538 0x00720648, 0x00730E28,
539 0x00740646, 0x00750E26,
540 0x00761B28, 0x007700E6,
541 0x007801E5, 0x00791786,
542 0x007A1E29, 0x007B0C68,
543 0x007C1E24, 0x007D0C69,
544 0x007E0955, 0x007F03C9,
545 0x008003E9, 0x00810975,
546 0x00820C49, 0x00831E04,
547 0x00840C48, 0x00851E05,
548 0x008617A6, 0x008701C5,
549 0x008800C6, 0x00891B08,
550 0x008A0E06, 0x008B0666,
551 0x008C0E08, 0x008D0668,
552 0x008E1D7C, 0x008F0CE5,
553 0x00900C45, 0x00911E08,
554 0x009217A9, 0x009301C4,
555 0x009417AA, 0x009501C9,
556 0x00960169, 0x0097588A,
557 0x00981888, 0x00990066,
558 0x009A0709, 0x009B07A8,
559 0x009C0704, 0x009D07A6,
560 0x009E16E6, 0x009F0345,
561 0x00A000C9, 0x00A11B05,
562 0x00A20E09, 0x00A30669,
563 0x00A41885, 0x00A50065,
564 0x00A60706, 0x00A707A5,
565 0x00A803A9, 0x00A90189,
566 0x00AA0029, 0x00AB0889,
567 0x00AC0744, 0x00AD06E9,
568 0x00AE0B06, 0x00AF0229,
569 0x00B00E05, 0x00B10665,
570 0x00B21974, 0x00B30CE8,
571 0x00B4070A, 0x00B507A9,
572 0x00B616E9, 0x00B70348,
573 0x00B8074A, 0x00B906E6,
574 0x00BA0B09, 0x00BB0226,
575 0x00BC1CE4, 0x00BD0D7D,
576 0x00BE0269, 0x00BF08C9,
577 0x00C000CA, 0x00C11B04,
578 0x00C21884, 0x00C3006A,
579 0x00C40E04, 0x00C50664,
580 0x00C60708, 0x00C707AA,
581 0x00C803A8, 0x00C90184,
582 0x00CA0749, 0x00CB06E4,
583 0x00CC0020, 0x00CD0888,
584 0x00CE0B08, 0x00CF0224,
585 0x00D00E0A, 0x00D1066A,
586 0x00D20705, 0x00D307A4,
587 0x00D41D78, 0x00D50CE9,
588 0x00D616EA, 0x00D70349,
589 0x00D80745, 0x00D906E8,
590 0x00DA1CE9, 0x00DB0D75,
591 0x00DC0B04, 0x00DD0228,
592 0x00DE0268, 0x00DF08C8,
593 0x00E003A5, 0x00E10185,
594 0x00E20746, 0x00E306EA,
595 0x00E40748, 0x00E506E5,
596 0x00E61CE8, 0x00E70D79,
597 0x00E81D74, 0x00E95CE6,
598 0x00EA02E9, 0x00EB0849,
599 0x00EC02E8, 0x00ED0848,
600 0x00EE0086, 0x00EF0A08,
601 0x00F00021, 0x00F10885,
602 0x00F20B05, 0x00F3022A,
603 0x00F40B0A, 0x00F50225,
604 0x00F60265, 0x00F708C5,
605 0x00F802E5, 0x00F90845,
606 0x00FA0089, 0x00FB0A09,
607 0x00FC008A, 0x00FD0A0A,
608 0x00FE02A9, 0x00FF0062,
609 };
610
611 if (!hbmMask)
612 return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0);
613
614 /* 1. make mask bitmap's dc */
615 hDCMask = NtGdiCreateCompatibleDC(hdcDest);
616 hOldMaskBitmap = (HBITMAP)NtGdiSelectBitmap(hDCMask, hbmMask);
617
618 /* 2. make masked Background bitmap */
619
620 /* 2.1 make bitmap */
621 hDC1 = NtGdiCreateCompatibleDC(hdcDest);
622 hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
623 hOldBitmap2 = (HBITMAP)NtGdiSelectBitmap(hDC1, hBitmap2);
624
625 /* 2.2 draw dest bitmap and mask */
626 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);
627 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);
628 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE, 0, 0);
629
630 /* 3. make masked Foreground bitmap */
631
632 /* 3.1 make bitmap */
633 hDC2 = NtGdiCreateCompatibleDC(hdcDest);
634 hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
635 hOldBitmap3 = (HBITMAP)NtGdiSelectBitmap(hDC2, hBitmap3);
636
637 /* 3.2 draw src bitmap and mask */
638 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);
639 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);
640 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND, 0, 0);
641
642 /* 4. combine both and copy the result to hdcDest */
643 NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT, 0, 0);
644 NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY, 0, 0);
645
646 /* 5. restore all objects */
647 NtGdiSelectBitmap(hDCMask, hOldMaskBitmap);
648 NtGdiSelectBitmap(hDC1, hOldBitmap2);
649 NtGdiSelectBitmap(hDC2, hOldBitmap3);
650
651 /* 6. delete all temp objects */
652 GreDeleteObject(hBitmap2);
653 GreDeleteObject(hBitmap3);
654
655 NtGdiDeleteObjectApp(hDC1);
656 NtGdiDeleteObjectApp(hDC2);
657 NtGdiDeleteObjectApp(hDCMask);
658
659 return TRUE;
660 }
661
662 BOOL
663 APIENTRY
664 NtGdiPlgBlt(
665 IN HDC hdcTrg,
666 IN LPPOINT pptlTrg,
667 IN HDC hdcSrc,
668 IN INT xSrc,
669 IN INT ySrc,
670 IN INT cxSrc,
671 IN INT cySrc,
672 IN HBITMAP hbmMask,
673 IN INT xMask,
674 IN INT yMask,
675 IN DWORD crBackColor)
676 {
677 UNIMPLEMENTED;
678 return FALSE;
679 }
680
681 BOOL APIENTRY
682 GreStretchBltMask(
683 HDC hDCDest,
684 INT XOriginDest,
685 INT YOriginDest,
686 INT WidthDest,
687 INT HeightDest,
688 HDC hDCSrc,
689 INT XOriginSrc,
690 INT YOriginSrc,
691 INT WidthSrc,
692 INT HeightSrc,
693 DWORD ROP,
694 IN DWORD dwBackColor,
695 HDC hDCMask,
696 INT XOriginMask,
697 INT YOriginMask)
698 {
699 PDC DCDest;
700 PDC DCSrc = NULL;
701 PDC DCMask = NULL;
702 PDC_ATTR pdcattr;
703 SURFACE *BitmapDest, *BitmapSrc = NULL;
704 SURFACE *BitmapMask = NULL;
705 RECTL DestRect;
706 RECTL SourceRect;
707 POINTL MaskPoint;
708 BOOL Status = FALSE;
709 EXLATEOBJ exlo;
710 XLATEOBJ *XlateObj = NULL;
711 POINTL BrushOrigin;
712 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
713
714 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
715 {
716 SetLastWin32Error(ERROR_INVALID_PARAMETER);
717 return FALSE;
718 }
719
720 DCDest = DC_LockDc(hDCDest);
721 if (NULL == DCDest)
722 {
723 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);
724 SetLastWin32Error(ERROR_INVALID_HANDLE);
725 return FALSE;
726 }
727
728 if (DCDest->dctype == DC_TYPE_INFO)
729 {
730 DC_UnlockDc(DCDest);
731 /* Yes, Windows really returns TRUE in this case */
732 return TRUE;
733 }
734
735 if (UsesSource)
736 {
737 if (hDCSrc != hDCDest)
738 {
739 DCSrc = DC_LockDc(hDCSrc);
740 if (NULL == DCSrc)
741 {
742 DC_UnlockDc(DCDest);
743 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);
744 SetLastWin32Error(ERROR_INVALID_HANDLE);
745 return FALSE;
746 }
747 if (DCSrc->dctype == DC_TYPE_INFO)
748 {
749 DC_UnlockDc(DCSrc);
750 DC_UnlockDc(DCDest);
751 /* Yes, Windows really returns TRUE in this case */
752 return TRUE;
753 }
754 }
755 else
756 {
757 DCSrc = DCDest;
758 }
759 }
760
761 pdcattr = DCDest->pdcattr;
762
763 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
764 DC_vUpdateFillBrush(DCDest);
765
766 DestRect.left = XOriginDest;
767 DestRect.top = YOriginDest;
768 DestRect.right = XOriginDest+WidthDest;
769 DestRect.bottom = YOriginDest+HeightDest;
770 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
771
772 DestRect.left += DCDest->ptlDCOrig.x;
773 DestRect.top += DCDest->ptlDCOrig.y;
774 DestRect.right += DCDest->ptlDCOrig.x;
775 DestRect.bottom += DCDest->ptlDCOrig.y;
776
777 SourceRect.left = XOriginSrc;
778 SourceRect.top = YOriginSrc;
779 SourceRect.right = XOriginSrc+WidthSrc;
780 SourceRect.bottom = YOriginSrc+HeightSrc;
781
782 if (UsesSource)
783 {
784 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
785
786 SourceRect.left += DCSrc->ptlDCOrig.x;
787 SourceRect.top += DCSrc->ptlDCOrig.y;
788 SourceRect.right += DCSrc->ptlDCOrig.x;
789 SourceRect.bottom += DCSrc->ptlDCOrig.y;
790 }
791
792 BrushOrigin.x = 0;
793 BrushOrigin.y = 0;
794
795 /* Determine surfaces to be used in the bitblt */
796 BitmapDest = DCDest->dclevel.pSurface;
797 if (BitmapDest == NULL)
798 goto failed;
799 if (UsesSource)
800 {
801 BitmapSrc = DCSrc->dclevel.pSurface;
802 if (BitmapSrc == NULL)
803 goto failed;
804
805 /* Create the XLATEOBJ. */
806 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
807 XlateObj = &exlo.xlo;
808 }
809
810 /* Offset the brush */
811 BrushOrigin.x += DCDest->ptlDCOrig.x;
812 BrushOrigin.y += DCDest->ptlDCOrig.y;
813
814 /* Make mask surface for source surface */
815 if (BitmapSrc && hDCMask)
816 {
817 DCMask = DC_LockDc(hDCMask);
818 if (DCMask)
819 {
820 BitmapMask = DCMask->dclevel.pSurface;
821 if (BitmapMask &&
822 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
823 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
824 {
825 DPRINT1("%dx%d mask is smaller than %dx%d bitmap\n",
826 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
827 WidthSrc, HeightSrc);
828 goto failed;
829 }
830 /* Create mask offset point */
831 MaskPoint.x = XOriginMask;
832 MaskPoint.y = YOriginMask;
833 IntLPtoDP(DCMask, &MaskPoint, 1);
834 MaskPoint.x += DCMask->ptlDCOrig.x;
835 MaskPoint.y += DCMask->ptlDCOrig.x;
836 }
837 }
838
839 /* Perform the bitblt operation */
840 Status = IntEngStretchBlt(&BitmapDest->SurfObj,
841 &BitmapSrc->SurfObj,
842 BitmapMask ? &BitmapMask->SurfObj : NULL,
843 DCDest->rosdc.CombinedClip,
844 XlateObj,
845 &DestRect,
846 &SourceRect,
847 BitmapMask ? &MaskPoint : NULL,
848 &DCDest->eboFill.BrushObject,
849 &BrushOrigin,
850 ROP3_TO_ROP4(ROP));
851
852 failed:
853 if (UsesSource)
854 {
855 EXLATEOBJ_vCleanup(&exlo);
856 }
857 if (UsesSource && hDCSrc != hDCDest)
858 {
859 DC_UnlockDc(DCSrc);
860 }
861 if (DCMask)
862 {
863 DC_UnlockDc(DCMask);
864 }
865 DC_UnlockDc(DCDest);
866
867 return Status;
868 }
869
870
871 BOOL APIENTRY
872 NtGdiStretchBlt(
873 HDC hDCDest,
874 INT XOriginDest,
875 INT YOriginDest,
876 INT WidthDest,
877 INT HeightDest,
878 HDC hDCSrc,
879 INT XOriginSrc,
880 INT YOriginSrc,
881 INT WidthSrc,
882 INT HeightSrc,
883 DWORD ROP,
884 IN DWORD dwBackColor)
885 {
886 return GreStretchBltMask(
887 hDCDest,
888 XOriginDest,
889 YOriginDest,
890 WidthDest,
891 HeightDest,
892 hDCSrc,
893 XOriginSrc,
894 YOriginSrc,
895 WidthSrc,
896 HeightSrc,
897 ROP,
898 dwBackColor,
899 NULL,
900 0,
901 0);
902 }
903
904
905 BOOL FASTCALL
906 IntPatBlt(
907 PDC pdc,
908 INT XLeft,
909 INT YLeft,
910 INT Width,
911 INT Height,
912 DWORD dwRop,
913 PBRUSH pbrush)
914 {
915 RECTL DestRect;
916 SURFACE *psurf;
917 EBRUSHOBJ eboFill;
918 POINTL BrushOrigin;
919 BOOL ret;
920
921 ASSERT(pbrush);
922
923 psurf = pdc->dclevel.pSurface;
924 if (psurf == NULL)
925 {
926 SetLastWin32Error(ERROR_INVALID_HANDLE);
927 return FALSE;
928 }
929
930 if (pbrush->flAttrs & GDIBRUSH_IS_NULL)
931 {
932 return TRUE;
933 }
934
935 if (Width > 0)
936 {
937 DestRect.left = XLeft;
938 DestRect.right = XLeft + Width;
939 }
940 else
941 {
942 DestRect.left = XLeft + Width + 1;
943 DestRect.right = XLeft + 1;
944 }
945
946 if (Height > 0)
947 {
948 DestRect.top = YLeft;
949 DestRect.bottom = YLeft + Height;
950 }
951 else
952 {
953 DestRect.top = YLeft + Height + 1;
954 DestRect.bottom = YLeft + 1;
955 }
956
957 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
958
959 DestRect.left += pdc->ptlDCOrig.x;
960 DestRect.top += pdc->ptlDCOrig.y;
961 DestRect.right += pdc->ptlDCOrig.x;
962 DestRect.bottom += pdc->ptlDCOrig.y;
963
964 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
965 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
966
967 EBRUSHOBJ_vInit(&eboFill, pbrush, pdc);
968
969 ret = IntEngBitBlt(
970 &psurf->SurfObj,
971 NULL,
972 NULL,
973 pdc->rosdc.CombinedClip,
974 NULL,
975 &DestRect,
976 NULL,
977 NULL,
978 &eboFill.BrushObject, // use pDC->eboFill
979 &BrushOrigin,
980 ROP3_TO_ROP4(dwRop));
981
982 EBRUSHOBJ_vCleanup(&eboFill);
983
984 return ret;
985 }
986
987 BOOL FASTCALL
988 IntGdiPolyPatBlt(
989 HDC hDC,
990 DWORD dwRop,
991 PPATRECT pRects,
992 INT cRects,
993 ULONG Reserved)
994 {
995 INT i;
996 PBRUSH pbrush;
997 PDC pdc;
998
999 pdc = DC_LockDc(hDC);
1000 if (!pdc)
1001 {
1002 SetLastWin32Error(ERROR_INVALID_HANDLE);
1003 return FALSE;
1004 }
1005
1006 if (pdc->dctype == DC_TYPE_INFO)
1007 {
1008 DC_UnlockDc(pdc);
1009 /* Yes, Windows really returns TRUE in this case */
1010 return TRUE;
1011 }
1012
1013 for (i = 0; i < cRects; i++)
1014 {
1015 pbrush = BRUSH_LockBrush(pRects->hBrush);
1016 if(pbrush != NULL)
1017 {
1018 IntPatBlt(
1019 pdc,
1020 pRects->r.left,
1021 pRects->r.top,
1022 pRects->r.right,
1023 pRects->r.bottom,
1024 dwRop,
1025 pbrush);
1026 BRUSH_UnlockBrush(pbrush);
1027 }
1028 pRects++;
1029 }
1030
1031 DC_UnlockDc(pdc);
1032
1033 return TRUE;
1034 }
1035
1036
1037 BOOL APIENTRY
1038 NtGdiPatBlt(
1039 HDC hDC,
1040 INT XLeft,
1041 INT YLeft,
1042 INT Width,
1043 INT Height,
1044 DWORD ROP)
1045 {
1046 PBRUSH pbrush;
1047 DC *dc;
1048 PDC_ATTR pdcattr;
1049 BOOL ret;
1050
1051 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
1052 if (UsesSource)
1053 {
1054 /* in this case we call on GdiMaskBlt */
1055 return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);
1056 }
1057
1058 dc = DC_LockDc(hDC);
1059 if (dc == NULL)
1060 {
1061 SetLastWin32Error(ERROR_INVALID_HANDLE);
1062 return FALSE;
1063 }
1064 if (dc->dctype == DC_TYPE_INFO)
1065 {
1066 DC_UnlockDc(dc);
1067 /* Yes, Windows really returns TRUE in this case */
1068 return TRUE;
1069 }
1070
1071 pdcattr = dc->pdcattr;
1072
1073 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1074 DC_vUpdateFillBrush(dc);
1075
1076 pbrush = BRUSH_LockBrush(pdcattr->hbrush);
1077 if (pbrush == NULL)
1078 {
1079 SetLastWin32Error(ERROR_INVALID_HANDLE);
1080 DC_UnlockDc(dc);
1081 return FALSE;
1082 }
1083
1084 ret = IntPatBlt(dc, XLeft, YLeft, Width, Height, ROP, pbrush);
1085
1086 BRUSH_UnlockBrush(pbrush);
1087 DC_UnlockDc(dc);
1088
1089 return ret;
1090 }
1091
1092 BOOL APIENTRY
1093 NtGdiPolyPatBlt(
1094 HDC hDC,
1095 DWORD dwRop,
1096 IN PPOLYPATBLT pRects,
1097 IN DWORD cRects,
1098 IN DWORD Mode)
1099 {
1100 PPATRECT rb = NULL;
1101 NTSTATUS Status = STATUS_SUCCESS;
1102 BOOL Ret;
1103
1104 if (cRects > 0)
1105 {
1106 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
1107 if (!rb)
1108 {
1109 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1110 return FALSE;
1111 }
1112 _SEH2_TRY
1113 {
1114 ProbeForRead(pRects,
1115 cRects * sizeof(PATRECT),
1116 1);
1117 RtlCopyMemory(rb,
1118 pRects,
1119 cRects * sizeof(PATRECT));
1120 }
1121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1122 {
1123 Status = _SEH2_GetExceptionCode();
1124 }
1125 _SEH2_END;
1126
1127 if (!NT_SUCCESS(Status))
1128 {
1129 ExFreePoolWithTag(rb, TAG_PATBLT);
1130 SetLastNtError(Status);
1131 return FALSE;
1132 }
1133 }
1134
1135 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1136
1137 if (cRects > 0)
1138 ExFreePoolWithTag(rb, TAG_PATBLT);
1139
1140 return Ret;
1141 }