Blame src/CmapAlloc.c

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