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