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