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