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