[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / bitblt.c
1 /*
2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bit blit functions
5 * FILE: subsys/win32k/objects/bitblt.c
6 * PROGRAMER: Unknown
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(GdiBlt);
11
12 #define ROP_USES_SOURCE(Rop) (((((Rop) & 0xCC0000) >> 2) != ((Rop) & 0x330000)) || ((((Rop) & 0xCC000000) >> 2) != ((Rop) & 0x33000000)))
13 #define ROP_USES_MASK(Rop) (((Rop) & 0xFF000000) != (((Rop) & 0xff0000) << 8))
14
15 #define FIXUP_ROP(Rop) if(((Rop) & 0xFF000000) == 0) Rop = MAKEROP4((Rop), (Rop))
16 #define ROP_TO_ROP4(Rop) ((Rop) >> 16)
17
18 BOOL APIENTRY
19 NtGdiAlphaBlend(
20 HDC hDCDest,
21 LONG XOriginDest,
22 LONG YOriginDest,
23 LONG WidthDest,
24 LONG HeightDest,
25 HDC hDCSrc,
26 LONG XOriginSrc,
27 LONG YOriginSrc,
28 LONG WidthSrc,
29 LONG HeightSrc,
30 BLENDFUNCTION BlendFunc,
31 HANDLE hcmXform)
32 {
33 PDC DCDest;
34 PDC DCSrc;
35 HDC ahDC[2];
36 PGDIOBJ apObj[2];
37 SURFACE *BitmapDest, *BitmapSrc;
38 RECTL DestRect, SourceRect;
39 BOOL bResult;
40 EXLATEOBJ exlo;
41 BLENDOBJ BlendObj;
42 BlendObj.BlendFunction = BlendFunc;
43
44 if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0)
45 {
46 EngSetLastError(ERROR_INVALID_PARAMETER);
47 return FALSE;
48 }
49
50 if ((hDCDest == NULL) || (hDCSrc == NULL))
51 {
52 EngSetLastError(ERROR_INVALID_PARAMETER);
53 return FALSE;
54 }
55
56 TRACE("Locking DCs\n");
57 ahDC[0] = hDCDest;
58 ahDC[1] = hDCSrc ;
59 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
60 {
61 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hDCDest, hDCSrc);
62 EngSetLastError(ERROR_INVALID_HANDLE);
63 return FALSE;
64 }
65 DCDest = apObj[0];
66 DCSrc = apObj[1];
67
68 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
69 {
70 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
71 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
72 /* Yes, Windows really returns TRUE in this case */
73 return TRUE;
74 }
75
76 DestRect.left = XOriginDest;
77 DestRect.top = YOriginDest;
78 DestRect.right = XOriginDest + WidthDest;
79 DestRect.bottom = YOriginDest + HeightDest;
80 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
81
82 DestRect.left += DCDest->ptlDCOrig.x;
83 DestRect.top += DCDest->ptlDCOrig.y;
84 DestRect.right += DCDest->ptlDCOrig.x;
85 DestRect.bottom += DCDest->ptlDCOrig.y;
86
87 SourceRect.left = XOriginSrc;
88 SourceRect.top = YOriginSrc;
89 SourceRect.right = XOriginSrc + WidthSrc;
90 SourceRect.bottom = YOriginSrc + HeightSrc;
91 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
92
93 SourceRect.left += DCSrc->ptlDCOrig.x;
94 SourceRect.top += DCSrc->ptlDCOrig.y;
95 SourceRect.right += DCSrc->ptlDCOrig.x;
96 SourceRect.bottom += DCSrc->ptlDCOrig.y;
97
98 if (!DestRect.right ||
99 !DestRect.bottom ||
100 !SourceRect.right ||
101 !SourceRect.bottom)
102 {
103 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
104 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
105 return TRUE;
106 }
107
108 /* Prepare DCs for blit */
109 TRACE("Preparing DCs for blit\n");
110 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
111
112 /* Determine surfaces to be used in the bitblt */
113 BitmapDest = DCDest->dclevel.pSurface;
114 if (!BitmapDest)
115 {
116 bResult = FALSE ;
117 goto leave ;
118 }
119
120 BitmapSrc = DCSrc->dclevel.pSurface;
121 if (!BitmapSrc)
122 {
123 bResult = FALSE;
124 goto leave;
125 }
126
127 /* Create the XLATEOBJ. */
128 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
129
130 /* Perform the alpha blend operation */
131 TRACE("Performing the alpha blend\n");
132 bResult = IntEngAlphaBlend(&BitmapDest->SurfObj,
133 &BitmapSrc->SurfObj,
134 DCDest->rosdc.CombinedClip,
135 &exlo.xlo,
136 &DestRect,
137 &SourceRect,
138 &BlendObj);
139
140 EXLATEOBJ_vCleanup(&exlo);
141 leave :
142 TRACE("Finishing blit\n");
143 DC_vFinishBlit(DCDest, DCSrc);
144 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
145 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
146
147 return bResult;
148 }
149
150 BOOL APIENTRY
151 NtGdiBitBlt(
152 HDC hDCDest,
153 INT XDest,
154 INT YDest,
155 INT Width,
156 INT Height,
157 HDC hDCSrc,
158 INT XSrc,
159 INT YSrc,
160 DWORD ROP,
161 IN DWORD crBackColor,
162 IN FLONG fl)
163 {
164 DWORD dwTRop;
165
166 if (ROP & CAPTUREBLT)
167 return NtGdiStretchBlt(hDCDest,
168 XDest,
169 YDest,
170 Width,
171 Height,
172 hDCSrc,
173 XSrc,
174 YSrc,
175 Width,
176 Height,
177 ROP,
178 crBackColor);
179
180 dwTRop = ROP & ~(NOMIRRORBITMAP|CAPTUREBLT);
181
182 /* Forward to NtGdiMaskBlt */
183 // TODO: What's fl for? LOL not to send this to MaskBit!
184 return NtGdiMaskBlt(hDCDest,
185 XDest,
186 YDest,
187 Width,
188 Height,
189 hDCSrc,
190 XSrc,
191 YSrc,
192 NULL,
193 0,
194 0,
195 dwTRop,
196 crBackColor);
197 }
198
199 BOOL APIENTRY
200 NtGdiTransparentBlt(
201 HDC hdcDst,
202 INT xDst,
203 INT yDst,
204 INT cxDst,
205 INT cyDst,
206 HDC hdcSrc,
207 INT xSrc,
208 INT ySrc,
209 INT cxSrc,
210 INT cySrc,
211 COLORREF TransColor)
212 {
213 PDC DCDest, DCSrc;
214 HDC ahDC[2];
215 PGDIOBJ apObj[2];
216 RECTL rcDest, rcSrc;
217 SURFACE *BitmapDest, *BitmapSrc = NULL;
218 ULONG TransparentColor = 0;
219 BOOL Ret = FALSE;
220 EXLATEOBJ exlo;
221
222 if ((hdcDst == NULL) || (hdcSrc == NULL))
223 {
224 EngSetLastError(ERROR_INVALID_PARAMETER);
225 return FALSE;
226 }
227
228 TRACE("Locking DCs\n");
229 ahDC[0] = hdcDst;
230 ahDC[1] = hdcSrc ;
231 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
232 {
233 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hdcDst, hdcSrc);
234 EngSetLastError(ERROR_INVALID_HANDLE);
235 return FALSE;
236 }
237 DCDest = apObj[0];
238 DCSrc = apObj[1];
239
240 if (DCDest->dctype == DC_TYPE_INFO || DCDest->dctype == DCTYPE_INFO)
241 {
242 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
243 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
244 /* Yes, Windows really returns TRUE in this case */
245 return TRUE;
246 }
247
248 rcDest.left = xDst;
249 rcDest.top = yDst;
250 rcDest.right = rcDest.left + cxDst;
251 rcDest.bottom = rcDest.top + cyDst;
252 IntLPtoDP(DCDest, (LPPOINT)&rcDest, 2);
253
254 rcDest.left += DCDest->ptlDCOrig.x;
255 rcDest.top += DCDest->ptlDCOrig.y;
256 rcDest.right += DCDest->ptlDCOrig.x;
257 rcDest.bottom += DCDest->ptlDCOrig.y;
258
259 rcSrc.left = xSrc;
260 rcSrc.top = ySrc;
261 rcSrc.right = rcSrc.left + cxSrc;
262 rcSrc.bottom = rcSrc.top + cySrc;
263 IntLPtoDP(DCSrc, (LPPOINT)&rcSrc, 2);
264
265 rcSrc.left += DCSrc->ptlDCOrig.x;
266 rcSrc.top += DCSrc->ptlDCOrig.y;
267 rcSrc.right += DCSrc->ptlDCOrig.x;
268 rcSrc.bottom += DCSrc->ptlDCOrig.y;
269
270 /* Prepare for blit */
271 DC_vPrepareDCsForBlit(DCDest, &rcDest, DCSrc, &rcSrc);
272
273 BitmapDest = DCDest->dclevel.pSurface;
274 if (!BitmapDest)
275 {
276 goto done;
277 }
278
279 BitmapSrc = DCSrc->dclevel.pSurface;
280 if (!BitmapSrc)
281 {
282 goto done;
283 }
284
285 /* Translate Transparent (RGB) Color to the source palette */
286 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, BitmapSrc->ppal, 0, 0, 0);
287 TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor);
288 EXLATEOBJ_vCleanup(&exlo);
289
290 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
291
292 Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
293 DCDest->rosdc.CombinedClip, &exlo.xlo, &rcDest, &rcSrc,
294 TransparentColor, 0);
295
296 EXLATEOBJ_vCleanup(&exlo);
297
298 done:
299 DC_vFinishBlit(DCDest, DCSrc);
300 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
301 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
302
303 return Ret;
304 }
305
306 BOOL APIENTRY
307 NtGdiMaskBlt(
308 HDC hdcDest,
309 INT nXDest,
310 INT nYDest,
311 INT nWidth,
312 INT nHeight,
313 HDC hdcSrc,
314 INT nXSrc,
315 INT nYSrc,
316 HBITMAP hbmMask,
317 INT xMask,
318 INT yMask,
319 DWORD dwRop,
320 IN DWORD crBackColor)
321 {
322 PDC DCDest;
323 PDC DCSrc = NULL;
324 HDC ahDC[2];
325 PGDIOBJ apObj[2];
326 PDC_ATTR pdcattr = NULL;
327 SURFACE *BitmapDest, *BitmapSrc = NULL, *psurfMask = NULL;
328 RECTL DestRect, SourceRect;
329 POINTL SourcePoint, MaskPoint;
330 BOOL Status = FALSE;
331 EXLATEOBJ exlo;
332 XLATEOBJ *XlateObj = NULL;
333 BOOL UsesSource = ROP_USES_SOURCE(dwRop);
334 BOOL UsesMask;
335
336 FIXUP_ROP(dwRop);
337
338 UsesMask = ROP_USES_MASK(dwRop);
339
340 //DPRINT1("dwRop : 0x%08x\n", dwRop);
341 if (!hdcDest || (UsesSource && !hdcSrc))
342 {
343 EngSetLastError(ERROR_INVALID_PARAMETER);
344 return FALSE;
345 }
346
347 /* Take care of mask bitmap */
348 if(hbmMask)
349 {
350 psurfMask = SURFACE_ShareLockSurface(hbmMask);
351 if(!psurfMask)
352 {
353 EngSetLastError(ERROR_INVALID_HANDLE);
354 return FALSE;
355 }
356 }
357
358 if(UsesMask)
359 {
360 if(!psurfMask)
361 {
362 EngSetLastError(ERROR_INVALID_PARAMETER);
363 return FALSE;
364 }
365 if(gajBitsPerFormat[psurfMask->SurfObj.iBitmapFormat] != 1)
366 {
367 EngSetLastError(ERROR_INVALID_PARAMETER);
368 SURFACE_ShareUnlockSurface(psurfMask);
369 return FALSE;
370 }
371 }
372 else if(psurfMask)
373 {
374 WARN("Getting Mask bitmap without needing it?\n");
375 SURFACE_ShareUnlockSurface(psurfMask);
376 psurfMask = NULL;
377 }
378 MaskPoint.x = xMask;
379 MaskPoint.y = yMask;
380
381 /* Take care of source and destination bitmap */
382 TRACE("Locking DCs\n");
383 ahDC[0] = hdcDest;
384 ahDC[1] = UsesSource ? hdcSrc : NULL;
385 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
386 {
387 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hdcDest, hdcSrc);
388 EngSetLastError(ERROR_INVALID_HANDLE);
389 return FALSE;
390 }
391 DCDest = apObj[0];
392 DCSrc = apObj[1];
393
394 ASSERT(DCDest);
395 if (NULL == DCDest)
396 {
397 if(DCSrc) DC_UnlockDc(DCSrc);
398 WARN("Invalid destination dc handle (0x%p) passed to NtGdiBitBlt\n", hdcDest);
399 return FALSE;
400 }
401
402 if (DCDest->dctype == DC_TYPE_INFO)
403 {
404 if(DCSrc) DC_UnlockDc(DCSrc);
405 DC_UnlockDc(DCDest);
406 /* Yes, Windows really returns TRUE in this case */
407 return TRUE;
408 }
409
410 if (UsesSource)
411 {
412 ASSERT(DCSrc);
413 if (DCSrc->dctype == DC_TYPE_INFO)
414 {
415 DC_UnlockDc(DCDest);
416 DC_UnlockDc(DCSrc);
417 /* Yes, Windows really returns TRUE in this case */
418 return TRUE;
419 }
420 }
421
422 pdcattr = DCDest->pdcattr;
423
424 DestRect.left = nXDest;
425 DestRect.top = nYDest;
426 DestRect.right = nXDest + nWidth;
427 DestRect.bottom = nYDest + nHeight;
428 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
429
430 DestRect.left += DCDest->ptlDCOrig.x;
431 DestRect.top += DCDest->ptlDCOrig.y;
432 DestRect.right += DCDest->ptlDCOrig.x;
433 DestRect.bottom += DCDest->ptlDCOrig.y;
434
435 SourcePoint.x = nXSrc;
436 SourcePoint.y = nYSrc;
437
438 if (UsesSource)
439 {
440 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
441
442 SourcePoint.x += DCSrc->ptlDCOrig.x;
443 SourcePoint.y += DCSrc->ptlDCOrig.y;
444 /* Calculate Source Rect */
445 SourceRect.left = SourcePoint.x;
446 SourceRect.top = SourcePoint.y;
447 SourceRect.right = SourcePoint.x + DestRect.right - DestRect.left;
448 SourceRect.bottom = SourcePoint.y + DestRect.bottom - DestRect.top ;
449 }
450 else
451 {
452 SourceRect.left = 0;
453 SourceRect.top = 0;
454 SourceRect.right = 0;
455 SourceRect.bottom = 0;
456 }
457
458 /* Prepare blit */
459 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
460
461 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
462 DC_vUpdateFillBrush(DCDest);
463
464 /* Determine surfaces to be used in the bitblt */
465 BitmapDest = DCDest->dclevel.pSurface;
466 if (!BitmapDest)
467 goto cleanup;
468
469 if (UsesSource)
470 {
471 {
472 BitmapSrc = DCSrc->dclevel.pSurface;
473 if (!BitmapSrc)
474 goto cleanup;
475 }
476 }
477
478 /* Create the XLATEOBJ. */
479 if (UsesSource)
480 {
481 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
482 XlateObj = &exlo.xlo;
483 }
484
485
486 /* Perform the bitblt operation */
487 Status = IntEngBitBlt(&BitmapDest->SurfObj,
488 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
489 psurfMask ? &psurfMask->SurfObj : NULL,
490 DCDest->rosdc.CombinedClip,
491 XlateObj,
492 &DestRect,
493 &SourcePoint,
494 &MaskPoint,
495 &DCDest->eboFill.BrushObject,
496 &DCDest->dclevel.pbrFill->ptOrigin,
497 ROP_TO_ROP4(dwRop));
498
499 if (UsesSource)
500 EXLATEOBJ_vCleanup(&exlo);
501 cleanup:
502 DC_vFinishBlit(DCDest, DCSrc);
503 if (UsesSource)
504 {
505 DC_UnlockDc(DCSrc);
506 }
507 DC_UnlockDc(DCDest);
508 if(psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
509
510 return Status;
511 }
512
513 BOOL
514 APIENTRY
515 NtGdiPlgBlt(
516 IN HDC hdcTrg,
517 IN LPPOINT pptlTrg,
518 IN HDC hdcSrc,
519 IN INT xSrc,
520 IN INT ySrc,
521 IN INT cxSrc,
522 IN INT cySrc,
523 IN HBITMAP hbmMask,
524 IN INT xMask,
525 IN INT yMask,
526 IN DWORD crBackColor)
527 {
528 FIXME("NtGdiPlgBlt: unimplemented.\n");
529 return FALSE;
530 }
531
532 BOOL APIENTRY
533 GreStretchBltMask(
534 HDC hDCDest,
535 INT XOriginDest,
536 INT YOriginDest,
537 INT WidthDest,
538 INT HeightDest,
539 HDC hDCSrc,
540 INT XOriginSrc,
541 INT YOriginSrc,
542 INT WidthSrc,
543 INT HeightSrc,
544 DWORD ROP,
545 IN DWORD dwBackColor,
546 HDC hDCMask,
547 INT XOriginMask,
548 INT YOriginMask)
549 {
550 PDC DCDest;
551 PDC DCSrc = NULL;
552 PDC DCMask = NULL;
553 HDC ahDC[3];
554 PGDIOBJ apObj[3];
555 PDC_ATTR pdcattr;
556 SURFACE *BitmapDest, *BitmapSrc = NULL;
557 SURFACE *BitmapMask = NULL;
558 RECTL DestRect;
559 RECTL SourceRect;
560 POINTL MaskPoint;
561 BOOL Status = FALSE;
562 EXLATEOBJ exlo;
563 XLATEOBJ *XlateObj = NULL;
564 POINTL BrushOrigin;
565 BOOL UsesSource;
566 BOOL UsesMask;
567
568 FIXUP_ROP(ROP);
569 UsesSource = ROP_USES_SOURCE(ROP);
570 UsesMask = ROP_USES_MASK(ROP);
571
572 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
573 {
574 EngSetLastError(ERROR_INVALID_PARAMETER);
575 return TRUE;
576 }
577
578 if (!hDCDest || (UsesSource && !hDCSrc) || (UsesMask && !hDCMask))
579 {
580 EngSetLastError(ERROR_INVALID_PARAMETER);
581 return FALSE;
582 }
583
584 ahDC[0] = hDCDest;
585 ahDC[1] = UsesSource ? hDCSrc : NULL;
586 ahDC[2] = UsesMask ? hDCMask : NULL;
587 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
588 {
589 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to GreStretchBltMask\n", hDCDest, hDCSrc);
590 EngSetLastError(ERROR_INVALID_HANDLE);
591 return FALSE;
592 }
593 DCDest = apObj[0];
594 DCSrc = apObj[1];
595 DCMask = apObj[2];
596
597 if (DCDest->dctype == DC_TYPE_INFO)
598 {
599 if(DCSrc) GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
600 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
601 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
602 /* Yes, Windows really returns TRUE in this case */
603 return TRUE;
604 }
605
606 if (UsesSource)
607 {
608 if (DCSrc->dctype == DC_TYPE_INFO)
609 {
610 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
611 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
612 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
613 /* Yes, Windows really returns TRUE in this case */
614 return TRUE;
615 }
616 }
617
618 pdcattr = DCDest->pdcattr;
619
620 DestRect.left = XOriginDest;
621 DestRect.top = YOriginDest;
622 DestRect.right = XOriginDest+WidthDest;
623 DestRect.bottom = YOriginDest+HeightDest;
624 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
625
626 DestRect.left += DCDest->ptlDCOrig.x;
627 DestRect.top += DCDest->ptlDCOrig.y;
628 DestRect.right += DCDest->ptlDCOrig.x;
629 DestRect.bottom += DCDest->ptlDCOrig.y;
630
631 SourceRect.left = XOriginSrc;
632 SourceRect.top = YOriginSrc;
633 SourceRect.right = XOriginSrc+WidthSrc;
634 SourceRect.bottom = YOriginSrc+HeightSrc;
635
636 if (UsesSource)
637 {
638 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
639
640 SourceRect.left += DCSrc->ptlDCOrig.x;
641 SourceRect.top += DCSrc->ptlDCOrig.y;
642 SourceRect.right += DCSrc->ptlDCOrig.x;
643 SourceRect.bottom += DCSrc->ptlDCOrig.y;
644 }
645
646 BrushOrigin.x = 0;
647 BrushOrigin.y = 0;
648
649 /* Only prepare Source and Dest, hdcMask represents a DIB */
650 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
651
652 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
653 DC_vUpdateFillBrush(DCDest);
654
655 /* Determine surfaces to be used in the bitblt */
656 BitmapDest = DCDest->dclevel.pSurface;
657 if (BitmapDest == NULL)
658 goto failed;
659 if (UsesSource)
660 {
661 BitmapSrc = DCSrc->dclevel.pSurface;
662 if (BitmapSrc == NULL)
663 goto failed;
664
665 /* Create the XLATEOBJ. */
666 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
667 XlateObj = &exlo.xlo;
668 }
669
670 /* Offset the brush */
671 BrushOrigin.x += DCDest->ptlDCOrig.x;
672 BrushOrigin.y += DCDest->ptlDCOrig.y;
673
674 /* Make mask surface for source surface */
675 if (BitmapSrc && DCMask)
676 {
677 BitmapMask = DCMask->dclevel.pSurface;
678 if (BitmapMask &&
679 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
680 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
681 {
682 WARN("%dx%d mask is smaller than %dx%d bitmap\n",
683 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
684 WidthSrc, HeightSrc);
685 EXLATEOBJ_vCleanup(&exlo);
686 goto failed;
687 }
688 /* Create mask offset point */
689 MaskPoint.x = XOriginMask;
690 MaskPoint.y = YOriginMask;
691 IntLPtoDP(DCMask, &MaskPoint, 1);
692 MaskPoint.x += DCMask->ptlDCOrig.x;
693 MaskPoint.y += DCMask->ptlDCOrig.y;
694 }
695
696 /* Perform the bitblt operation */
697 Status = IntEngStretchBlt(&BitmapDest->SurfObj,
698 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
699 BitmapMask ? &BitmapMask->SurfObj : NULL,
700 DCDest->rosdc.CombinedClip,
701 XlateObj,
702 &DCDest->dclevel.ca,
703 &DestRect,
704 &SourceRect,
705 BitmapMask ? &MaskPoint : NULL,
706 &DCDest->eboFill.BrushObject,
707 &BrushOrigin,
708 ROP_TO_ROP4(ROP));
709 if (UsesSource)
710 {
711 EXLATEOBJ_vCleanup(&exlo);
712 }
713
714 failed:
715 DC_vFinishBlit(DCDest, DCSrc);
716 if (UsesSource)
717 {
718 DC_UnlockDc(DCSrc);
719 }
720 if (DCMask)
721 {
722 DC_UnlockDc(DCMask);
723 }
724 DC_UnlockDc(DCDest);
725
726 return Status;
727 }
728
729
730 BOOL APIENTRY
731 NtGdiStretchBlt(
732 HDC hDCDest,
733 INT XOriginDest,
734 INT YOriginDest,
735 INT WidthDest,
736 INT HeightDest,
737 HDC hDCSrc,
738 INT XOriginSrc,
739 INT YOriginSrc,
740 INT WidthSrc,
741 INT HeightSrc,
742 DWORD ROP,
743 IN DWORD dwBackColor)
744 {
745 DWORD dwTRop = ROP & ~(NOMIRRORBITMAP|CAPTUREBLT);
746
747 return GreStretchBltMask(
748 hDCDest,
749 XOriginDest,
750 YOriginDest,
751 WidthDest,
752 HeightDest,
753 hDCSrc,
754 XOriginSrc,
755 YOriginSrc,
756 WidthSrc,
757 HeightSrc,
758 dwTRop,
759 dwBackColor,
760 NULL,
761 0,
762 0);
763 }
764
765
766 BOOL FASTCALL
767 IntPatBlt(
768 PDC pdc,
769 INT XLeft,
770 INT YLeft,
771 INT Width,
772 INT Height,
773 DWORD dwRop,
774 PEBRUSHOBJ pebo)
775 {
776 RECTL DestRect;
777 SURFACE *psurf;
778 POINTL BrushOrigin;
779 BOOL ret;
780 PBRUSH pbrush;
781
782 ASSERT(pebo);
783 pbrush = pebo->pbrush;
784 ASSERT(pbrush);
785
786 FIXUP_ROP(dwRop);
787
788 if (pbrush->flAttrs & BR_IS_NULL)
789 {
790 return TRUE;
791 }
792
793 if (Width > 0)
794 {
795 DestRect.left = XLeft;
796 DestRect.right = XLeft + Width;
797 }
798 else
799 {
800 DestRect.left = XLeft + Width + 1;
801 DestRect.right = XLeft + 1;
802 }
803
804 if (Height > 0)
805 {
806 DestRect.top = YLeft;
807 DestRect.bottom = YLeft + Height;
808 }
809 else
810 {
811 DestRect.top = YLeft + Height + 1;
812 DestRect.bottom = YLeft + 1;
813 }
814
815 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
816
817 DestRect.left += pdc->ptlDCOrig.x;
818 DestRect.top += pdc->ptlDCOrig.y;
819 DestRect.right += pdc->ptlDCOrig.x;
820 DestRect.bottom += pdc->ptlDCOrig.y;
821 #ifdef _USE_DIBLIB_
822 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x + XLeft;
823 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y + YLeft;
824 #else
825 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
826 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
827 #endif
828
829 DC_vPrepareDCsForBlit(pdc, &DestRect, NULL, NULL);
830
831 psurf = pdc->dclevel.pSurface;
832
833 ret = IntEngBitBlt(
834 &psurf->SurfObj,
835 NULL,
836 NULL,
837 pdc->rosdc.CombinedClip,
838 NULL,
839 &DestRect,
840 NULL,
841 NULL,
842 &pebo->BrushObject,
843 &BrushOrigin,
844 ROP_TO_ROP4(dwRop));
845
846 DC_vFinishBlit(pdc, NULL);
847
848 return ret;
849 }
850
851 BOOL FASTCALL
852 IntGdiPolyPatBlt(
853 HDC hDC,
854 DWORD dwRop,
855 PPATRECT pRects,
856 INT cRects,
857 ULONG Reserved)
858 {
859 INT i;
860 PBRUSH pbrush;
861 PDC pdc;
862 EBRUSHOBJ eboFill;
863
864 pdc = DC_LockDc(hDC);
865 if (!pdc)
866 {
867 EngSetLastError(ERROR_INVALID_HANDLE);
868 return FALSE;
869 }
870
871 if (pdc->dctype == DC_TYPE_INFO)
872 {
873 DC_UnlockDc(pdc);
874 /* Yes, Windows really returns TRUE in this case */
875 return TRUE;
876 }
877
878 for (i = 0; i < cRects; i++)
879 {
880 pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
881
882 /* Check if we could lock the brush */
883 if (pbrush != NULL)
884 {
885 /* Initialize a brush object */
886 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, pdc);
887
888 IntPatBlt(
889 pdc,
890 pRects->r.left,
891 pRects->r.top,
892 pRects->r.right,
893 pRects->r.bottom,
894 dwRop,
895 &eboFill);
896
897 /* Cleanup the brush object and unlock the brush */
898 EBRUSHOBJ_vCleanup(&eboFill);
899 BRUSH_ShareUnlockBrush(pbrush);
900 }
901 pRects++;
902 }
903
904 DC_UnlockDc(pdc);
905
906 return TRUE;
907 }
908
909 BOOL
910 APIENTRY
911 NtGdiPatBlt(
912 _In_ HDC hdcDest,
913 _In_ INT x,
914 _In_ INT y,
915 _In_ INT cx,
916 _In_ INT cy,
917 _In_ DWORD dwRop)
918 {
919 BOOL bResult;
920 PDC pdc;
921
922 /* Mask away everything except foreground rop index */
923 dwRop = dwRop & 0x00FF0000;
924 dwRop |= dwRop << 8;
925
926 /* Check if the rop uses a source */
927 if (ROP_USES_SOURCE(dwRop))
928 {
929 /* This is not possible */
930 return 0;
931 }
932
933 /* Lock the DC */
934 pdc = DC_LockDc(hdcDest);
935 if (pdc == NULL)
936 {
937 EngSetLastError(ERROR_INVALID_HANDLE);
938 return FALSE;
939 }
940
941 /* Check if the DC has no surface (empty mem or info DC) */
942 if (pdc->dclevel.pSurface == NULL)
943 {
944 /* Nothing to do, Windows returns TRUE! */
945 DC_UnlockDc(pdc);
946 return TRUE;
947 }
948
949 /* Update the fill brush, if neccessary */
950 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
951 DC_vUpdateFillBrush(pdc);
952
953 /* Call the internal function */
954 bResult = IntPatBlt(pdc, x, y, cx, cy, dwRop, &pdc->eboFill);
955
956 /* Unlock the DC and return the result */
957 DC_UnlockDc(pdc);
958 return bResult;
959 }
960
961 BOOL
962 APIENTRY
963 NtGdiPolyPatBlt(
964 HDC hDC,
965 DWORD dwRop,
966 IN PPOLYPATBLT pRects,
967 IN DWORD cRects,
968 IN DWORD Mode)
969 {
970 PPATRECT rb = NULL;
971 NTSTATUS Status = STATUS_SUCCESS;
972 BOOL Ret;
973
974 if (cRects > 0)
975 {
976 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, GDITAG_PLGBLT_DATA);
977 if (!rb)
978 {
979 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
980 return FALSE;
981 }
982 _SEH2_TRY
983 {
984 ProbeForRead(pRects,
985 cRects * sizeof(PATRECT),
986 1);
987 RtlCopyMemory(rb,
988 pRects,
989 cRects * sizeof(PATRECT));
990 }
991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
992 {
993 Status = _SEH2_GetExceptionCode();
994 }
995 _SEH2_END;
996
997 if (!NT_SUCCESS(Status))
998 {
999 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1000 SetLastNtError(Status);
1001 return FALSE;
1002 }
1003 }
1004
1005 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1006
1007 if (cRects > 0)
1008 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1009
1010 return Ret;
1011 }
1012
1013
1014 COLORREF
1015 APIENTRY
1016 NtGdiSetPixel(
1017 _In_ HDC hdc,
1018 _In_ INT x,
1019 _In_ INT y,
1020 _In_ COLORREF crColor)
1021 {
1022 PDC pdc;
1023 ULONG iOldColor, iSolidColor;
1024 BOOL bResult;
1025 PEBRUSHOBJ pebo;
1026 ULONG ulDirty;
1027 EXLATEOBJ exlo;
1028
1029 /* Lock the DC */
1030 pdc = DC_LockDc(hdc);
1031 if (!pdc)
1032 {
1033 EngSetLastError(ERROR_INVALID_HANDLE);
1034 return -1;
1035 }
1036
1037 /* Check if the DC has no surface (empty mem or info DC) */
1038 if (pdc->dclevel.pSurface == NULL)
1039 {
1040 /* Fail! */
1041 DC_UnlockDc(pdc);
1042 return -1;
1043 }
1044
1045 /* Translate the color to the target format */
1046 iSolidColor = TranslateCOLORREF(pdc, crColor);
1047
1048 /* Use the DC's text brush, which is always a solid brush */
1049 pebo = &pdc->eboText;
1050
1051 /* Save the old solid color and set the one for the pixel */
1052 iOldColor = EBRUSHOBJ_iSetSolidColor(pebo, iSolidColor);
1053
1054 /* Save dirty flags and reset dirty text brush flag */
1055 ulDirty = pdc->pdcattr->ulDirty_;
1056 pdc->pdcattr->ulDirty_ &= ~DIRTY_TEXT;
1057
1058 /* Call the internal function */
1059 bResult = IntPatBlt(pdc, x, y, 1, 1, PATCOPY, pebo);
1060
1061 /* Restore old text brush color and dirty flags */
1062 EBRUSHOBJ_iSetSolidColor(pebo, iOldColor);
1063 pdc->pdcattr->ulDirty_ = ulDirty;
1064
1065 /* Initialize an XLATEOBJ from the target surface to RGB */
1066 EXLATEOBJ_vInitialize(&exlo,
1067 pdc->dclevel.pSurface->ppal,
1068 &gpalRGB,
1069 0,
1070 pdc->pdcattr->crBackgroundClr,
1071 pdc->pdcattr->crForegroundClr);
1072
1073 /* Translate the color back to RGB */
1074 crColor = XLATEOBJ_iXlate(&exlo.xlo, iSolidColor);
1075
1076 /* Cleanup and return the target format color */
1077 EXLATEOBJ_vCleanup(&exlo);
1078
1079 /* Unlock the DC */
1080 DC_UnlockDc(pdc);
1081
1082 /* Return the new RGB color or -1 on failure */
1083 return bResult ? crColor : -1;
1084 }
1085
1086 COLORREF
1087 APIENTRY
1088 NtGdiGetPixel(
1089 _In_ HDC hdc,
1090 _In_ INT x,
1091 _In_ INT y)
1092 {
1093 PDC pdc;
1094 ULONG ulRGBColor = CLR_INVALID;
1095 POINTL ptlSrc;
1096 PSURFACE psurfSrc, psurfDest;
1097
1098 /* Lock the DC */
1099 pdc = DC_LockDc(hdc);
1100 if (!pdc)
1101 {
1102 EngSetLastError(ERROR_INVALID_HANDLE);
1103 return CLR_INVALID;
1104 }
1105
1106 /* Check if the DC has no surface (empty mem or info DC) */
1107 psurfSrc = pdc->dclevel.pSurface;
1108 if (psurfSrc == NULL)
1109 {
1110 /* Fail! */
1111 goto leave;
1112 }
1113
1114 /* Get the logical coordinates */
1115 ptlSrc.x = x;
1116 ptlSrc.y = y;
1117
1118 /* Translate coordinates to device coordinates */
1119 IntLPtoDP(pdc, &ptlSrc, 1);
1120 ptlSrc.x += pdc->ptlDCOrig.x;
1121 ptlSrc.y += pdc->ptlDCOrig.y;
1122
1123 /* Check if the pixel is outside the surface */
1124 if ((ptlSrc.x >= psurfSrc->SurfObj.sizlBitmap.cx) ||
1125 (ptlSrc.y >= psurfSrc->SurfObj.sizlBitmap.cy))
1126 {
1127 /* Fail! */
1128 goto leave;
1129 }
1130
1131 /* Allocate a surface */
1132 psurfDest = SURFACE_AllocSurface(STYPE_BITMAP,
1133 1,
1134 1,
1135 BMF_32BPP,
1136 0,
1137 0,
1138 &ulRGBColor);
1139 if (psurfDest)
1140 {
1141 RECTL rclDest = {0, 0, 1, 1};
1142 EXLATEOBJ exlo;
1143
1144 /* Translate from the source palette to RGB color */
1145 EXLATEOBJ_vInitialize(&exlo,
1146 psurfSrc->ppal,
1147 &gpalRGB,
1148 0,
1149 RGB(0xff,0xff,0xff),
1150 RGB(0,0,0));
1151
1152 /* Call the copy bits function */
1153 EngCopyBits(&psurfDest->SurfObj,
1154 &psurfSrc->SurfObj,
1155 NULL,
1156 &exlo.xlo,
1157 &rclDest,
1158 &ptlSrc);
1159
1160 /* Cleanup the XLATEOBJ */
1161 EXLATEOBJ_vCleanup(&exlo);
1162
1163 /* Delete the surface */
1164 GDIOBJ_vDeleteObject(&psurfDest->BaseObject);
1165 }
1166
1167 leave:
1168 /* Unlock the DC */
1169 DC_UnlockDc(pdc);
1170
1171 /* Return the new RGB color or -1 on failure */
1172 return ulRGBColor;
1173 }
1174