xref: /reactos/win32ss/gdi/ntgdi/bitblt.c (revision 02e84521)
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 BOOL
1126 IntGdiFillRgn(
1127     _In_ PDC pdc,
1128     _In_ PREGION prgn,
1129     _In_opt_ PBRUSH pbrFill)
1130 {
1131     PREGION prgnClip;
1132     XCLIPOBJ xcoClip;
1133     EBRUSHOBJ eboFill;
1134     BRUSHOBJ *pbo;
1135     BOOL bRet;
1136     DWORD rop2Fg;
1137     MIX mix;
1138     NT_ASSERT((pdc != NULL) && (prgn != NULL));
1139 
1140     if (pdc->dclevel.pSurface == NULL)
1141     {
1142         return TRUE;
1143     }
1144 
1145     prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
1146     if (prgnClip == NULL)
1147     {
1148         return FALSE;
1149     }
1150 
1151     /* Transform region into device coordinates */
1152     if (!REGION_LPTODP(pdc, prgnClip, prgn))
1153     {
1154         REGION_Delete(prgnClip);
1155         return FALSE;
1156     }
1157 
1158     /* Intersect with the system or RAO region (these are (atm) without DC-origin) */
1159     if (pdc->prgnRao)
1160         IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
1161     else
1162         IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
1163 
1164     /* Now account for the DC-origin */
1165     if (!REGION_bOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y))
1166     {
1167         REGION_Delete(prgnClip);
1168         return FALSE;
1169     }
1170 
1171     if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1172     {
1173         RECTL rcrgn;
1174         REGION_GetRgnBox(prgnClip, &rcrgn);
1175         IntUpdateBoundsRect(pdc, &rcrgn);
1176     }
1177 
1178     IntEngInitClipObj(&xcoClip);
1179     IntEngUpdateClipRegion(&xcoClip,
1180                            prgnClip->rdh.nCount,
1181                            prgnClip->Buffer,
1182                            &prgnClip->rdh.rcBound );
1183 
1184     /* Get the FG rop and create a MIX based on the BK mode */
1185     rop2Fg = FIXUP_ROP2(pdc->pdcattr->jROP2);
1186     mix = rop2Fg | (pdc->pdcattr->jBkMode == OPAQUE ? rop2Fg : R2_NOP) << 8;
1187 
1188     /* Prepare DC for blit */
1189     DC_vPrepareDCsForBlit(pdc, &prgnClip->rdh.rcBound, NULL, NULL);
1190 
1191     /* Check if we have a fill brush */
1192     if (pbrFill != NULL)
1193     {
1194         /* Initialize the brush object */
1195         /// \todo Check parameters
1196         EBRUSHOBJ_vInit(&eboFill, pbrFill, pdc->dclevel.pSurface, 0x00FFFFFF, 0, NULL);
1197         pbo = &eboFill.BrushObject;
1198     }
1199     else
1200     {
1201         /* Update the fill brush if needed */
1202         if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1203             DC_vUpdateFillBrush(pdc);
1204 
1205         /* Use the DC brush object */
1206         pbo = &pdc->eboFill.BrushObject;
1207     }
1208 
1209     /* Call the internal function */
1210     bRet = IntEngPaint(&pdc->dclevel.pSurface->SurfObj,
1211                        (CLIPOBJ *)&xcoClip,
1212                        pbo,
1213                        &pdc->pdcattr->ptlBrushOrigin,
1214                        mix);
1215 
1216     DC_vFinishBlit(pdc, NULL);
1217     REGION_Delete(prgnClip);
1218     IntEngFreeClipResources(&xcoClip);
1219 
1220     // Fill the region
1221     return bRet;
1222 }
1223 
1224 BOOL
1225 FASTCALL
1226 IntGdiPaintRgn(
1227     _In_ PDC pdc,
1228     _In_ PREGION prgn)
1229 {
1230     return IntGdiFillRgn(pdc, prgn, NULL);
1231 }
1232 
1233 BOOL
1234 APIENTRY
1235 NtGdiFillRgn(
1236     _In_ HDC hdc,
1237     _In_ HRGN hrgn,
1238     _In_ HBRUSH hbrush)
1239 {
1240     PDC pdc;
1241     PREGION prgn;
1242     PBRUSH pbrFill;
1243     BOOL bResult;
1244 
1245     /* Lock the DC */
1246     pdc = DC_LockDc(hdc);
1247     if (pdc == NULL)
1248     {
1249         ERR("Failed to lock hdc %p\n", hdc);
1250         return FALSE;
1251     }
1252 
1253     /* Check if the DC has no surface (empty mem or info DC) */
1254     if (pdc->dclevel.pSurface == NULL)
1255     {
1256         DC_UnlockDc(pdc);
1257         return TRUE;
1258     }
1259 
1260     /* Lock the region */
1261     prgn = REGION_LockRgn(hrgn);
1262     if (prgn == NULL)
1263     {
1264         ERR("Failed to lock hrgn %p\n", hrgn);
1265         DC_UnlockDc(pdc);
1266         return FALSE;
1267     }
1268 
1269     /* Lock the brush */
1270     pbrFill = BRUSH_ShareLockBrush(hbrush);
1271     if (pbrFill == NULL)
1272     {
1273         ERR("Failed to lock hbrush %p\n", hbrush);
1274         REGION_UnlockRgn(prgn);
1275         DC_UnlockDc(pdc);
1276         return FALSE;
1277     }
1278 
1279     /* Call the internal function */
1280     bResult = IntGdiFillRgn(pdc, prgn, pbrFill);
1281 
1282     /* Cleanup locks */
1283     BRUSH_ShareUnlockBrush(pbrFill);
1284     REGION_UnlockRgn(prgn);
1285     DC_UnlockDc(pdc);
1286 
1287     return bResult;
1288 }
1289 
1290 BOOL
1291 APIENTRY
1292 NtGdiFrameRgn(
1293     _In_ HDC hdc,
1294     _In_ HRGN hrgn,
1295     _In_ HBRUSH hbrush,
1296     _In_ INT xWidth,
1297     _In_ INT yHeight)
1298 {
1299     HRGN hrgnFrame;
1300     BOOL bResult;
1301 
1302     hrgnFrame = GreCreateFrameRgn(hrgn, xWidth, yHeight);
1303     if (hrgnFrame == NULL)
1304     {
1305         return FALSE;
1306     }
1307 
1308     bResult = NtGdiFillRgn(hdc, hrgnFrame, hbrush);
1309 
1310     GreDeleteObject(hrgnFrame);
1311     return bResult;
1312 }
1313 
1314 BOOL
1315 APIENTRY
1316 NtGdiInvertRgn(
1317     _In_ HDC hdc,
1318     _In_ HRGN hrgn)
1319 {
1320     BOOL bResult;
1321     PDC pdc;
1322     PREGION prgn;
1323 
1324     /* Lock the DC */
1325     pdc = DC_LockDc(hdc);
1326     if (pdc == NULL)
1327     {
1328         EngSetLastError(ERROR_INVALID_HANDLE);
1329         return FALSE;
1330     }
1331 
1332     /* Check if the DC has no surface (empty mem or info DC) */
1333     if (pdc->dclevel.pSurface == NULL)
1334     {
1335         /* Nothing to do, Windows returns TRUE! */
1336         DC_UnlockDc(pdc);
1337         return TRUE;
1338     }
1339 
1340     /* Lock the region */
1341     prgn = REGION_LockRgn(hrgn);
1342     if (prgn == NULL)
1343     {
1344         DC_UnlockDc(pdc);
1345         return FALSE;
1346     }
1347 
1348     /* Call the internal function */
1349     bResult = IntGdiBitBltRgn(pdc,
1350                               prgn,
1351                               NULL, // pbo
1352                               NULL, // pptlBrush,
1353                               ROP4_DSTINVERT);
1354 
1355     /* Unlock the region and DC and return the result */
1356     REGION_UnlockRgn(prgn);
1357     DC_UnlockDc(pdc);
1358     return bResult;
1359 }
1360 
1361 COLORREF
1362 APIENTRY
1363 NtGdiSetPixel(
1364     _In_ HDC hdc,
1365     _In_ INT x,
1366     _In_ INT y,
1367     _In_ COLORREF crColor)
1368 {
1369     PDC pdc;
1370     ULONG iOldColor, iSolidColor;
1371     BOOL bResult;
1372     PEBRUSHOBJ pebo;
1373     ULONG ulDirty;
1374     EXLATEOBJ exlo;
1375 
1376     /* Lock the DC */
1377     pdc = DC_LockDc(hdc);
1378     if (!pdc)
1379     {
1380         EngSetLastError(ERROR_INVALID_HANDLE);
1381         return -1;
1382     }
1383 
1384     /* Check if the DC has no surface (empty mem or info DC) */
1385     if (pdc->dclevel.pSurface == NULL)
1386     {
1387         /* Fail! */
1388         DC_UnlockDc(pdc);
1389         return -1;
1390     }
1391 
1392     if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1393     {
1394        RECTL rcDst;
1395 
1396        RECTL_vSetRect(&rcDst, x, y, x+1, y+1);
1397 
1398        IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
1399 
1400        rcDst.left   += pdc->ptlDCOrig.x;
1401        rcDst.top    += pdc->ptlDCOrig.y;
1402        rcDst.right  += pdc->ptlDCOrig.x;
1403        rcDst.bottom += pdc->ptlDCOrig.y;
1404 
1405        IntUpdateBoundsRect(pdc, &rcDst);
1406     }
1407 
1408     /* Translate the color to the target format */
1409     iSolidColor = TranslateCOLORREF(pdc, crColor);
1410 
1411     /* Use the DC's text brush, which is always a solid brush */
1412     pebo = &pdc->eboText;
1413 
1414     /* Save the old solid color and set the one for the pixel */
1415     iOldColor = EBRUSHOBJ_iSetSolidColor(pebo, iSolidColor);
1416 
1417     /* Save dirty flags and reset dirty text brush flag */
1418     ulDirty = pdc->pdcattr->ulDirty_;
1419     pdc->pdcattr->ulDirty_ &= ~DIRTY_TEXT;
1420 
1421     /* Call the internal function */
1422     bResult = IntPatBlt(pdc, x, y, 1, 1, PATCOPY, pebo);
1423 
1424     /* Restore old text brush color and dirty flags */
1425     EBRUSHOBJ_iSetSolidColor(pebo, iOldColor);
1426     pdc->pdcattr->ulDirty_ = ulDirty;
1427 
1428     /// FIXME: we shouldn't dereference pSurface while the PDEV is not locked!
1429     /* Initialize an XLATEOBJ from the target surface to RGB */
1430     EXLATEOBJ_vInitialize(&exlo,
1431                           pdc->dclevel.pSurface->ppal,
1432                           &gpalRGB,
1433                           0,
1434                           pdc->pdcattr->crBackgroundClr,
1435                           pdc->pdcattr->crForegroundClr);
1436 
1437     /* Translate the color back to RGB */
1438     crColor = XLATEOBJ_iXlate(&exlo.xlo, iSolidColor);
1439 
1440     /* Cleanup and return the target format color */
1441     EXLATEOBJ_vCleanup(&exlo);
1442 
1443     /* Unlock the DC */
1444     DC_UnlockDc(pdc);
1445 
1446     /* Return the new RGB color or -1 on failure */
1447     return bResult ? crColor : -1;
1448 }
1449 
1450 COLORREF
1451 APIENTRY
1452 NtGdiGetPixel(
1453     _In_ HDC hdc,
1454     _In_ INT x,
1455     _In_ INT y)
1456 {
1457     PDC pdc;
1458     ULONG ulRGBColor = CLR_INVALID;
1459     POINTL ptlSrc;
1460     RECT rcDest;
1461     PSURFACE psurfSrc, psurfDest;
1462 
1463     /* Lock the DC */
1464     pdc = DC_LockDc(hdc);
1465     if (!pdc)
1466     {
1467         EngSetLastError(ERROR_INVALID_HANDLE);
1468         return CLR_INVALID;
1469     }
1470 
1471     /* Check if the DC has no surface (empty mem or info DC) */
1472     if (pdc->dclevel.pSurface == NULL)
1473     {
1474         /* Fail! */
1475         goto leave;
1476     }
1477 
1478     /* Get the logical coordinates */
1479     ptlSrc.x = x;
1480     ptlSrc.y = y;
1481 
1482     /* Translate coordinates to device coordinates */
1483     IntLPtoDP(pdc, &ptlSrc, 1);
1484     ptlSrc.x += pdc->ptlDCOrig.x;
1485     ptlSrc.y += pdc->ptlDCOrig.y;
1486 
1487     rcDest.left = x;
1488     rcDest.top = y;
1489     rcDest.right = x + 1;
1490     rcDest.bottom = y + 1;
1491 
1492     /* Prepare DC for blit */
1493     DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1494 
1495     /* Check if the pixel is outside the surface */
1496     psurfSrc = pdc->dclevel.pSurface;
1497     if ((ptlSrc.x >= psurfSrc->SurfObj.sizlBitmap.cx) ||
1498         (ptlSrc.y >= psurfSrc->SurfObj.sizlBitmap.cy) ||
1499         (ptlSrc.x < 0) ||
1500         (ptlSrc.y < 0))
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 
1553