Blame src/CmapAlloc.c

Packit cd2a55
/*
Packit cd2a55
Packit cd2a55
Copyright 1989, 1994, 1998  The Open Group
Packit cd2a55
Packit cd2a55
Permission to use, copy, modify, distribute, and sell this software and its
Packit cd2a55
documentation for any purpose is hereby granted without fee, provided that
Packit cd2a55
the above copyright notice appear in all copies and that both that
Packit cd2a55
copyright notice and this permission notice appear in supporting
Packit cd2a55
documentation.
Packit cd2a55
Packit cd2a55
The above copyright notice and this permission notice shall be included in
Packit cd2a55
all copies or substantial portions of the Software.
Packit cd2a55
Packit cd2a55
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit cd2a55
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit cd2a55
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit cd2a55
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit cd2a55
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit cd2a55
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit cd2a55
Packit cd2a55
Except as contained in this notice, the name of The Open Group shall not be
Packit cd2a55
used in advertising or otherwise to promote the sale, use or other dealings
Packit cd2a55
in this Software without prior written authorization from The Open Group.
Packit cd2a55
Packit cd2a55
*/
Packit cd2a55
Packit cd2a55
/*
Packit cd2a55
 * Author:  Donna Converse, MIT X Consortium
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
#ifdef HAVE_CONFIG_H
Packit cd2a55
#include <config.h>
Packit cd2a55
#endif
Packit cd2a55
#include <X11/Xlib.h>
Packit cd2a55
#include <X11/Xatom.h>
Packit cd2a55
#include <X11/Xutil.h>
Packit cd2a55
#include <X11/Xmu/StdCmap.h>
Packit cd2a55
#include <stdio.h>
Packit cd2a55
Packit cd2a55
#define lowbit(x) ((x) & (~(x) + 1))
Packit cd2a55
Packit cd2a55
/*
Packit cd2a55
 * Prototypes
Packit cd2a55
 */
Packit cd2a55
static void best_allocation(XVisualInfo*, unsigned long*, unsigned long*,
Packit cd2a55
			    unsigned long*);
Packit cd2a55
static int default_allocation(XVisualInfo*, unsigned long*,
Packit cd2a55
			      unsigned long*, unsigned long*);
Packit cd2a55
static void gray_allocation(int, unsigned long*, unsigned long*,
Packit cd2a55
			    unsigned long*);
