[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 DestRect.left = XDest;
233 DestRect.top = YDest;
234 DestRect.right = XDest+Width;
235 DestRect.bottom = YDest+Height;
236 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
237
238 DestRect.left += DCDest->ptlDCOrig.x;
239 DestRect.top += DCDest->ptlDCOrig.y;
240 DestRect.right += DCDest->ptlDCOrig.x;
241 DestRect.bottom += DCDest->ptlDCOrig.y;
242
243 SourcePoint.x = XSrc;
244 SourcePoint.y = YSrc;
245
246 if (UsesSource)
247 {
248 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
249
250 SourcePoint.x += DCSrc->ptlDCOrig.x;
251 SourcePoint.y += DCSrc->ptlDCOrig.y;
252 /* Calculate Source Rect */
253 SourceRect.left = SourcePoint.x;
254 SourceRect.top = SourcePoint.y;
255 SourceRect.right = SourcePoint.x + DestRect.right - DestRect.left;
256 SourceRect.bottom = SourcePoint.y + DestRect.bottom - DestRect.top ;
257 }
258
259 /* Prepare blit */
260 DC_vPrepareDCsForBlit(DCDest, DestRect, DCSrc, SourceRect);
261
262 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
263 DC_vUpdateFillBrush(DCDest);
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 DestRect.left = XOriginDest;
785 DestRect.top = YOriginDest;
786 DestRect.right = XOriginDest+WidthDest;
787 DestRect.bottom = YOriginDest+HeightDest;
788 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
789
790 DestRect.left += DCDest->ptlDCOrig.x;
791 DestRect.top += DCDest->ptlDCOrig.y;
792 DestRect.right += DCDest->ptlDCOrig.x;
793 DestRect.bottom += DCDest->ptlDCOrig.y;
794
795 SourceRect.left = XOriginSrc;
796 SourceRect.top = YOriginSrc;
797 SourceRect.right = XOriginSrc+WidthSrc;
798 SourceRect.bottom = YOriginSrc+HeightSrc;
799
800 if (UsesSource)
801 {
802 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
803
804 SourceRect.left += DCSrc->ptlDCOrig.x;
805 SourceRect.top += DCSrc->ptlDCOrig.y;
806 SourceRect.right += DCSrc->ptlDCOrig.x;
807 SourceRect.bottom += DCSrc->ptlDCOrig.y;
808 }
809
810 BrushOrigin.x = 0;
811 BrushOrigin.y = 0;
812
813 /* Only prepare Source and Dest, hdcMask represents a DIB */
814 DC_vPrepareDCsForBlit(DCDest, DestRect, DCSrc, SourceRect);
815
816 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
817 DC_vUpdateFillBrush(DCDest);
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 POINTL BrushOrigin;
940 BOOL ret;
941
942 ASSERT(pbrush);
943
944 if (pbrush->flAttrs & GDIBRUSH_IS_NULL)
945 {
946 return TRUE;
947 }
948
949 if (Width > 0)
950 {
951 DestRect.left = XLeft;
952 DestRect.right = XLeft + Width;
953 }
954 else
955 {
956 DestRect.left = XLeft + Width + 1;
957 DestRect.right = XLeft + 1;
958 }
959
960 if (Height > 0)
961 {
962 DestRect.top = YLeft;
963 DestRect.bottom = YLeft + Height;
964 }
965 else
966 {
967 DestRect.top = YLeft + Height + 1;
968 DestRect.bottom = YLeft + 1;
969 }
970
971 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
972
973 DestRect.left += pdc->ptlDCOrig.x;
974 DestRect.top += pdc->ptlDCOrig.y;
975 DestRect.right += pdc->ptlDCOrig.x;
976 DestRect.bottom += pdc->ptlDCOrig.y;
977
978 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
979 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
980
981 DC_vPrepareDCsForBlit(pdc, DestRect, NULL, DestRect);
982
983 psurf = pdc->dclevel.pSurface;
984
985 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
986 DC_vUpdateFillBrush(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 &pdc->eboFill.BrushObject,
998 &BrushOrigin,
999 ROP3_TO_ROP4(dwRop));
1000
1001 DC_vFinishBlit(pdc, NULL);
1002
1003 return ret;
1004 }
1005
1006 BOOL FASTCALL
1007 IntGdiPolyPatBlt(
1008 HDC hDC,
1009 DWORD dwRop,
1010 PPATRECT pRects,
1011 INT cRects,
1012 ULONG Reserved)
1013 {
1014 INT i;
1015 PBRUSH pbrush;
1016 PDC pdc;
1017
1018 pdc = DC_LockDc(hDC);
1019 if (!pdc)
1020 {
1021 SetLastWin32Error(ERROR_INVALID_HANDLE);
1022 return FALSE;
1023 }
1024
1025 if (pdc->dctype == DC_TYPE_INFO)
1026 {
1027 DC_UnlockDc(pdc);
1028 /* Yes, Windows really returns TRUE in this case */
1029 return TRUE;
1030 }
1031
1032 for (i = 0; i < cRects; i++)
1033 {
1034 pbrush = BRUSH_LockBrush(pRects->hBrush);
1035 if(pbrush != NULL)
1036 {
1037 IntPatBlt(
1038 pdc,
1039 pRects->r.left,
1040 pRects->r.top,
1041 pRects->r.right,
1042 pRects->r.bottom,
1043 dwRop,
1044 pbrush);
1045 BRUSH_UnlockBrush(pbrush);
1046 }
1047 pRects++;
1048 }
1049
1050 DC_UnlockDc(pdc);
1051
1052 return TRUE;
1053 }
1054
1055
1056 BOOL APIENTRY
1057 NtGdiPatBlt(
1058 HDC hDC,
1059 INT XLeft,
1060 INT YLeft,
1061 INT Width,
1062 INT Height,
1063 DWORD ROP)
1064 {
1065 PBRUSH pbrush;
1066 DC *dc;
1067 PDC_ATTR pdcattr;
1068 BOOL ret;
1069
1070 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
1071 if (UsesSource)
1072 {
1073 /* in this case we call on GdiMaskBlt */
1074 return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);
1075 }
1076
1077 dc = DC_LockDc(hDC);
1078 if (dc == NULL)
1079 {
1080 SetLastWin32Error(ERROR_INVALID_HANDLE);
1081 return FALSE;
1082 }
1083 if (dc->dctype == DC_TYPE_INFO)
1084 {
1085 DC_UnlockDc(dc);
1086 /* Yes, Windows really returns TRUE in this case */
1087 return TRUE;
1088 }
1089
1090 pdcattr = dc->pdcattr;
1091
1092 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1093 DC_vUpdateFillBrush(dc);
1094
1095 pbrush = BRUSH_LockBrush(pdcattr->hbrush);
1096 if (pbrush == NULL)
1097 {
1098 SetLastWin32Error(ERROR_INVALID_HANDLE);
1099 DC_UnlockDc(dc);
1100 return FALSE;
1101 }
1102
1103 ret = IntPatBlt(dc, XLeft, YLeft, Width, Height, ROP, pbrush);
1104
1105 BRUSH_UnlockBrush(pbrush);
1106 DC_UnlockDc(dc);
1107
1108 return ret;
1109 }
1110
1111 BOOL APIENTRY
1112 NtGdiPolyPatBlt(
1113 HDC hDC,
1114 DWORD dwRop,
1115 IN PPOLYPATBLT pRects,
1116 IN DWORD cRects,
1117 IN DWORD Mode)
1118 {
1119 PPATRECT rb = NULL;
1120 NTSTATUS Status = STATUS_SUCCESS;
1121 BOOL Ret;
1122
1123 if (cRects > 0)
1124 {
1125 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
1126 if (!rb)
1127 {
1128 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1129 return FALSE;
1130 }
1131 _SEH2_TRY
1132 {
1133 ProbeForRead(pRects,
1134 cRects * sizeof(PATRECT),
1135 1);
1136 RtlCopyMemory(rb,
1137 pRects,
1138 cRects * sizeof(PATRECT));
1139 }
1140 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1141 {
1142 Status = _SEH2_GetExceptionCode();
1143 }
1144 _SEH2_END;
1145
1146 if (!NT_SUCCESS(Status))
1147 {
1148 ExFreePoolWithTag(rb, TAG_PATBLT);
1149 SetLastNtError(Status);
1150 return FALSE;
1151 }
1152 }
1153
1154 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1155
1156 if (cRects > 0)
1157 ExFreePoolWithTag(rb, TAG_PATBLT);
1158
1159 return Ret;
1160 }