xref: /reactos/win32ss/gdi/eng/bitblt_new.c (revision 40462c92)
1 
2 #include <win32k.h>
3 #include "../diblib/DibLib_interface.h"
4 DBG_DEFAULT_CHANNEL(GdiFont);
5 
6 #define SURFOBJ_flags(pso) (CONTAINING_RECORD(pso, SURFACE, SurfObj)->flags)
7 
8 // FIXME this needs to be updated, once we use the new structure
9 extern XCLIPOBJ gxcoTrivial;
10 /*
11 {
12     {0, {LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX}, DC_TRIVIAL, FC_RECT, TC_RECTANGLES, 0},
13     0, 0, 0
14 };
15 */
16 
17 static
18 void
19 CalculateCoordinates(
20     PBLTDATA pbltdata,
21     PRECTL prclClipped,
22     PRECTL prclOrg,
23     PPOINTL pptlSrc,
24     PPOINTL pptlMask,
25     PPOINTL pptlPat,
26     PSIZEL psizlPat)
27 {
28     ULONG cx, cy;
29 
30     /* Calculate width and height of this rect */
31     pbltdata->ulWidth = prclClipped->right - prclClipped->left;
32     pbltdata->ulHeight = prclClipped->bottom - prclClipped->top;
33 
34     /* Calculate the x offset to the origin coordinates */
35     if (pbltdata->siDst.iFormat == 0)
36         cx = (prclClipped->right - 1 - prclOrg->left);
37     else
38         cx = (prclClipped->left - prclOrg->left);
39 
40     /* Calculate the y offset to the origin coordinates */
41     if (pbltdata->dy < 0)
42         cy = (prclClipped->bottom - 1 - prclOrg->top);
43     else
44         cy = (prclClipped->top - prclOrg->top);
45 
46     /* Calculate the target start point */
47     pbltdata->siDst.ptOrig.x = prclOrg->left + cx;
48     pbltdata->siDst.ptOrig.y = prclOrg->top + cy;
49 
50     /* Calculate start position for target */
51     pbltdata->siDst.pjBase = pbltdata->siDst.pvScan0;
52     pbltdata->siDst.pjBase += pbltdata->siDst.ptOrig.y * pbltdata->siDst.lDelta;
53     pbltdata->siDst.pjBase += pbltdata->siDst.ptOrig.x * pbltdata->siDst.jBpp / 8;
54 
55     if (pptlSrc)
56     {
57         /* Calculate start point and bitpointer for source */
58         pbltdata->siSrc.ptOrig.x = pptlSrc->x + cx;
59         pbltdata->siSrc.ptOrig.y = pptlSrc->y + cy;
60         pbltdata->siSrc.pjBase = pbltdata->siSrc.pvScan0;
61         pbltdata->siSrc.pjBase += pbltdata->siSrc.ptOrig.y * pbltdata->siSrc.lDelta;
62         pbltdata->siSrc.pjBase += pbltdata->siSrc.ptOrig.x * pbltdata->siSrc.jBpp / 8;
63     }
64 
65     if (pptlMask)
66     {
67         /* Calculate start point and bitpointer for mask */
68         pbltdata->siMsk.ptOrig.x = pptlMask->x + cx;
69         pbltdata->siMsk.ptOrig.y = pptlMask->y + cy;
70         pbltdata->siMsk.pjBase = pbltdata->siMsk.pvScan0;
71         pbltdata->siMsk.pjBase += pbltdata->siMsk.ptOrig.y * pbltdata->siMsk.lDelta;
72         pbltdata->siMsk.pjBase += pbltdata->siMsk.ptOrig.x * pbltdata->siMsk.jBpp / 8;
73     }
74 
75     if (pptlPat)
76     {
77         /* Calculate start point and bitpointer for pattern */
78         pbltdata->siPat.ptOrig.x = (pptlPat->x + cx) % psizlPat->cx;
79         pbltdata->siPat.ptOrig.y = (pptlPat->y + cy) % psizlPat->cy;
80         pbltdata->siPat.pjBase = pbltdata->siPat.pvScan0;
81 
82         /* Check for bottom-up case */
83         if (pbltdata->dy < 0)
84         {
85             pbltdata->siPat.pjBase += (psizlPat->cy - 1) * pbltdata->siPat.lDelta;
86             pbltdata->siPat.ptOrig.y = psizlPat->cy - 1 - pbltdata->siPat.ptOrig.y;
87         }
88 
89         /* Check for right-to-left case */
90         if (pbltdata->siDst.iFormat == 0)
91         {
92             pbltdata->siPat.pjBase += (psizlPat->cx - 1) * pbltdata->siMsk.jBpp / 8;
93             pbltdata->siPat.ptOrig.x = psizlPat->cx - 1 - pbltdata->siPat.ptOrig.x;
94         }
95     }
96 }
97 
98 BOOL
99 APIENTRY
100 EngBitBlt(
101     _Inout_ SURFOBJ *psoTrg,
102     _In_opt_ SURFOBJ *psoSrc,
103     _In_opt_ SURFOBJ *psoMask,
104     _In_opt_ CLIPOBJ *pco,
105     _In_opt_ XLATEOBJ *pxlo,
106     _In_ RECTL *prclTrg,
107     _When_(psoSrc, _In_) POINTL *pptlSrc,
108     _When_(psoMask, _In_) POINTL *pptlMask,
109     _In_opt_ BRUSHOBJ *pbo,
110     _When_(pbo, _In_) POINTL *pptlBrush,
111     _In_ ROP4 rop4)
112 {
113     BLTDATA bltdata;
114     ULONG i, iFunctionIndex, iDirection = CD_ANY;
115     RECTL rcTrg;
116     PFN_DIBFUNCTION pfnBitBlt;
117     BOOL bEnumMore;
118     RECT_ENUM rcenum;
119     PSIZEL psizlPat;
120     SURFOBJ *psoPattern;
121 
122 //static int count = 0;
123 //if (++count >= 1230) __debugbreak();
124 
125     /* Sanity checks */
126     ASSERT(psoTrg);
127     ASSERT(psoTrg->iBitmapFormat >= BMF_1BPP);
128     ASSERT(psoTrg->iBitmapFormat <= BMF_32BPP);
129     ASSERT(prclTrg);
130     ASSERT(prclTrg->left >= 0);
131     ASSERT(prclTrg->top >= 0);
132     ASSERT(prclTrg->right <= psoTrg->sizlBitmap.cx);
133     ASSERT(prclTrg->bottom <= psoTrg->sizlBitmap.cy);
134 
135     rcTrg = *prclTrg;
136 
137     bltdata.dy = 1;
138     bltdata.rop4 = rop4;
139     bltdata.apfnDoRop[0] = gapfnRop[ROP4_BKGND(rop4)];
140     bltdata.apfnDoRop[1] = gapfnRop[ROP4_FGND(rop4)];
141     if (!pxlo) pxlo = &gexloTrivial.xlo;
142     bltdata.pxlo = pxlo;
143     bltdata.pfnXlate = XLATEOBJ_pfnXlate(pxlo);
144 
145     /* Check if the ROP uses a source */
146     if (ROP4_USES_SOURCE(rop4))
147     {
148         /* Sanity checks */
149         ASSERT(psoSrc);
150         ASSERT(psoSrc->iBitmapFormat >= BMF_1BPP);
151         ASSERT(psoSrc->iBitmapFormat <= BMF_32BPP);
152         ASSERT(pptlSrc);
153         ASSERT(pptlSrc->x >= 0);
154         ASSERT(pptlSrc->y >= 0);
155         ASSERT(pptlSrc->x <= psoSrc->sizlBitmap.cx);
156         ASSERT(pptlSrc->y <= psoSrc->sizlBitmap.cy);
157 
158         /* Check if source and target are equal */
159         if (psoSrc == psoTrg)
160         {
161             /* Analyze the copying direction */
162             if (rcTrg.top > pptlSrc->y)
163             {
164                 /* Need to copy from bottom to top */
165                 iDirection = rcTrg.left < pptlSrc->x ? CD_RIGHTUP : CD_LEFTUP;
166                 bltdata.dy = -1;
167             }
168             else
169                 iDirection = rcTrg.left < pptlSrc->x ? CD_RIGHTDOWN : CD_LEFTDOWN;
170 
171             /* Check for special right to left case */
172             if ((rcTrg.top == pptlSrc->y) && (rcTrg.left > pptlSrc->x))
173             {
174                 /* Use 0 as target format to get special right to left versions */
175                 bltdata.siDst.iFormat = 0;
176                 bltdata.siSrc.iFormat = psoSrc->iBitmapFormat;
177                 //__debugbreak();
178             }
179             else
180             {
181                 /* Use 0 as source format to get special equal surface versions */
182                 bltdata.siDst.iFormat = psoTrg->iBitmapFormat;
183                 bltdata.siSrc.iFormat = 0;
184             }
185         }
186         else
187         {
188             bltdata.siDst.iFormat = psoTrg->iBitmapFormat;
189             bltdata.siSrc.iFormat = psoSrc->iBitmapFormat;
190         }
191 
192         /* Set the source format info */
193         bltdata.siSrc.pvScan0 = psoSrc->pvScan0;
194         bltdata.siSrc.lDelta = psoSrc->lDelta;
195         bltdata.siSrc.cjAdvanceY = bltdata.dy * psoSrc->lDelta;
196         bltdata.siSrc.jBpp = gajBitsPerFormat[psoSrc->iBitmapFormat];
197     }
198     else
199     {
200         bltdata.siDst.iFormat = psoTrg->iBitmapFormat;
201     }
202 
203     /* Set the destination format info */
204     bltdata.siDst.pvScan0 = psoTrg->pvScan0;
205     bltdata.siDst.lDelta = psoTrg->lDelta;
206     bltdata.siDst.cjAdvanceY = bltdata.dy * psoTrg->lDelta;
207     bltdata.siDst.jBpp = gajBitsPerFormat[psoTrg->iBitmapFormat];
208 
209     /* Check if the ROP uses a pattern / brush */
210     if (ROP4_USES_PATTERN(rop4))
211     {
212         /* Must have a brush */
213         NT_ASSERT(pbo); // FIXME: test this!
214 
215         /* Copy the solid color */
216         bltdata.ulSolidColor = pbo->iSolidColor;
217 
218         /* Check if this is a pattern brush */
219         if (pbo->iSolidColor == 0xFFFFFFFF)
220         {
221             /* Get the realized pattern bitmap */
222             psoPattern = BRUSHOBJ_psoPattern(pbo);
223             if (!psoPattern)
224             {
225                 __debugbreak();
226                 return FALSE;
227             }
228 
229             /* Set the pattern format info */
230             bltdata.siPat.iFormat = psoPattern->iBitmapFormat;
231             bltdata.siPat.pvScan0 = psoPattern->pvScan0;
232             bltdata.siPat.lDelta = psoPattern->lDelta;
233             bltdata.siPat.cjAdvanceY = bltdata.dy * psoPattern->lDelta;
234             bltdata.siPat.jBpp = gajBitsPerFormat[psoPattern->iBitmapFormat];
235 
236             bltdata.ulPatWidth = psoPattern->sizlBitmap.cx;
237             bltdata.ulPatHeight = psoPattern->sizlBitmap.cy;
238 
239             psizlPat = &psoPattern->sizlBitmap;
240         }
241         else
242         {
243             pptlBrush = NULL;
244             psizlPat = NULL;
245         }
246     }
247     else
248     {
249         pptlBrush = NULL;
250         psizlPat = NULL;
251     }
252 
253     /* Check if the ROP uses a mask */
254     if (ROP4_USES_MASK(rop4))
255     {
256         //__debugbreak();
257 
258         /* Check if we don't have a mask surface */
259         if (psoMask == NULL)
260         {
261             /* Must have a brush */
262             NT_ASSERT(pbo); // FIXME: test this!
263 
264             /* Check if the BRUSHOBJ can provide the mask */
265             psoMask = BRUSHOBJ_psoMask(pbo);
266             if (psoMask == NULL)
267             {
268                 /* We have no mask, assume the mask is all foreground */
269                 rop4 = (rop4 & 0xFF) || ((rop4 & 0xFF) << 8);
270             }
271         }
272 
273         /* Set the mask format info */
274         bltdata.siMsk.iFormat = psoMask->iBitmapFormat;
275         bltdata.siMsk.pvScan0 = psoMask->pvScan0;
276         bltdata.siMsk.lDelta = psoMask->lDelta;
277         bltdata.siMsk.cjAdvanceY = bltdata.dy * psoMask->lDelta;
278         bltdata.siMsk.jBpp = 1;
279 
280         /* Calculate the masking function index */
281         iFunctionIndex = ROP4_USES_PATTERN(rop4) ? 1 : 0;
282         iFunctionIndex |= ROP4_USES_SOURCE(rop4) ? 2 : 0;
283         iFunctionIndex |= ROP4_USES_DEST(rop4) ? 4 : 0;
284 
285         /* Get the masking function */
286         pfnBitBlt = gapfnMaskFunction[iFunctionIndex];
287     }
288     else
289     {
290         /* Get the function index from the foreground ROP index*/
291         iFunctionIndex = gajIndexPerRop[ROP4_FGND(rop4)];
292 
293         /* Get the dib function */
294         pfnBitBlt = gapfnDibFunction[iFunctionIndex];
295     }
296 
297     /* If no clip object is given, use trivial one */
298     if (!pco) pco = (CLIPOBJ*)&gxcoTrivial;
299 
300     /* Check if we need to enumerate rects */
301     if (pco->iDComplexity == DC_COMPLEX)
302     {
303         /* Start the enumeration of the clip object */
304         CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iDirection, 0);
305         bEnumMore = CLIPOBJ_bEnum(pco, sizeof(rcenum), (ULONG*)&rcenum);
306     }
307     else if (pco->iDComplexity == DC_RECT)
308     {
309         /* Use the clip bounds */
310         rcenum.arcl[0] = pco->rclBounds;
311         rcenum.c = 1;
312         bEnumMore = FALSE;
313     }
314     else
315     {
316         /* Use the target rect */
317         rcenum.arcl[0] = rcTrg;
318         rcenum.c = 1;
319         bEnumMore = FALSE;
320     }
321 
322     /* Enter enumeration loop */
323     while (TRUE)
324     {
325         /* Loop all rectangles we got */
326         for (i = 0; i < rcenum.c; i++)
327         {
328             /* Intersect this rect with the target rect */
329             if (!RECTL_bIntersectRect(&rcenum.arcl[i], &rcenum.arcl[i], &rcTrg))
330             {
331                 /* This rect is outside the bounds, continue */
332                 continue;
333             }
334 
335             /* Calculate coordinates and pointers */
336             CalculateCoordinates(&bltdata,
337                                  &rcenum.arcl[i],
338                                  prclTrg,
339                                  pptlSrc,
340                                  pptlMask,
341                                  pptlBrush,
342                                  psizlPat);
343 
344             /* Call the dib function */
345             pfnBitBlt(&bltdata);
346         }
347 
348         /* Bail out, when there's nothing more to do */
349         if(!bEnumMore) break;
350 
351         /* Enumerate more rectangles */
352         bEnumMore = CLIPOBJ_bEnum(pco, sizeof(rcenum), (ULONG*)&rcenum);
353     }
354 
355     return TRUE;
356 }
357 
358 
359 static
360 VOID
361 AdjustOffsetAndSize(
362     _Out_ PPOINTL pptOffset,
363     _Out_ PSIZEL psizTrg,
364     _In_ PPOINTL pptlSrc,
365     _In_ PSIZEL psizSrc)
366 {
367     LONG x, y, cxMax, cyMax;
368 
369     x = pptlSrc->x + pptOffset->x;
370     if (x < 0) pptOffset->x -= x, x = 0;
371 
372     cxMax = psizSrc->cx - x;
373     if (psizTrg->cx > cxMax) psizTrg->cx = cxMax;
374 
375     y = pptlSrc->y + pptOffset->y;
376     if (y < 0) pptOffset->y -= y, y = 0;
377 
378     cyMax = psizSrc->cy - y;
379     if (psizTrg->cy > cyMax) psizTrg->cy = cyMax;
380 }
381 
382 BOOL
383 APIENTRY
384 IntEngBitBlt(
385     _Inout_ SURFOBJ *psoTrg,
386     _In_opt_ SURFOBJ *psoSrc,
387     _In_opt_ SURFOBJ *psoMask,
388     _In_opt_ CLIPOBJ *pco,
389     _In_opt_ XLATEOBJ *pxlo,
390     _In_ RECTL *prclTrg,
391     _When_(psoSrc, _In_) POINTL *pptlSrc,
392     _When_(psoMask, _In_) POINTL *pptlMask,
393     _In_opt_ BRUSHOBJ *pbo,
394     _When_(pbo, _In_) POINTL *pptlBrush,
395     _In_ ROP4 rop4)
396 {
397     BOOL bResult;
398     RECTL rcClipped;
399     POINTL ptOffset, ptSrc, ptMask, ptBrush;
400     SIZEL sizTrg;
401     PFN_DrvBitBlt pfnBitBlt;
402 
403 //__debugbreak();
404 
405     /* Sanity checks */
406     ASSERT(IS_VALID_ROP4(rop4));
407     ASSERT(psoTrg);
408     ASSERT(psoTrg->iBitmapFormat >= BMF_1BPP);
409     ASSERT(psoTrg->iBitmapFormat <= BMF_32BPP);
410     ASSERT(prclTrg);
411 
412     /* Clip the target rect to the extents of the target surface */
413     if (!RECTL_bClipRectBySize(&rcClipped, prclTrg, &psoTrg->sizlBitmap))
414     {
415         /* Nothing left */
416         return TRUE;
417     }
418 
419     /* If no clip object is given, use trivial one */
420     if (!pco) pco = (CLIPOBJ*)&gxcoTrivial;
421 
422     /* Check if there is something to clip */
423     if (pco->iDComplexity != DC_TRIVIAL)
424     {
425         /* Clip the target rect to the bounds of the clipping region */
426         if (!RECTL_bIntersectRect(&rcClipped, &rcClipped, &pco->rclBounds))
427         {
428             /* Nothing left */
429             return TRUE;
430         }
431     }
432 
433     /* Don't pass a clip object with a single rectangle */
434     if (pco->iDComplexity == DC_RECT) pco = (CLIPOBJ*)&gxcoTrivial;
435 
436     /* Calculate initial offset and size */
437     ptOffset.x = rcClipped.left - prclTrg->left;
438     ptOffset.y = rcClipped.top - prclTrg->top;
439     sizTrg.cx = rcClipped.right - rcClipped.left;
440     sizTrg.cy = rcClipped.bottom - rcClipped.top;
441 
442     /* Check if the ROP uses a source */
443     if (ROP4_USES_SOURCE(rop4))
444     {
445         /* Must have a source surface and point */
446         ASSERT(psoSrc);
447         ASSERT(pptlSrc);
448 
449         /* Get the source point */
450         ptSrc = *pptlSrc;
451 
452         /* Clip against the extents of the source surface */
453         AdjustOffsetAndSize(&ptOffset, &sizTrg, &ptSrc, &psoSrc->sizlBitmap);
454     }
455     else
456     {
457         psoSrc = NULL;
458         ptSrc.x = 0;
459         ptSrc.y = 0;
460     }
461 
462     /* Check if the ROP uses a mask */
463     if (ROP4_USES_MASK(rop4))
464     {
465         /* Must have a mask surface and point */
466         ASSERT(psoMask);
467         ASSERT(pptlMask);
468 
469         /* Get the mask point */
470         ptMask = *pptlMask;
471 
472         /* Clip against the extents of the mask surface */
473         AdjustOffsetAndSize(&ptOffset, &sizTrg, &ptMask, &psoMask->sizlBitmap);
474     }
475     else
476     {
477         psoMask = NULL;
478         ptMask.x = 0;
479         ptMask.y = 0;
480     }
481 
482     /* Check if all has been clipped away */
483     if ((sizTrg.cx <= 0) || (sizTrg.cy <= 0))
484         return TRUE;
485 
486     /* Adjust the points */
487     ptSrc.x += ptOffset.x;
488     ptSrc.y += ptOffset.y;
489     ptMask.x += ptOffset.x;
490     ptMask.y += ptOffset.y;
491 
492     /* Check if we have a brush origin */
493     if (pptlBrush)
494     {
495         /* calculate the new brush origin */
496         ptBrush.x = pptlBrush->x + ptOffset.x;
497         ptBrush.y = pptlBrush->y + ptOffset.y;
498     }
499 
500     /* Recalculate the target rect */
501     rcClipped.left = prclTrg->left + ptOffset.x;
502     rcClipped.top = prclTrg->top + ptOffset.y;
503     rcClipped.right = rcClipped.left + sizTrg.cx;
504     rcClipped.bottom = rcClipped.top + sizTrg.cy;
505 
506     /* Is the target surface device managed? */
507     if (SURFOBJ_flags(psoTrg) & HOOK_BITBLT)
508     {
509         /* Is the source a different device managed surface? */
510         if (psoSrc && (psoSrc->hdev != psoTrg->hdev) &&
511             (SURFOBJ_flags(psoSrc) & HOOK_BITBLT))
512         {
513             ERR("Need to copy to standard bitmap format!\n");
514             ASSERT(FALSE);
515         }
516 
517         pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
518     }
519     /* Otherwise is the source surface device managed? */
520     else if (psoSrc && (SURFOBJ_flags(psoSrc) & HOOK_BITBLT))
521     {
522         pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
523     }
524     else
525     {
526         pfnBitBlt = EngBitBlt;
527     }
528 
529     bResult = pfnBitBlt(psoTrg,
530                         psoSrc,
531                         psoMask,
532                         pco,
533                         pxlo,
534                         &rcClipped,
535                         psoSrc ? &ptSrc : NULL,
536                         psoMask ? &ptMask : NULL,
537                         pbo,
538                         pptlBrush ? &ptBrush : NULL,
539                         rop4);
540 
541     // FIXME: cleanup temp surface!
542 
543     return bResult;
544 }
545 
546 BOOL
547 APIENTRY
548 NtGdiEngBitBlt(
549     IN SURFOBJ *psoTrgUMPD,
550     IN SURFOBJ *psoSrcUMPD,
551     IN SURFOBJ *psoMaskUMPD,
552     IN CLIPOBJ *pcoUMPD,
553     IN XLATEOBJ *pxloUMPD,
554     IN RECTL *prclTrg,
555     IN POINTL *pptlSrc,
556     IN POINTL *pptlMask,
557     IN BRUSHOBJ *pboUMPD,
558     IN POINTL *pptlBrush,
559     IN ROP4 rop4)
560 {
561     RECTL  rclTrg;
562     POINTL ptlSrc, ptlMask, ptlBrush;
563     HSURF hsurfTrg, hsurfSrc = NULL, hsurfMask = NULL;
564     HANDLE hBrushObj; // HUMPDOBJ
565     SURFOBJ *psoTrg, *psoSrc, *psoMask;
566     CLIPOBJ *pco;
567     XLATEOBJ *pxlo;
568     BRUSHOBJ *pbo;
569     BOOL bResult;
570 
571     _SEH2_TRY
572     {
573         ProbeForRead(prclTrg, sizeof(RECTL), 1);
574         rclTrg = *prclTrg;
575 
576         ProbeForRead(psoTrgUMPD, sizeof(SURFOBJ), 1);
577         hsurfTrg = psoTrgUMPD->hsurf;
578 
579         if (ROP4_USES_SOURCE(rop4))
580         {
581             ProbeForRead(pptlSrc, sizeof(POINTL), 1);
582             ptlSrc = *pptlSrc;
583 
584             ProbeForRead(psoSrcUMPD, sizeof(SURFOBJ), 1);
585             hsurfSrc = psoSrcUMPD->hsurf;
586         }
587 
588         if (ROP4_USES_MASK(rop4))
589         {
590             ProbeForRead(pptlMask, sizeof(POINTL), 1);
591             ptlMask = *pptlMask;
592 
593             ProbeForRead(psoMaskUMPD, sizeof(SURFOBJ), 1);
594             hsurfMask = psoMaskUMPD->hsurf;
595         }
596 
597         if (ROP4_USES_PATTERN(rop4))
598         {
599             ProbeForRead(pptlBrush, sizeof(POINTL), 1);
600             ptlBrush = *pptlBrush;
601 
602             ProbeForRead(psoSrcUMPD, sizeof(SURFOBJ), 1);
603             hBrushObj = pboUMPD->pvRbrush; // FIXME
604         }
605     }
606     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
607     {
608         _SEH2_YIELD(return FALSE);
609     }
610     _SEH2_END;
611 
612     // FIXME: these need to be converted/locked!
613     psoTrg = NULL;
614     psoSrc = NULL;
615     psoMask = NULL;
616     pco = NULL;
617     pxlo = NULL;
618     pbo = NULL;
619 
620     bResult = EngBitBlt(psoTrg,
621                         psoSrc,
622                         psoMask,
623                         pco,
624                         pxlo,
625                         &rclTrg,
626                         pptlSrc ? &ptlSrc : NULL,
627                         pptlMask ? &ptlMask : NULL,
628                         pbo,
629                         pptlBrush ? &ptlBrush : NULL,
630                         rop4);
631 
632     return bResult;
633 }
634 
635 BOOL
636 APIENTRY
637 EngCopyBits(
638     SURFOBJ *psoTrg,
639     SURFOBJ *psoSrc,
640     CLIPOBJ *pco,
641     XLATEOBJ *pxlo,
642     RECTL *prclTrg,
643     POINTL *pptlSrc)
644 {
645     PFN_DrvCopyBits pfnCopyBits;
646 
647     /* Is the target surface device managed? */
648     if (SURFOBJ_flags(psoTrg) & HOOK_COPYBITS)
649     {
650         pfnCopyBits = GDIDEVFUNCS(psoTrg).CopyBits;
651     }
652     if (SURFOBJ_flags(psoSrc) & HOOK_COPYBITS)
653     {
654         pfnCopyBits = GDIDEVFUNCS(psoSrc).CopyBits;
655     }
656     else
657     {
658         /* Use SRCCOPY for 2 bitmaps */
659         return EngBitBlt(psoTrg,
660                          psoSrc,
661                          NULL,
662                          pco,
663                          pxlo,
664                          prclTrg,
665                          pptlSrc,
666                          NULL,
667                          NULL,
668                          NULL,
669                          ROP4_SRCCOPY);
670     }
671 
672     /* Forward to the driver */
673     return pfnCopyBits(psoTrg, psoSrc, pco, pxlo, prclTrg, pptlSrc);
674 }
675 
676 BOOL
677 APIENTRY
678 IntEngCopyBits(
679     SURFOBJ *psoTrg,
680     SURFOBJ *psoSrc,
681     CLIPOBJ *pco,
682     XLATEOBJ *pxlo,
683     RECTL *prclTrg,
684     POINTL *pptlSrc)
685 {
686     return EngCopyBits(psoTrg, psoSrc, pco, pxlo, prclTrg, pptlSrc);
687 }
688