99287173993b6c007e5e23a9d8d44c8a5c5af95a
[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: win32ss/gdi/ntgdi/bitblt.c
6 * PROGRAMER: Unknown
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(GdiBlt);
11
12 BOOL APIENTRY
13 NtGdiAlphaBlend(
14 HDC hDCDest,
15 LONG XOriginDest,
16 LONG YOriginDest,
17 LONG WidthDest,
18 LONG HeightDest,
19 HDC hDCSrc,
20 LONG XOriginSrc,
21 LONG YOriginSrc,
22 LONG WidthSrc,
23 LONG HeightSrc,
24 BLENDFUNCTION BlendFunc,
25 HANDLE hcmXform)
26 {
27 PDC DCDest;
28 PDC DCSrc;
29 HDC ahDC[2];
30 PGDIOBJ apObj[2];
31 SURFACE *BitmapDest, *BitmapSrc;
32 RECTL DestRect, SourceRect;
33 BOOL bResult;
34 EXLATEOBJ exlo;
35 BLENDOBJ BlendObj;
36 BlendObj.BlendFunction = BlendFunc;
37
38 if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0)
39 {
40 EngSetLastError(ERROR_INVALID_PARAMETER);
41 return FALSE;
42 }
43
44 if ((hDCDest == NULL) || (hDCSrc == NULL))
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 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
82 {
83 IntUpdateBoundsRect(DCDest, &DestRect);
84 }
85
86 SourceRect.left = XOriginSrc;
87 SourceRect.top = YOriginSrc;
88 SourceRect.right = XOriginSrc + WidthSrc;
89 SourceRect.bottom = YOriginSrc + HeightSrc;
90 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
91
92 SourceRect.left += DCSrc->ptlDCOrig.x;
93 SourceRect.top += DCSrc->ptlDCOrig.y;
94 SourceRect.right += DCSrc->ptlDCOrig.x;
95 SourceRect.bottom += DCSrc->ptlDCOrig.y;
96
97 if (!DestRect.right ||
98 !DestRect.bottom ||
99 !SourceRect.right ||
100 !SourceRect.bottom)
101 {
102 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
103 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
104 return TRUE;
105 }
106
107 /* Prepare DCs for blit */
108 TRACE("Preparing DCs for blit\n");
109 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
110
111 /* Determine surfaces to be used in the bitblt */
112 BitmapDest = DCDest->dclevel.pSurface;
113 if (!BitmapDest)
114 {
115 bResult = FALSE ;
116 goto leave ;
117 }
118
119 BitmapSrc = DCSrc->dclevel.pSurface;
120 if (!BitmapSrc)
121 {
122 bResult = FALSE;
123 goto leave;
124 }
125
126 /* Create the XLATEOBJ. */
127 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
128
129 /* Perform the alpha blend operation */
130 TRACE("Performing the alpha blend\n");
131 bResult = IntEngAlphaBlend(&BitmapDest->SurfObj,
132 &BitmapSrc->SurfObj,
133 &DCDest->co.ClipObj,
134 &exlo.xlo,
135 &DestRect,
136 &SourceRect,
137 &BlendObj);
138
139 EXLATEOBJ_vCleanup(&exlo);
140 leave :
141 TRACE("Finishing blit\n");
142 DC_vFinishBlit(DCDest, DCSrc);
143 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
144 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
145
146 return bResult;
147 }
148
149 BOOL APIENTRY
150 NtGdiBitBlt(
151 HDC hDCDest,
152 INT XDest,
153 INT YDest,
154 INT Width,
155 INT Height,
156 HDC hDCSrc,
157 INT XSrc,
158 INT YSrc,
159 DWORD dwRop,
160 IN DWORD crBackColor,
161 IN FLONG fl)
162 {
163
164 if (dwRop & CAPTUREBLT)
165 {
166 return NtGdiStretchBlt(hDCDest,
167 XDest,
168 YDest,
169 Width,
170 Height,
171 hDCSrc,
172 XSrc,
173 YSrc,
174 Width,
175 Height,
176 dwRop,
177 crBackColor);
178 }
179
180 dwRop = dwRop & ~(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 MAKEROP4(dwRop, dwRop),
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 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
271 {
272 IntUpdateBoundsRect(DCDest, &rcDest);
273 }
274
275 /* Prepare for blit */
276 DC_vPrepareDCsForBlit(DCDest, &rcDest, DCSrc, &rcSrc);
277
278 BitmapDest = DCDest->dclevel.pSurface;
279 if (!BitmapDest)
280 {
281 goto done;
282 }
283
284 BitmapSrc = DCSrc->dclevel.pSurface;
285 if (!BitmapSrc)
286 {
287 goto done;
288 }
289
290 /* Translate Transparent (RGB) Color to the source palette */
291 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, BitmapSrc->ppal, 0, 0, 0);
292 TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor);
293 EXLATEOBJ_vCleanup(&exlo);
294
295 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
296
297 Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
298 &DCDest->co.ClipObj, &exlo.xlo, &rcDest, &rcSrc,
299 TransparentColor, 0);
300
301 EXLATEOBJ_vCleanup(&exlo);
302
303 done:
304 DC_vFinishBlit(DCDest, DCSrc);
305 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
306 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
307
308 return Ret;
309 }
310
311 BOOL APIENTRY
312 NtGdiMaskBlt(
313 HDC hdcDest,
314 INT nXDest,
315 INT nYDest,
316 INT nWidth,
317 INT nHeight,
318 HDC hdcSrc,
319 INT nXSrc,
320 INT nYSrc,
321 HBITMAP hbmMask,
322 INT xMask,
323 INT yMask,
324 DWORD dwRop4,
325 IN DWORD crBackColor)
326 {
327 PDC DCDest;
328 PDC DCSrc = NULL;
329 HDC ahDC[2];
330 PGDIOBJ apObj[2];
331 PDC_ATTR pdcattr = NULL;
332 SURFACE *BitmapDest, *BitmapSrc = NULL, *psurfMask = NULL;
333 RECTL DestRect, SourceRect;
334 POINTL SourcePoint, MaskPoint;
335 BOOL Status = FALSE;
336 EXLATEOBJ exlo;
337 XLATEOBJ *XlateObj = NULL;
338 BOOL UsesSource;
339 ROP4 rop4;
340
341 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4);
342
343 UsesSource = ROP4_USES_SOURCE(rop4);
344 if (!hdcDest || (UsesSource && !hdcSrc))
345 {
346 EngSetLastError(ERROR_INVALID_PARAMETER);
347 return FALSE;
348 }
349
350 /* Check if we need a mask and have a mask bitmap */
351 if (ROP4_USES_MASK(rop4) && (hbmMask != NULL))
352 {
353 /* Reference the mask bitmap */
354 psurfMask = SURFACE_ShareLockSurface(hbmMask);
355 if (psurfMask == NULL)
356 {
357 EngSetLastError(ERROR_INVALID_HANDLE);
358 return FALSE;
359 }
360
361 /* Make sure the mask bitmap is 1 BPP */
362 if (gajBitsPerFormat[psurfMask->SurfObj.iBitmapFormat] != 1)
363 {
364 EngSetLastError(ERROR_INVALID_PARAMETER);
365 SURFACE_ShareUnlockSurface(psurfMask);
366 return FALSE;
367 }
368 }
369 else
370 {
371 /* We use NULL, if we need a mask, the Eng function will take care of
372 that and use the brushobject to get a mask */
373 psurfMask = NULL;
374 }
375
376 MaskPoint.x = xMask;
377 MaskPoint.y = yMask;
378
379 /* Take care of source and destination bitmap */
380 TRACE("Locking DCs\n");
381 ahDC[0] = hdcDest;
382 ahDC[1] = UsesSource ? hdcSrc : NULL;
383 if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
384 {
385 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to NtGdiAlphaBlend\n", hdcDest, hdcSrc);
386 EngSetLastError(ERROR_INVALID_HANDLE);
387 return FALSE;
388 }
389 DCDest = apObj[0];
390 DCSrc = apObj[1];
391
392 ASSERT(DCDest);
393 if (NULL == DCDest)
394 {
395 if(DCSrc) DC_UnlockDc(DCSrc);
396 WARN("Invalid destination dc handle (0x%p) passed to NtGdiBitBlt\n", hdcDest);
397 return FALSE;
398 }
399
400 if (DCDest->dctype == DC_TYPE_INFO)
401 {
402 if(DCSrc) DC_UnlockDc(DCSrc);
403 DC_UnlockDc(DCDest);
404 /* Yes, Windows really returns TRUE in this case */
405 return TRUE;
406 }
407
408 if (UsesSource)
409 {
410 ASSERT(DCSrc);
411 if (DCSrc->dctype == DC_TYPE_INFO)
412 {
413 DC_UnlockDc(DCDest);
414 DC_UnlockDc(DCSrc);
415 /* Yes, Windows really returns TRUE in this case */
416 return TRUE;
417 }
418 }
419
420 pdcattr = DCDest->pdcattr;
421
422 DestRect.left = nXDest;
423 DestRect.top = nYDest;
424 DestRect.right = nXDest + nWidth;
425 DestRect.bottom = nYDest + nHeight;
426 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
427
428 DestRect.left += DCDest->ptlDCOrig.x;
429 DestRect.top += DCDest->ptlDCOrig.y;
430 DestRect.right += DCDest->ptlDCOrig.x;
431 DestRect.bottom += DCDest->ptlDCOrig.y;
432
433 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
434 {
435 IntUpdateBoundsRect(DCDest, &DestRect);
436 }
437
438 SourcePoint.x = nXSrc;
439 SourcePoint.y = nYSrc;
440
441 if (UsesSource)
442 {
443 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
444
445 SourcePoint.x += DCSrc->ptlDCOrig.x;
446 SourcePoint.y += DCSrc->ptlDCOrig.y;
447 /* Calculate Source Rect */
448 SourceRect.left = SourcePoint.x;
449 SourceRect.top = SourcePoint.y;
450 SourceRect.right = SourcePoint.x + DestRect.right - DestRect.left;
451 SourceRect.bottom = SourcePoint.y + DestRect.bottom - DestRect.top ;
452 }
453 else
454 {
455 SourceRect.left = 0;
456 SourceRect.top = 0;
457 SourceRect.right = 0;
458 SourceRect.bottom = 0;
459 }
460
461 /* Prepare blit */
462 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
463
464 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
465 DC_vUpdateFillBrush(DCDest);
466
467 /* Determine surfaces to be used in the bitblt */
468 BitmapDest = DCDest->dclevel.pSurface;
469 if (!BitmapDest)
470 goto cleanup;
471
472 if (UsesSource)
473 {
474 {
475 BitmapSrc = DCSrc->dclevel.pSurface;
476 if (!BitmapSrc)
477 goto cleanup;
478 }
479 }
480
481 /* Create the XLATEOBJ. */
482 if (UsesSource)
483 {
484 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
485 XlateObj = &exlo.xlo;
486 }
487
488
489 /* Perform the bitblt operation */
490 Status = IntEngBitBlt(&BitmapDest->SurfObj,
491 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
492 psurfMask ? &psurfMask->SurfObj : NULL,
493 &DCDest->co.ClipObj,
494 XlateObj,
495 &DestRect,
496 &SourcePoint,
497 &MaskPoint,
498 &DCDest->eboFill.BrushObject,
499 &DCDest->dclevel.pbrFill->ptOrigin,
500 rop4);
501
502 if (UsesSource)
503 EXLATEOBJ_vCleanup(&exlo);
504 cleanup:
505 DC_vFinishBlit(DCDest, DCSrc);
506 if (UsesSource)
507 {
508 DC_UnlockDc(DCSrc);
509 }
510 DC_UnlockDc(DCDest);
511 if(psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
512
513 return Status;
514 }
515
516 BOOL
517 APIENTRY
518 NtGdiPlgBlt(
519 IN HDC hdcTrg,
520 IN LPPOINT pptlTrg,
521 IN HDC hdcSrc,
522 IN INT xSrc,
523 IN INT ySrc,
524 IN INT cxSrc,
525 IN INT cySrc,
526 IN HBITMAP hbmMask,
527 IN INT xMask,
528 IN INT yMask,
529 IN DWORD crBackColor)
530 {
531 FIXME("NtGdiPlgBlt: unimplemented.\n");
532 return FALSE;
533 }
534
535 BOOL
536 NTAPI
537 GreStretchBltMask(
538 HDC hDCDest,
539 INT XOriginDest,
540 INT YOriginDest,
541 INT WidthDest,
542 INT HeightDest,
543 HDC hDCSrc,
544 INT XOriginSrc,
545 INT YOriginSrc,
546 INT WidthSrc,
547 INT HeightSrc,
548 DWORD dwRop4,
549 IN DWORD dwBackColor,
550 HDC hDCMask,
551 INT XOriginMask,
552 INT YOriginMask)
553 {
554 PDC DCDest;
555 PDC DCSrc = NULL;
556 PDC DCMask = NULL;
557 HDC ahDC[3];
558 PGDIOBJ apObj[3];
559 PDC_ATTR pdcattr;
560 SURFACE *BitmapDest, *BitmapSrc = NULL;
561 SURFACE *BitmapMask = NULL;
562 RECTL DestRect;
563 RECTL SourceRect;
564 POINTL MaskPoint;
565 BOOL Status = FALSE;
566 EXLATEOBJ exlo;
567 XLATEOBJ *XlateObj = NULL;
568 POINTL BrushOrigin;
569 BOOL UsesSource;
570 BOOL UsesMask;
571 ROP4 rop4;
572
573 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4);
574
575 UsesSource = ROP4_USES_SOURCE(rop4);
576 UsesMask = ROP4_USES_MASK(rop4);
577
578 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
579 {
580 EngSetLastError(ERROR_INVALID_PARAMETER);
581 return TRUE;
582 }
583
584 if (!hDCDest || (UsesSource && !hDCSrc) || (UsesMask && !hDCMask))
585 {
586 EngSetLastError(ERROR_INVALID_PARAMETER);
587 return FALSE;
588 }
589
590 ahDC[0] = hDCDest;
591 ahDC[1] = UsesSource ? hDCSrc : NULL;
592 ahDC[2] = UsesMask ? hDCMask : NULL;
593 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
594 {
595 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to GreStretchBltMask\n", hDCDest, hDCSrc);
596 EngSetLastError(ERROR_INVALID_HANDLE);
597 return FALSE;
598 }
599 DCDest = apObj[0];
600 DCSrc = apObj[1];
601 DCMask = apObj[2];
602
603 if (DCDest->dctype == DC_TYPE_INFO)
604 {
605 if(DCSrc) GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
606 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
607 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
608 /* Yes, Windows really returns TRUE in this case */
609 return TRUE;
610 }
611
612 if (UsesSource)
613 {
614 if (DCSrc->dctype == DC_TYPE_INFO)
615 {
616 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
617 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
618 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
619 /* Yes, Windows really returns TRUE in this case */
620 return TRUE;
621 }
622 }
623
624 pdcattr = DCDest->pdcattr;
625
626 DestRect.left = XOriginDest;
627 DestRect.top = YOriginDest;
628 DestRect.right = XOriginDest+WidthDest;
629 DestRect.bottom = YOriginDest+HeightDest;
630 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
631
632 DestRect.left += DCDest->ptlDCOrig.x;
633 DestRect.top += DCDest->ptlDCOrig.y;
634 DestRect.right += DCDest->ptlDCOrig.x;
635 DestRect.bottom += DCDest->ptlDCOrig.y;
636
637 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
638 {
639 IntUpdateBoundsRect(DCDest, &DestRect);
640 }
641
642 SourceRect.left = XOriginSrc;
643 SourceRect.top = YOriginSrc;
644 SourceRect.right = XOriginSrc+WidthSrc;
645 SourceRect.bottom = YOriginSrc+HeightSrc;
646
647 if (UsesSource)
648 {
649 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
650
651 SourceRect.left += DCSrc->ptlDCOrig.x;
652 SourceRect.top += DCSrc->ptlDCOrig.y;
653 SourceRect.right += DCSrc->ptlDCOrig.x;
654 SourceRect.bottom += DCSrc->ptlDCOrig.y;
655 }
656
657 BrushOrigin.x = 0;
658 BrushOrigin.y = 0;
659
660 /* Only prepare Source and Dest, hdcMask represents a DIB */
661 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
662
663 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
664 DC_vUpdateFillBrush(DCDest);
665
666 /* Determine surfaces to be used in the bitblt */
667 BitmapDest = DCDest->dclevel.pSurface;
668 if (BitmapDest == NULL)
669 goto failed;
670 if (UsesSource)
671 {
672 BitmapSrc = DCSrc->dclevel.pSurface;
673 if (BitmapSrc == NULL)
674 goto failed;
675
676 /* Create the XLATEOBJ. */
677 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
678 XlateObj = &exlo.xlo;
679 }
680
681 /* Offset the brush */
682 BrushOrigin.x += DCDest->ptlDCOrig.x;
683 BrushOrigin.y += DCDest->ptlDCOrig.y;
684
685 /* Make mask surface for source surface */
686 if (BitmapSrc && DCMask)
687 {
688 BitmapMask = DCMask->dclevel.pSurface;
689 if (BitmapMask &&
690 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
691 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
692 {
693 WARN("%dx%d mask is smaller than %dx%d bitmap\n",
694 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
695 WidthSrc, HeightSrc);
696 EXLATEOBJ_vCleanup(&exlo);
697 goto failed;
698 }
699 /* Create mask offset point */
700 MaskPoint.x = XOriginMask;
701 MaskPoint.y = YOriginMask;
702 IntLPtoDP(DCMask, &MaskPoint, 1);
703 MaskPoint.x += DCMask->ptlDCOrig.x;
704 MaskPoint.y += DCMask->ptlDCOrig.y;
705 }
706
707 /* Perform the bitblt operation */
708 Status = IntEngStretchBlt(&BitmapDest->SurfObj,
709 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
710 BitmapMask ? &BitmapMask->SurfObj : NULL,
711 &DCDest->co.ClipObj,
712 XlateObj,
713 &DCDest->dclevel.ca,
714 &DestRect,
715 &SourceRect,
716 BitmapMask ? &MaskPoint : NULL,
717 &DCDest->eboFill.BrushObject,
718 &BrushOrigin,
719 rop4);
720 if (UsesSource)
721 {
722 EXLATEOBJ_vCleanup(&exlo);
723 }
724
725 failed:
726 DC_vFinishBlit(DCDest, DCSrc);
727 if (UsesSource)
728 {
729 DC_UnlockDc(DCSrc);
730 }
731 if (DCMask)
732 {
733 DC_UnlockDc(DCMask);
734 }
735 DC_UnlockDc(DCDest);
736
737 return Status;
738 }
739
740
741 BOOL APIENTRY
742 NtGdiStretchBlt(
743 HDC hDCDest,
744 INT XOriginDest,
745 INT YOriginDest,
746 INT WidthDest,
747 INT HeightDest,
748 HDC hDCSrc,
749 INT XOriginSrc,
750 INT YOriginSrc,
751 INT WidthSrc,
752 INT HeightSrc,
753 DWORD dwRop3,
754 IN DWORD dwBackColor)
755 {
756 dwRop3 = dwRop3 & ~(NOMIRRORBITMAP|CAPTUREBLT);
757
758 return GreStretchBltMask(
759 hDCDest,
760 XOriginDest,
761 YOriginDest,
762 WidthDest,
763 HeightDest,
764 hDCSrc,
765 XOriginSrc,
766 YOriginSrc,
767 WidthSrc,
768 HeightSrc,
769 MAKEROP4(dwRop3 & 0xFF0000, dwRop3),
770 dwBackColor,
771 NULL,
772 0,
773 0);
774 }
775
776
777 BOOL FASTCALL
778 IntPatBlt(
779 PDC pdc,
780 INT XLeft,
781 INT YLeft,
782 INT Width,
783 INT Height,
784 DWORD dwRop3,
785 PEBRUSHOBJ pebo)
786 {
787 RECTL DestRect;
788 SURFACE *psurf;
789 POINTL BrushOrigin;
790 BOOL ret;
791 PBRUSH pbrush;
792
793 ASSERT(pebo);
794 pbrush = pebo->pbrush;
795 ASSERT(pbrush);
796
797 if (pbrush->flAttrs & BR_IS_NULL)
798 {
799 return TRUE;
800 }
801
802 if (Width > 0)
803 {
804 DestRect.left = XLeft;
805 DestRect.right = XLeft + Width;
806 }
807 else
808 {
809 DestRect.left = XLeft + Width + 1;
810 DestRect.right = XLeft + 1;
811 }
812
813 if (Height > 0)
814 {
815 DestRect.top = YLeft;
816 DestRect.bottom = YLeft + Height;
817 }
818 else
819 {
820 DestRect.top = YLeft + Height + 1;
821 DestRect.bottom = YLeft + 1;
822 }
823
824 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
825
826 DestRect.left += pdc->ptlDCOrig.x;
827 DestRect.top += pdc->ptlDCOrig.y;
828 DestRect.right += pdc->ptlDCOrig.x;
829 DestRect.bottom += pdc->ptlDCOrig.y;
830
831 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
832 {
833 IntUpdateBoundsRect(pdc, &DestRect);
834 }
835
836 #ifdef _USE_DIBLIB_
837 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x + XLeft;
838 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y + YLeft;
839 #else
840 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
841 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
842 #endif
843
844 DC_vPrepareDCsForBlit(pdc, &DestRect, NULL, NULL);
845
846 psurf = pdc->dclevel.pSurface;
847
848 ret = IntEngBitBlt(&psurf->SurfObj,
849 NULL,
850 NULL,
851 &pdc->co.ClipObj,
852 NULL,
853 &DestRect,
854 NULL,
855 NULL,
856 &pebo->BrushObject,
857 &BrushOrigin,
858 WIN32_ROP3_TO_ENG_ROP4(dwRop3));
859
860 DC_vFinishBlit(pdc, NULL);
861
862 return ret;
863 }
864
865 BOOL FASTCALL
866 IntGdiPolyPatBlt(
867 HDC hDC,
868 DWORD dwRop,
869 PPATRECT pRects,
870 INT cRects,
871 ULONG Reserved)
872 {
873 INT i;
874 PBRUSH pbrush;
875 PDC pdc;
876 EBRUSHOBJ eboFill;
877
878 pdc = DC_LockDc(hDC);
879 if (!pdc)
880 {
881 EngSetLastError(ERROR_INVALID_HANDLE);
882 return FALSE;
883 }
884
885 if (pdc->dctype == DC_TYPE_INFO)
886 {
887 DC_UnlockDc(pdc);
888 /* Yes, Windows really returns TRUE in this case */
889 return TRUE;
890 }
891
892 for (i = 0; i < cRects; i++)
893 {
894 pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
895
896 /* Check if we could lock the brush */
897 if (pbrush != NULL)
898 {
899 /* Initialize a brush object */
900 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, pdc);
901
902 IntPatBlt(
903 pdc,
904 pRects->r.left,
905 pRects->r.top,
906 pRects->r.right,
907 pRects->r.bottom,
908 dwRop,
909 &eboFill);
910
911 /* Cleanup the brush object and unlock the brush */
912 EBRUSHOBJ_vCleanup(&eboFill);
913 BRUSH_ShareUnlockBrush(pbrush);
914 }
915 pRects++;
916 }
917
918 DC_UnlockDc(pdc);
919
920 return TRUE;
921 }
922
923 BOOL
924 APIENTRY
925 NtGdiPatBlt(
926 _In_ HDC hdcDest,
927 _In_ INT x,
928 _In_ INT y,
929 _In_ INT cx,
930 _In_ INT cy,
931 _In_ DWORD dwRop)
932 {
933 BOOL bResult;
934 PDC pdc;
935
936 /* Convert the ROP3 to a ROP4 */
937 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
938
939 /* Check if the rop uses a source */
940 if (WIN32_ROP4_USES_SOURCE(dwRop))
941 {
942 /* This is not possible */
943 return FALSE;
944 }
945
946 /* Lock the DC */
947 pdc = DC_LockDc(hdcDest);
948 if (pdc == NULL)
949 {
950 EngSetLastError(ERROR_INVALID_HANDLE);
951 return FALSE;
952 }
953
954 /* Check if the DC has no surface (empty mem or info DC) */
955 if (pdc->dclevel.pSurface == NULL)
956 {
957 /* Nothing to do, Windows returns TRUE! */
958 DC_UnlockDc(pdc);
959 return TRUE;
960 }
961
962 /* Update the fill brush, if necessary */
963 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
964 DC_vUpdateFillBrush(pdc);
965
966 /* Call the internal function */
967 bResult = IntPatBlt(pdc, x, y, cx, cy, dwRop, &pdc->eboFill);
968
969 /* Unlock the DC and return the result */
970 DC_UnlockDc(pdc);
971 return bResult;
972 }
973
974 BOOL
975 APIENTRY
976 NtGdiPolyPatBlt(
977 HDC hDC,
978 DWORD dwRop,
979 IN PPOLYPATBLT pRects,
980 IN DWORD cRects,
981 IN DWORD Mode)
982 {
983 PPATRECT rb = NULL;
984 NTSTATUS Status = STATUS_SUCCESS;
985 BOOL Ret;
986
987 if (cRects > 0)
988 {
989 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, GDITAG_PLGBLT_DATA);
990 if (!rb)
991 {
992 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
993 return FALSE;
994 }
995 _SEH2_TRY
996 {
997 ProbeForRead(pRects,
998 cRects * sizeof(PATRECT),
999 1);
1000 RtlCopyMemory(rb,
1001 pRects,
1002 cRects * sizeof(PATRECT));
1003 }
1004 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1005 {
1006 Status = _SEH2_GetExceptionCode();
1007 }
1008 _SEH2_END;
1009
1010 if (!NT_SUCCESS(Status))
1011 {
1012 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1013 SetLastNtError(Status);
1014 return FALSE;
1015 }
1016 }
1017
1018 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1019
1020 if (cRects > 0)
1021 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1022
1023 return Ret;
1024 }
1025
1026 static
1027 BOOL
1028 FASTCALL
1029 REGION_LPTODP(
1030 _In_ PDC pdc,
1031 _Inout_ PREGION prgnDest,
1032 _In_ PREGION prgnSrc)
1033 {
1034 if (IntGdiCombineRgn(prgnDest, prgnSrc, NULL, RGN_COPY) == ERROR)
1035 return FALSE;
1036
1037 return REGION_bXformRgn(prgnDest, DC_pmxWorldToDevice(pdc));
1038 }
1039
1040 BOOL
1041 APIENTRY
1042 IntGdiBitBltRgn(
1043 _In_ PDC pdc,
1044 _In_ PREGION prgn,
1045 _In_opt_ BRUSHOBJ *pbo,
1046 _In_opt_ POINTL *pptlBrush,
1047 _In_ ROP4 rop4)
1048 {
1049 PREGION prgnClip;
1050 XCLIPOBJ xcoClip;
1051 BOOL bResult;
1052 NT_ASSERT((pdc != NULL) && (prgn != NULL));
1053
1054 /* Check if we have a surface */
1055 if (pdc->dclevel.pSurface == NULL)
1056 {
1057 return TRUE;
1058 }
1059
1060 /* Create an empty clip region */
1061 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1062 if (prgnClip == NULL)
1063 {
1064 return FALSE;
1065 }
1066
1067 /* Transform given region into device coordinates */
1068 if (!REGION_LPTODP(pdc, prgnClip, prgn))
1069 {
1070 REGION_Delete(prgnClip);
1071 return FALSE;
1072 }
1073
1074 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1075 if (pdc->prgnRao)
1076 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1077 else
1078 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1079
1080 /* Now account for the DC-origin */
1081 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1082 {
1083 REGION_Delete(prgnClip);
1084 return FALSE;
1085 }
1086
1087 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1088 {
1089 RECTL rcrgn;
1090 REGION_GetRgnBox(prgnClip, &rcrgn);
1091 IntUpdateBoundsRect(pdc, &rcrgn);
1092 }
1093
1094 /* Prepare the DC */
1095 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1096
1097 /* Initialize a clip object */
1098 IntEngInitClipObj(&xcoClip);
1099 IntEngUpdateClipRegion(&xcoClip,
1100 prgnClip->rdh.nCount,
1101 prgnClip->Buffer,
1102 &prgnClip->rdh.rcBound);
1103
1104 /* Call the Eng or Drv function */
1105 bResult = IntEngBitBlt(&pdc->dclevel.pSurface->SurfObj,
1106 NULL,
1107 NULL,
1108 &xcoClip.ClipObj,
1109 NULL,
1110 &prgnClip->rdh.rcBound,
1111 NULL,
1112 NULL,
1113 pbo,
1114 pptlBrush,
1115 rop4);
1116
1117 /* Cleanup */
1118 DC_vFinishBlit(pdc, NULL);
1119 REGION_Delete(prgnClip);
1120 IntEngFreeClipResources(&xcoClip);
1121
1122 /* Return the result */
1123 return bResult;
1124 }
1125
1126 static
1127 BOOL
1128 IntGdiFillRgn(
1129 _In_ PDC pdc,
1130 _In_ PREGION prgn,
1131 _In_opt_ PBRUSH pbrFill)
1132 {
1133 PREGION prgnClip;
1134 XCLIPOBJ xcoClip;
1135 EBRUSHOBJ eboFill;
1136 BRUSHOBJ *pbo;
1137 BOOL bRet;
1138 DWORD rop2Fg;
1139 MIX mix;
1140 NT_ASSERT((pdc != NULL) && (prgn != NULL));
1141
1142 if (pdc->dclevel.pSurface == NULL)
1143 {
1144 return TRUE;
1145 }
1146
1147 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1148 if (prgnClip == NULL)
1149 {
1150 return FALSE;
1151 }
1152
1153 /* Transform region into device coordinates */
1154 if (!REGION_LPTODP(pdc, prgnClip, prgn))
1155 {
1156 REGION_Delete(prgnClip);
1157 return FALSE;
1158 }
1159
1160 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1161 if (pdc->prgnRao)
1162 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1163 else
1164 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1165
1166 /* Now account for the DC-origin */
1167 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1168 {
1169 REGION_Delete(prgnClip);
1170 return FALSE;
1171 }
1172
1173 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1174 {
1175 RECTL rcrgn;
1176 REGION_GetRgnBox(prgnClip, &rcrgn);
1177 IntUpdateBoundsRect(pdc, &rcrgn);
1178 }
1179
1180 IntEngInitClipObj(&xcoClip);
1181 IntEngUpdateClipRegion(&xcoClip,
1182 prgnClip->rdh.nCount,
1183 prgnClip->Buffer,
1184 &prgnClip->rdh.rcBound );
1185
1186 /* Get the FG rop and create a MIX based on the BK mode */
1187 rop2Fg = FIXUP_ROP2(pdc->pdcattr->jROP2);
1188 mix = rop2Fg | (pdc->pdcattr->jBkMode == OPAQUE ? rop2Fg : R2_NOP) << 8;
1189
1190 /* Prepare DC for blit */
1191 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1192
1193 /* Check if we have a fill brush */
1194 if (pbrFill != NULL)
1195 {
1196 /* Initialize the brush object */
1197 /// \todo Check parameters
1198 EBRUSHOBJ_vInit(&eboFill, pbrFill, pdc->dclevel.pSurface, 0x00FFFFFF, 0, NULL);
1199 pbo = &eboFill.BrushObject;
1200 }
1201 else
1202 {
1203 /* Update the fill brush if needed */
1204 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1205 DC_vUpdateFillBrush(pdc);
1206
1207 /* Use the DC brush object */
1208 pbo = &pdc->eboFill.BrushObject;
1209 }
1210
1211 /* Call the internal function */
1212 bRet = IntEngPaint(&pdc->dclevel.pSurface->SurfObj,
1213 &xcoClip.ClipObj,
1214 pbo,
1215 &pdc->pdcattr->ptlBrushOrigin,
1216 mix);
1217
1218 DC_vFinishBlit(pdc, NULL);
1219 REGION_Delete(prgnClip);
1220 IntEngFreeClipResources(&xcoClip);
1221
1222 // Fill the region
1223 return bRet;
1224 }
1225
1226 BOOL
1227 FASTCALL
1228 IntGdiPaintRgn(
1229 _In_ PDC pdc,
1230 _In_ PREGION prgn)
1231 {
1232 return IntGdiFillRgn(pdc, prgn, NULL);
1233 }
1234
1235 BOOL
1236 APIENTRY
1237 NtGdiFillRgn(
1238 _In_ HDC hdc,
1239 _In_ HRGN hrgn,
1240 _In_ HBRUSH hbrush)
1241 {
1242 PDC pdc;
1243 PREGION prgn;
1244 PBRUSH pbrFill;
1245 BOOL bResult;
1246
1247 /* Lock the DC */
1248 pdc = DC_LockDc(hdc);
1249 if (pdc == NULL)
1250 {
1251 ERR("Failed to lock hdc %p\n", hdc);
1252 return FALSE;
1253 }
1254
1255 /* Check if the DC has no surface (empty mem or info DC) */
1256 if (pdc->dclevel.pSurface == NULL)
1257 {
1258 DC_UnlockDc(pdc);
1259 return TRUE;
1260 }
1261
1262 /* Lock the region */
1263 prgn = REGION_LockRgn(hrgn);
1264 if (prgn == NULL)
1265 {
1266 ERR("Failed to lock hrgn %p\n", hrgn);
1267 DC_UnlockDc(pdc);
1268 return FALSE;
1269 }
1270
1271 /* Lock the brush */
1272 pbrFill = BRUSH_ShareLockBrush(hbrush);
1273 if (pbrFill == NULL)
1274 {
1275 ERR("Failed to lock hbrush %p\n", hbrush);
1276 REGION_UnlockRgn(prgn);
1277 DC_UnlockDc(pdc);
1278 return FALSE;
1279 }
1280
1281 /* Call the internal function */
1282 bResult = IntGdiFillRgn(pdc, prgn, pbrFill);
1283
1284 /* Cleanup locks */
1285 BRUSH_ShareUnlockBrush(pbrFill);
1286 REGION_UnlockRgn(prgn);
1287 DC_UnlockDc(pdc);
1288
1289 return bResult;
1290 }
1291
1292 BOOL
1293 APIENTRY
1294 NtGdiFrameRgn(
1295 _In_ HDC hdc,
1296 _In_ HRGN hrgn,
1297 _In_ HBRUSH hbrush,
1298 _In_ INT xWidth,
1299 _In_ INT yHeight)
1300 {
1301 HRGN hrgnFrame;
1302 BOOL bResult;
1303
1304 hrgnFrame = GreCreateFrameRgn(hrgn, xWidth, yHeight);
1305 if (hrgnFrame == NULL)
1306 {
1307 return FALSE;
1308 }
1309
1310 bResult = NtGdiFillRgn(hdc, hrgnFrame, hbrush);
1311
1312 GreDeleteObject(hrgnFrame);
1313 return bResult;
1314 }
1315
1316 BOOL
1317 APIENTRY
1318 NtGdiInvertRgn(
1319 _In_ HDC hdc,
1320 _In_ HRGN hrgn)
1321 {
1322 BOOL bResult;
1323 PDC pdc;
1324 PREGION prgn;
1325
1326 /* Lock the DC */
1327 pdc = DC_LockDc(hdc);
1328 if (pdc == NULL)
1329 {
1330 EngSetLastError(ERROR_INVALID_HANDLE);
1331 return FALSE;
1332 }
1333
1334 /* Check if the DC has no surface (empty mem or info DC) */
1335 if (pdc->dclevel.pSurface == NULL)
1336 {
1337 /* Nothing to do, Windows returns TRUE! */
1338 DC_UnlockDc(pdc);
1339 return TRUE;
1340 }
1341
1342 /* Lock the region */
1343 prgn = REGION_LockRgn(hrgn);
1344 if (prgn == NULL)
1345 {
1346 DC_UnlockDc(pdc);
1347 return FALSE;
1348 }
1349
1350 /* Call the internal function */
1351 bResult = IntGdiBitBltRgn(pdc,
1352 prgn,
1353 NULL, // pbo
1354 NULL, // pptlBrush,
1355 ROP4_DSTINVERT);
1356
1357 /* Unlock the region and DC and return the result */
1358 REGION_UnlockRgn(prgn);
1359 DC_UnlockDc(pdc);
1360 return bResult;
1361 }
1362
1363 COLORREF
1364 APIENTRY
1365 NtGdiSetPixel(
1366 _In_ HDC hdc,
1367 _In_ INT x,
1368 _In_ INT y,
1369 _In_ COLORREF crColor)
1370 {
1371 PDC pdc;
1372 ULONG iOldColor, iSolidColor;
1373 BOOL bResult;
1374 PEBRUSHOBJ pebo;
1375 ULONG ulDirty;
1376 EXLATEOBJ exlo;
1377
1378 /* Lock the DC */
1379 pdc = DC_LockDc(hdc);
1380 if (!pdc)
1381 {
1382 EngSetLastError(ERROR_INVALID_HANDLE);
1383 return -1;
1384 }
1385
1386 /* Check if the DC has no surface (empty mem or info DC) */
1387 if (pdc->dclevel.pSurface == NULL)
1388 {
1389 /* Fail! */
1390 DC_UnlockDc(pdc);
1391 return -1;
1392 }
1393
1394 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1395 {
1396 RECTL rcDst;
1397
1398 RECTL_vSetRect(&rcDst, x, y, x+1, y+1);
1399
1400 IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
1401
1402 rcDst.left += pdc->ptlDCOrig.x;
1403 rcDst.top += pdc->ptlDCOrig.y;
1404 rcDst.right += pdc->ptlDCOrig.x;
1405 rcDst.bottom += pdc->ptlDCOrig.y;
1406
1407 IntUpdateBoundsRect(pdc, &rcDst);
1408 }
1409
1410 /* Translate the color to the target format */
1411 iSolidColor = TranslateCOLORREF(pdc, crColor);
1412
1413 /* Use the DC's text brush, which is always a solid brush */
1414 pebo = &pdc->eboText;
1415
1416 /* Save the old solid color and set the one for the pixel */
1417 iOldColor = EBRUSHOBJ_iSetSolidColor(pebo, iSolidColor);
1418
1419 /* Save dirty flags and reset dirty text brush flag */
1420 ulDirty = pdc->pdcattr->ulDirty_;
1421 pdc->pdcattr->ulDirty_ &= ~DIRTY_TEXT;
1422
1423 /* Call the internal function */
1424 bResult = IntPatBlt(pdc, x, y, 1, 1, PATCOPY, pebo);
1425
1426 /* Restore old text brush color and dirty flags */
1427 EBRUSHOBJ_iSetSolidColor(pebo, iOldColor);
1428 pdc->pdcattr->ulDirty_ = ulDirty;
1429
1430 /// FIXME: we shouldn't dereference pSurface while the PDEV is not locked!
1431 /* Initialize an XLATEOBJ from the target surface to RGB */
1432 EXLATEOBJ_vInitialize(&exlo,
1433 pdc->dclevel.pSurface->ppal,
1434 &gpalRGB,
1435 0,
1436 pdc->pdcattr->crBackgroundClr,
1437 pdc->pdcattr->crForegroundClr);
1438
1439 /* Translate the color back to RGB */
1440 crColor = XLATEOBJ_iXlate(&exlo.xlo, iSolidColor);
1441
1442 /* Cleanup and return the target format color */
1443 EXLATEOBJ_vCleanup(&exlo);
1444
1445 /* Unlock the DC */
1446 DC_UnlockDc(pdc);
1447
1448 /* Return the new RGB color or -1 on failure */
1449 return bResult ? crColor : -1;
1450 }
1451
1452 COLORREF
1453 APIENTRY
1454 NtGdiGetPixel(
1455 _In_ HDC hdc,
1456 _In_ INT x,
1457 _In_ INT y)
1458 {
1459 PDC pdc;
1460 ULONG ulRGBColor = CLR_INVALID;
1461 POINTL ptlSrc;
1462 RECT rcDest;
1463 PSURFACE psurfSrc, psurfDest;
1464
1465 /* Lock the DC */
1466 pdc = DC_LockDc(hdc);
1467 if (!pdc)
1468 {
1469 EngSetLastError(ERROR_INVALID_HANDLE);
1470 return CLR_INVALID;
1471 }
1472
1473 /* Check if the DC has no surface (empty mem or info DC) */
1474 if (pdc->dclevel.pSurface == NULL)
1475 {
1476 /* Fail! */
1477 goto leave;
1478 }
1479
1480 /* Get the logical coordinates */
1481 ptlSrc.x = x;
1482 ptlSrc.y = y;
1483
1484 /* Translate coordinates to device coordinates */
1485 IntLPtoDP(pdc, &ptlSrc, 1);
1486 ptlSrc.x += pdc->ptlDCOrig.x;
1487 ptlSrc.y += pdc->ptlDCOrig.y;
1488
1489 rcDest.left = x;
1490 rcDest.top = y;
1491 rcDest.right = x + 1;
1492 rcDest.bottom = y + 1;
1493
1494 /* Prepare DC for blit */
1495 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1496
1497 /* Check if the pixel is outside the surface */
1498 psurfSrc = pdc->dclevel.pSurface;
1499 if ((ptlSrc.x >= psurfSrc->SurfObj.sizlBitmap.cx) ||
1500 (ptlSrc.y >= psurfSrc->SurfObj.sizlBitmap.cy))
1501 {
1502 /* Fail! */
1503 goto leave;
1504 }
1505
1506 /* Allocate a surface */
1507 psurfDest = SURFACE_AllocSurface(STYPE_BITMAP,
1508 1,
1509 1,
1510 BMF_32BPP,
1511 0,
1512 0,
1513 0,
1514 &ulRGBColor);
1515 if (psurfDest)
1516 {
1517 RECTL rclDest = {0, 0, 1, 1};
1518 EXLATEOBJ exlo;
1519
1520 /* Translate from the source palette to RGB color */
1521 EXLATEOBJ_vInitialize(&exlo,
1522 psurfSrc->ppal,
1523 &gpalRGB,
1524 0,
1525 RGB(0xff,0xff,0xff),
1526 RGB(0,0,0));
1527
1528 /* Call the copy bits function */
1529 EngCopyBits(&psurfDest->SurfObj,
1530 &psurfSrc->SurfObj,
1531 NULL,
1532 &exlo.xlo,
1533 &rclDest,
1534 &ptlSrc);
1535
1536 /* Cleanup the XLATEOBJ */
1537 EXLATEOBJ_vCleanup(&exlo);
1538
1539 /* Delete the surface */
1540 GDIOBJ_vDeleteObject(&psurfDest->BaseObject);
1541 }
1542
1543 leave:
1544
1545 /* Unlock the DC */
1546 DC_vFinishBlit(pdc, NULL);
1547 DC_UnlockDc(pdc);
1548
1549 /* Return the new RGB color or -1 on failure */
1550 return ulRGBColor;
1551 }
1552