Packit cd2a55
static int icbrt(int);
Packit cd2a55
static int icbrt_with_bits(int, int);
Packit cd2a55
static int icbrt_with_guess(int, int);
Packit cd2a55
Packit cd2a55
/* To determine the best allocation of reds, greens, and blues in a
Packit cd2a55
 * standard colormap, use XmuGetColormapAllocation.
Packit cd2a55
 * 	vinfo		specifies visual information for a chosen visual
Packit cd2a55
 *	property	specifies one of the standard colormap property names
Packit cd2a55
 * 	red_max		returns maximum red value
Packit cd2a55
 *      green_max	returns maximum green value
Packit cd2a55
 * 	blue_max	returns maximum blue value
Packit cd2a55
 *
Packit cd2a55
 * XmuGetColormapAllocation returns 0 on failure, non-zero on success.
Packit cd2a55
 * It is assumed that the visual is appropriate for the colormap property.
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
Status
Packit cd2a55
XmuGetColormapAllocation(XVisualInfo *vinfo, Atom property,
Packit cd2a55
			 unsigned long *red_max,
Packit cd2a55
			 unsigned long *green_max,
Packit cd2a55
			 unsigned long *blue_max)
Packit cd2a55
{
Packit cd2a55
    Status 	status = 1;
Packit cd2a55
Packit cd2a55
    if (vinfo->colormap_size <= 2)
Packit cd2a55
	return 0;
Packit cd2a55
Packit cd2a55
    switch (property)
Packit cd2a55
    {
Packit cd2a55
      case XA_RGB_DEFAULT_MAP:
Packit cd2a55
	status = default_allocation(vinfo, red_max, green_max, blue_max);
Packit cd2a55
	break;
Packit cd2a55
      case XA_RGB_BEST_MAP:
Packit cd2a55
	best_allocation(vinfo, red_max, green_max, blue_max);
Packit cd2a55
	break;
Packit cd2a55
      case XA_RGB_GRAY_MAP:
Packit cd2a55
	gray_allocation(vinfo->colormap_size, red_max, green_max, blue_max);
Packit cd2a55
	break;
Packit cd2a55
      case XA_RGB_RED_MAP:
Packit cd2a55
	*red_max = vinfo->colormap_size - 1;
Packit cd2a55
	*green_max = *blue_max = 0;
Packit cd2a55
	break;
Packit cd2a55
      case XA_RGB_GREEN_MAP:
Packit cd2a55
	*green_max = vinfo->colormap_size - 1;
Packit cd2a55
	*red_max = *blue_max = 0;
Packit cd2a55
	break;
Packit cd2a55
      case XA_RGB_BLUE_MAP:
Packit cd2a55
	*blue_max = vinfo->colormap_size - 1;
Packit cd2a55
	*red_max = *green_max = 0;
Packit cd2a55
	break;
Packit cd2a55
      default:
Packit cd2a55
	status = 0;
Packit cd2a55
    }
Packit cd2a55
    return status;
Packit cd2a55
}
Packit cd2a55
Packit cd2a55
/****************************************************************************/
Packit cd2a55
/* Determine the appropriate color allocations of a gray scale.
Packit cd2a55
 *
Packit cd2a55
 * Keith Packard, MIT X Consortium
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
static void
Packit cd2a55
gray_allocation(int n, unsigned long *red_max, unsigned long *green_max,
Packit cd2a55
		unsigned long *blue_max)
Packit cd2a55
{
Packit cd2a55
    *red_max = (n * 30) / 100;
Packit cd2a55
    *green_max = (n * 59) / 100;
Packit cd2a55
    *blue_max = (n * 11) / 100;
Packit cd2a55
    *green_max += ((n - 1) - (*red_max + *green_max + *blue_max));
Packit cd2a55
}
Packit cd2a55
Packit cd2a55
/****************************************************************************/
Packit cd2a55
/* Determine an appropriate color allocation for the RGB_DEFAULT_MAP.
Packit cd2a55
 * If a map has less than a minimum number of definable entries, we do not
Packit cd2a55
 * produce an allocation for an RGB_DEFAULT_MAP.
Packit cd2a55
 *
Packit cd2a55
 * For 16 planes, the default colormap will have 27 each RGB; for 12 planes,
Packit cd2a55
 * 12 each.  For 8 planes, let n = the number of colormap entries, which may
Packit cd2a55
 * be 256 or 254.  Then, maximum red value = floor(cube_root(n - 125)) - 1.
Packit cd2a55
 * Maximum green and maximum blue values are identical to maximum red.
Packit cd2a55
 * This leaves at least 125 cells which clients can allocate.
Packit cd2a55
 *
Packit cd2a55
 * Return 0 if an allocation has been determined, non-zero otherwise.
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
static int
Packit cd2a55
default_allocation(XVisualInfo *vinfo, unsigned long *red,
Packit cd2a55
		   unsigned long *green, unsigned long *blue)
Packit cd2a55
{
Packit cd2a55
    int			ngrays;		/* number of gray cells */
Packit cd2a55
Packit cd2a55
    switch (vinfo->class) {
Packit cd2a55
      case PseudoColor:
Packit cd2a55
Packit cd2a55
	if (vinfo->colormap_size > 65000)
Packit cd2a55
	    /* intended for displays with 16 planes */
Packit cd2a55
	    *red = *green = *blue = (unsigned long) 27;
Packit cd2a55
	else if (vinfo->colormap_size > 4000)
Packit cd2a55
	    /* intended for displays with 12 planes */
Packit cd2a55
	    *red = *green = *blue = (unsigned long) 12;
Packit cd2a55
	else if (vinfo->colormap_size < 250)
Packit cd2a55
	    return 0;
Packit cd2a55
	else
Packit cd2a55
	    /* intended for displays with 8 planes */
Packit cd2a55
	    *red = *green = *blue = (unsigned long)
Packit cd2a55
		(icbrt(vinfo->colormap_size - 125) - 1);
Packit cd2a55
	break;
Packit cd2a55
Packit cd2a55
      case DirectColor:
Packit cd2a55
Packit cd2a55
	if (vinfo->colormap_size < 10)
Packit cd2a55
	    return 0;
Packit cd2a55
	*red = *green = *blue = vinfo->colormap_size / 2 - 1;
Packit cd2a55
	break;
Packit cd2a55
Packit cd2a55
      case TrueColor:
Packit cd2a55
Packit cd2a55
	*red = vinfo->red_mask / lowbit(vinfo->red_mask);
Packit cd2a55
	*green = vinfo->green_mask / lowbit(vinfo->green_mask);
Packit cd2a55
	*blue = vinfo->blue_mask / lowbit(vinfo->blue_mask);
Packit cd2a55
	break;
Packit cd2a55
Packit cd2a55
      case GrayScale:
Packit cd2a55
Packit cd2a55
	if (vinfo->colormap_size > 65000)
Packit cd2a55
	    ngrays = 4096;
Packit cd2a55
	else if (vinfo->colormap_size > 4000)
Packit cd2a55
	    ngrays = 512;
Packit cd2a55
	else if (vinfo->colormap_size < 250)
Packit cd2a55
	    return 0;
Packit cd2a55
	else
Packit cd2a55
	    ngrays = 12;
Packit cd2a55
	gray_allocation(ngrays, red, green, blue);
Packit cd2a55
	break;
Packit cd2a55
Packit cd2a55
      default:
Packit cd2a55
	return 0;
Packit cd2a55
    }
