/******************************Module*Header*******************************\ * Module Name: brushddi.cxx * * This provides the call backs necesary for brush realization. * * Created: 25-Apr-1991 20:59:49 * Author: Patrick Haluptzok patrickh * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" BOOL EngRealizeBrush( BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask, XLATEOBJ *pxlo, ULONG iHatch ); BOOL bGetRealizedBrush( BRUSH *pbrush, EBRUSHOBJ *pebo, PFN_DrvRealizeBrush pfnDrv ); #if DBG ULONG dbrushalloc = 0, dbrushcachecheck = 0; ULONG dbrushcachegrabbed = 0, dbrushcachehit = 0; #endif /******************************Public*Routine******************************\ * BRUSHOBJ_pvAllocRbrush * * Allocates memory for the driver's realization of a brush. This is always * called by the driver, never by the engine. * * History: * 25-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ PVOID BRUSHOBJ_pvAllocRbrush( BRUSHOBJ *pbo, ULONG cj ) { ASSERTGDI(cj != 0, "ERROR GDI BRUSHOBJ_pvAllocRbrush cj = 0"); ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI BRUSHOBJ_pvAllocRbrush solid color brush passed in"); DBRUSH *pdbrush; #if DBG dbrushalloc++; #endif // // If there's a cached DBRUSH, try to use it instead of allocating // if (gpCachedDbrush != NULL) { #if DBG dbrushcachecheck++; #endif // // Try to grab the cached DBRUSH // if ((pdbrush = (PDBRUSH) InterlockedExchangePointer((PVOID *)&gpCachedDbrush, NULL)) != NULL) { #if DBG dbrushcachegrabbed++; #endif // // Got the cached DBRUSH; see if it's big enough // // Note: -4 because we define the realization buffer start as aj[0] // if (pdbrush->ulSizeGet() >= (sizeof(DBRUSH) - 4 + cj)) { #if DBG dbrushcachehit++; #endif // // It's big enough, so we'll use it and we're done // return(pbo->pvRbrush = pdbrush->aj); } else { // // Not big enough; free it and do a normal allocation // VFREEMEM(pdbrush); } } } // Note: -4 because we define the realization buffer start as aj[0] if ((pdbrush = (DBRUSH *)PALLOCMEM(ULONGSIZE_T(sizeof(DBRUSH) - 4 + cj),'rbdG')) != NULL) { // // Remember the size of the allocation, for caching. // pdbrush->ulSizeSet(sizeof(DBRUSH) - 4 + cj); return(pbo->pvRbrush = pdbrush->aj); } else { WARNING("Failed memory alloc BRUSHOBJ_pvAllocRbrush\n"); return(NULL); } } // // User mode printer driver support // PVOID BRUSHOBJ_pvAllocRbrushUMPD( BRUSHOBJ *pbo, ULONG cj ) { if (pbo->pvRbrush == NULL) { DBRUSH *pdbrush; cj += MAGIC_DBR_DIFF; if (pdbrush = (DBRUSH *) EngAllocUserMem(cj, UMPD_MEMORY_TAG)) { pdbrush->ulSizeSet(cj); pdbrush->bMultiBrush(FALSE); pdbrush->bUMPDRBrush(TRUE); pbo->pvRbrush = pdbrush->aj; } } else { RIP("BRUSHOBJ_pvAllocRbrush when pvRbrush is not NULL\n"); } return pbo->pvRbrush; } /******************************Public*Routine******************************\ * vTryToCacheRealization * * Attempt to cache the realization pointed to by pdbrush and described by pebo * in the logical brush pointed to by pbrush. The way this works is that only * the first realization of the logical brush can be cached. crFore is the key * that indicates when the cached realization is valid. If crFore is not -1 when * the logical brush is being realized, we just go realize the brush; if it's * not -1, we check the cache ID fields to see if we can use the cached fields. * InterlockedExchange() is used below to set crFore to make sure the cache ID * fields are set before crFore. bCacheGrabbed() is used to protect the setting * of the cache ID fields; once it's set, no one else can modify the cache ID * fields, but no one else will try to use them until crFore is not -1. * * Also initializes the reference count in the realization to indicates either * 1 or 2 current uses, depending on whether caching took place. * * History: * 31-Oct-1993 -by- Michael Abrash [mikeab] * Wrote it. \**************************************************************************/ VOID vTryToCacheRealization( EBRUSHOBJ *pebo, PRBRUSH prbrush, PBRUSH pbrush, BOOL bType ) { // Reference count the realization once for being selected into this DC. This // assumes we won't succeed in caching the brush next; if we do, we do a double // reference count, once for caching in the logical brush and once for // selecting into the DC prbrush->cRef(1); // See if we can cache this realization in the logical brush; we can't if // another realization has already been cached in the logical brush if ( !pbrush->bCacheGrabbed() ) { // Try to grab the "can cache" flag; if we don't get it, someone just // sneaked in and got it ahead of us, so we're out of luck and can't cache if ( pbrush->bGrabCache() ) { // We got the "can cache" flag, so now we can cache this realization // in the logical brush // It's cached in the brush, so it won't be deleted until the logical // brush goes away and it's not selected into any DCs, so reference // count the realization again. We don't need to do an // InterlockedIncrement here because until crFore is set, no one else // can get at this realization. InterlockedExchange() is used below to // set crFore to make sure the reference count is set before anyone // else can see the caching info prbrush->cRef(2); // These cache ID fields must be set before crFore, because crFore // is the key that indicates when the cached realization is valid. // If crFore is -1 when the logical brush is being realized, we // just go realize the brush; if it's not -1, we check the cache ID // fields to see if we can use the cached fields. // InterlockedExchange() is used below to set crFore to make sure // the cache ID fields are set before crFore if (bType == CR_ENGINE_REALIZATION) { pbrush->SetEngineRealization(); } else { pbrush->SetDriverRealization(); } pbrush->crBack(pebo->crCurrentBack()); pbrush->ulPalTime(pebo->ulDCPalTime()); pbrush->ulSurfTime(pebo->ulSurfPalTime()); pbrush->ulRealization((ULONG_PTR)prbrush); pbrush->hdevRealization(pebo->psoTarg()->hdev()); pbrush->crPalColor(pebo->crDCPalColor()); // This must be set last, because once it's set, other selections of // this logical brush will attempt to use the cached brush. The use of // InterlockedExchange in this method enforces this pbrush->crForeLocked(pebo->crCurrentText()); // The realization is now cached in the logical brush } } } /******************************Public*Routine******************************\ * BRUSHOBJ_pvGetRbrush * * Returns a pointer to the driver's realization of the brush. * * History: * 31-Oct-1993 -by- Michael Abrash * Rewrote to cache the first realization in the logical brush. * * 8-Sep-1992 -by- Paul Butzi * Rewrote it. * * Wed 05-Jun-1991 -by- Patrick Haluptzok [patrickh] * major revision * * 25-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ PVOID BRUSHOBJ_pvGetRbrush( BRUSHOBJ *pbo ) { EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo; ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor"); // // Check if the brush has already been realized. // if (pebo->pvRbrush != NULL) { return(pebo->pvRbrush); } // // Get this thing realized. // PDEVOBJ pdo(pebo->psoTarg()->hdev()); if (!bGetRealizedBrush(pebo->pbrush(), pebo, PPFNDRV(pdo, RealizeBrush))) { if (pebo->pvRbrush != NULL) { VFREEMEM(DBRUSHSTART(pebo->pvRbrush)); // free the DBRUSH pebo->pvRbrush = NULL; // mark that there's no realization } return(NULL); } // // Try to cache the realization in the logical brush // //Make sure the brush is indeed realized if (pebo->pvRbrush == NULL) return(NULL); vTryToCacheRealization(pebo, (PDBRUSH) DBRUSHSTART(pebo->pvRbrush), pebo->pbrush(), CR_DRIVER_REALIZATION); return pebo->pvRbrush; } // // User mode printer driver support // PVOID BRUSHOBJ_pvGetRbrushUMPD( BRUSHOBJ *pbo ) { EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo; if (pbo->iSolidColor != 0xFFFFFFFF) { RIP("BRUSHOBJ_pvGetRbrush called for solid brush\n"); return NULL; } // // Check if the brush has already been realized // if (pebo->pvRbrush != NULL) return pebo->pvRbrush; // // Realize the brush // PDEVOBJ pdo(pebo->psoTarg()->hdev()); if (!bGetRealizedBrush(pebo->pbrush(), pebo, PPFNDRV(pdo, RealizeBrush))) { if (pebo->pvRbrush != NULL) { EngFreeUserMem(DBRUSHSTART(pebo->pvRbrush)); pebo->pvRbrush = NULL; } return NULL; } //Make sure the brush is indeed realized if (pebo->pvRbrush == NULL) return(NULL); #if defined(_WIN64) // // if we are doing WOW64 printing, skip the caching. // PW32THREAD pThread = W32GetCurrentThread(); if (pThread->pClientID == NULL) #endif { // Try to cache the realization in the logical brush vTryToCacheRealization(pebo, (PDBRUSH)DBRUSHSTART(pebo->pvRbrush), pebo->pbrush(), CR_DRIVER_REALIZATION); } return pebo->pvRbrush; } /******************************Public*Routine******************************\ * BRUSHOBJ_ulGetBrushColor * * Returns the RGB color for a solid brush. * * Oct-18-1995 -by- Lingyun Wang * Wrote it. \**************************************************************************/ ULONG BRUSHOBJ_ulGetBrushColor( BRUSHOBJ *pbo ) { EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo; if (pebo->bIsSolid()) { if(pebo->flColorType & BR_ORIGCOLOR) { pebo->flColorType &= ~BR_ORIGCOLOR; return ((ULONG)(pebo->crOrignal())); } else { return ((ULONG)(pebo->crRealized())); } } else { return (ULONG)(-1); } } /******************************Public*Routine******************************\ * BRUSHOBJ_hGetColorTransform * * Retuens the color transform for a brush. * * Feb-14-1997 -by- Hideyuki Nagase * Wrote it. ***************************************************************************/ HANDLE BRUSHOBJ_hGetColorTransform( BRUSHOBJ *pbo ) { ICMAPI(("BRUSHOBJ_hGetColorTransform()\n")); if (pbo == NULL) { WARNING("BRUSHOBJ_hGetColorTransform() BRUSHOBJ is NULL\n"); return(NULL); } EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo; // // if ICM is not enabled for this. Or if ICM is done by host, // Color transform handle is for host ICM it is no meanings // for device driver. then just return NULL. // if (pebo->bIsDeviceICM()) { if (pebo->hcmXform()) { COLORTRANSFORMOBJ CXFormObj(pebo->hcmXform()); if (CXFormObj.bValid()) { return(CXFormObj.hGetDeviceColorTransform()); } ICMMSG(("BRUSHOBJ_hGetColorTransform() COLORTRANSFORMOBJ is invalid\n")); } else { ICMMSG(("BRUSHOBJ_hGetColorTransform() Ident. color transform\n")); } } else { ICMMSG(("BRUSHOBJ_hGetColorTransform() ICM on device is not enabled\n")); } return(NULL); } /******************************Public*Routine******************************\ * pvGetEngRbrush * * Returns: A pointer to the engines's realization of a logical brush. * * Only the engine calls this, it is not exported. * * History: * 31-Oct-1993 -by- Michael Abrash * Rewrote to cache the first realization in the logical brush. * * 8-Sep-1992 -by- Paul Butzi * Rewrote it. * * Wed 05-Jun-1991 -by- Patrick Haluptzok [patrickh] * major revision * * 25-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it - First pass. \**************************************************************************/ PVOID pvGetEngRbrush( BRUSHOBJ *pbo ) { EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo; ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor"); // Check if the brush has already been realized. if (pebo->pengbrush() != (PVOID) NULL) { return pebo->pengbrush(); } // Get this thing realized. PDEVOBJ pdo(pebo->psoTarg()->hdev()); if (!bGetRealizedBrush(pebo->pbrush(), pebo, EngRealizeBrush)) { if (pebo->pengbrush() != NULL) { VFREEMEM(pebo->pengbrush()); // free the DBRUSH pebo->pengbrush(NULL); // mark that there's no realization } return(NULL); } // Try to cache the realization in the logical brush vTryToCacheRealization(pebo, pebo->pengbrush(), pebo->pbrush(), CR_ENGINE_REALIZATION); return(pebo->pengbrush()); } /******************************Public*Routine******************************\ * bGetRealizedBrush * * Returns: Pointer to a Realized brush. * * NOTE: The surface in pebo->psoTarg() is the surface of the original * destination of the drawing call. If a display driver was called, * but it punts by calling back to the engine with an engine-managed * bitmap it created, psoTarg() will still point to the original * display surface, not the DIB surface. The surface will have the * same hdev, iFormat, etc., but this means that the iType will be * wrong, so don't reference it! (EngRealizeBrush actually accounts * for this little lie.) * * History: * 14-Jul-1992 -by- Eric Kutter [erick] * added exception handling, changed from VOID to BOOL * * Mon 07-Oct-1991 -by- Patrick Haluptzok [patrickh] * add support for DIB_PAL_COLORS flag. * * 04-Jun-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ BOOL bGetRealizedBrush( BRUSH *pbrush, EBRUSHOBJ *pebo, PFN_DrvRealizeBrush pfnDrv ) { ASSERTGDI(pebo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor"); ASSERTGDI(pfnDrv != (PFN_DrvRealizeBrush) 0, "ERROR pfnDrv"); // // quick out if it is a NULL brush // if (pbrush->ulStyle() == HS_NULL) { WARNING1("You are doing output calls with a NULL brush\n"); return(FALSE); } // // Dispatch off to driver to get brush realized. // ULONG ulStyle = pbrush->ulStyle(); SURFOBJ *psoPattern; SURFOBJ *psoMask = NULL; XEPALOBJ palSrc; XEPALOBJ palDest; SURFREF SurfBmoPattern; EXLATEOBJ exlo; XLATE *pxlo = NULL; SURFMEM SurfDimo; // // We default to this. // PDEVOBJ po(pebo->psoTarg()->hdev()); ASSERTGDI(po.bValid(), "ERROR BRUSHOBJ_ 5"); // // We need to hold the Devlock to protect against dynamic mode changes // while we muck around in the driver. If we're being call by the // driver, we're guaranteed to already be holding it, so we only have // to do this if we're being called by GDI's Eng functions. // DEVLOCKOBJ dlo; if (pfnDrv == EngRealizeBrush) { dlo.vLock(po); } else { dlo.vInit(); } if (pbrush->ulStyle() < HS_DDI_MAX) { // // For hatch brushes, the pattern is also the mask // SurfBmoPattern.vAltLock((HSURF)po.hbmPattern(pbrush->ulStyle())); psoMask = SurfBmoPattern.pSurfobj(); if (exlo.pCreateXlateObject(2)) { ULONG ulValue1, ulValue2; if (pebo->bIsCMYKColor()) { // // We are in CMYK color context, we just set CMYK color // ulValue1 = pebo->crCurrentBack(); ulValue2 = pebo->crRealized(); exlo.pxlo()->vSetIndex(0, ulValue1); exlo.pxlo()->vSetIndex(1, ulValue2); pxlo = exlo.pxlo(); pxlo->vCheckForICM(pebo->hcmXform(),pebo->lIcmMode()); pxlo->ppalSrc = ppalMono; pxlo->ppalDst = pebo->palSurf().ppalGet(); pxlo->ppalDstDC = pebo->palDC().ppalGet(); } else { ulValue1 = ulGetNearestIndexFromColorref( pebo->palSurf(), pebo->palDC(), pebo->crCurrentBack() ); ulValue2 = ulGetNearestIndexFromColorref( pebo->palSurf(), pebo->palDC(), pebo->crRealized() ); // // Windows compability issue: // force to draw on the background // // We force the forground to be mapped // to an index opposite to the background // if ((pebo->psoTarg()->iFormat() == BMF_1BPP) && (pebo->palSurf().bIsIndexed()) && (pebo->crCurrentBack() != pebo->crRealized()) && (ulValue1 == ulValue2)) { ulValue2 = 1-ulValue1; } exlo.pxlo()->vSetIndex(0, ulValue1); exlo.pxlo()->vSetIndex(1, ulValue2); pxlo = exlo.pxlo(); pxlo->vCheckForICM(pebo->hcmXform(),pebo->lIcmMode()); pxlo->vCheckForTrivial(); pxlo->ppalSrc = ppalMono; pxlo->ppalDst = pebo->palSurf().ppalGet(); pxlo->ppalDstDC = pebo->palDC().ppalGet(); } pxlo->iForeDst = ulValue1; pxlo->iBackDst = ulValue2; pxlo->flPrivate |= XLATE_FROM_MONO; } else { WARNING("ERROR failed to create hatch xlate\n"); return(FALSE); } } else if (pbrush->ulStyle() < HS_NULL) { // // For solid brushes. // ASSERTGDI(pbrush->flAttrs() & BR_IS_SOLID, "ERROR non-solid brush"); ASSERTGDI((pbrush->flAttrs() & BR_DITHER_OK) || (po.bCapsForceDither()), "ERROR BRUSHOBJ_ 1"); // // We will not dither CMYK color brush. Driver should not call BRUSHOBJ_pvGetRbrush // with CMYK solid color brush. // if (pebo->bIsCMYKColor()) { WARNING("ERROR bGetRealizedBrush() Can't dither CMYK color brush\n"); return (FALSE); } // // This means they want us to dither the color and nothing // in their palette is close enough that we can't just use // a solid color. // if (pebo->crRealized() & 0x01000000) { pebo->crRealized(rgbFromColorref(pebo->palSurf(), pebo->palDC(), pebo->crRealized())); } // // Use the nifty DitherOnRealize option, if the driver supports it and // we're not realizing the brush on behalf of the engine simulations // (since the engine will be drawing, it will need its own realization, // not the driver's): // if ((po.flGraphicsCaps() & GCAPS_DITHERONREALIZE) && (pfnDrv != EngRealizeBrush)) { if ((*pfnDrv) (pebo, pebo->psoTarg()->pSurfobj(), (SURFOBJ *) NULL, (SURFOBJ *) NULL, NULL, pebo->crRealized() | RB_DITHERCOLOR)) { return(TRUE); } } DEVBITMAPINFO dbmi; if (pebo->psoTarg()->iFormat() == BMF_1BPP) { dbmi.iFormat = BMF_1BPP; } else { dbmi.iFormat = po.iDitherFormat(); } dbmi.cxBitmap = po.cxDither(); dbmi.cyBitmap = po.cyDither(); dbmi.hpal = 0; dbmi.fl = BMF_TOPDOWN; if (!SurfDimo.bCreateDIB(&dbmi, NULL)) { WARNING("Failed memory alloc in dither brush\n"); return(FALSE); } ULONG iRes; ULONG iDitherMode = ((pebo->psoTarg()->iFormat() == BMF_1BPP) ? DM_MONOCHROME: DM_DEFAULT); if (PPFNVALID(po, DitherColor)) { iRes = (*PPFNDRV(po, DitherColor)) ( po.bUMPD() ? (DHPDEV)po.ppdev : po.dhpdev(), iDitherMode, pebo->crRealized(), (PULONG) SurfDimo.ps->pvBits()); } else { iRes = EngDitherColor(po.hdev(), iDitherMode, pebo->crRealized(), (PULONG) SurfDimo.ps->pvBits()); } switch (iRes) { case DCR_DRIVER: pxlo = &xloIdent; break; case DCR_HALFTONE: { if ((po.pDevHTInfo() == NULL) && !po.bEnableHalftone(NULL)) return(FALSE); DEVICEHALFTONEINFO *pDevHTInfo = (DEVICEHALFTONEINFO *)po.pDevHTInfo(); COLORTRIAD ColorTriad; CHBINFO CHBInfo; COLORREF cr = pebo->crRealized(); ColorTriad.Type = COLOR_TYPE_RGB; ColorTriad.BytesPerPrimary = sizeof(BYTE); ColorTriad.BytesPerEntry = sizeof(DWORD); ColorTriad.PrimaryOrder = PRIMARY_ORDER_RGB; ColorTriad.PrimaryValueMax = 255; ColorTriad.ColorTableEntries = 1; ColorTriad.pColorTable = (LPVOID)&cr; CHBInfo.Flags = (BYTE)((po.GdiInfo()->flHTFlags & HT_FLAG_OUTPUT_CMY) ? 0 : CHBF_USE_ADDITIVE_PRIMS); // Control ICM bits for halftoning if ((pebo->bIsAppsICM()) || (!pebo->bDeviceCalibrate() && (pebo->bIsHostICM() || pebo->bIsDeviceICM()))) { ICMDUMP(("bGetRealizedBrush(): ICM with Halftone (Dynamic Bit On)\n")); // Some kind of ICM (ICM on Application, Graphics Engine or Device) // is enabled, so tell halftoning code to disable thier color adjustment. CHBInfo.Flags |= CHBF_ICM_ON; } else { ICMDUMP(("bGetRealizedBrush(): ICM with Halftone (Dynamic Bit Off)\n")); } if ((pDevHTInfo->cxPattern != dbmi.cxBitmap) || (pDevHTInfo->cyPattern != dbmi.cyBitmap)) { SurfDimo.ps->bDeleteSurface(); dbmi.cxBitmap = pDevHTInfo->cxPattern; dbmi.cyBitmap = pDevHTInfo->cyPattern; if (!SurfDimo.bCreateDIB(&dbmi, NULL)) { WARNING("Failed memory alloc in dither brush1\n"); return(FALSE); } } switch(po.GdiInfo()->ulHTOutputFormat) { case HT_FORMAT_1BPP: CHBInfo.DestSurfaceFormat = (BYTE)BMF_1BPP; break; case HT_FORMAT_4BPP: CHBInfo.DestSurfaceFormat = (BYTE)BMF_4BPP; break; case HT_FORMAT_4BPP_IRGB: CHBInfo.DestSurfaceFormat = (BYTE)BMF_4BPP_VGA16; break; case HT_FORMAT_8BPP: CHBInfo.DestSurfaceFormat = (BYTE)BMF_8BPP_VGA256; break; case HT_FORMAT_16BPP: // // Need to switch between BMF_16BPP_555 and BMF_16BPP_565 // CHBInfo.DestSurfaceFormat = (BYTE)BMF_16BPP_555; break; case HT_FORMAT_32BPP: CHBInfo.DestSurfaceFormat = (BYTE)BMF_32BPP; break; default: WARNING("Halftone format not supported\n"); return(FALSE); } CHBInfo.DestScanLineAlignBytes = BMF_ALIGN_DWORD; CHBInfo.DestPrimaryOrder = (BYTE)po.GdiInfo()->ulPrimaryOrder; // Brushes, unlike scanned in images, have linear RGB gamma. // Use a gamma value of 1 can produce lighter, closer to wfw halftone // images for solid brushes. This is to fix powerpnt shaded background // printing. Other apps that print black text on dark background will // benefit from this fix as well. COLORADJUSTMENT ca = *pebo->pColorAdjustment(); ca.caRedGamma = 10000; ca.caGreenGamma = 10000; ca.caBlueGamma = 10000; if (HT_CreateHalftoneBrush( pDevHTInfo, (PHTCOLORADJUSTMENT)&ca, &ColorTriad, CHBInfo, (PULONG)SurfDimo.ps->pvBits()) > 0) { // Set up the translate object. if (po.bHTPalIsDevPal()) { pxlo = &xloIdent; } else { EPALOBJ palHT((HPALETTE)pDevHTInfo->DeviceOwnData); palDest.ppalSet(pebo->psoTarg()->ppal()); if (!exlo.bInitXlateObj( pebo->hcmXform(), pebo->lIcmMode(), palHT, palDest, pebo->palDC(), pebo->palDC(), pebo->crCurrentText(), pebo->crCurrentBack(), 0x00FFFFFF )) { WARNING("Failed to create an xlate bGetRealizedBrush DIB_PAL_COLORS\n"); return(FALSE); } pxlo = exlo.pxlo(); } break; } } // case DCR_HALFTONE default: WARNING("DrvDitherColor returned invalid value or failed\n"); return(FALSE); } // switch (iRes) } else // if (pbrush->ulStyle() >= HS_NULL) { BOOL bIcmBrush = FALSE; // // For bitmap/pattern brushes. // HSURF hDIB = (HSURF)pbrush->hbmPattern(); ASSERTGDI(pbrush->ulStyle() <= HS_PATMSK, "ERROR ulStyle is bad"); // ICM is enabled ? and the Brush is DIB ? For Device Depend Bitmap, we will // not enable ICM. Only for DIB. if (pebo->bIsHostICM()) { if (pebo->hcmXform() != NULL) { if (pbrush->flAttrs() & BR_IS_DIB) { // if ICM is enabled, the BRUSHOBJ should have color transform. if (pbrush->iUsage() == DIB_RGB_COLORS) { ICMMSG(("bGetRealizedBrush: TRY Find ICM DIB\n")); // Find color translated brush DIB. HSURF hIcmDIB = (HSURF)(pbrush->hFindIcmDIB(pebo->hcmXform())); if (hIcmDIB == NULL) { // Somehow, we could not find DIB, just use orginal. WARNING1("bGetRealizedBrush(): hFindIcmDIB() returns NULL\n"); } else { // Replace DIB handle with ICM-ed DIB. hDIB = hIcmDIB; bIcmBrush = TRUE; } } else { // if DIB is other than DIB_RGB_COLORS, ICM DIB will not be used. ICMMSG(("bGetRealizedBrush(): Brush color is not DIB_RGB_COLORS\n")); } } else if (pbrush->flAttrs() & BR_IS_MONOCHROME) { ICMMSG(("bGetRealizedBrush(): Brush color is BR_IS_MONOCHROME\n")); bIcmBrush = TRUE; } } else { // ICM is enabled, but no color transform, it means identical color transform // so, there is no ICM-ed DIB. ICMMSG(("bGetRealizedBrush(): Color transform is identical\n")); // If we are in CMYK mode, we must have color transform. if (!pebo->bIsCMYKColor()) { bIcmBrush = TRUE; } } } else if (pebo->bIsAppsICM() || pebo->bIsDeviceICM()) { bIcmBrush = TRUE; } SurfBmoPattern.vAltLock(hDIB); if(!SurfBmoPattern.bValid()) { WARNING("WARNING:bGetRealizedBrush(): Invalid SurfBmopattern\n"); return(FALSE); } palSrc.ppalSet(SurfBmoPattern.ps->ppal()); palDest.ppalSet(pebo->psoTarg()->ppal()); if (pbrush->bPalColors()) { ASSERTGDI(palSrc.bValid(), "ERROR3invalid hpal pvGetEngRbrush\n"); if (!exlo.bMakeXlate((PUSHORT) palSrc.apalColorGet(), pebo->palDC(), pebo->psoTarg(), palSrc.cColorTableLength(), palSrc.cEntries())) { WARNING("Failed to create an xlate bGetRealizedBrush DIB_PAL_COLORS\n"); return(FALSE); } pxlo = exlo.pxlo(); } else if (pbrush->bPalIndices()) { if (SurfBmoPattern.ps->iFormat() != pebo->psoTarg()->iFormat()) { WARNING("Output failed: DIB_PAL_INDICES brush not compatible with dest surface\n"); return(FALSE); } pxlo = &xloIdent; } else { // With our wonderful API we can't fail a brush selection like Windows would. // Instead we let the app think he selected the bitmap brush in and then at // realize time if that wasn't a valid selection we fail the realize. Good // luck writing new apps. PPALETTE ppalSrcTmp; // We need to make sure this could be selected into this DC. If it is a device // managed bitmap, it must be the same device. if (( (SurfBmoPattern.ps->iType() != STYPE_BITMAP) || (SurfBmoPattern.ps->dhsurf() != 0) ) && (SurfBmoPattern.ps->hdev() != po.hdev())) { WARNING1("bGetRealizedBrush failed Device surface for another PDEV\n"); return (FALSE); } else if (SurfBmoPattern.ps->ppal() != NULL) { // No problem, we already have color information. ppalSrcTmp = SurfBmoPattern.ps->ppal(); } else { if (SurfBmoPattern.ps->iFormat() == po.iDitherFormat()) { if (po.bIsPalManaged()) { ppalSrcTmp = (PPALETTE) NULL; } else { ppalSrcTmp = po.ppalSurf(); } } else if (SurfBmoPattern.ps->iFormat() == pebo->iMetaFormat()) { // We can try to use palette from meta. ppalSrcTmp = pebo->palMeta().ppalGet(); } else if (SurfBmoPattern.ps->iFormat() == BMF_8BPP) { if (po.bIsPalManaged()) { ppalSrcTmp = (PPALETTE) NULL; } else { ppalSrcTmp = ppalDefaultSurface8bpp; } } else { if (po.bMetaDriver()) ppalSrcTmp = (PPALETTE) NULL; else { WARNING("bGetRealizedBrush failed - bitmap not compatible with surface\n"); return FALSE; } } } // Replace source palette with proper one which decided in above. palSrc.ppalSet(ppalSrcTmp); if (!exlo.bInitXlateObj( (bIcmBrush ? pebo->hcmXform() : NULL), (bIcmBrush ? pebo->lIcmMode() : DC_ICM_OFF), palSrc, palDest, pebo->palDC(), pebo->palDC(), pebo->crCurrentText(), pebo->crCurrentBack(), 0x00FFFFFF )) { WARNING("Failed to create an xlate pvGetRbrush\n"); return (FALSE); } pxlo = exlo.pxlo(); } } // Do the right thing if a pattern is provided if (SurfBmoPattern.bValid()) { psoPattern = SurfBmoPattern.pSurfobj(); } else { // Check for dithering if (SurfDimo.bValid()) { psoPattern = SurfDimo.pSurfobj(); } else psoPattern = (SURFOBJ *) NULL; } // Call off to driver to the RealizeBrush return((*pfnDrv) (pebo, pebo->psoTarg()->pSurfobj(), psoPattern, psoMask, pxlo, ulStyle)); }