CrCmap.c

Go to the documentation of this file.
00001 /* $Xorg: CrCmap.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
00002 
00003 /* 
00004 
00005 Copyright 1989, 1998  The Open Group
00006 
00007 Permission to use, copy, modify, distribute, and sell this software and its
00008 documentation for any purpose is hereby granted without fee, provided that
00009 the above copyright notice appear in all copies and that both that
00010 copyright notice and this permission notice appear in supporting
00011 documentation.
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 Except as contained in this notice, the name of The Open Group shall not be
00024 used in advertising or otherwise to promote the sale, use or other dealings
00025 in this Software without prior written authorization from The Open Group.
00026 
00027 */
00028 /* $XFree86: xc/lib/Xmu/CrCmap.c,v 3.6 2001/01/17 19:42:53 dawes Exp $ */
00029 
00030 /*
00031  * Author:  Donna Converse, MIT X Consortium
00032  */
00033 
00034 /*
00035  * CreateCmap.c - given a standard colormap description, make the map.
00036  */
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <X11/Xlib.h>
00041 #include <X11/Xutil.h>
00042 #include <X11/Xmu/StdCmap.h>
00043 
00044 /*
00045  * Prototypes
00046  */
00047 /* allocate entire map Read Only */
00048 static int ROmap(Display*, Colormap, unsigned long[], int, int);
00049 
00050 /* allocate a cell, prefer Read Only */
00051 static Status ROorRWcell(Display*, Colormap, unsigned long[], int,
00052                          XColor*, unsigned long);
00053 
00054 /* allocate a cell Read Write */
00055 static Status RWcell(Display*, Colormap, XColor*, XColor*, unsigned long*);
00056 
00057 /* for quicksort */
00058 static int compare(_Xconst void*, _Xconst void*);
00059 
00060 /* find contiguous sequence of cells */
00061 static Status contiguous(unsigned long[], int, int, unsigned long, int*, int*);
00062 
00063 /* frees resources before quitting */
00064 static void free_cells(Display*, Colormap, unsigned long[], int, int);
00065 
00066 /* create a map in a RO visual type */
00067 static Status readonly_map(Display*, XVisualInfo*, XStandardColormap*);
00068 
00069 /* create a map in a RW visual type */
00070 static Status readwrite_map(Display*, XVisualInfo*, XStandardColormap*);
00071 
00072 #define lowbit(x) ((x) & (~(x) + 1))
00073 #define TRUEMATCH(mult,max,mask) \
00074     (colormap->max * colormap->mult <= vinfo->mask && \
00075      lowbit(vinfo->mask) == colormap->mult)
00076 
00077 /*
00078  * To create any one colormap which is described by an XStandardColormap
00079  * structure, use XmuCreateColormap().
00080  *
00081  * Return 0 on failure, non-zero on success.
00082  * Resources created by this function are not made permanent.
00083  * No argument error checking is provided.  Use at your own risk.
00084  *
00085  * All colormaps are created with read only allocations, with the exception
00086  * of read only allocations of colors in the default map or otherwise
00087  * which fail to return the expected pixel value, and these are individually 
00088  * defined as read/write allocations.  This is done so that all the cells
00089  * defined in the default map are contiguous, for use in image processing.
00090  * This typically happens with White and Black in the default map.
00091  *
00092  * Colormaps of static visuals are considered to be successfully created if
00093  * the map of the static visual matches the definition given in the
00094  * standard colormap structure.
00095  */
00096    
00097 Status
00098 XmuCreateColormap(Display *dpy, XStandardColormap *colormap)
00099      /* dpy      - specifies the connection under which the map is created
00100       * colormap - specifies the map to be created, and returns, particularly
00101       *            if the map is created as a subset of the default colormap
00102       *            of the screen, the base_pixel of the map.
00103                                          */
00104 {
00105     XVisualInfo         vinfo_template; /* template visual information */
00106     XVisualInfo         *vinfo;         /* matching visual information */
00107     XVisualInfo         *vpointer;      /* for freeing the entire list */
00108     long                vinfo_mask;     /* specifies the visual mask value */
00109     int                 n;              /* number of matching visuals */
00110     int                 status;         
00111 
00112     vinfo_template.visualid = colormap->visualid;
00113     vinfo_mask = VisualIDMask;
00114     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
00115         return 0;
00116 
00117     /* A visual id may be valid on multiple screens.  Also, there may 
00118      * be multiple visuals with identical visual ids at different depths.  
00119      * If the colormap is the Default Colormap, use the Default Visual.
00120      * Otherwise, arbitrarily, use the deepest visual.
00121      */
00122     vpointer = vinfo;
00123     if (n > 1)
00124     {
00125         register int    i;
00126         register int    screen_number;
00127         Bool            def_cmap;
00128 
00129         def_cmap = False;
00130         for (screen_number = ScreenCount(dpy); --screen_number >= 0; )
00131             if (colormap->colormap == DefaultColormap(dpy, screen_number)) {
00132                 def_cmap = True;
00133                 break;
00134             }
00135 
00136         if (def_cmap) {
00137             for (i=0; i < n; i++, vinfo++) {
00138                 if (vinfo->visual == DefaultVisual(dpy, screen_number))
00139                         break;
00140             }
00141         } else {
00142             int                 maxdepth = 0;
00143             XVisualInfo         *v = NULL;
00144 
00145             for (i=0; i < n; i++, vinfo++)
00146                 if (vinfo->depth > maxdepth) {
00147                     maxdepth = vinfo->depth;
00148                     v = vinfo;
00149                 }
00150             vinfo = v;
00151         }
00152     }
00153 
00154     if (vinfo->class == PseudoColor || vinfo->class == DirectColor ||
00155         vinfo->class == GrayScale)
00156         status = readwrite_map(dpy, vinfo, colormap);
00157     else if (vinfo->class == TrueColor)
00158         status = TRUEMATCH(red_mult, red_max, red_mask) &&
00159                  TRUEMATCH(green_mult, green_max, green_mask) &&
00160                  TRUEMATCH(blue_mult, blue_max, blue_mask);
00161     else 
00162         status = readonly_map(dpy, vinfo, colormap);
00163     
00164     XFree((char *) vpointer);
00165     return status;
00166 }
00167 
00168 /****************************************************************************/
00169 static Status
00170 readwrite_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
00171 {
00172     register unsigned long i, n;        /* index counters */
00173     unsigned long       ncolors;        /* number of colors to be defined */
00174     int                 npixels;        /* number of pixels allocated R/W */
00175     int                 first_index;    /* first index of pixels to use */
00176     int                 remainder;      /* first index of remainder */
00177     XColor              color;          /* the definition of a color */
00178     unsigned long       *pixels;        /* array of colormap pixels */
00179     unsigned long       delta;
00180 
00181     
00182     /* Determine ncolors, the number of colors to be defined.
00183      * Insure that 1 < ncolors <= the colormap size.
00184      */
00185     if (vinfo->class == DirectColor) {
00186         ncolors = colormap->red_max;
00187         if (colormap->green_max > ncolors)
00188             ncolors = colormap->green_max;
00189         if (colormap->blue_max > ncolors)
00190             ncolors = colormap->blue_max;
00191         ncolors++;
00192         delta = lowbit(vinfo->red_mask) +
00193                 lowbit(vinfo->green_mask) +
00194                 lowbit(vinfo->blue_mask);
00195     } else {
00196         ncolors = colormap->red_max * colormap->red_mult +
00197                   colormap->green_max * colormap->green_mult +
00198                   colormap->blue_max * colormap->blue_mult + 1;
00199         delta = 1;
00200     }
00201     if (ncolors <= 1 || (int) ncolors > vinfo->colormap_size)   return 0;
00202 
00203     /* Allocate Read/Write as much of the colormap as we can possibly get.
00204      * Then insure that the pixels we were allocated are given in 
00205      * monotonically increasing order, using a quicksort.  Next, insure
00206      * that our allocation includes a subset of contiguous pixels at least
00207      * as long as the number of colors to be defined.  Now we know that 
00208      * these conditions are met:
00209      *  1) There are no free cells in the colormap.
00210      *  2) We have a contiguous sequence of pixels, monotonically 
00211      *     increasing, of length >= the number of colors requested.
00212      *
00213      * One cell at a time, we will free, compute the next color value, 
00214      * then allocate read only.  This takes a long time.
00215      * This is done to insure that cells are allocated read only in the
00216      * contiguous order which we prefer.  If the server has a choice of
00217      * cells to grant to an allocation request, the server may give us any
00218      * cell, so that is why we do these slow gymnastics.
00219      */
00220 
00221     if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size,
00222                                       sizeof(unsigned long))) == NULL)
00223         return 0;
00224 
00225     if ((npixels = ROmap(dpy, colormap->colormap, pixels,
00226                            vinfo->colormap_size, ncolors)) == 0) {
00227         free((char *) pixels);
00228         return 0;
00229     }
00230 
00231     qsort((char *) pixels, npixels, sizeof(unsigned long), compare);
00232 
00233     if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder))
00234     {
00235         /* can't find enough contiguous cells, give up */
00236         XFreeColors(dpy, colormap->colormap, pixels, npixels,
00237                     (unsigned long) 0);
00238         free((char *) pixels);
00239         return 0;
00240     }
00241     colormap->base_pixel = pixels[first_index];
00242 
00243     /* construct a gray map */
00244     if (colormap->red_mult == 1 && colormap->green_mult == 1 &&
00245         colormap->blue_mult == 1)
00246         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
00247         {
00248             color.pixel = n;
00249             color.blue = color.green = color.red =
00250                 (unsigned short) ((i * 65535) / (colormap->red_max +
00251                                                  colormap->green_max +
00252                                                  colormap->blue_max));
00253 
00254             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
00255                              first_index + i))
00256                 return 0;
00257         }
00258 
00259     /* construct a red ramp map */
00260     else if (colormap->green_max == 0 && colormap->blue_max == 0)
00261         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
00262         {
00263             color.pixel = n;
00264             color.red = (unsigned short) ((i * 65535) / colormap->red_max);
00265             color.green = color.blue = 0;
00266 
00267             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
00268                              first_index + i))
00269                 return 0;
00270         }
00271 
00272     /* construct a green ramp map */
00273     else if (colormap->red_max == 0 && colormap->blue_max == 0)
00274         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
00275         {
00276             color.pixel = n;
00277             color.green = (unsigned short) ((i * 65535) / colormap->green_max);
00278             color.red = color.blue = 0;
00279 
00280             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
00281                              first_index + i))
00282                 return 0;
00283         }
00284 
00285     /* construct a blue ramp map */
00286     else if (colormap->red_max == 0 && colormap->green_max == 0)
00287         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
00288         {
00289             color.pixel = n;
00290             color.blue = (unsigned short) ((i * 65535) / colormap->blue_max);
00291             color.red = color.green = 0;
00292 
00293             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
00294                              first_index + i))
00295                 return 0;
00296         }
00297 
00298     /* construct a standard red green blue cube map */
00299     else
00300     {
00301 #define calc(max,mult) (((n / colormap->mult) % \
00302                          (colormap->max + 1)) * 65535) / colormap->max
00303 
00304         for (n=0, i=0; i < ncolors; i++, n += delta)
00305         {
00306             color.pixel = n + colormap->base_pixel;
00307             color.red = calc(red_max, red_mult);
00308             color.green = calc(green_max, green_mult);
00309             color.blue = calc(blue_max, blue_mult);
00310             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
00311                              first_index + i))
00312                 return 0;
00313         }
00314 #undef calc
00315     }
00316     /* We have a read-only map defined.  Now free unused cells,
00317      * first those occuring before the contiguous sequence begins,
00318      * then any following the contiguous sequence.
00319      */
00320 
00321     if (first_index)
00322         XFreeColors(dpy, colormap->colormap, pixels, first_index, 
00323                     (unsigned long) 0);
00324     if (remainder)
00325         XFreeColors(dpy, colormap->colormap,
00326                     &(pixels[first_index + ncolors]), remainder,
00327                     (unsigned long) 0);
00328 
00329     free((char *) pixels);
00330     return 1;
00331 }
00332 
00333 
00334 /****************************************************************************/
00335 static int
00336 ROmap(Display *dpy, Colormap cmap, unsigned long pixels[], int m, int n)
00337      /*
00338       * dpy     - the X server connection
00339       * cmap    - specifies colormap ID
00340       * pixels  - returns pixel allocations
00341       * m       - specifies colormap size
00342       * n       - specifies number of colors
00343       */
00344 {
00345     register int        p;
00346 
00347     /* first try to allocate the entire colormap */
00348     if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL, 
00349                          (unsigned) 0, pixels, (unsigned) m))
00350         return m;
00351 
00352     /* Allocate all available cells in the colormap, using a binary
00353      * algorithm to discover how many cells we can allocate in the colormap.
00354      */
00355     m--;
00356     while (n <= m) {
00357         p = n + ((m - n + 1) / 2);
00358         if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
00359                              (unsigned) 0, pixels, (unsigned) p)) {
00360             if (p == m)
00361                 return p;
00362             else {
00363                 XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
00364                 n = p;
00365             }
00366         }
00367         else
00368             m = p - 1;
00369     }
00370     return 0;
00371 }
00372       
00373 
00374 /****************************************************************************/
00375 static Status
00376 contiguous(unsigned long pixels[], int npixels, int ncolors,
00377            unsigned long delta, int *first, int *rem)
00378      /* pixels  - specifies allocated pixels
00379       * npixels - specifies count of alloc'd pixels
00380       * ncolors - specifies needed sequence length
00381       * delta   - between pixels
00382       * first   - returns first index of sequence
00383       * rem     - returns first index after sequence, or 0, if none follow
00384       */
00385 {
00386     register int i = 1;         /* walking index into the pixel array */
00387     register int count = 1;     /* length of sequence discovered so far */
00388 
00389     *first = 0;
00390     if (npixels == ncolors) {
00391         *rem = 0;
00392         return 1;
00393     }
00394     *rem = npixels - 1;
00395     while (count < ncolors && ncolors - count <= *rem)
00396     {
00397         if (pixels[i-1] + delta == pixels[i])
00398             count++;
00399         else {
00400             count = 1;
00401             *first = i;
00402         }
00403         i++;
00404         (*rem)--;
00405     }
00406     if (count != ncolors)
00407         return 0;
00408     return 1;
00409 }
00410 
00411 
00412 /****************************************************************************/
00413 static Status
00414 ROorRWcell(Display *dpy, Colormap cmap, unsigned long pixels[],
00415            int npixels, XColor *color, unsigned long p)
00416 {
00417     unsigned long       pixel;
00418     XColor              request;
00419 
00420     /* Free the read/write allocation of one cell in the colormap.
00421      * Request a read only allocation of one cell in the colormap.
00422      * If the read only allocation cannot be granted, give up, because
00423      * there must be no free cells in the colormap.
00424      * If the read only allocation is granted, but gives us a cell which
00425      * is not the one that we just freed, it is probably the case that
00426      * we are trying allocate White or Black or some other color which
00427      * already has a read-only allocation in the map.  So we try to 
00428      * allocate the previously freed cell with a read/write allocation,
00429      * because we want contiguous cells for image processing algorithms.
00430      */
00431      
00432     pixel = color->pixel;
00433     request.red = color->red;
00434     request.green = color->green;
00435     request.blue = color->blue;
00436 
00437     XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0);
00438     if (! XAllocColor(dpy, cmap, color) 
00439         || (color->pixel != pixel &&
00440             (!RWcell(dpy, cmap, color, &request, &pixel)))) 
00441     {
00442         free_cells(dpy, cmap, pixels, npixels, (int)p);
00443         return 0;
00444     }
00445     return 1;
00446 }
00447 
00448 
00449 /****************************************************************************/
00450 static void
00451 free_cells(Display *dpy, Colormap cmap, unsigned long pixels[],
00452            int npixels, int p)
00453      /*
00454       * pixels  - to be freed
00455       * npixels - original number allocated
00456       */
00457 {
00458     /* One of the npixels allocated has already been freed.
00459      * p is the index of the freed pixel.
00460      * First free the pixels preceeding p, and there are p of them;
00461      * then free the pixels following p, there are npixels - p - 1 of them.
00462      */
00463     XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
00464     XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0);
00465     free((char *) pixels);
00466 }
00467 
00468 
00469 /****************************************************************************/
00470 static Status
00471 RWcell(Display *dpy, Colormap cmap, XColor *color, XColor *request,
00472        unsigned long *pixel)
00473 {
00474     unsigned long       n = *pixel;
00475 
00476     XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0);
00477     if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL,
00478                            (unsigned) 0, pixel, (unsigned) 1))
00479         return 0;
00480     if (*pixel != n)
00481     {
00482         XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0);
00483         return 0;
00484     }
00485     color->pixel = *pixel;
00486     color->flags = DoRed | DoGreen | DoBlue;
00487     color->red = request->red;
00488     color->green = request->green;
00489     color->blue = request->blue;
00490     XStoreColors(dpy, cmap, color, 1);
00491     return 1;
00492 }
00493 
00494 
00495 /****************************************************************************/
00496 static int
00497 compare(_Xconst void *e1, _Xconst void *e2)
00498 {
00499   return ((int)(*(long *)e1 - *(long *)e2));
00500 }
00501 
00502 
00503 /****************************************************************************/
00504 static Status
00505 readonly_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
00506 {
00507     int                 i, last_pixel;
00508     XColor              color;
00509 
00510     last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) * 
00511         (colormap->blue_max + 1) + colormap->base_pixel - 1;
00512 
00513     for(i=colormap->base_pixel; i <= last_pixel; i++) {
00514 
00515         color.pixel = (unsigned long) i;
00516         color.red = (unsigned short)
00517             (((i/colormap->red_mult) * 65535) / colormap->red_max);
00518 
00519         if (vinfo->class == StaticColor) {
00520             color.green = (unsigned short)
00521                 ((((i/colormap->green_mult) % (colormap->green_max + 1)) *
00522                   65535) / colormap->green_max);
00523             color.blue = (unsigned short)
00524                 (((i%colormap->green_mult) * 65535) / colormap->blue_max);
00525         }
00526         else    /* vinfo->class == GrayScale, old style allocation XXX */
00527             color.green = color.blue = color.red;
00528 
00529         XAllocColor(dpy, colormap->colormap, &color);
00530         if (color.pixel != (unsigned long) i)
00531             return 0;
00532     }
00533     return 1;
00534 }

Generated on Sun Mar 4 15:03:56 2007 for Scilab [trunk] by  doxygen 1.5.1