Packit cd2a55
    return 1;
Packit cd2a55
}
Packit cd2a55
Packit cd2a55
/****************************************************************************/
Packit cd2a55
/* Determine an appropriate color allocation for the RGB_BEST_MAP.
Packit cd2a55
 *
Packit cd2a55
 * For a DirectColor or TrueColor visual, the allocation is determined
Packit cd2a55
 * by the red_mask, green_mask, and blue_mask members of the visual info.
Packit cd2a55
 *
Packit cd2a55
 * Otherwise, if the colormap size is an integral power of 2, determine
Packit cd2a55
 * the allocation according to the number of bits given to each color,
Packit cd2a55
 * with green getting more than red, and red more than blue, if there
Packit cd2a55
 * are to be inequities in the distribution.  If the colormap size is
Packit cd2a55
 * not an integral power of 2, let n = the number of colormap entries.
Packit cd2a55
 * Then maximum red value = floor(cube_root(n)) - 1;
Packit cd2a55
 * 	maximum blue value = floor(cube_root(n)) - 1;
Packit cd2a55
 *	maximum green value = n / ((# red values) * (# blue values)) - 1;
Packit cd2a55
 * Which, on a GPX, allows for 252 entries in the best map, out of 254
Packit cd2a55
 * defineable colormap entries.
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
static void
Packit cd2a55
best_allocation(XVisualInfo *vinfo, unsigned long *red, unsigned long *green,
Packit cd2a55
		unsigned long *blue)
Packit cd2a55
{
Packit cd2a55
Packit cd2a55
    if (vinfo->class == DirectColor ||	vinfo->class == TrueColor)
Packit cd2a55
    {
Packit cd2a55
	*red = vinfo->red_mask;
Packit cd2a55
	while ((*red & 01) == 0)
Packit cd2a55
	    *red >>= 1;
Packit cd2a55
	*green = vinfo->green_mask;
Packit cd2a55
	while ((*green & 01) == 0)
Packit cd2a55
	    *green >>=1;
Packit cd2a55
	*blue = vinfo->blue_mask;
Packit cd2a55
	while ((*blue & 01) == 0)
Packit cd2a55
	    *blue >>= 1;
Packit cd2a55
    }
Packit cd2a55
    else
Packit cd2a55
    {
Packit cd2a55
	register int bits, n;
Packit cd2a55
Packit cd2a55
	/* Determine n such that n is the least integral power of 2 which is
Packit cd2a55
	 * greater than or equal to the number of entries in the colormap.
Packit cd2a55
         */
Packit cd2a55
	n = 1;
Packit cd2a55
	bits = 0;
Packit cd2a55
	while (vinfo->colormap_size > n)
Packit cd2a55
	{
Packit cd2a55
	    n = n << 1;
Packit cd2a55
	    bits++;
Packit cd2a55
	}
Packit cd2a55
Packit cd2a55
	/* If the number of entries in the colormap is a power of 2, determine
Packit cd2a55
	 * the allocation by "dealing" the bits, first to green, then red, then
Packit cd2a55
	 * blue.  If not, find the maximum integral red, green, and blue values
Packit cd2a55
	 * which, when multiplied together, do not exceed the number of
Packit cd2a55
Packit cd2a55
	 * colormap entries.
Packit cd2a55
	 */
