/******************************Module*Header*******************************\ * Module Name: engbrush.cxx * * Brush realization for the engine. * * Created: 13-May-1991 23:25:49 * Author: Patrick Haluptzok patrickh * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" #if DBG ULONG engbrushalloc = 0, engbrushcachecheck = 0; ULONG engbrushcachegrabbed = 0, engbrushcachehit = 0; #endif /******************************Public*Routine******************************\ * EngRealizeBrush * * Realizes a brush for the engine simulations. * * We realize a brush by converting psoPattern to have the same bpp and color * format as the destination surface. We copy the monochrome mask unmodified. * * psoPattern is assumed never to be NULL. * * Returns: TRUE for success, FALSE for failure. * * History: * 21-Nov-1993 -by- Michael Abrash [mikeab] * Removed impossible case of psoPattern == NULL, cleaned up. * * 20-Jan-1992 -by- Donald Sidoroff [donalds] * Tiled pattern and mask to DWORD boundaries * * 25-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ BOOL EngRealizeBrush( BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask, XLATEOBJ *pxlo, ULONG iHatch) { PSURFACE pSurfTarg = SURFOBJ_TO_SURFACE(psoTarget); PSURFACE pSurfPat = SURFOBJ_TO_SURFACE(psoPattern); PSURFACE pSurfMsk = SURFOBJ_TO_SURFACE(psoMask); ULONG ulSizeTotal; ULONG ulSizePat; ULONG cjScanPat, cjScanMsk; SIZEL sizlPat; SIZEL sizlMsk; LONG cxPatRealized; LONG cxMskRealized; ULONG iFormat; POINTL ptlSrc; RECTL rclDst; DEVBITMAPINFO dbmi; BOOL bHalftoneTile = FALSE; ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor"); ASSERTGDI(pSurfTarg != NULL, "ERROR GDI EngRealizeBrush NULL psoTarg"); ASSERTGDI(pSurfPat != NULL, "ERROR GDI EngRealizeBrush NULL psoPattern"); ASSERTGDI(!(iHatch & RB_DITHERCOLOR), "ERROR GDI EngRealizeBrush RB_DITHERCOLOR set"); // // Calculate the space needed for the pattern. // iFormat = pSurfTarg->iFormat(); // // Check if they are having the engine simulate to a bitmap compatible // with their surface. The brushobj has the device's surfobj in it // but we assume if they got here it's because they created a bitmap // compatible with thier format and // are drawing on it. Maybe we should have the pvGetEngBrush pass // the pSurfTarg along so we know what it is here, because from // here we haven't got access to the real surfobj being painted on. // ASSERTGDI(pSurfPat->iType() == STYPE_BITMAP, "ERROR GDI EngRealizeBrush2"); sizlPat = pSurfPat->sizl(); PDEVICEHALFTONEINFO pDevHTInfo = NULL; PDEVOBJ po(pSurfTarg->hdev()); // The following list shows the halftone dithering cell size mapped to // cxPattern x cyPattern in pDevHTInfo // // This is done only for 1bpp in the following code // // dither cell chosen at UI --> what we got from pDevHTInfo // // 2x2 --> 8x4 // 4x4 --> 8x4 // 6x6 --> 12x6 // 8x8 --> 8x8 // 10x10 --> 10x10 // 12x12 --> 12x12 // 14x14 --> 14x14 // 16x16 --> 16x16 // 91x91 --> 91x91 // if ((po.pDevHTInfo() != NULL) || po.bEnableHalftone(NULL)) { pDevHTInfo = (DEVICEHALFTONEINFO *)po.pDevHTInfo(); } switch(iFormat) { case BMF_1BPP: ulSizePat = 1; if ((sizlPat.cx == 32) || (sizlPat.cx == 16) || (sizlPat.cx == 8)) { cxPatRealized = 32; // // take the least common multiple // of 32(dword aligned) and pDevHTInfocxPattern // if (pDevHTInfo) { switch (pDevHTInfo->cxPattern) { case 12: cxPatRealized = 96; bHalftoneTile = TRUE; break; case 10: cxPatRealized = 160; bHalftoneTile = TRUE; break; case 14: cxPatRealized = 224; bHalftoneTile = TRUE; break; case 91: break; default: break; } } } else { cxPatRealized = (sizlPat.cx + 63) & ~31; } break; case BMF_4BPP: ulSizePat = 4; if (sizlPat.cx == 8) { cxPatRealized = 8; } else { cxPatRealized = (sizlPat.cx + 15) & ~7; } break; case BMF_8BPP: ulSizePat = 8; cxPatRealized = (sizlPat.cx + 7) & ~3; break; case BMF_16BPP: ulSizePat = 16; cxPatRealized = (sizlPat.cx + 7) & ~3; break; case BMF_24BPP: ulSizePat = 24; cxPatRealized = (sizlPat.cx + 7) & ~3; break; case BMF_32BPP: ulSizePat = 32; cxPatRealized = sizlPat.cx; break; default: RIP("ERROR GDI EngRealizeBrush3"); } // // Calculate the size to hold the pattern in the Target's format. // cjScanPat = (ulSizePat * cxPatRealized) >> 3; ulSizeTotal = sizeof(ENGBRUSH) + (ulSizePat = sizlPat.cy * cjScanPat); // // Calculate the additional space needed if we have a mask passed down. // if (pSurfMsk != NULL) { ASSERTGDI(pSurfMsk->iFormat() == BMF_1BPP, "ERROR GDI EngRealizeBrush4"); ASSERTGDI(pSurfMsk->iType() == STYPE_BITMAP, "ERROR GDI EngRealizeBrush5"); sizlMsk = pSurfMsk->sizl(); if ((sizlMsk.cx == 32) || (sizlMsk.cx == 16) || (sizlMsk.cx == 8)) { cxMskRealized = 32; } else { cxMskRealized = (sizlMsk.cx + 63) & ~31; } cjScanMsk = cxMskRealized >> 3; ulSizeTotal += sizlMsk.cy * cjScanMsk; } // // Allocate memory for the realization. // PENGBRUSH pengbrush; #if DBG engbrushalloc++; #endif // // If there's a cached ENGBRUSH, try to use it instead of allocating // if (gpCachedEngbrush != NULL) { #if DBG engbrushcachecheck++; #endif // // Try to grab the cached ENGBRUSH // if ((pengbrush = (PENGBRUSH) InterlockedExchangePointer((PVOID *)&gpCachedEngbrush, NULL)) != NULL) { #if DBG engbrushcachegrabbed++; #endif // // Got the cached ENGBRUSH; see if it's big enough // // Note: -4 because we define the realization buffer start as aj[0] if (pengbrush->ulSizeGet() >= (sizeof(ENGBRUSH) - 4 + ulSizeTotal)) { #if DBG engbrushcachehit++; #endif // // It's big enough, so we'll use it and we're done // goto BrushAllocated; } else { // // Not big enough; free it and do a normal allocation // VFREEMEM(pengbrush); } } } // Note: -4 because we define the realization buffer start as aj[0] if ((pengbrush = (PENGBRUSH) PALLOCMEM(ULONG(sizeof(ENGBRUSH) - 4 + ulSizeTotal),'rbeG')) == NULL) { WARNING("GDI EngRealizeBrush Couldn't allocate for engine realization"); return(FALSE); } BrushAllocated: EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo; // // Store the pointer to the realization in the brush. // pebo->pengbrush(pengbrush); // // Remember the size of the allocation, for caching. // pengbrush->ulSizeSet(sizeof(ENGBRUSH) - 4 + ulSizeTotal); // // Set up the Pat part. The pattern can never be NULL. // pengbrush->lDeltaPat = cjScanPat; pengbrush->cxPatR = cxPatRealized; pengbrush->cxPat = bHalftoneTile ? cxPatRealized : sizlPat.cx; pengbrush->cyPat = sizlPat.cy; pengbrush->pjPat = pengbrush->aj; pengbrush->iDitherFormat = iFormat; dbmi.iFormat = iFormat; dbmi.cxBitmap = cxPatRealized; dbmi.cyBitmap = sizlPat.cy; dbmi.hpal = 0; dbmi.fl = BMF_TOPDOWN; SURFMEM SurfDimo; SurfDimo.bCreateDIB(&dbmi, pengbrush->pjPat); if (!SurfDimo.bValid()) { // hmgr logs out of memory error return(FALSE); } ptlSrc.x = 0; ptlSrc.y = 0; rclDst.left = 0; rclDst.top = 0; rclDst.right = sizlPat.cx; rclDst.bottom = sizlPat.cy; // Below cases, we need halftoning for this brush. // // 1) Target surface is 1bpp, and this is pattern/bitmap brush, and the foreground // and background are differrent // 2) Target surface is 4bpp, and ICM is enabled in system or apps, and this is NOT // monochrone brush with same fore and background color. BOOL bSameColor = (((EBRUSHOBJ *)pbo)->crCurrentText() == ((EBRUSHOBJ *)pbo)->crCurrentBack()); if (((iFormat == BMF_1BPP) && (iHatch >= HS_NULL) && !bSameColor) // 1 || ((iFormat == BMF_4BPP) && (pebo->bIsAppsICM() || pebo->bIsHostICM()) // 2 && !(bSameColor && (pebo->bIsMonochrome()))) ) { PALMEMOBJ palHatch; EXLATEOBJ exloHatch; PALETTE *ppalOrg = NULL; // Special case to go thru halftone code POINTL ptl; ptl.x = 0; ptl.y = 0; RECTL rclSrc; rclSrc = rclDst; SurfDimo.ps->hdev(pSurfTarg->hdev()); BOOL bHatch = (iHatch < HS_DDI_MAX); // If this is Hatch or monochrome brush, and ICM is enabled, ... if ((bHatch || pebo->bIsMonochrome()) && (pebo->bIsAppsICM() || pebo->bIsHostICM())) { // Create temporary palette for hatch/mono brush from back/foregournd color // This is nessesary to let halftone bitblt work correctly. COLORREF aPalHatch[2]; // If this is hatch brush, get foreground color from crRealized. // For monochrome brush, get from current text color. if (bHatch) { ICMMSG(("EngRealizeBrush called with hatch brush\n")); ICMMSG(("Forground color = %x\n", pebo->crRealized())); ICMMSG(("Background color = %x\n", pebo->crCurrentBack())); // crCurrentBack goes to index 0 // crRealized goes to index 1 // // See brushddi.cxx : bGetRealizedBrush() for hatch brush case. aPalHatch[0] = pebo->crCurrentBack(); aPalHatch[1] = pebo->crRealized(); } else // if (pebo->bIsMonochorme()) { ICMMSG(("EngRealizeBrush called with monochrome brush\n")); ICMMSG(("Forground color = %x\n", pebo->crCurrentText())); ICMMSG(("Background color = %x\n", pebo->crCurrentBack())); // Text color goes to index 0. // Background color goes to index 1. // // See ylateobj.cxx : CreateXlateObject() when source is monochrome case. aPalHatch[0] = pebo->crCurrentText(); aPalHatch[1] = pebo->crCurrentBack(); } if (palHatch.bCreatePalette(PAL_INDEXED, 2, (PULONG) aPalHatch, 0, 0, 0, PAL_FREE)) { if (exloHatch.bInitXlateObj( pebo->hcmXform(), pebo->lIcmMode(), palHatch.ppalGet(), pebo->psoTarg()->ppal(), pebo->palDC(), pebo->palDC(), pebo->crCurrentText(), pebo->crCurrentBack(), 0x00FFFFFF)) { pxlo = exloHatch.pxlo(); // // Halftone code always pick up palette from surface, if it exist, // and the palette in monochrome bitmap is black/white, but here, // text/background color must be used, so disable surface palette // here by put null, so that halftone code will pick up right palette // from XLATEOBJ. // ppalOrg = pSurfPat->ppal(); pSurfPat->ppal(NULL); } else { WARNING1("EngRealizeBrush: failed to create xlate for ICM\n"); } } else { WARNING1("EngRealizeBrush: failed to create palette for ICM\n"); } } if ((iFormat == BMF_1BPP) && bHalftoneTile) { rclDst.right = cxPatRealized; EngHTBlt( SurfDimo.pSurfobj(), // Target surface pSurfPat->pSurfobj(), // Source surface NULL, // mask surface (CLIPOBJ *) NULL, // Clip through this pxlo, // Color translation NULL, // pca &ptl, // pptlBrushOrg &rclDst, &rclSrc, NULL, BBPF_TILE_SRC, NULL); } else { while (rclDst.left != cxPatRealized) { EngStretchBlt( SurfDimo.pSurfobj(), // Target surface pSurfPat->pSurfobj(), // Source surface NULL, // mask surface (CLIPOBJ *) NULL, // Clip through this pxlo, // Color translation NULL, // pca &ptl, // pptlBrushOrg &rclDst, &rclSrc, NULL, HALFTONE); rclDst.left = rclDst.right; rclDst.right += sizlPat.cx; if (rclDst.right > cxPatRealized) rclDst.right = cxPatRealized; } } if (ppalOrg) { pSurfPat->ppal(ppalOrg); } } else // normal cases { while (rclDst.left != cxPatRealized) { EngCopyBits( SurfDimo.pSurfobj(), // Target surface pSurfPat->pSurfobj(), // Source surface (CLIPOBJ *) NULL, // Clip through this pxlo, // Color translation &rclDst, // Target offset and extent &ptlSrc); rclDst.left = rclDst.right; rclDst.right += sizlPat.cx; if (rclDst.right > cxPatRealized) rclDst.right = cxPatRealized; } } // // Set up the Msk part. // if (pSurfMsk == (PSURFACE) NULL) { // // Flag that there's no mask. // pengbrush->pjMsk = (PBYTE) NULL; } else { pengbrush->lDeltaMsk = cjScanMsk; pengbrush->cxMskR = cxMskRealized; pengbrush->cxMsk = sizlMsk.cx; pengbrush->cyMsk = sizlMsk.cy; pengbrush->pjMsk = pengbrush->aj + ulSizePat; dbmi.iFormat = BMF_1BPP; dbmi.cxBitmap = cxMskRealized; dbmi.cyBitmap = sizlMsk.cy; dbmi.hpal = (HPALETTE)0; dbmi.fl = BMF_TOPDOWN; SURFMEM SurfDimo; SurfDimo.bCreateDIB(&dbmi, pengbrush->pjMsk); if (!SurfDimo.bValid()) { // hmgr logs out of memory error return(FALSE); } ptlSrc.x = 0; ptlSrc.y = 0; rclDst.left = 0; rclDst.top = 0; rclDst.right = sizlMsk.cx; rclDst.bottom = sizlMsk.cy; while (rclDst.left != cxMskRealized) { EngCopyBits( SurfDimo.pSurfobj(), // target surface pSurfMsk->pSurfobj(), // source surface (CLIPOBJ *) NULL, // no clipping NULL, // no color translation &rclDst, // target offset and extent &ptlSrc // source start point ); rclDst.left = rclDst.right; rclDst.right += sizlMsk.cx; if (rclDst.right > cxMskRealized) { rclDst.right = cxMskRealized; } } } return(TRUE); }