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