Packit cd2a55
	if (n == vinfo->colormap_size)
Packit cd2a55
	{
Packit cd2a55
	    register int r, g, b;
Packit cd2a55
	    b = bits / 3;
Packit cd2a55
	    g = b + ((bits % 3) ? 1 : 0);
Packit cd2a55
	    r = b + (((bits % 3) == 2) ? 1 : 0);
Packit cd2a55
	    *red = 1 << r;
Packit cd2a55
	    *green = 1 << g;
Packit cd2a55
	    *blue = 1 << b;
Packit cd2a55
	}
Packit cd2a55
	else
Packit cd2a55
	{
Packit cd2a55
	    *red = icbrt_with_bits(vinfo->colormap_size, bits);
Packit cd2a55
	    *blue = *red;
Packit cd2a55
	    *green = (vinfo->colormap_size / ((*red) * (*blue)));
Packit cd2a55
	}
Packit cd2a55
	(*red)--;
Packit cd2a55
	(*green)--;
Packit cd2a55
	(*blue)--;
Packit cd2a55
    }
Packit cd2a55
    return;
Packit cd2a55
}
Packit cd2a55
Packit cd2a55
/*
Packit cd2a55
 * integer cube roots by Newton's method
Packit cd2a55
 *
Packit cd2a55
 * Stephen Gildea, MIT X Consortium, July 1991
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
static int
Packit cd2a55
icbrt(int a)
Packit cd2a55
{
Packit cd2a55
    register int bits = 0;
Packit cd2a55
    register unsigned n = a;
Packit cd2a55
Packit cd2a55
    while (n)
Packit cd2a55
    {
Packit cd2a55
	bits++;
Packit cd2a55
	n >>= 1;
Packit cd2a55
    }
Packit cd2a55
    return icbrt_with_bits(a, bits);
Packit cd2a55
}
Packit cd2a55
Packit cd2a55
Packit cd2a55
static int
Packit cd2a55
icbrt_with_bits(int a, int bits)
Packit cd2a55
     /* bits - log 2 of a */
Packit cd2a55
{
Packit cd2a55
    return icbrt_with_guess(a, a>>2*bits/3);
Packit cd2a55
}
Packit cd2a55
Packit cd2a55
#ifdef _X_ROOT_STATS
Packit cd2a55
int icbrt_loopcount;
Packit cd2a55
#endif
Packit cd2a55
Packit cd2a55
/* Newton's Method:  x_n+1 = x_n - ( f(x_n) / f'(x_n) ) */
Packit cd2a55
Packit cd2a55
/* for cube roots, x^3 - a = 0,  x_new = x - 1/3 (x - a/x^2) */
Packit cd2a55
Packit cd2a55
/*
Packit cd2a55
 * Quick and dirty cube roots.  Nothing fancy here, just Newton's method.
Packit cd2a55
 * Only works for positive integers (since that's all we need).
Packit cd2a55
 * We actually return floor(cbrt(a)) because that's what we need here, too.
Packit cd2a55
 */
Packit cd2a55
Packit cd2a55
static int
Packit cd2a55
icbrt_with_guess(int a, int guess)
Packit cd2a55
{
Packit cd2a55
    register int delta;
Packit cd2a55
Packit cd2a55
#ifdef _X_ROOT_STATS
Packit cd2a55
    icbrt_loopcount = 0;
Packit cd2a55
#endif
Packit cd2a55
    if (a <= 0)
Packit cd2a55
	return 0;
Packit cd2a55
    if (guess < 1)
Packit cd2a55
	guess = 1;
Packit cd2a55
Packit cd2a55
    do {
Packit cd2a55
#ifdef _X_ROOT_STATS
Packit cd2a55
	icbrt_loopcount++;
Packit cd2a55
#endif
Packit cd2a55
	delta = (guess - a/(guess*guess))/3;
Packit cd2a55
#if defined(DEBUG) && defined(_X_ROOT_STATS)
Packit cd2a55
	printf("pass %d: guess=%d, delta=%d\n", icbrt_loopcount, guess, delta);
Packit cd2a55
#endif
Packit cd2a55
	guess -= delta;
Packit cd2a55
    } while (delta != 0);
Packit cd2a55
Packit cd2a55
    if (guess*guess*guess > a)
Packit cd2a55
	guess--;
Packit cd2a55
Packit cd2a55
    return guess;
Packit cd2a55
}