/******************************Module*Header*******************************\ * Module Name: patblt.cxx * * This contains the special case blting code for P, Pn, DPx and Dn rops * with solid color and patterns. * * Created: 03-Mar-1991 22:01:14 * Author: Patrick Haluptzok patrickh * * Copyright (c) 1991-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" // The amount to shift cx and xDstStart left by ULONG aulShiftFormat[7] = { 0, // BMF_DEVICE 0, // BMF_1BPP 2, // BMF_4BPP 3, // BMF_8BPP 4, // BMF_16BPP 0, // BMF_24BPP 5 // BMF_32BPP }; PFN_PATBLT apfnPatBlt[][3] = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, { vPatCpyRect8, vPatNotRect8, vPatXorRect8 }, { vPatCpyRect8, vPatNotRect8, vPatXorRect8 }, { vPatCpyRect8, vPatNotRect8, vPatXorRect8 }, { vPatCpyRect8, vPatNotRect8, vPatXorRect8 } }; ULONG aulMulFormat[] = { 0, // BMF_DEVICE 0, // BMF_1BPP 0, // BMF_4BPP 1, // BMF_8BPP 2, // BMF_16BPP 3, // BMF_24BPP 4 // BMF_32BPP }; /******************************Public*Routine******************************\ * vDIBSolidBlt * * This does solid color and DstInvert blts. * * History: * 03-Feb-1992 -by- Donald Sidoroff [donalds] * Improved it. * * 01-Mar-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ VOID vDIBSolidBlt( SURFACE *pSurfDst, RECTL *prclDst, CLIPOBJ *pco, ULONG iColor, // the index to use for color. BOOL bInvert) { PFN_SOLIDBLT pfnDibSolid; ULONG cShift; // Shift by this for format conversion ULONG ircl; PBYTE pjDstBits; LONG lDeltaDst; BOOL bMore = FALSE; BOOL bClip = FALSE; CLIPENUMRECT clenr; //ASSERTGDI(pSurfDst->iType() == STYPE_BITMAP, "ERROR GDI vDibSo"); // Set ircl to be the format of the dst surface. ircl = pSurfDst->iFormat(); // Assert the world is in order for our switch ASSERTGDI((ircl >= BMF_1BPP) && (ircl <= BMF_32BPP), "ERROR GDI vDibPatBlt"); // Set up cShift, pfnDibSolid, and iColor. cShift = aulShiftFormat[ircl]; if (bInvert) { if (ircl == BMF_24BPP) pfnDibSolid = vSolidXorRect24; else pfnDibSolid = vSolidXorRect1; } else { if (ircl == BMF_24BPP) pfnDibSolid = vSolidFillRect24; else pfnDibSolid = vSolidFillRect1; } // Note cascaded fall through on switch to build up iColor. // Also note that 24BPP doesn't change. // Finally, note that the non-significant bits have to be masked off because // we generate Pn in the calling routine with ~. switch(ircl) { case BMF_1BPP: if ((iColor &= 1) != 0) iColor = 0xFFFFFFFF; break; case BMF_4BPP: iColor &= 0x0F; iColor = iColor | (iColor << 4); case BMF_8BPP: iColor &= 0xFF; iColor = iColor | (iColor << 8); case BMF_16BPP: iColor &= 0xFFFF; iColor = iColor | (iColor << 16); } if (pco != (CLIPOBJ *) NULL) { switch(pco->iDComplexity) { case DC_TRIVIAL: break; case DC_RECT: bClip = TRUE; clenr.c = 1; clenr.arcl[0] = pco->rclBounds; // Use acclerator for clipping break; case DC_COMPLEX: bClip = TRUE; bMore = TRUE; ((ECLIPOBJ *) pco)->cEnumStart(FALSE,CT_RECTANGLES,CD_ANY,CLIPOBJ_ENUM_LIMIT); break; default: RIP("ERROR: vDIBSolidBlt - bad clipping type"); } } pjDstBits = (PBYTE) pSurfDst->pvScan0(); lDeltaDst = pSurfDst->lDelta(); if (!bClip) { (*pfnDibSolid)( prclDst, 1, pjDstBits, lDeltaDst, iColor, cShift); } else do { if (bMore) bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr), (PVOID) &clenr); for (ircl = 0; ircl < clenr.c; ircl++) { PRECTL prcl = &clenr.arcl[ircl]; if (prcl->left < prclDst->left) prcl->left = prclDst->left; if (prcl->right > prclDst->right) prcl->right = prclDst->right; if (prcl->top < prclDst->top) prcl->top = prclDst->top; if (prcl->bottom > prclDst->bottom) prcl->bottom = prclDst->bottom; // We check for NULL or inverted rectanges because we may get them. if ((prcl->top < prcl->bottom) && (prcl->left < prcl->right)) { (*pfnDibSolid)( prcl, 1, pjDstBits, lDeltaDst, iColor, cShift); } } } while (bMore); } /******************************Public*Routine******************************\ * vDIBPatBlt * * This does pattern blts * * History: * 20-Jan-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/ VOID vDIBPatBlt( SURFACE *pSurfDst, CLIPOBJ *pco, RECTL *prclDst, BRUSHOBJ *pbo, POINTL *pptlBrush, ULONG iMode) { PFN_PATBLT pfnPat; PATBLTFRAME pbf; CLIPENUMRECT clenr; ULONG ircl; BOOL bMore = FALSE; BOOL bClip = FALSE; ASSERTGDI(pSurfDst->iType() == STYPE_BITMAP, "ERROR GDI vDibPat"); // Set ircl to be the format of the dst surface. ircl = pSurfDst->iFormat(); // Assert the world is in order for our switch ASSERTGDI((ircl >= BMF_1BPP) && (ircl <= BMF_32BPP), "ERROR GDI vDibPatBlt"); // Set up pfnPat and cMul. pfnPat = apfnPatBlt[ircl][iMode]; pbf.cMul = aulMulFormat[ircl]; if (pco != (CLIPOBJ *) NULL) { switch(pco->iDComplexity) { case DC_TRIVIAL: break; case DC_RECT: bClip = TRUE; clenr.c = 1; clenr.arcl[0] = pco->rclBounds; // Use acclerator for clipping break; case DC_COMPLEX: bClip = TRUE; bMore = TRUE; ((ECLIPOBJ *) pco)->cEnumStart(FALSE,CT_RECTANGLES,CD_ANY,CLIPOBJ_ENUM_LIMIT); break; default: RIP("ERROR: vDibPatBlt - bad clipping type"); } } pbf.pvTrg = pSurfDst->pvScan0(); pbf.lDeltaTrg = pSurfDst->lDelta(); pbf.pvPat = (PVOID) ((EBRUSHOBJ *) pbo)->pengbrush()->pjPat; pbf.lDeltaPat = ((EBRUSHOBJ *) pbo)->pengbrush()->lDeltaPat; pbf.cxPat = ((EBRUSHOBJ *) pbo)->pengbrush()->cxPat * pbf.cMul; pbf.cyPat = ((EBRUSHOBJ *) pbo)->pengbrush()->cyPat; pbf.xPat = pptlBrush->x * pbf.cMul; pbf.yPat = pptlBrush->y; if (!bClip) { pbf.pvObj = (PVOID) prclDst; (*pfnPat)(&pbf); } else do { if (bMore) bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr), (PVOID) &clenr); for (ircl = 0; ircl < clenr.c; ircl++) { PRECTL prcl = &clenr.arcl[ircl]; if (prcl->left < prclDst->left) prcl->left = prclDst->left; if (prcl->right > prclDst->right) prcl->right = prclDst->right; if (prcl->top < prclDst->top) prcl->top = prclDst->top; if (prcl->bottom > prclDst->bottom) prcl->bottom = prclDst->bottom; // We check for NULL or inverted rectanges because we may get them. if ((prcl->top < prcl->bottom) && (prcl->left < prcl->right)) { pbf.pvObj = (PVOID) prcl; (*pfnPat)(&pbf); } } } while (bMore); } /******************************Public*Routine******************************\ * vDIBPatBltSrccopy8x8 * * This does only SRCCOPY blts of 8x8 patterns to DIBs. * lDelta for the pattern must be exactly # of bytes per pixel * 8. * * History: * 07-Nov-1992 -by- Michael Abrash [mikeab] * Wrote it. \**************************************************************************/ VOID vDIBPatBltSrccopy8x8( SURFACE *pSurfDst, CLIPOBJ *pco, RECTL *prclDst, BRUSHOBJ *pbo, POINTL *pptlBrush, PFN_PATBLT2 pfnPat) { PATBLTFRAME pbf; CLIPENUMRECT clenr; BOOL bMore; PRECTL prcl; INT ircl; // Assert this is the right sort of destination ASSERTGDI(pSurfDst->iType() == STYPE_BITMAP, "ERROR GDI vDibPat"); pbf.pvTrg = pSurfDst->pvScan0(); pbf.lDeltaTrg = pSurfDst->lDelta(); pbf.pvPat = (PVOID) ((EBRUSHOBJ *) pbo)->pengbrush()->pjPat; pbf.lDeltaPat = ((EBRUSHOBJ *) pbo)->pengbrush()->lDeltaPat; // // Force the X and Y pattern origin coordinates into the ranges 0-7 and 0-7, // so we don't have to do modulo arithmetic all over again at a lower level // pbf.xPat = pptlBrush->x & 0x07; pbf.yPat = pptlBrush->y & 0x07; if (pco == (CLIPOBJ *) NULL) { // Unclipped pbf.pvObj = (PVOID) prclDst; pfnPat(&pbf, 1); return; } else { switch(pco->iDComplexity) { case DC_TRIVIAL: // unclipped pbf.pvObj = (PVOID) prclDst; pfnPat(&pbf, 1); return; case DC_RECT: // rectangle clipped clenr.arcl[0] = pco->rclBounds; // Use acclerator for clipping // Clip the destination rectangle to the clip rectangle; it's // guaranteed that the resulting rectangle will never be null if (clenr.arcl[0].left <= prclDst->left) clenr.arcl[0].left = prclDst->left; if (clenr.arcl[0].right >= prclDst->right) clenr.arcl[0].right = prclDst->right; if (clenr.arcl[0].top <= prclDst->top) clenr.arcl[0].top = prclDst->top; if (clenr.arcl[0].bottom >= prclDst->bottom) clenr.arcl[0].bottom = prclDst->bottom; if ((clenr.arcl[0].left < clenr.arcl[0].right) && (clenr.arcl[0].top < clenr.arcl[0].bottom)) { pbf.pvObj = (PVOID) clenr.arcl; pfnPat(&pbf, 1); } return; case DC_COMPLEX: // complex region clipped ((ECLIPOBJ *) pco)->cEnumStart(FALSE, CT_RECTANGLES, CD_ANY, CLIPOBJ_ENUM_LIMIT); do { // Get the next batch of rectangles in the clip region bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr), (PVOID) &clenr); // If there are any rectangles in this enumeration, clip the // destination rectangle to each clip region rectangle, then // fill all the rectangles at once if (clenr.c > 0) { // Clip the rectangles for (ircl = 0, prcl = clenr.arcl; ircl < (INT) clenr.c; ircl++, prcl++) { if (prcl->left < prclDst->left) prcl->left = prclDst->left; if (prcl->right > prclDst->right) prcl->right = prclDst->right; if (prcl->top < prclDst->top) prcl->top = prclDst->top; if (prcl->bottom > prclDst->bottom) prcl->bottom = prclDst->bottom; // // make sure rectangle is not inverted, // this can happen for single scan line // clip regions clipped to dst. If found, // set to NULL rectangle // if (prcl->right < prcl->left) { prcl->right = prcl->left; } if (prcl->bottom < prcl->top) { prcl->bottom = prcl->top; } } // Draw the rectangles pbf.pvObj = (PVOID) clenr.arcl; pfnPat(&pbf, (INT) clenr.c); } } while (bMore); return; default: RIP("ERROR: vDIBPatBltSrccopy8x8 - bad clipping type"); } } } /******************************Public*Routine******************************\ * vDIBnPatBltSrccopy6x6 * * This does SRCCOPY pattern blts to 6x6 4-bpp DIBs and 1-bpp DIBs. * lDelta for the pattern must be exactly 6 pixels (4 bytes). * * History: * 07-Nov-1992 -by- Michael Abrash [mikeab] * Wrote it. * * 17-Nov-1992 -by- Stephen Estrop [StephenE] * Made it take a pointer to a \**************************************************************************/ VOID vDIBnPatBltSrccopy6x6( SURFACE *pSurfDst, CLIPOBJ *pco, RECTL *prclDst, BRUSHOBJ *pbo, POINTL *pptlBrush, PFN_PATBLT2 pfnPatBlt) { PATBLTFRAME pbf; CLIPENUMRECT clenr; BOOL bMore; PRECTL prcl; ULONG ircl; // Assert this is the right sort of destination ASSERTGDI(pSurfDst->iType() == STYPE_BITMAP, "ERROR GDI vDibPat"); pbf.pvTrg = pSurfDst->pvScan0(); pbf.lDeltaTrg = pSurfDst->lDelta(); pbf.pvPat = (PVOID) ((EBRUSHOBJ *) pbo)->pengbrush()->pjPat; // Force the X and Y pattern origin coordinates into the ranges 0-5 and 0-5, // so we don't have to do modulo arithmetic all over again at a lower level if (pptlBrush->x >= 0) pbf.xPat = pptlBrush->x % 0x06; else pbf.xPat = (6 - 1) - ((-pptlBrush->x - 1) % 6); if (pptlBrush->y >= 0) pbf.yPat = pptlBrush->y % 0x06; else pbf.yPat = (6 - 1) - ((-pptlBrush->y - 1) % 6); if (pco == (CLIPOBJ *) NULL) { // Unclipped pbf.pvObj = (PVOID) prclDst; (*pfnPatBlt)(&pbf, 1); return; } else { switch(pco->iDComplexity) { case DC_TRIVIAL: // unclipped pbf.pvObj = (PVOID) prclDst; (*pfnPatBlt)(&pbf, 1); return; case DC_RECT: // rectangle clipped clenr.arcl[0] = pco->rclBounds; // Use acclerator for clipping // Clip the destination rectangle to the clip rectangle if (clenr.arcl[0].left <= prclDst->left) clenr.arcl[0].left = prclDst->left; if (clenr.arcl[0].right >= prclDst->right) clenr.arcl[0].right = prclDst->right; if (clenr.arcl[0].top <= prclDst->top) clenr.arcl[0].top = prclDst->top; if (clenr.arcl[0].bottom >= prclDst->bottom) clenr.arcl[0].bottom = prclDst->bottom; if ((clenr.arcl[0].left < clenr.arcl[0].right) && (clenr.arcl[0].top < clenr.arcl[0].bottom)) { pbf.pvObj = (PVOID) clenr.arcl; (*pfnPatBlt)(&pbf, 1); } return; case DC_COMPLEX: // complex region clipped ((ECLIPOBJ *) pco)->cEnumStart(FALSE, CT_RECTANGLES, CD_ANY, CLIPOBJ_ENUM_LIMIT); do { // Get the next batch of rectangles in the clip region bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr), (PVOID) &clenr); // If there are any rectangles in this enumeration, clip the // destination rectangle to each clip region rectangle, then // fill all the rectangles at once if (clenr.c > 0) { // Clip the rectangles for (ircl = 0, prcl = clenr.arcl; ircl < clenr.c; ircl++, prcl++) { if (prcl->left < prclDst->left) prcl->left = prclDst->left; if (prcl->right > prclDst->right) prcl->right = prclDst->right; if (prcl->top < prclDst->top) prcl->top = prclDst->top; if (prcl->bottom > prclDst->bottom) prcl->bottom = prclDst->bottom; } // Draw the rectangles pbf.pvObj = (PVOID) clenr.arcl; (*pfnPatBlt)(&pbf, clenr.c); } } while (bMore); return; default: RIP("ERROR: vDIBnSrccopyPatBlt - bad clipping type"); } } }