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