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