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