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