/******************************Module*Header*******************************\ * Module Name: paleng.cxx * * Palette support routines used by NT components. * * Created: 27-Nov-1990 12:28:40 * Author: Patrick Haluptzok patrickh * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" /******************************Public*Routine******************************\ * GreSetPaletteOwner * * Sets the palette owner. * \**************************************************************************/ BOOL GreSetPaletteOwner( HPALETTE hpal, W32PID lPid) { BOOL bRet = FALSE; if (hpal==(HPALETTE)STOCKOBJ_PAL) { WARNING("GreSetPaletteOwner: Cannot set owner for the stock Palette\n"); } else { bRet = HmgSetOwner((HOBJ)hpal,lPid,PAL_TYPE); } return (bRet); } /******************************Public*Routine******************************\ * CreateSurfacePal * * Turns a physical palette into a palette managed palette for a device. * * History: * Tue 04-Dec-1990 -by- Patrick Haluptzok [patrickh] * Wrote it. \**************************************************************************/ BOOL CreateSurfacePal(XEPALOBJ palSrc, FLONG iPalType, ULONG ulNumReserved, ULONG ulNumPalReg) { ASSERTGDI(iPalType == PAL_MANAGED, "ERROR: CreateSurfacePalette passed bad iPalType\n"); ASSERTGDI(palSrc.bValid(), "ERROR CreateSurfacePal palSrc"); ASSERTGDI(palSrc.cEntries() != 0, "ERROR CreateSurfacePal"); // // If it is a Palette managed surface we must keep an exact // copy of it's origal state for certain functionality. // PALMEMOBJ pal; BOOL b; b = pal.bCreatePalette(palSrc.iPalMode(), palSrc.cEntries(), (PULONG) palSrc.apalColorGet(), 0, 0, 0, iPalType); if (b) { ASSERTGDI(pal.bIsIndexed(), "Creating a non-indexed managed surface ???"); ASSERTGDI(pal.bIsPalManaged(), "ERROR PAL_MANaged not pal managed"); // // Now we have to set the type or the source to be PAL_MANAGED. // palSrc.flPalSet((palSrc.flPal() & ~(PAL_FIXED)) | PAL_MANAGED); // // Set the used and foreground flags on the reserved palette entries. // PAL_ULONG palTemp; ASSERTGDI((ulNumReserved & 0x00001) == 0, "ERROR non multiple of 2 reserved colors"); palSrc.ulNumReserved(ulNumReserved); pal.ulNumReserved(ulNumReserved); ulNumReserved >>= 1; ULONG iPalMode; for (iPalMode = 0; iPalMode < ulNumReserved; iPalMode++) { palTemp.ul = pal.ulEntryGet(iPalMode); palTemp.pal.peFlags = (PC_FOREGROUND | PC_USED); pal.ulEntrySet(iPalMode, palTemp.ul); palTemp.ul = pal.ulEntryGet(iPalMode + (ulNumPalReg - ulNumReserved)); palTemp.pal.peFlags = (PC_FOREGROUND | PC_USED); pal.ulEntrySet(iPalMode + (ulNumPalReg - ulNumReserved), palTemp.ul); } // // Ok the palette is in perfect initial shape, copy it. // palSrc.vCopyEntriesFrom(pal); palSrc.ppalOriginal(pal.ppalGet()); pal.ulTime(palSrc.ulTime()); pal.vKeepIt(); } return(b); } /******************************Public*Routine******************************\ * ulGetNearestIndexFromColorref * * Given the surface palette and the DC palette, this returns the index in * palSurf that crColor maps to. * * Modifies: Nothing. * * Returns: Index in palSurf that crColor maps to. * * PALETTERGB puts a 2 in the high byte. * PALETTEINDEX puts a 1 in the high byte. * * History: * Mon 02-Sep-1991 -by- Patrick Haluptzok [patrickh] * Wrote it. \**************************************************************************/ ULONG ulGetNearestIndexFromColorref( XEPALOBJ palSurf, XEPALOBJ palDC, ULONG crColor, ULONG seSearchExactFirst) { ASSERTGDI(palDC.bValid(), "ERROR invalid palDC"); PDEV *ppdev = (PDEV *)palDC.hdev(); PAL_ULONG palTemp; palTemp.ul = crColor; // // Check if it's palette managed. If it's a device bitmap for a palette managed // device it will have an invalid palette. If the palettes valid then it may be // the palette managed device's palette. // if ((!palSurf.bValid()) || (palSurf.bIsPalManaged())) { // // RGB: Match to default palette or dither // // PALETTERGB: Match RGB value to nearest entry in palette // // PALETTEINDEX: The low 16 bits is a direct index to a palette entry // // // Check if it's a color forces us to access the xlate // if (palTemp.ul & 0x03000000) { if (palTemp.ul & 0x01000000) { // // PALETTEINDEX: // // This means they have an explicit entry in the DC palette they want // palTemp.pal.peFlags = 0; if (palTemp.ul >= palDC.cEntries()) { palTemp.ul = 0; } } else { // // PALETTERGB: // // Get rid of the top byte first. It's 0x02 and we want to // search with this being an RGB. // palTemp.pal.peFlags = 0; palTemp.ul = palDC.ulGetNearestFromPalentry( palTemp.pal, seSearchExactFirst ); } // // If the DC's palette is the default palette, adjust if this is in the // top 10 colors, then we're done, because there's no translation of // the default palette // if (palDC.bIsPalDefault()) { if (palTemp.ul >= 10) { palTemp.ul = palTemp.ul + 236; } return(palTemp.ul); } // // Now do the right thing based on whether we are on the device bitmap // or the device surface. // if ((palSurf.bValid()) && (palDC.ptransCurrent() != NULL)) { return(palDC.ulTranslateDCtoCurrent(palTemp.ul)); } if ((!palSurf.bValid()) && (palDC.ptransFore() != NULL)) { return(palDC.ulTranslateDCtoFore(palTemp.ul)); } // // App is in hosed state which is possible in multi-tasking system. // Map as best we can into static colors, get the RGB from palDC. // palTemp.pal = palDC.palentryGet(palTemp.ul); // // If PC_EXPLICIT is set just return value modulo 256. // if (palTemp.pal.peFlags == PC_EXPLICIT) { return(palTemp.ul & 0x000000FF); } } // // check for DIBINDEX // if ((palTemp.ul & 0x10ff0000) == 0x10ff0000) { return(palTemp.ul & 0x000000FF); } // // At this point palTemp is an RGB value // // Well we need to match against the default palette. We quickly // check for black and white and pass the rest through. // palTemp.pal.peFlags = 0; if (palTemp.ul == 0xFFFFFF) { palTemp.ul = 19; } else if (palTemp.ul != 0) { palTemp.ul = ((XEPALOBJ) ppalDefault).ulGetNearestFromPalentry( palTemp.pal, seSearchExactFirst ); } if (palTemp.ul >= 10) { palTemp.ul = palTemp.ul + 236; } return(palTemp.ul); } // // This means they are not palette managed. // if (palTemp.ul & 0x01000000) { // // PALETTEINDEX: // This means they have an explicit entry in the DC palette they want. // palTemp.ul &= 0x0000FFFF; if (palTemp.ul >= palDC.cEntries()) { palTemp.ul = 0; } palTemp.pal = palDC.palentryGet(palTemp.ul); } else if ((palTemp.ul & 0x10ff0000) == 0x10ff0000) { // // check for DIBINDEX // palTemp.ul &= 0x000000FF; return((palTemp.ul >= palSurf.cEntries()) ? 0 : palTemp.ul); } else { // // We just look for the closest RGB. // palTemp.pal.peFlags = 0; } // // Now it is time to look in the surface palette for the matching color. // return(palSurf.ulGetNearestFromPalentry(palTemp.pal, seSearchExactFirst)); } /******************************Public*Routine******************************\ * ulGetMatchingIndexFromColorref * * Given the surface palette and the DC palette, this returns the index in * palSurf that crColor maps to exactly, or 0xFFFFFFFF if it doesn't map * exactly to any color. Note that if the "find nearest in palette managed" * bit (0x20000000) is set, the nearest color qualifies as a match, because * that's what they're asking for. However, there is no guarantee that either * of the special bits will result in a match, because the palette may be in * an incorrect state or they could be asking for a direct index into the DC * palette that produces a color that's not in the surface's palette (in the * case of a non-palette-managed surface). * * Modifies: Nothing. * * Returns: Index in palSurf that crColor maps to. * * PALETTERGB puts a 2 in the high byte (find nearest) * PALETTEINDEX puts a 1 in the high byte (find specified index) * * History: * Sun 27-Dec-1992 -by- Michael Abrash [mikeab] * Wrote it. \**************************************************************************/ ULONG ulGetMatchingIndexFromColorref( XEPALOBJ palSurf, XEPALOBJ palDC, ULONG crColor ) { ASSERTGDI(palDC.bValid(), "ERROR invalid palDC"); PAL_ULONG palTemp; PDEV *ppdev = (PDEV *)palDC.hdev(); palTemp.ul = crColor; // // Check if it's palette managed. If it's a device bitmap for a palette managed // device it will have an invalid palette. If the palette's valid then it may be // the palette managed device's palette. // if ((!palSurf.bValid()) || (palSurf.bIsPalManaged())) { // // RGB: Match to default palette or dither // // PALETTERGB: Match RGB value to nearest entry in palette // // PALETTEINDEX: The low 16 bits is a direct index to a palette entry // // // Check if it's a color forces us to access the xlate // if (palTemp.ul & 0x03000000) { if (palTemp.ul & 0x01000000) { // // PALETTEINDEX: // // This means they have an explicit entry in the DC palette they // want; only the lower byte is valid // palTemp.ul &= 0x0000FFFF; if (palTemp.ul >= palDC.cEntries()) { palTemp.ul = 0; } } else // (palTemp.ul & 0x02000000) { // // Get rid of the top byte first. It's 0x02 and we want to search // the DC's palette for the nearest match with this being an RGB. // Note that in this case the nearest match and exact match are // logically equivalent // palTemp.pal.peFlags = 0; palTemp.ul = palDC.ulGetNearestFromPalentry(palTemp.pal); } // // If the DC's palette is the default palette, adjust if this is in the // top 10 colors, then we're done, because there's no translation of // the default palette // if (palDC.bIsPalDefault()) { if (palTemp.ul >= 10) { palTemp.ul = palTemp.ul + 236; } return(palTemp.ul); } // // Now do the right thing based on whether we are on the device bitmap // or the device surface // if ((palSurf.bValid()) && (palDC.ptransCurrent() != NULL)) { // // We're drawing to a palette managed device surface, using the // current translation (which may be either back or fore, depending // on whether the application is in the foreground and owns the // palette) // return(palDC.ulTranslateDCtoCurrent(palTemp.ul)); } if ((!palSurf.bValid()) && (palDC.ptransFore() != NULL)) { // // We're drawing to a bitmap for a palette managed device, using // the fore translation (always treat drawing to a bitmap as // foreground drawing) // return(palDC.ulTranslateDCtoFore(palTemp.ul)); } // // App is in hosed state which is possible in multi-tasking system. // Map as best we can into static colors, get the RGB from palDC and // try to find that in the default palette // palTemp.pal = palDC.palentryGet(palTemp.ul); // // If PC_EXPLICIT is set just return value modulo 256. // if (palTemp.pal.peFlags == PC_EXPLICIT) { return(palTemp.ul & 0x000000FF); } } // // check for DIBINDEX // if ((palTemp.ul & 0x10ff0000) == 0x10ff0000) { return(palTemp.ul & 0x000000FF); } // // Well, we're palette managed and have a plain old RGB (or failed to // find the desired translation), so we need to match against the // default palette. We quickly check for black and white and pass // the rest through. // palTemp.pal.peFlags = 0; if (palTemp.ul == 0xFFFFFF) { palTemp.ul = 19; } else if (palTemp.ul != 0) { palTemp.ul = ((XEPALOBJ) ppalDefault).ulGetMatchFromPalentry(palTemp.pal); } // // If we're in the top half of the default palette, adjust to the high end // of the 256-color palette, where the top half of the default palette // actually resides // if ((palTemp.ul != 0xFFFFFFFF) && (palTemp.ul >= 10)) { palTemp.ul = palTemp.ul + 236; } return(palTemp.ul); } // // Not palette managed. // if (palTemp.ul & 0x01000000) { // // This means they have an explicit entry in the DC palette they want. // Limit the maximum explicit entry to 8 bits. // palTemp.ul &= 0x0000FFFF; // // If the index is off the end of the palette, wrap it modulo the palette // length. // if (palTemp.ul >= palDC.cEntries()) { palTemp.ul = 0; } // // Search the palette for the color closest to the color selected from the // DC palette by the specified index // palTemp.pal = palDC.palentryGet(palTemp.ul); } else if ((palTemp.ul & 0x10ff0000) == 0x10ff0000) { // // check for DIBINDEX // palTemp.ul &= 0x000000FF; return((palTemp.ul >= palSurf.cEntries()) ? 0 : palTemp.ul); } else { // // We just look for the closest RGB; mask off the flags. // palTemp.pal.peFlags = 0; } // // Now it is time to look in the surface palette for the matching color. // return(palSurf.ulGetMatchFromPalentry(palTemp.pal)); } /******************************Public*Routine******************************\ * ulColorRefToRGB * * Given a color ref this returns the RGB it corresponds to. * * This is a helper function given a color ref that may contain * DIBINDEX value, do the appropriate translation of the DIBINDEX. * * History: * 19-Jan-2001 -by- Barton House bhouse * Wrote it. \**************************************************************************/ ULONG ulColorRefToRGB( XEPALOBJ palSurf, XEPALOBJ palDC, ULONG iColorRef ) { if((iColorRef & 0x10FF0000) == 0x10FF0000) { return ulIndexToRGB(palSurf, palDC, iColorRef & 0xFF); } else { return iColorRef; } } /******************************Public*Routine******************************\ * ulIndexToRGB * * Given an index this returns the RGB it corresponds to. * * History: * 21-Nov-1992 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ ULONG ulIndexToRGB( XEPALOBJ palSurf, XEPALOBJ palDC, ULONG iSolidColor ) { ASSERTGDI(palDC.bValid(), "ERROR invalid palDC"); PAL_ULONG palTemp; if (palSurf.bValid()) { return(palSurf.ulIndexToRGB(iSolidColor)); } // // It's a palette managed device bitmap. // if (iSolidColor < 10) { palTemp.pal = logDefaultPal.palPalEntry[iSolidColor]; return(palTemp.ul); } if (iSolidColor > 245) { palTemp.pal = logDefaultPal.palPalEntry[iSolidColor - 236]; return(palTemp.ul); } // // Well it's the first entry in the logical palette that mapped here in the // foreground xlate. If the foreground Xlate is invalid, who knows, return 0. // SEMOBJ semo(ghsemPalette); if (palDC.ptransFore() != NULL) { PBYTE pjTemp = palDC.ptransFore()->ajVector; palTemp.ul = palDC.cEntries(); for (palTemp.ul = 0; palTemp.ul < palDC.cEntries(); palTemp.ul++,pjTemp++) { if (*pjTemp == ((BYTE) iSolidColor)) return(palDC.ulEntryGet(palTemp.ul)); } } // // Well we just don't know. // return(0); } /******************************Public*Routine******************************\ * bIsCompatible * * This returns TRUE if the bitmap can be selected into this PDEV's memory * DC's based on "Can we determine the color information". It also returns * the palette you could use for a reference for color information. * * History: * 28-Jan-1993 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ BOOL bIsCompatible(PPALETTE *pppalReference, PPALETTE ppalBM, SURFACE *pSurfBM, HDEV hdev) { BOOL bRet = TRUE; XEPALOBJ palBM(ppalBM); PDEVOBJ po(hdev); // 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 (((pSurfBM->iType() != STYPE_BITMAP) || (pSurfBM->dhsurf() != 0)) && (pSurfBM->hdev() != hdev)) { WARNING1("bIsCompatible failed Device surface for another PDEV\n"); bRet = FALSE; } else if (palBM.bValid()) { // No problem, we already have color information. *pppalReference = palBM.ppalGet(); } else if (pSurfBM->iFormat() != po.iDitherFormat()) { // Check surface is compatible with PDEV for selection. WARNING1("bIsCompatible: Bitmap not compatible with DC\n"); bRet = FALSE; } else { // If it's not palette managed set in palette for the device. Otherwise // leave it NULL and the right stuff will happen. if (!po.bIsPalManaged()) { *pppalReference = po.ppalSurf(); } else { *pppalReference = (PPALETTE) NULL; ASSERTGDI(po.iDitherFormat() == BMF_8BPP, "ERROR GetDIBits no palette not 8BPP"); } } return(bRet); } /******************************Public*Routine******************************\ * rgbFromColorref * * Given the surface palette and the DC palette, this returns the rgb that * this colorref represents. * * Returns: RGB that crColor maps to. * * PALETTERGB puts a 2 in the high byte (find nearest) * PALETTEINDEX puts a 1 in the high byte (find specified index) * * History: * Thu 18-Feb-1993 -by- Patrick Haluptzok [patrickh] * Wrote it. \**************************************************************************/ ULONG rgbFromColorref( XEPALOBJ palSurf, XEPALOBJ palDC, ULONG crColor ) { ASSERTGDI(palDC.bValid(), "ERROR invalid palDC"); PAL_ULONG palTemp; palTemp.ul = crColor; if (palTemp.ul & 0x01000000) { // // This means they have an explicit entry in the DC palette they // want. Only the lower byte is valid. // palTemp.ul &= 0x0000FFFF; if (palTemp.ul >= palDC.cEntries()) { palTemp.ul = 0; } palTemp.pal = palDC.palentryGet(palTemp.ul); // // If PC_EXPLICIT reach into the surface palette if possible. // if (palTemp.pal.peFlags == PC_EXPLICIT) { if (palSurf.bValid()) { if (palSurf.cEntries()) { palTemp.ul &= 0x000000FF; if (palTemp.ul >= palSurf.cEntries()) { palTemp.ul = palTemp.ul % palSurf.cEntries(); } palTemp.pal = palSurf.palentryGet(palTemp.ul); } } } } palTemp.pal.peFlags = 0; return(palTemp.ul); } /******************************Public*Routine******************************\ * bEqualRGB_In_Palette * * This function determines if 2 palettes contain identical RGB entries and * palette sizes and therefore have an identity xlate between them. This is * need with DIBSECTIONS which may have duplicate palette entries but still * should have identity xlates when blting between them. * * History: * 10-Mar-1994 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ BOOL bEqualRGB_In_Palette(XEPALOBJ palSrc, XEPALOBJ palDst) { ASSERTGDI(palSrc.bValid(), "ERROR invalid SRC"); ASSERTGDI(palDst.bValid(), "ERROR invalid DST"); // // Check for equal size palettes that are == to 256 in size. // 256 is the size of our palette managed palettes. // if ((palSrc.cEntries() != palDst.cEntries()) || (palDst.cEntries() != 256)) { return(FALSE); } // // If the Dst is a DC palette make sure it contains an identity // realization in it. // UINT uiIndex; if (palDst.bIsPalDC()) { // // Check the translate for the current if it's the screen, otherwise // check the translate for the foreground for a bitmap. // TRANSLATE *ptrans = palDst.ptransFore(); if (ptrans == NULL) return(FALSE); uiIndex = palDst.cEntries(); while(uiIndex--) { if (ptrans->ajVector[uiIndex] != uiIndex) return(FALSE); } } uiIndex = palDst.cEntries(); ULONG ulTemp; while(uiIndex--) { ulTemp = palSrc.ulEntryGet(uiIndex) ^ palDst.ulEntryGet(uiIndex); if (ulTemp & 0xFFFFFF) { return(FALSE); } } return(TRUE); }