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