/* * Color functions * * Copyright 1993 Alexandre Julliard */ #include #include #include #include "windows.h" #include "options.h" #include "gdi.h" #include "color.h" #include "palette.h" #include "stddebug.h" #include "debug.h" #include "xmalloc.h" Colormap COLOR_WinColormap = 0; static int COLOR_FixedMap = 0; static int COLOR_Redshift = 0; static int COLOR_Redmax = 0; static int COLOR_Greenshift = 0; static int COLOR_Greenmax = 0; static int COLOR_Blueshift = 0; static int COLOR_Bluemax = 0; static int COLOR_Graymax = 0; /* System palette static colors */ #define NB_RESERVED_COLORS 20 /* The first and last eight colors are EGA colors */ static PALETTEENTRY COLOR_sysPaletteEntries[NB_RESERVED_COLORS] = { /* red green blue flags */ { 0x00, 0x00, 0x00, 0 }, { 0x80, 0x00, 0x00, 0 }, { 0x00, 0x80, 0x00, 0 }, { 0x80, 0x80, 0x00, 0 }, { 0x00, 0x00, 0x80, 0 }, { 0x80, 0x00, 0x80, 0 }, { 0x00, 0x80, 0x80, 0 }, { 0xc0, 0xc0, 0xc0, 0 }, { 0xc0, 0xdc, 0xc0, 0 }, { 0xa6, 0xca, 0xf0, 0 }, { 0xff, 0xfb, 0xf0, 0 }, { 0xa0, 0xa0, 0xa4, 0 }, { 0x80, 0x80, 0x80, 0 }, { 0xff, 0x00, 0x00, 0 }, { 0x00, 0xff, 0x00, 0 }, { 0xff, 0xff, 0x00, 0 }, { 0x00, 0x00, 0xff, 0 }, { 0xff, 0x00, 0xff, 0 }, { 0x00, 0xff, 0xff, 0 }, { 0xff, 0xff, 0xff, 0 } }; static HANDLE hSysColorTranslation = 0; static HANDLE hRevSysColorTranslation = 0; /* Map an EGA index (0..15) to a pixel value. Used for dithering. */ int COLOR_mapEGAPixel[16]; int* COLOR_PaletteToPixel = NULL; int* COLOR_PixelToPalette = NULL; int COLOR_ColormapSize = 0; /*********************************************************************** * COLOR_BuildMap * * Fill the private colormap. */ static BOOL COLOR_BuildMap( Colormap map, int depth, int size ) { XColor color; int r, g, b, red_incr, green_incr, blue_incr; int index = 0; /* Fill the whole map with a range of colors */ blue_incr = 0x10000 >> (depth / 3); red_incr = 0x10000 >> ((depth + 1) / 3); green_incr = 0x10000 >> ((depth + 2) / 3); for (r = red_incr - 1; r < 0x10000; r += red_incr) for (g = green_incr - 1; g < 0x10000; g += green_incr) for (b = blue_incr - 1; b < 0x10000; b += blue_incr) { if (index >= size) break; color.pixel = index++; color.red = r; color.green = g; color.blue = b; XStoreColor( display, map, &color ); } return TRUE; } /*********************************************************************** * COLOR_InitPalette * * Create the system palette. */ static HPALETTE16 COLOR_InitPalette(void) { int i, size, pixel; XColor color; HPALETTE16 hpalette; LOGPALETTE * palPtr; WORD *colorTranslation, *revTranslation; size = DefaultVisual( display, DefaultScreen(display) )->map_entries; COLOR_ColormapSize = size; if (screenDepth <= 8) { if (!(hSysColorTranslation = GDI_HEAP_ALLOC(sizeof(WORD)*NB_RESERVED_COLORS ))) return FALSE; if (!(hRevSysColorTranslation = GDI_HEAP_ALLOC( sizeof(WORD)*size ))) return FALSE; colorTranslation = (WORD *) GDI_HEAP_LIN_ADDR( hSysColorTranslation ); revTranslation = (WORD *) GDI_HEAP_LIN_ADDR( hRevSysColorTranslation ); } else colorTranslation = revTranslation = NULL; if ((COLOR_WinColormap == DefaultColormapOfScreen(screen)) && (screenDepth <= 8)) { COLOR_PaletteToPixel = (int *)xmalloc( sizeof(int) * size ); COLOR_PixelToPalette = (int *)xmalloc( sizeof(int) * size ); for (i = 0; i < size; i++) /* Set the default mapping */ COLOR_PaletteToPixel[i] = COLOR_PixelToPalette[i] = i; } for (i = 0; i < NB_RESERVED_COLORS; i++) { color.red = COLOR_sysPaletteEntries[i].peRed * 65535 / 255; color.green = COLOR_sysPaletteEntries[i].peGreen * 65535 / 255; color.blue = COLOR_sysPaletteEntries[i].peBlue * 65535 / 255; color.flags = DoRed | DoGreen | DoBlue; if (i < NB_RESERVED_COLORS/2) { /* Bottom half of the colormap */ pixel = i; if (pixel >= size/2) continue; } else { /* Top half of the colormap */ pixel = size - NB_RESERVED_COLORS + i; if (pixel < size/2) continue; } if (COLOR_WinColormap != DefaultColormapOfScreen(screen)) { color.pixel = pixel; XStoreColor( display, COLOR_WinColormap, &color ); } else { if (!XAllocColor( display, COLOR_WinColormap, &color )) { fprintf(stderr, "Warning: Not enough free colors. Try using the -privatemap option.\n" ); color.pixel = color.red = color.green = color.blue = 0; } else if (COLOR_PaletteToPixel) { COLOR_PaletteToPixel[pixel] = color.pixel; COLOR_PixelToPalette[color.pixel] = pixel; } } if (colorTranslation) colorTranslation[i] = color.pixel; if (revTranslation) revTranslation[color.pixel] = i; /* Set EGA mapping if color in the first or last eight */ if (i < 8) COLOR_mapEGAPixel[i] = color.pixel; else if (i >= NB_RESERVED_COLORS-8) COLOR_mapEGAPixel[i - (NB_RESERVED_COLORS-16)] = color.pixel; } palPtr = malloc( sizeof(LOGPALETTE) + (NB_RESERVED_COLORS-1)*sizeof(PALETTEENTRY) ); if (!palPtr) return FALSE; palPtr->palVersion = 0x300; palPtr->palNumEntries = NB_RESERVED_COLORS; memcpy( palPtr->palPalEntry, COLOR_sysPaletteEntries, sizeof(COLOR_sysPaletteEntries) ); hpalette = CreatePalette( palPtr ); free( palPtr ); return hpalette; } void COLOR_Computeshifts(unsigned long maskbits, int *shift, int *max) { int i; if(maskbits==0) { *shift=0; *max=0; return; } for(i=0;!(maskbits&1);i++) maskbits >>= 1; *shift = i; *max = maskbits; } /*********************************************************************** * COLOR_Init * * Initialize color map and system palette. */ HPALETTE16 COLOR_Init(void) { Visual * visual = DefaultVisual( display, DefaultScreen(display) ); switch(visual->class) { case GrayScale: case PseudoColor: case DirectColor: COLOR_FixedMap = 0; if (Options.usePrivateMap) { COLOR_WinColormap = XCreateColormap( display, rootWindow, visual, AllocAll ); if (COLOR_WinColormap) { COLOR_BuildMap( COLOR_WinColormap, screenDepth, visual->map_entries ); if (rootWindow != DefaultRootWindow(display)) { XSetWindowAttributes win_attr; win_attr.colormap = COLOR_WinColormap; XChangeWindowAttributes( display, rootWindow, CWColormap, &win_attr ); } break; } } COLOR_WinColormap = DefaultColormapOfScreen( screen ); break; case StaticGray: COLOR_WinColormap = DefaultColormapOfScreen( screen ); COLOR_FixedMap = 1; COLOR_Graymax = (1<red_mask, &COLOR_Redshift, &COLOR_Redmax); COLOR_Computeshifts(visual->green_mask, &COLOR_Greenshift, &COLOR_Greenmax); COLOR_Computeshifts(visual->blue_mask, &COLOR_Blueshift, &COLOR_Bluemax); break; } return COLOR_InitPalette(); } /*********************************************************************** * COLOR_IsSolid * * Check whether 'color' can be represented with a solid color. */ BOOL COLOR_IsSolid( COLORREF color ) { int i; PALETTEENTRY *pEntry = COLOR_sysPaletteEntries; if (color & 0xff000000) return TRUE; if (!color || (color == 0xffffff)) return TRUE; for (i = NB_RESERVED_COLORS; i > 0; i--, pEntry++) { if ((GetRValue(color) == pEntry->peRed) && (GetGValue(color) == pEntry->peGreen) && (GetBValue(color) == pEntry->peBlue)) return TRUE; } return FALSE; } /*********************************************************************** * COLOR_ToPhysical * * Return the physical color closest to 'color'. * * ESW: This still needs a lot of work; in particular, what happens when * we have really large (> 8 bit) DirectColor boards? * But it should work better in 16 and 24 bit modes now. * (At least it pays attention to the X server's description * in TrueColor mode, instead of blindly passing through the * color spec and swapping red to blue or losing blue and part of the * green entirely, depending on what mode one is in!) * */ int COLOR_ToPhysical( DC *dc, COLORREF color ) { WORD index = 0; WORD *mapping; unsigned char spec_type; spec_type = color >> 24; if (spec_type == 0xff) { spec_type = 0; /* 'write' seems to need that for 'Page 1' text */ color &= 0xffffff; } if (spec_type > 2) fprintf(stderr, "COLOR_ToPhysical : color >> 24 not in {-1,0,1,2} : %08lx\n", color); if (dc && (dc->w.bitsPerPixel == 1) && (spec_type == 0)) { /* monochrome */ if (((color >> 16) & 0xff) + ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) return 1; /* white */ else return 0; /* black */ } if (COLOR_FixedMap) { /* there is no colormap possible; we are going to have to compute the pixel value from the visual information stored earlier */ unsigned long red, green, blue; unsigned idx; PALETTEOBJ * palPtr; switch(spec_type) { case 0: /* RGB */ case 2: /* PALETTERGB -- needs some work, but why bother; we've got a REALLY LARGE number of colors...? */ default: red = GetRValue(color); green = GetGValue(color); blue = GetBValue(color); break; case 1: /* PALETTEIDX -- hmm, get the real color from the stock palette */ palPtr = (PALETTEOBJ *) GDI_GetObjPtr( STOCK_DEFAULT_PALETTE, PALETTE_MAGIC); idx = color & 0xffff; if (idx >= palPtr->logpalette.palNumEntries) { fprintf(stderr, "COLOR_ToPhysical(%lx) : idx %d is out of bounds, assuming black\n", color, idx); /* out of bounds */ red = green = blue = 0; } else { red = palPtr->logpalette.palPalEntry[idx].peRed; green = palPtr->logpalette.palPalEntry[idx].peGreen; blue = palPtr->logpalette.palPalEntry[idx].peBlue; } } if (COLOR_Graymax) { /* grayscale only; return scaled value */ return ( (red * 30 + green * 69 + blue * 11) * COLOR_Graymax) / 25500; } else { /* scale each individually and construct the TrueColor pixel value */ if (COLOR_Redmax != 255) red = (red * COLOR_Redmax) / 255; if (COLOR_Greenmax != 255) green = (green * COLOR_Greenmax) / 255; if (COLOR_Bluemax != 255) blue = (blue * COLOR_Bluemax) / 255; return (red << COLOR_Redshift) | (green << COLOR_Greenshift) | (blue << COLOR_Blueshift); } } else switch(spec_type) { default: case 0: /* RGB */ index = GetNearestPaletteIndex( STOCK_DEFAULT_PALETTE, color ); break; case 1: /* PALETTEINDEX */ index = color & 0xffff; break; case 2: /* PALETTERGB */ if (dc) index = GetNearestPaletteIndex( dc->w.hPalette, color ); else index = 0; break; } if (dc&&dc->u.x.pal.mappingSize) { if (index >= dc->u.x.pal.mappingSize) { fprintf(stderr, "COLOR_ToPhysical(%lx) : idx %d is >= dc->u.x.pal.mappingSize, assuming pixel 0\n", color, index); return 0; } mapping = (WORD *) GDI_HEAP_LIN_ADDR( dc->u.x.pal.hMapping ); } else { if (index >= NB_RESERVED_COLORS) { fprintf(stderr, "COLOR_ToPhysical(%lx) : idx %d is >= NB_RESERVED_COLORS, assuming pixel 0\n", color, index); return 0; } mapping = (WORD *) GDI_HEAP_LIN_ADDR( hSysColorTranslation ); } if (mapping) return mapping[index]; else return index; /* Identity mapping */ } /*********************************************************************** * COLOR_SetMapping * * Set the color-mapping table in a DC. */ void COLOR_SetMapping( DC *dc, HANDLE map, HANDLE revMap, WORD size ) { WORD *pmap, *pnewmap; WORD i; if (dc->u.x.pal.hMapping && (dc->u.x.pal.hMapping != hSysColorTranslation)) GDI_HEAP_FREE( dc->u.x.pal.hMapping ); if (dc->u.x.pal.hRevMapping && (dc->u.x.pal.hRevMapping != hRevSysColorTranslation)) GDI_HEAP_FREE( dc->u.x.pal.hRevMapping ); if (map && (map != hSysColorTranslation)) { /* Copy mapping table */ dc->u.x.pal.hMapping = GDI_HEAP_ALLOC( sizeof(WORD) * size ); pmap = (WORD *) GDI_HEAP_LIN_ADDR( map ); pnewmap = (WORD *) GDI_HEAP_LIN_ADDR( dc->u.x.pal.hMapping ); memcpy( pnewmap, pmap, sizeof(WORD)*size ); /* Build reverse table */ dc->u.x.pal.hRevMapping = GDI_HEAP_ALLOC(sizeof(WORD)*COLOR_ColormapSize); pmap = (WORD *) GDI_HEAP_LIN_ADDR( dc->u.x.pal.hRevMapping ); for (i = 0; i < size; i++) pmap[pnewmap[i]] = i; } else { dc->u.x.pal.hMapping = map; dc->u.x.pal.hRevMapping = map ? hRevSysColorTranslation : 0; } dc->u.x.pal.mappingSize = size; } /*********************************************************************** * RealizeDefaultPalette (GDI.365) */ WORD RealizeDefaultPalette( HDC hdc ) { DC *dc; if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0; dc->w.hPalette = STOCK_DEFAULT_PALETTE; COLOR_SetMapping( dc, hSysColorTranslation, hRevSysColorTranslation, NB_RESERVED_COLORS ); return NB_RESERVED_COLORS; }