38c92e3bb21574e279c05afc25b4f8b9dcea494e
[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: 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 (CLIPOBJ *)&DCDest->co,
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 (CLIPOBJ *)&DCDest->co, &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 NtGdiMaskBlt\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 NtGdiMaskBlt\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 /* Perform the bitblt operation */
489 Status = IntEngBitBlt(&BitmapDest->SurfObj,
490 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
491 psurfMask ? &psurfMask->SurfObj : NULL,
492 (CLIPOBJ *)&DCDest->co,
493 XlateObj,
494 &DestRect,
495 &SourcePoint,
496 &MaskPoint,
497 &DCDest->eboFill.BrushObject,
498 &DCDest->dclevel.pbrFill->ptOrigin,
499 rop4);
500
501 if (UsesSource)
502 EXLATEOBJ_vCleanup(&exlo);
503 cleanup:
504 DC_vFinishBlit(DCDest, DCSrc);
505 if (UsesSource)
506 {
507 DC_UnlockDc(DCSrc);
508 }
509 DC_UnlockDc(DCDest);
510 if(psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
511
512 return Status;
513 }
514
515 BOOL
516 APIENTRY
517 NtGdiPlgBlt(
518 IN HDC hdcTrg,
519 IN LPPOINT pptlTrg,
520 IN HDC hdcSrc,
521 IN INT xSrc,
522 IN INT ySrc,
523 IN INT cxSrc,
524 IN INT cySrc,
525 IN HBITMAP hbmMask,
526 IN INT xMask,
527 IN INT yMask,
528 IN DWORD crBackColor)
529 {
530 FIXME("NtGdiPlgBlt: unimplemented.\n");
531 return FALSE;
532 }
533
534 BOOL
535 NTAPI
536 GreStretchBltMask(
537 HDC hDCDest,
538 INT XOriginDest,
539 INT YOriginDest,
540 INT WidthDest,
541 INT HeightDest,
542 HDC hDCSrc,
543 INT XOriginSrc,
544 INT YOriginSrc,
545 INT WidthSrc,
546 INT HeightSrc,
547 DWORD dwRop4,
548 IN DWORD dwBackColor,
549 HDC hDCMask,
550 INT XOriginMask,
551 INT YOriginMask)
552 {
553 PDC DCDest;
554 PDC DCSrc = NULL;
555 PDC DCMask = NULL;
556 HDC ahDC[3];
557 PGDIOBJ apObj[3];
558 PDC_ATTR pdcattr;
559 SURFACE *BitmapDest, *BitmapSrc = NULL;
560 SURFACE *BitmapMask = NULL;
561 RECTL DestRect;
562 RECTL SourceRect;
563 POINTL MaskPoint;
564 BOOL Status = FALSE;
565 EXLATEOBJ exlo;
566 XLATEOBJ *XlateObj = NULL;
567 POINTL BrushOrigin;
568 BOOL UsesSource;
569 BOOL UsesMask;
570 ROP4 rop4;
571
572 rop4 = WIN32_ROP4_TO_ENG_ROP4(dwRop4);
573
574 UsesSource = ROP4_USES_SOURCE(rop4);
575 UsesMask = ROP4_USES_MASK(rop4);
576
577 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
578 {
579 EngSetLastError(ERROR_INVALID_PARAMETER);
580 return TRUE;
581 }
582
583 if (!hDCDest || (UsesSource && !hDCSrc) || (UsesMask && !hDCMask))
584 {
585 EngSetLastError(ERROR_INVALID_PARAMETER);
586 return FALSE;
587 }
588
589 ahDC[0] = hDCDest;
590 ahDC[1] = UsesSource ? hDCSrc : NULL;
591 ahDC[2] = UsesMask ? hDCMask : NULL;
592 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahDC, apObj, GDIObjType_DC_TYPE))
593 {
594 WARN("Invalid dc handle (dest=0x%p, src=0x%p) passed to GreStretchBltMask\n", hDCDest, hDCSrc);
595 EngSetLastError(ERROR_INVALID_HANDLE);
596 return FALSE;
597 }
598 DCDest = apObj[0];
599 DCSrc = apObj[1];
600 DCMask = apObj[2];
601
602 if (DCDest->dctype == DC_TYPE_INFO)
603 {
604 if(DCSrc) GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
605 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
606 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
607 /* Yes, Windows really returns TRUE in this case */
608 return TRUE;
609 }
610
611 if (UsesSource)
612 {
613 if (DCSrc->dctype == DC_TYPE_INFO)
614 {
615 GDIOBJ_vUnlockObject(&DCDest->BaseObject);
616 GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
617 if(DCMask) GDIOBJ_vUnlockObject(&DCMask->BaseObject);
618 /* Yes, Windows really returns TRUE in this case */
619 return TRUE;
620 }
621 }
622
623 pdcattr = DCDest->pdcattr;
624
625 DestRect.left = XOriginDest;
626 DestRect.top = YOriginDest;
627 DestRect.right = XOriginDest+WidthDest;
628 DestRect.bottom = YOriginDest+HeightDest;
629 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
630
631 DestRect.left += DCDest->ptlDCOrig.x;
632 DestRect.top += DCDest->ptlDCOrig.y;
633 DestRect.right += DCDest->ptlDCOrig.x;
634 DestRect.bottom += DCDest->ptlDCOrig.y;
635
636 if (DCDest->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
637 {
638 IntUpdateBoundsRect(DCDest, &DestRect);
639 }
640
641 SourceRect.left = XOriginSrc;
642 SourceRect.top = YOriginSrc;
643 SourceRect.right = XOriginSrc+WidthSrc;
644 SourceRect.bottom = YOriginSrc+HeightSrc;
645
646 if (UsesSource)
647 {
648 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
649
650 SourceRect.left += DCSrc->ptlDCOrig.x;
651 SourceRect.top += DCSrc->ptlDCOrig.y;
652 SourceRect.right += DCSrc->ptlDCOrig.x;
653 SourceRect.bottom += DCSrc->ptlDCOrig.y;
654 }
655
656 BrushOrigin.x = 0;
657 BrushOrigin.y = 0;
658
659 /* Only prepare Source and Dest, hdcMask represents a DIB */
660 DC_vPrepareDCsForBlit(DCDest, &DestRect, DCSrc, &SourceRect);
661
662 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
663 DC_vUpdateFillBrush(DCDest);
664
665 /* Determine surfaces to be used in the bitblt */
666 BitmapDest = DCDest->dclevel.pSurface;
667 if (BitmapDest == NULL)
668 goto failed;
669 if (UsesSource)
670 {
671 BitmapSrc = DCSrc->dclevel.pSurface;
672 if (BitmapSrc == NULL)
673 goto failed;
674
675 /* Create the XLATEOBJ. */
676 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
677 XlateObj = &exlo.xlo;
678 }
679
680 /* Offset the brush */
681 BrushOrigin.x += DCDest->ptlDCOrig.x;
682 BrushOrigin.y += DCDest->ptlDCOrig.y;
683
684 /* Make mask surface for source surface */
685 if (BitmapSrc && DCMask)
686 {
687 BitmapMask = DCMask->dclevel.pSurface;
688 if (BitmapMask &&
689 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
690 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
691 {
692 WARN("%dx%d mask is smaller than %dx%d bitmap\n",
693 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
694 WidthSrc, HeightSrc);
695 EXLATEOBJ_vCleanup(&exlo);
696 goto failed;
697 }
698 /* Create mask offset point */
699 MaskPoint.x = XOriginMask;
700 MaskPoint.y = YOriginMask;
701 IntLPtoDP(DCMask, &MaskPoint, 1);
702 MaskPoint.x += DCMask->ptlDCOrig.x;
703 MaskPoint.y += DCMask->ptlDCOrig.y;
704 }
705
706 /* Perform the bitblt operation */
707 Status = IntEngStretchBlt(&BitmapDest->SurfObj,
708 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
709 BitmapMask ? &BitmapMask->SurfObj : NULL,
710 (CLIPOBJ *)&DCDest->co,
711 XlateObj,
712 &DCDest->dclevel.ca,
713 &DestRect,
714 &SourceRect,
715 BitmapMask ? &MaskPoint : NULL,
716 &DCDest->eboFill.BrushObject,
717 &BrushOrigin,
718 rop4);
719 if (UsesSource)
720 {
721 EXLATEOBJ_vCleanup(&exlo);
722 }
723
724 failed:
725 DC_vFinishBlit(DCDest, DCSrc);
726 if (UsesSource)
727 {
728 DC_UnlockDc(DCSrc);
729 }
730 if (DCMask)
731 {
732 DC_UnlockDc(DCMask);
733 }
734 DC_UnlockDc(DCDest);
735
736 return Status;
737 }
738
739
740 BOOL APIENTRY
741 NtGdiStretchBlt(
742 HDC hDCDest,
743 INT XOriginDest,
744 INT YOriginDest,
745 INT WidthDest,
746 INT HeightDest,
747 HDC hDCSrc,
748 INT XOriginSrc,
749 INT YOriginSrc,
750 INT WidthSrc,
751 INT HeightSrc,
752 DWORD dwRop3,
753 IN DWORD dwBackColor)
754 {
755 dwRop3 = dwRop3 & ~(NOMIRRORBITMAP|CAPTUREBLT);
756
757 return GreStretchBltMask(
758 hDCDest,
759 XOriginDest,
760 YOriginDest,
761 WidthDest,
762 HeightDest,
763 hDCSrc,
764 XOriginSrc,
765 YOriginSrc,
766 WidthSrc,
767 HeightSrc,
768 MAKEROP4(dwRop3 & 0xFF0000, dwRop3),
769 dwBackColor,
770 NULL,
771 0,
772 0);
773 }
774
775
776 BOOL FASTCALL
777 IntPatBlt(
778 PDC pdc,
779 INT XLeft,
780 INT YLeft,
781 INT Width,
782 INT Height,
783 DWORD dwRop3,
784 PEBRUSHOBJ pebo)
785 {
786 RECTL DestRect;
787 SURFACE *psurf;
788 POINTL BrushOrigin;
789 BOOL ret;
790 PBRUSH pbrush;
791
792 ASSERT(pebo);
793 pbrush = pebo->pbrush;
794 ASSERT(pbrush);
795
796 if (pbrush->flAttrs & BR_IS_NULL)
797 {
798 return TRUE;
799 }
800
801 if (Width > 0)
802 {
803 DestRect.left = XLeft;
804 DestRect.right = XLeft + Width;
805 }
806 else
807 {
808 DestRect.left = XLeft + Width + 1;
809 DestRect.right = XLeft + 1;
810 }
811
812 if (Height > 0)
813 {
814 DestRect.top = YLeft;
815 DestRect.bottom = YLeft + Height;
816 }
817 else
818 {
819 DestRect.top = YLeft + Height + 1;
820 DestRect.bottom = YLeft + 1;
821 }
822
823 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
824
825 DestRect.left += pdc->ptlDCOrig.x;
826 DestRect.top += pdc->ptlDCOrig.y;
827 DestRect.right += pdc->ptlDCOrig.x;
828 DestRect.bottom += pdc->ptlDCOrig.y;
829
830 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
831 {
832 IntUpdateBoundsRect(pdc, &DestRect);
833 }
834
835 #ifdef _USE_DIBLIB_
836 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x + XLeft;
837 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y + YLeft;
838 #else
839 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
840 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
841 #endif
842
843 DC_vPrepareDCsForBlit(pdc, &DestRect, NULL, NULL);
844
845 psurf = pdc->dclevel.pSurface;
846
847 ret = IntEngBitBlt(&psurf->SurfObj,
848 NULL,
849 NULL,
850 (CLIPOBJ *)&pdc->co,
851 NULL,
852 &DestRect,
853 NULL,
854 NULL,
855 &pebo->BrushObject,
856 &BrushOrigin,
857 WIN32_ROP3_TO_ENG_ROP4(dwRop3));
858
859 DC_vFinishBlit(pdc, NULL);
860
861 return ret;
862 }
863
864 BOOL FASTCALL
865 IntGdiPolyPatBlt(
866 HDC hDC,
867 DWORD dwRop,
868 PPATRECT pRects,
869 INT cRects,
870 ULONG Reserved)
871 {
872 INT i;
873 PBRUSH pbrush;
874 PDC pdc;
875 EBRUSHOBJ eboFill;
876
877 pdc = DC_LockDc(hDC);
878 if (!pdc)
879 {
880 EngSetLastError(ERROR_INVALID_HANDLE);
881 return FALSE;
882 }
883
884 if (pdc->dctype == DC_TYPE_INFO)
885 {
886 DC_UnlockDc(pdc);
887 /* Yes, Windows really returns TRUE in this case */
888 return TRUE;
889 }
890
891 for (i = 0; i < cRects; i++)
892 {
893 pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
894
895 /* Check if we could lock the brush */
896 if (pbrush != NULL)
897 {
898 /* Initialize a brush object */
899 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, pdc);
900
901 IntPatBlt(
902 pdc,
903 pRects->r.left,
904 pRects->r.top,
905 pRects->r.right,
906 pRects->r.bottom,
907 dwRop,
908 &eboFill);
909
910 /* Cleanup the brush object and unlock the brush */
911 EBRUSHOBJ_vCleanup(&eboFill);
912 BRUSH_ShareUnlockBrush(pbrush);
913 }
914 pRects++;
915 }
916
917 DC_UnlockDc(pdc);
918
919 return TRUE;
920 }
921
922 BOOL
923 APIENTRY
924 NtGdiPatBlt(
925 _In_ HDC hdcDest,
926 _In_ INT x,
927 _In_ INT y,
928 _In_ INT cx,
929 _In_ INT cy,
930 _In_ DWORD dwRop)
931 {
932 BOOL bResult;
933 PDC pdc;
934
935 /* Convert the ROP3 to a ROP4 */
936 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
937
938 /* Check if the rop uses a source */
939 if (WIN32_ROP4_USES_SOURCE(dwRop))
940 {
941 /* This is not possible */
942 return FALSE;
943 }
944
945 /* Lock the DC */
946 pdc = DC_LockDc(hdcDest);
947 if (pdc == NULL)
948 {
949 EngSetLastError(ERROR_INVALID_HANDLE);
950 return FALSE;
951 }
952
953 /* Check if the DC has no surface (empty mem or info DC) */
954 if (pdc->dclevel.pSurface == NULL)
955 {
956 /* Nothing to do, Windows returns TRUE! */
957 DC_UnlockDc(pdc);
958 return TRUE;
959 }
960
961 /* Update the fill brush, if necessary */
962 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
963 DC_vUpdateFillBrush(pdc);
964
965 /* Call the internal function */
966 bResult = IntPatBlt(pdc, x, y, cx, cy, dwRop, &pdc->eboFill);
967
968 /* Unlock the DC and return the result */
969 DC_UnlockDc(pdc);
970 return bResult;
971 }
972
973 BOOL
974 APIENTRY
975 NtGdiPolyPatBlt(
976 HDC hDC,
977 DWORD dwRop,
978 IN PPOLYPATBLT pRects,
979 IN DWORD cRects,
980 IN DWORD Mode)
981 {
982 PPATRECT rb = NULL;
983 NTSTATUS Status = STATUS_SUCCESS;
984 BOOL Ret;
985
986 if (cRects > 0)
987 {
988 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, GDITAG_PLGBLT_DATA);
989 if (!rb)
990 {
991 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
992 return FALSE;
993 }
994 _SEH2_TRY
995 {
996 ProbeForRead(pRects,
997 cRects * sizeof(PATRECT),
998 1);
999 RtlCopyMemory(rb,
1000 pRects,
1001 cRects * sizeof(PATRECT));
1002 }
1003 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1004 {
1005 Status = _SEH2_GetExceptionCode();
1006 }
1007 _SEH2_END;
1008
1009 if (!NT_SUCCESS(Status))
1010 {
1011 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1012 SetLastNtError(Status);
1013 return FALSE;
1014 }
1015 }
1016
1017 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1018
1019 if (cRects > 0)
1020 ExFreePoolWithTag(rb, GDITAG_PLGBLT_DATA);
1021
1022 return Ret;
1023 }
1024
1025 static
1026 BOOL
1027 FASTCALL
1028 REGION_LPTODP(
1029 _In_ PDC pdc,
1030 _Inout_ PREGION prgnDest,
1031 _In_ PREGION prgnSrc)
1032 {
1033 if (IntGdiCombineRgn(prgnDest, prgnSrc, NULL, RGN_COPY) == ERROR)
1034 return FALSE;
1035
1036 return REGION_bXformRgn(prgnDest, DC_pmxWorldToDevice(pdc));
1037 }
1038
1039 BOOL
1040 APIENTRY
1041 IntGdiBitBltRgn(
1042 _In_ PDC pdc,
1043 _In_ PREGION prgn,
1044 _In_opt_ BRUSHOBJ *pbo,
1045 _In_opt_ POINTL *pptlBrush,
1046 _In_ ROP4 rop4)
1047 {
1048 PREGION prgnClip;
1049 XCLIPOBJ xcoClip;
1050 BOOL bResult;
1051 NT_ASSERT((pdc != NULL) && (prgn != NULL));
1052
1053 /* Check if we have a surface */
1054 if (pdc->dclevel.pSurface == NULL)
1055 {
1056 return TRUE;
1057 }
1058
1059 /* Create an empty clip region */
1060 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1061 if (prgnClip == NULL)
1062 {
1063 return FALSE;
1064 }
1065
1066 /* Transform given region into device coordinates */
1067 if (!REGION_LPTODP(pdc, prgnClip, prgn))
1068 {
1069 REGION_Delete(prgnClip);
1070 return FALSE;
1071 }
1072
1073 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1074 if (pdc->prgnRao)
1075 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1076 else
1077 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1078
1079 /* Now account for the DC-origin */
1080 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1081 {
1082 REGION_Delete(prgnClip);
1083 return FALSE;
1084 }
1085
1086 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1087 {
1088 RECTL rcrgn;
1089 REGION_GetRgnBox(prgnClip, &rcrgn);
1090 IntUpdateBoundsRect(pdc, &rcrgn);
1091 }
1092
1093 /* Prepare the DC */
1094 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1095
1096 /* Initialize a clip object */
1097 IntEngInitClipObj(&xcoClip);
1098 IntEngUpdateClipRegion(&xcoClip,
1099 prgnClip->rdh.nCount,
1100 prgnClip->Buffer,
1101 &prgnClip->rdh.rcBound);
1102
1103 /* Call the Eng or Drv function */
1104 bResult = IntEngBitBlt(&pdc->dclevel.pSurface->SurfObj,
1105 NULL,
1106 NULL,
1107 (CLIPOBJ *)&xcoClip,
1108 NULL,
1109 &prgnClip->rdh.rcBound,
1110 NULL,
1111 NULL,
1112 pbo,
1113 pptlBrush,
1114 rop4);
1115
1116 /* Cleanup */
1117 DC_vFinishBlit(pdc, NULL);
1118 REGION_Delete(prgnClip);
1119 IntEngFreeClipResources(&xcoClip);
1120
1121 /* Return the result */
1122 return bResult;
1123 }
1124
1125 static
1126 BOOL
1127 IntGdiFillRgn(
1128 _In_ PDC pdc,
1129 _In_ PREGION prgn,
1130 _In_opt_ PBRUSH pbrFill)
1131 {
1132 PREGION prgnClip;
1133 XCLIPOBJ xcoClip;
1134 EBRUSHOBJ eboFill;
1135 BRUSHOBJ *pbo;
1136 BOOL bRet;
1137 DWORD rop2Fg;
1138 MIX mix;
1139 NT_ASSERT((pdc != NULL) && (prgn != NULL));
1140
1141 if (pdc->dclevel.pSurface == NULL)
1142 {
1143 return TRUE;
1144 }
1145
1146 prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1147 if (prgnClip == NULL)
1148 {
1149 return FALSE;
1150 }
1151
1152 /* Transform region into device coordinates */
1153 if (!REGION_LPTODP(pdc, prgnClip, prgn))
1154 {
1155 REGION_Delete(prgnClip);
1156 return FALSE;
1157 }
1158
1159 /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1160 if (pdc->prgnRao)
1161 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1162 else
1163 IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1164
1165 /* Now account for the DC-origin */
1166 if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1167 {
1168 REGION_Delete(prgnClip);
1169 return FALSE;
1170 }
1171
1172 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1173 {
1174 RECTL rcrgn;
1175 REGION_GetRgnBox(prgnClip, &rcrgn);
1176 IntUpdateBoundsRect(pdc, &rcrgn);
1177 }
1178
1179 IntEngInitClipObj(&xcoClip);
1180 IntEngUpdateClipRegion(&xcoClip,
1181 prgnClip->rdh.nCount,
1182 prgnClip->Buffer,
1183 &prgnClip->rdh.rcBound );
1184
1185 /* Get the FG rop and create a MIX based on the BK mode */
1186 rop2Fg = FIXUP_ROP2(pdc->pdcattr->jROP2);
1187 mix = rop2Fg | (pdc->pdcattr->jBkMode == OPAQUE ? rop2Fg : R2_NOP) << 8;
1188
1189 /* Prepare DC for blit */
1190 DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1191
1192 /* Check if we have a fill brush */
1193 if (pbrFill != NULL)
1194 {
1195 /* Initialize the brush object */
1196 /// \todo Check parameters
1197 EBRUSHOBJ_vInit(&eboFill, pbrFill, pdc->dclevel.pSurface, 0x00FFFFFF, 0, NULL);
1198 pbo = &eboFill.BrushObject;
1199 }
1200 else
1201 {
1202 /* Update the fill brush if needed */
1203 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1204 DC_vUpdateFillBrush(pdc);
1205
1206 /* Use the DC brush object */
1207 pbo = &pdc->eboFill.BrushObject;
1208 }
1209
1210 /* Call the internal function */
1211 bRet = IntEngPaint(&pdc->dclevel.pSurface->SurfObj,
1212 (CLIPOBJ *)&xcoClip,
1213 pbo,
1214 &pdc->pdcattr->ptlBrushOrigin,
1215 mix);
1216
1217 DC_vFinishBlit(pdc, NULL);
1218 REGION_Delete(prgnClip);
1219 IntEngFreeClipResources(&xcoClip);
1220
1221 // Fill the region
1222 return bRet;
1223 }
1224
1225 BOOL
1226 FASTCALL
1227 IntGdiPaintRgn(
1228 _In_ PDC pdc,
1229 _In_ PREGION prgn)
1230 {
1231 return IntGdiFillRgn(pdc, prgn, NULL);
1232 }
1233
1234 BOOL
1235 APIENTRY
1236 NtGdiFillRgn(
1237 _In_ HDC hdc,
1238 _In_ HRGN hrgn,
1239 _In_ HBRUSH hbrush)
1240 {
1241 PDC pdc;
1242 PREGION prgn;
1243 PBRUSH pbrFill;
1244 BOOL bResult;
1245
1246 /* Lock the DC */
1247 pdc = DC_LockDc(hdc);
1248 if (pdc == NULL)
1249 {
1250 ERR("Failed to lock hdc %p\n", hdc);
1251 return FALSE;
1252 }
1253
1254 /* Check if the DC has no surface (empty mem or info DC) */
1255 if (pdc->dclevel.pSurface == NULL)
1256 {
1257 DC_UnlockDc(pdc);
1258 return TRUE;
1259 }
1260
1261 /* Lock the region */
1262 prgn = REGION_LockRgn(hrgn);
1263 if (prgn == NULL)
1264 {
1265 ERR("Failed to lock hrgn %p\n", hrgn);
1266 DC_UnlockDc(pdc);
1267 return FALSE;
1268 }
1269
1270 /* Lock the brush */
1271 pbrFill = BRUSH_ShareLockBrush(hbrush);
1272 if (pbrFill == NULL)
1273 {
1274 ERR("Failed to lock hbrush %p\n", hbrush);
1275 REGION_UnlockRgn(prgn);
1276 DC_UnlockDc(pdc);
1277 return FALSE;
1278 }
1279
1280 /* Call the internal function */
1281 bResult = IntGdiFillRgn(pdc, prgn, pbrFill);
1282
1283 /* Cleanup locks */
1284 BRUSH_ShareUnlockBrush(pbrFill);
1285 REGION_UnlockRgn(prgn);
1286 DC_UnlockDc(pdc);
1287
1288 return bResult;
1289 }
1290
1291 BOOL
1292 APIENTRY
1293 NtGdiFrameRgn(
1294 _In_ HDC hdc,
1295 _In_ HRGN hrgn,
1296 _In_ HBRUSH hbrush,
1297 _In_ INT xWidth,
1298 _In_ INT yHeight)
1299 {
1300 HRGN hrgnFrame;
1301 BOOL bResult;
1302
1303 hrgnFrame = GreCreateFrameRgn(hrgn, xWidth, yHeight);
1304 if (hrgnFrame == NULL)
1305 {
1306 return FALSE;
1307 }
1308
1309 bResult = NtGdiFillRgn(hdc, hrgnFrame, hbrush);
1310
1311 GreDeleteObject(hrgnFrame);
1312 return bResult;
1313 }
1314
1315 BOOL
1316 APIENTRY
1317 NtGdiInvertRgn(
1318 _In_ HDC hdc,
1319 _In_ HRGN hrgn)
1320 {
1321 BOOL bResult;
1322 PDC pdc;
1323 PREGION prgn;
1324
1325 /* Lock the DC */
1326 pdc = DC_LockDc(hdc);
1327 if (pdc == NULL)
1328 {
1329 EngSetLastError(ERROR_INVALID_HANDLE);
1330 return FALSE;
1331 }
1332
1333 /* Check if the DC has no surface (empty mem or info DC) */
1334 if (pdc->dclevel.pSurface == NULL)
1335 {
1336 /* Nothing to do, Windows returns TRUE! */
1337 DC_UnlockDc(pdc);
1338 return TRUE;
1339 }
1340
1341 /* Lock the region */
1342 prgn = REGION_LockRgn(hrgn);
1343 if (prgn == NULL)
1344 {
1345 DC_UnlockDc(pdc);
1346 return FALSE;
1347 }
1348
1349 /* Call the internal function */
1350 bResult = IntGdiBitBltRgn(pdc,
1351 prgn,
1352 NULL, // pbo
1353 NULL, // pptlBrush,
1354 ROP4_DSTINVERT);
1355
1356 /* Unlock the region and DC and return the result */
1357 REGION_UnlockRgn(prgn);
1358 DC_UnlockDc(pdc);
1359 return bResult;
1360 }
1361
1362 COLORREF
1363 APIENTRY
1364 NtGdiSetPixel(
1365 _In_ HDC hdc,
1366 _In_ INT x,
1367 _In_ INT y,
1368 _In_ COLORREF crColor)
1369 {
1370 PDC pdc;
1371 ULONG iOldColor, iSolidColor;
1372 BOOL bResult;
1373 PEBRUSHOBJ pebo;
1374 ULONG ulDirty;
1375 EXLATEOBJ exlo;
1376
1377 /* Lock the DC */
1378 pdc = DC_LockDc(hdc);
1379 if (!pdc)
1380 {
1381 EngSetLastError(ERROR_INVALID_HANDLE);
1382 return -1;
1383 }
1384
1385 /* Check if the DC has no surface (empty mem or info DC) */
1386 if (pdc->dclevel.pSurface == NULL)
1387 {
1388 /* Fail! */
1389 DC_UnlockDc(pdc);
1390 return -1;
1391 }
1392
1393 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1394 {
1395 RECTL rcDst;
1396
1397 RECTL_vSetRect(&rcDst, x, y, x+1, y+1);
1398
1399 IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
1400
1401 rcDst.left += pdc->ptlDCOrig.x;
1402 rcDst.top += pdc->ptlDCOrig.y;
1403 rcDst.right += pdc->ptlDCOrig.x;
1404 rcDst.bottom += pdc->ptlDCOrig.y;
1405
1406 IntUpdateBoundsRect(pdc, &rcDst);
1407 }
1408
1409 /* Translate the color to the target format */
1410 iSolidColor = TranslateCOLORREF(pdc, crColor);
1411
1412 /* Use the DC's text brush, which is always a solid brush */
1413 pebo = &pdc->eboText;
1414
1415 /* Save the old solid color and set the one for the pixel */
1416 iOldColor = EBRUSHOBJ_iSetSolidColor(pebo, iSolidColor);
1417
1418 /* Save dirty flags and reset dirty text brush flag */
1419 ulDirty = pdc->pdcattr->ulDirty_;
1420 pdc->pdcattr->ulDirty_ &= ~DIRTY_TEXT;
1421
1422 /* Call the internal function */
1423 bResult = IntPatBlt(pdc, x, y, 1, 1, PATCOPY, pebo);
1424
1425 /* Restore old text brush color and dirty flags */
1426 EBRUSHOBJ_iSetSolidColor(pebo, iOldColor);
1427 pdc->pdcattr->ulDirty_ = ulDirty;
1428
1429 /// FIXME: we shouldn't dereference pSurface while the PDEV is not locked!
1430 /* Initialize an XLATEOBJ from the target surface to RGB */
1431 EXLATEOBJ_vInitialize(&exlo,
1432 pdc->dclevel.pSurface->ppal,
1433 &gpalRGB,
1434 0,
1435 pdc->pdcattr->crBackgroundClr,
1436 pdc->pdcattr->crForegroundClr);
1437
1438 /* Translate the color back to RGB */
1439 crColor = XLATEOBJ_iXlate(&exlo.xlo, iSolidColor);
1440
1441 /* Cleanup and return the target format color */
1442 EXLATEOBJ_vCleanup(&exlo);
1443
1444 /* Unlock the DC */
1445 DC_UnlockDc(pdc);
1446
1447 /* Return the new RGB color or -1 on failure */
1448 return bResult ? crColor : -1;
1449 }
1450
1451 COLORREF
1452 APIENTRY
1453 NtGdiGetPixel(
1454 _In_ HDC hdc,
1455 _In_ INT x,
1456 _In_ INT y)
1457 {
1458 PDC pdc;
1459 ULONG ulRGBColor = CLR_INVALID;
1460 POINTL ptlSrc;
1461 RECT rcDest;
1462 PSURFACE psurfSrc, psurfDest;
1463
1464 /* Lock the DC */
1465 pdc = DC_LockDc(hdc);
1466 if (!pdc)
1467 {
1468 EngSetLastError(ERROR_INVALID_HANDLE);
1469 return CLR_INVALID;
1470 }
1471
1472 /* Check if the DC has no surface (empty mem or info DC) */
1473 if (pdc->dclevel.pSurface == NULL)
1474 {
1475 /* Fail! */
1476 goto leave;
1477 }
1478
1479 /* Get the logical coordinates */
1480 ptlSrc.x = x;
1481 ptlSrc.y = y;
1482
1483 /* Translate coordinates to device coordinates */
1484 IntLPtoDP(pdc, &ptlSrc, 1);
1485 ptlSrc.x += pdc->ptlDCOrig.x;
1486 ptlSrc.y += pdc->ptlDCOrig.y;
1487
1488 rcDest.left = x;
1489 rcDest.top = y;
1490 rcDest.right = x + 1;
1491 rcDest.bottom = y + 1;
1492
1493 /* Prepare DC for blit */
1494 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1495
1496 /* Check if the pixel is outside the surface */
1497 psurfSrc = pdc->dclevel.pSurface;
1498 if ((ptlSrc.x >= psurfSrc->SurfObj.sizlBitmap.cx) ||
1499 (ptlSrc.y >= psurfSrc->SurfObj.sizlBitmap.cy) ||
1500 (ptlSrc.x < 0) ||
1501 (ptlSrc.y < 0))
1502 {
1503 /* Fail! */
1504 goto leave;
1505 }
1506
1507 /* Allocate a surface */
1508 psurfDest = SURFACE_AllocSurface(STYPE_BITMAP,
1509 1,
1510 1,
1511 BMF_32BPP,
1512 0,
1513 0,
1514 0,
1515 &ulRGBColor);
1516 if (psurfDest)
1517 {
1518 RECTL rclDest = {0, 0, 1, 1};
1519 EXLATEOBJ exlo;
1520
1521 /* Translate from the source palette to RGB color */
1522 EXLATEOBJ_vInitialize(&exlo,
1523 psurfSrc->ppal,
1524 &gpalRGB,
1525 0,
1526 RGB(0xff,0xff,0xff),
1527 RGB(0,0,0));
1528
1529 /* Call the copy bits function */
1530 EngCopyBits(&psurfDest->SurfObj,
1531 &psurfSrc->SurfObj,
1532 NULL,
1533 &exlo.xlo,
1534 &rclDest,
1535 &ptlSrc);
1536
1537 /* Cleanup the XLATEOBJ */
1538 EXLATEOBJ_vCleanup(&exlo);
1539
1540 /* Delete the surface */
1541 GDIOBJ_vDeleteObject(&psurfDest->BaseObject);
1542 }
1543
1544 leave:
1545
1546 /* Unlock the DC */
1547 DC_vFinishBlit(pdc, NULL);
1548 DC_UnlockDc(pdc);
1549
1550 /* Return the new RGB color or -1 on failure */
1551 return ulRGBColor;
1552 }
1553