1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /* Color Context module
21 * Copyright 1994,1995 John L. Cwikla
22 * Copyright (C) 1997 by Ripley Software Development
23 * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
26 /* Copyright 1994,1995 John L. Cwikla
28 * Permission to use, copy, modify, distribute, and sell this software
29 * and its documentation for any purpose is hereby granted without fee,
30 * provided that the above copyright notice appears in all copies and that
31 * both that copyright notice and this permission notice appear in
32 * supporting documentation, and that the name of John L. Cwikla or
33 * Wolfram Research, Inc not be used in advertising or publicity
34 * pertaining to distribution of the software without specific, written
35 * prior permission. John L. Cwikla and Wolfram Research, Inc make no
36 * representations about the suitability of this software for any
37 * purpose. It is provided "as is" without express or implied warranty.
39 * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
40 * regard to this software, including all implied warranties of
41 * merchantability and fitness, in no event shall John L. Cwikla or
42 * Wolfram Research, Inc be liable for any special, indirect or
43 * consequential damages or any damages whatsoever resulting from loss of
44 * use, data or profits, whether in an action of contract, negligence or
45 * other tortious action, arising out of or in connection with the use or
46 * performance of this software.
51 * Wolfram Research Inc.
57 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
58 * file for a list of people on the GTK+ Team. See the ChangeLog
59 * files for a list of changes. These files are distributed with
60 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
67 #include "gdkprivate.h"
71 #define MAX_IMAGE_COLORS 256
75 hash_color (gconstpointer key)
77 const GdkColor *color = key;
79 return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
83 compare_colors (gconstpointer a,
86 const GdkColor *aa = a;
87 const GdkColor *bb = b;
89 return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
93 free_hash_entry (gpointer key,
97 g_free (key); /* key and value are the same GdkColor */
101 pixel_sort (const void *a, const void *b)
103 return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
106 /* XXX: This function does an XQueryColors() the hard way, because there is
107 * no corresponding function in Gdk.
111 my_x_query_colors (GdkColormap *colormap,
118 xcolors = g_new (XColor, ncolors);
119 for (i = 0; i < ncolors; i++)
120 xcolors[i].pixel = colors[i].pixel;
122 XQueryColors (gdk_display, GDK_COLORMAP_XCOLORMAP (colormap), xcolors, ncolors);
124 for (i = 0; i < ncolors; i++)
126 colors[i].red = xcolors[i].red;
127 colors[i].green = xcolors[i].green;
128 colors[i].blue = xcolors[i].blue;
135 query_colors (GdkColorContext *cc)
138 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
139 cc->cmap = g_new (GdkColor, cc->num_colors);
141 for (i = 0; i < cc->num_colors; i++)
142 cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
144 my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors);
146 qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort);
150 init_bw (GdkColorContext *cc)
154 g_warning ("init_bw: failed to allocate colors, falling back to black and white");
156 cc->mode = GDK_CC_MODE_BW;
158 color.red = color.green = color.blue = 0;
160 if (!gdk_color_alloc (cc->colormap, &color))
163 cc->black_pixel = color.pixel;
165 color.red = color.green = color.blue = 0xffff;
167 if (!gdk_color_alloc (cc->colormap, &color))
168 cc->white_pixel = cc->black_pixel ? 0 : 1;
170 cc->white_pixel = color.pixel;
176 init_gray (GdkColorContext *cc)
178 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
179 GdkColor *clrs, *cstart;
183 cc->num_colors = GDK_VISUAL_XVISUAL (cc->visual)->map_entries;
185 cc->clut = g_new (gulong, cc->num_colors);
186 cstart = g_new (GdkColor, cc->num_colors);
190 dinc = 65535.0 / (cc->num_colors - 1);
194 for (i = 0; i < cc->num_colors; i++)
196 clrs->red = clrs->green = clrs->blue = dinc * i;
198 if (!gdk_color_alloc (cc->colormap, clrs))
200 gdk_colors_free (cc->colormap, cc->clut, i, 0);
204 if (cc->num_colors > 1)
216 cc->clut[i] = clrs++->pixel;
221 /* XXX: is this the right thing to do? */
222 ccp->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP (cc->colormap);
223 ccp->std_cmap.base_pixel = 0;
224 ccp->std_cmap.red_max = cc->num_colors - 1;
225 ccp->std_cmap.green_max = 0;
226 ccp->std_cmap.blue_max = 0;
227 ccp->std_cmap.red_mult = 1;
228 ccp->std_cmap.green_mult = 0;
229 ccp->std_cmap.blue_mult = 0;
231 cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
232 cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
236 cc->mode = GDK_CC_MODE_MY_GRAY;
240 init_color (GdkColorContext *cc)
242 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
246 while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL (cc->visual)->map_entries)
250 cc->num_colors = cubeval * cubeval * cubeval;
252 ccp->std_cmap.red_max = cubeval - 1;
253 ccp->std_cmap.green_max = cubeval - 1;
254 ccp->std_cmap.blue_max = cubeval - 1;
255 ccp->std_cmap.red_mult = cubeval * cubeval;
256 ccp->std_cmap.green_mult = cubeval;
257 ccp->std_cmap.blue_mult = 1;
258 ccp->std_cmap.base_pixel = 0;
260 cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
261 cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
262 cc->num_colors = DisplayCells (ccp->xdisplay, gdk_screen);
264 /* a CLUT for storing allocated pixel indices */
266 cc->max_colors = cc->num_colors;
267 cc->clut = g_new (gulong, cc->max_colors);
269 for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
270 cc->clut[cubeval] = cubeval;
274 cc->mode = GDK_CC_MODE_STD_CMAP;
279 init_true_color (GdkColorContext *cc)
281 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
282 gulong rmask, gmask, bmask;
284 cc->mode = GDK_CC_MODE_TRUE;
288 rmask = cc->masks.red = cc->visual->red_mask;
307 gmask = cc->masks.green = cc->visual->green_mask;
309 cc->shifts.green = 0;
326 bmask = cc->masks.blue = cc->visual->blue_mask;
343 cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
344 cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
345 cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
349 init_direct_color (GdkColorContext *cc)
352 GdkColor *clrs, *cstart;
353 gulong rval, gval, bval;
359 init_true_color (cc); /* for shift stuff */
361 rval = cc->visual->red_mask >> cc->shifts.red;
362 gval = cc->visual->green_mask >> cc->shifts.green;
363 bval = cc->visual->blue_mask >> cc->shifts.blue;
365 rtable = g_new (gulong, rval + 1);
366 gtable = g_new (gulong, gval + 1);
367 btable = g_new (gulong, bval + 1);
369 cc->max_entry = MAX (rval, gval);
370 cc->max_entry = MAX (cc->max_entry, bval);
372 cstart = g_new (GdkColor, cc->max_entry + 1);
373 cc->clut = g_new (gulong, cc->max_entry + 1);
377 for (n = 0; n < rval; n++)
378 rtable[n] = rval ? (65535.0 / rval * n) : 0;
380 for (n = 0; n < gval; n++)
381 gtable[n] = gval ? (65535.0 / gval * n) : 0;
383 for (n = 0; n < bval; n++)
384 btable[n] = bval ? (65535.0 / bval * n) : 0;
386 cc->max_entry = MAX (rval, gval);
387 cc->max_entry = MAX (cc->max_entry, bval);
391 cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
393 for (n = 0; n < cc->max_entry; n++)
395 dinc = (double) n / cc->max_entry;
397 clrs->red = rtable[(int) (dinc * rval)];
398 clrs->green = gtable[(int) (dinc * gval)];
399 clrs->blue = btable[(int) (dinc * bval)];
401 if (gdk_color_alloc (cc->colormap, clrs))
403 cc->clut[count++] = clrs->pixel;
408 gdk_colors_free (cc->colormap, cc->clut, count, 0);
414 cc->masks.red = (cc->masks.red >> 1) & cc->visual->red_mask;
415 cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
416 cc->masks.blue = (cc->masks.blue >> 1) & cc->visual->blue_mask;
426 cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
428 if (cc->num_colors >1)
440 /* Update allocated color count; original num_colors is max_entry, which
441 * is not necessarily the same as the really allocated number of colors.
444 cc->num_colors = count;
453 init_palette (GdkColorContext *cc)
455 /* restore correct mode for this cc */
457 switch (cc->visual->type)
459 case GDK_VISUAL_STATIC_GRAY:
460 case GDK_VISUAL_GRAYSCALE:
461 if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
462 cc->mode = GDK_CC_MODE_BW;
464 cc->mode = GDK_CC_MODE_MY_GRAY;
467 case GDK_VISUAL_TRUE_COLOR:
468 case GDK_VISUAL_DIRECT_COLOR:
469 cc->mode = GDK_CC_MODE_TRUE;
472 case GDK_VISUAL_STATIC_COLOR:
473 case GDK_VISUAL_PSEUDO_COLOR:
474 cc->mode = GDK_CC_MODE_STD_CMAP;
478 cc->mode = GDK_CC_MODE_UNDEFINED;
482 /* previous palette */
485 g_free (cc->palette);
488 g_free (cc->fast_dither);
490 /* clear hash table if present */
494 /* XXX: quick-and-dirty way to remove everything */
496 g_hash_table_destroy (cc->color_hash);
497 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
502 cc->fast_dither = NULL;
506 gdk_color_context_new (GdkVisual *visual,
507 GdkColormap *colormap)
509 GdkColorContextPrivate *ccp;
510 gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
513 GdkColormap *default_colormap;
515 g_assert (visual != NULL);
516 g_assert (colormap != NULL);
518 ccp = g_new (GdkColorContextPrivate, 1);
519 cc = (GdkColorContext *) ccp;
520 ccp->xdisplay = gdk_display;
522 cc->colormap = colormap;
525 cc->mode = GDK_CC_MODE_UNDEFINED;
526 cc->need_to_free_colormap = FALSE;
528 cc->color_hash = NULL;
531 cc->fast_dither = NULL;
533 default_colormap = gdk_colormap_get_system ();
537 while (retry_count < 2)
539 /* Only create a private colormap if the visual found isn't equal
540 * to the default visual and we don't have a private colormap,
541 * -or- if we are instructed to create a private colormap (which
542 * never is the case for XmHTML).
545 if (use_private_colormap
546 || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
547 && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
549 g_warning ("gdk_color_context_new: non-default visual detected, "
550 "using private colormap");
552 cc->colormap = gdk_colormap_new (cc->visual, FALSE);
554 cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
555 != GDK_COLORMAP_XCOLORMAP (default_colormap));
558 switch (visual->type)
560 case GDK_VISUAL_STATIC_GRAY:
561 case GDK_VISUAL_GRAYSCALE:
562 GDK_NOTE (COLOR_CONTEXT,
563 g_message ("gdk_color_context_new: visual class is %s\n",
564 (visual->type == GDK_VISUAL_STATIC_GRAY) ?
565 "GDK_VISUAL_STATIC_GRAY" :
566 "GDK_VISUAL_GRAYSCALE"));
568 if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
575 case GDK_VISUAL_TRUE_COLOR: /* shifts */
576 GDK_NOTE (COLOR_CONTEXT,
577 g_message ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
579 init_true_color (cc);
582 case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
583 GDK_NOTE (COLOR_CONTEXT,
584 g_message ("gdk_color_context_new: visual class is GDK_VISUAL_DIRECT_COLOR\n"));
586 init_direct_color (cc);
589 case GDK_VISUAL_STATIC_COLOR:
590 case GDK_VISUAL_PSEUDO_COLOR:
591 GDK_NOTE (COLOR_CONTEXT,
592 g_message ("gdk_color_context_new: visual class is %s\n",
593 (visual->type == GDK_VISUAL_STATIC_COLOR) ?
594 "GDK_VISUAL_STATIC_COLOR" :
595 "GDK_VISUAL_PSEUDO_COLOR"));
601 g_assert_not_reached ();
604 if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
606 use_private_colormap = TRUE;
613 /* no. of colors allocated yet */
615 cc->num_allocated = 0;
617 GDK_NOTE (COLOR_CONTEXT,
618 g_message ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
619 cc->visual->depth, cc->num_colors));
621 /* check if we need to initialize a hash table */
623 if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
624 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
626 return (GdkColorContext *) cc;
630 gdk_color_context_new_mono (GdkVisual *visual,
631 GdkColormap *colormap)
633 GdkColorContextPrivate *ccp;
636 g_assert (visual != NULL);
637 g_assert (colormap != NULL);
639 cc = g_new (GdkColorContext, 1);
640 ccp = (GdkColorContextPrivate *) cc;
641 ccp->xdisplay = gdk_display;
643 cc->colormap = colormap;
646 cc->mode = GDK_CC_MODE_UNDEFINED;
647 cc->need_to_free_colormap = FALSE;
651 return (GdkColorContext *) cc;
654 /* This doesn't currently free black/white, hmm... */
657 gdk_color_context_free (GdkColorContext *cc)
659 g_assert (cc != NULL);
661 if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
662 || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
664 gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
667 else if (cc->clut != NULL)
669 gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
673 if (cc->cmap != NULL)
676 if (cc->need_to_free_colormap)
677 gdk_colormap_unref (cc->colormap);
679 /* free any palette that has been associated with this GdkColorContext */
685 g_hash_table_foreach (cc->color_hash,
688 g_hash_table_destroy (cc->color_hash);
695 gdk_color_context_get_pixel (GdkColorContext *cc,
701 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
702 g_assert (cc != NULL);
703 g_assert (failed != NULL);
713 value = (red / 65535.0 * 0.30
714 + green / 65535.0 * 0.59
715 + blue / 65535.0 * 0.11);
718 return cc->white_pixel;
720 return cc->black_pixel;
723 case GDK_CC_MODE_MY_GRAY:
725 gulong ired, igreen, iblue;
727 red = red * 0.30 + green * 0.59 + blue * 0.11;
731 if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
732 ired = ccp->std_cmap.red_max;
734 ired *= ccp->std_cmap.red_mult;
736 if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
737 igreen = ccp->std_cmap.green_max;
739 igreen *= ccp->std_cmap.green_mult;
741 if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
742 iblue = ccp->std_cmap.blue_max;
744 iblue *= ccp->std_cmap.blue_mult;
746 if (cc->clut != NULL)
747 return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
749 return ccp->std_cmap.base_pixel + ired + igreen + iblue;
752 case GDK_CC_MODE_TRUE:
754 gulong ired, igreen, iblue;
756 if (cc->clut == NULL)
758 red >>= 16 - cc->bits.red;
759 green >>= 16 - cc->bits.green;
760 blue >>= 16 - cc->bits.blue;
762 ired = (red << cc->shifts.red) & cc->masks.red;
763 igreen = (green << cc->shifts.green) & cc->masks.green;
764 iblue = (blue << cc->shifts.blue) & cc->masks.blue;
766 return ired | igreen | iblue;
769 ired = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
770 igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
771 iblue = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
773 return ired | igreen | iblue;
776 case GDK_CC_MODE_PALETTE:
777 return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
779 case GDK_CC_MODE_STD_CMAP:
789 result = g_hash_table_lookup (cc->color_hash, &color);
798 if (!gdk_color_alloc (cc->colormap, &color))
804 /* XXX: the following comment comes directly from
805 * XCC.c. I don't know if it is relevant for
806 * gdk_color_alloc() as it is for XAllocColor()
810 * I can't figure this out entirely, but it *is* possible
811 * that XAllocColor succeeds, even if the number of
812 * allocations we've made exceeds the number of available
813 * colors in the current colormap. And therefore it
814 * might be necessary for us to resize the CLUT.
817 if (cc->num_allocated == cc->max_colors)
821 GDK_NOTE (COLOR_CONTEXT,
822 g_message ("gdk_color_context_get_pixel: "
823 "resizing CLUT to %i entries\n",
826 cc->clut = g_realloc (cc->clut,
827 cc->max_colors * sizeof (gulong));
830 /* Key and value are the same color structure */
832 cnew = g_new (GdkColor, 1);
834 g_hash_table_insert (cc->color_hash, cnew, cnew);
836 cc->clut[cc->num_allocated] = color.pixel;
842 return result->pixel;
848 gdk_color_context_get_pixels (GdkColorContext *cc,
857 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
858 gint bad_alloc = FALSE;
859 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
860 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
861 #ifdef G_ENABLE_DEBUG
862 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
864 g_assert (cc != NULL);
865 g_assert (reds != NULL);
866 g_assert (greens != NULL);
867 g_assert (blues != NULL);
868 g_assert (colors != NULL);
869 g_assert (nallocated != NULL);
871 memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
872 memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
873 memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
875 /* Will only have a value if used by the progressive image loader */
881 /* First allocate all pixels */
883 for (i = 0; i < ncolors; i++)
885 /* colors[i] is only zero if the pixel at that location hasn't
886 * been allocated yet. This is a sanity check required for proper
887 * color allocation by the progressive image loader
892 defs[i].red = reds[i];
893 defs[i].green = greens[i];
894 defs[i].blue = blues[i];
896 colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
899 /* successfully allocated, store it */
903 defs[i].pixel = colors[i];
904 allocated[ncols++] = colors[i];
913 /* all colors available, all done */
915 if ((ncols == ncolors) || (nopen == 0))
917 GDK_NOTE (COLOR_CONTEXT,
918 g_message ("gdk_color_context_get_pixels: got all %i colors; "
919 "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
924 /* The fun part. We now try to allocate the colors we couldn't allocate
925 * directly. The first step will map a color onto its nearest color
926 * that has been allocated (either by us or someone else). If any colors
927 * remain unallocated, we map these onto the colors that we have allocated
931 /* read up to MAX_IMAGE_COLORS colors of the current colormap */
933 cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
935 /* see if the colormap has any colors to read */
939 g_warning ("gdk_color_context_get_pixels: oops! no colors available, "
940 "your images will look *really* ugly.");
945 #ifdef G_ENABLE_DEBUG
949 /* initialize pixels */
951 for (i = 0; i < cmapsize; i++)
954 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
957 /* read the colormap */
959 my_x_query_colors (cc->colormap, cmap, cmapsize);
961 /* get a close match for any unallocated colors */
969 gint d, j, mdist, close, ri, gi, bi;
977 /* Store these vals. Small performance increase as this skips three
978 * indexing operations in the loop code.
985 /* Walk all colors in the colormap and see which one is the
986 * closest. Uses plain least squares.
989 for (j = 0; (j < cmapsize) && (mdist != 0); j++)
991 /* Don't replace these by shifts; the sign may get clobbered */
993 rd = (ri - cmap[j].red) / 256;
994 gd = (gi - cmap[j].green) / 256;
995 bd = (bi - cmap[j].blue) / 256;
997 d = rd * rd + gd * gd + bd * bd;
1008 rd = cmap[close].red;
1009 gd = cmap[close].green;
1010 bd = cmap[close].blue;
1014 colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1020 defs[i] = cmap[close];
1021 defs[i].pixel = colors[i];
1022 allocated[ncols++] = colors[i];
1023 #ifdef G_ENABLE_DEBUG
1027 failed[nopen++] = i;
1029 failed[nopen++] = i;
1030 /* deal with in next stage if allocation failed */
1032 while (++idx < counter);
1034 *nallocated = ncols;
1036 /* This is the maximum no. of allocated colors. See also the nopen == 0
1040 if ((ncols == ncolors) || (nopen == 0))
1042 GDK_NOTE (COLOR_CONTEXT,
1043 g_message ("gdk_color_context_get_pixels: got %i colors, %i exact and "
1044 "%i close (%i colors allocated so far)\n",
1045 ncolors, exact_col, close_col, cc->num_allocated));
1050 /* Now map any remaining unallocated pixels into the colors we did get */
1056 gint d, mdist, close, ri, gi, bi;
1070 /* search allocated colors */
1072 for (j = 0; (j < ncols) && (mdist != 0); j++)
1076 /* Don't replace these by shifts; the sign may get clobbered */
1078 rd = (ri - defs[k].red) / 256;
1079 gd = (gi - defs[k].green) / 256;
1080 bd = (bi - defs[k].blue) / 256;
1082 d = rd * rd + gd * gd + bd * bd;
1093 /* too bad, map to black */
1095 defs[i].pixel = cc->black_pixel;
1096 defs[i].red = defs[i].green = defs[i].blue = 0;
1097 #ifdef G_ENABLE_DEBUG
1103 defs[i] = defs[close];
1104 #ifdef G_ENABLE_DEBUG
1109 colors[i] = defs[i].pixel;
1111 while (++idx < nopen);
1113 GDK_NOTE (COLOR_CONTEXT,
1114 g_message ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
1115 "%i substituted, %i to black (%i colors allocated so far)\n",
1116 ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1120 gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
1130 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1131 gint bad_alloc = FALSE;
1132 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1133 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1134 #ifdef G_ENABLE_DEBUG
1135 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1138 g_assert (cc != NULL);
1139 g_assert (reds != NULL);
1140 g_assert (greens != NULL);
1141 g_assert (blues != NULL);
1142 g_assert (used != NULL);
1143 g_assert (colors != NULL);
1144 g_assert (nallocated != NULL);
1146 memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
1147 memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
1148 memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
1150 /* Will only have a value if used by the progressive image loader */
1152 ncols = *nallocated;
1156 /* First allocate all pixels */
1158 for (i = 0; i < ncolors; i++)
1160 /* used[i] is only -1 if the pixel at that location hasn't
1161 * been allocated yet. This is a sanity check required for proper
1162 * color allocation by the progressive image loader.
1163 * When colors[i] == 0 it indicates the slot is available for
1167 if (used[i] != FALSE)
1171 defs[i].red = reds[i];
1172 defs[i].green = greens[i];
1173 defs[i].blue = blues[i];
1175 colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
1177 /* successfully allocated, store it */
1181 defs[i].pixel = colors[i];
1182 allocated[ncols++] = colors[i];
1185 failed[nopen++] = i;
1189 GDK_NOTE (COLOR_CONTEXT,
1190 g_message ("gdk_color_context_get_pixels_incremental: "
1191 "pixel at slot %i already allocated, skipping\n", i));
1196 *nallocated = ncols;
1198 if ((ncols == ncolors) || (nopen == 0))
1200 GDK_NOTE (COLOR_CONTEXT,
1201 g_message ("gdk_color_context_get_pixels_incremental: got all %i colors "
1202 "(%i colors allocated so far)\n",
1203 ncolors, cc->num_allocated));
1208 cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
1212 g_warning ("gdk_color_context_get_pixels_incremental: oops! "
1213 "No colors available images will look *really* ugly.");
1217 #ifdef G_ENABLE_DEBUG
1221 /* initialize pixels */
1223 for (i = 0; i < cmapsize; i++)
1226 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1231 my_x_query_colors (cc->colormap, cmap, cmapsize);
1233 /* now match any unallocated colors */
1241 gint d, j, mdist, close, ri, gi, bi;
1255 for (j = 0; (j < cmapsize) && (mdist != 0); j++)
1257 /* Don't replace these by shifts; the sign may get clobbered */
1259 rd = (ri - cmap[j].red) / 256;
1260 gd = (gi - cmap[j].green) / 256;
1261 bd = (bi - cmap[j].blue) / 256;
1263 d = rd * rd + gd * gd + bd * bd;
1274 rd = cmap[close].red;
1275 gd = cmap[close].green;
1276 bd = cmap[close].blue;
1280 colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1286 defs[i] = cmap[close];
1287 defs[i].pixel = colors[i];
1288 allocated[ncols++] = colors[i];
1289 #ifdef G_ENABLE_DEBUG
1294 failed[nopen++] = i;
1297 failed[nopen++] = i;
1298 /* deal with in next stage if allocation failed */
1300 while (++idx < counter);
1302 *nallocated = ncols;
1304 if ((ncols == ncolors) || (nopen == 0))
1306 GDK_NOTE (COLOR_CONTEXT,
1307 g_message ("gdk_color_context_get_pixels_incremental: "
1308 "got %i colors, %i exact and %i close "
1309 "(%i colors allocated so far)\n",
1310 ncolors, exact_col, close_col, cc->num_allocated));
1315 /* map remaining unallocated pixels into colors we did get */
1321 gint d, mdist, close, ri, gi, bi;
1333 /* search allocated colors */
1335 for (j = 0; (j < ncols) && (mdist != 0); j++)
1340 /* Don't replace these by shifts; the sign may get clobbered */
1342 rd = (ri - defs[k].red) / 256;
1343 gd = (gi - defs[k].green) / 256;
1344 bd = (bi - defs[k].blue) / 256;
1346 d = rd * rd + gd * gd + bd * bd;
1357 /* too bad, map to black */
1359 defs[i].pixel = cc->black_pixel;
1360 defs[i].red = defs[i].green = defs[i].blue = 0;
1361 #ifdef G_ENABLE_DEBUG
1367 defs[i] = defs[close];
1368 #ifdef G_ENABLE_DEBUG
1373 colors[i] = defs[i].pixel;
1375 while (++idx < nopen);
1377 GDK_NOTE (COLOR_CONTEXT,
1378 g_message ("gdk_color_context_get_pixels_incremental: "
1379 "got %i colors, %i exact, %i close, %i substituted, %i to black "
1380 "(%i colors allocated so far)\n",
1381 ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1385 gdk_color_context_query_color (GdkColorContext *cc,
1388 return gdk_color_context_query_colors (cc, color, 1);
1392 gdk_color_context_query_colors (GdkColorContext *cc,
1399 g_assert (cc != NULL);
1400 g_assert (colors != NULL);
1404 case GDK_CC_MODE_BW:
1405 for (i = 0, tc = colors; i < num_colors; i++, tc++)
1407 if (tc->pixel == cc->white_pixel)
1408 tc->red = tc->green = tc->blue = 65535;
1410 tc->red = tc->green = tc->blue = 0;
1414 case GDK_CC_MODE_TRUE:
1415 if (cc->clut == NULL)
1416 for (i = 0, tc = colors; i < num_colors; i++, tc++)
1418 tc->red = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
1419 tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
1420 tc->blue = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
1424 my_x_query_colors (cc->colormap, colors, num_colors);
1429 case GDK_CC_MODE_STD_CMAP:
1431 if (cc->cmap == NULL)
1433 my_x_query_colors (cc->colormap, colors, num_colors);
1438 gint first, last, half;
1441 for (i = 0, tc = colors; i < num_colors; i++)
1444 last = cc->num_colors - 1;
1446 while (first <= last)
1448 half = (first + last) / 2;
1449 half_pixel = cc->cmap[half].pixel;
1451 if (tc->pixel == half_pixel)
1453 tc->red = cc->cmap[half].red;
1454 tc->green = cc->cmap[half].green;
1455 tc->blue = cc->cmap[half].blue;
1456 first = last + 1; /* false break */
1460 if (tc->pixel > half_pixel)
1475 gdk_color_context_add_palette (GdkColorContext *cc,
1483 g_assert (cc != NULL);
1485 /* initialize this palette (will also erase previous palette as well) */
1489 /* restore previous mode if we aren't adding a new palette */
1491 if (num_palette == 0)
1493 /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
1495 /* XXX: here, the hash table is already initialized */
1500 /* Initialize a hash table for this palette (we need one for allocating
1501 * the pixels in the palette using the current settings)
1504 if (cc->color_hash == NULL)
1505 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
1507 /* copy incoming palette */
1509 cc->palette = g_new0(GdkColor, num_palette);
1513 for (i = 0; i < num_palette; i++)
1518 /* try to allocate this color */
1521 g = palette[i].green;
1522 b = palette[i].blue;
1524 gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
1526 /* only store if we succeed */
1530 /* store in palette */
1532 cc->palette[j].red = r;
1533 cc->palette[j].green = g;
1534 cc->palette[j].blue = b;
1535 cc->palette[j].pixel = pixel[0];
1537 /* move to next slot */
1545 if (j != num_palette)
1546 cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
1548 /* clear the hash table, we don't use it when dithering */
1552 g_hash_table_destroy (cc->color_hash);
1553 cc->color_hash = NULL;
1556 /* store real palette size */
1558 cc->num_palette = j;
1560 /* switch to palette mode */
1562 cc->mode = GDK_CC_MODE_PALETTE;
1566 qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
1568 cc->fast_dither = NULL;
1574 gdk_color_context_init_dither (GdkColorContext *cc)
1576 gint rr, gg, bb, err, erg, erb;
1577 gint success = FALSE;
1579 g_assert (cc != NULL);
1581 /* now we can initialize the fast dither matrix */
1583 if (cc->fast_dither == NULL)
1584 cc->fast_dither = g_new (GdkColorContextDither, 1);
1586 /* Fill it. We ignore unsuccessful allocations, they are just mapped
1587 * to black instead */
1589 for (rr = 0; rr < 32; rr++)
1590 for (gg = 0; gg < 32; gg++)
1591 for (bb = 0; bb < 32; bb++)
1593 err = (rr << 3) | (rr >> 2);
1594 erg = (gg << 3) | (gg >> 2);
1595 erb = (bb << 3) | (bb >> 2);
1597 cc->fast_dither->fast_rgb[rr][gg][bb] =
1598 gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
1599 cc->fast_dither->fast_err[rr][gg][bb] = err;
1600 cc->fast_dither->fast_erg[rr][gg][bb] = erg;
1601 cc->fast_dither->fast_erb[rr][gg][bb] = erb;
1606 gdk_color_context_free_dither (GdkColorContext *cc)
1608 g_assert (cc != NULL);
1610 if (cc->fast_dither)
1611 g_free (cc->fast_dither);
1613 cc->fast_dither = NULL;
1617 gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
1624 gint dif, dr, dg, db, j = -1;
1625 gint mindif = 0x7fffffff;
1626 gint err = 0, erg = 0, erb = 0;
1629 g_assert (cc != NULL);
1630 g_assert (red != NULL);
1631 g_assert (green != NULL);
1632 g_assert (blue != NULL);
1633 g_assert (failed != NULL);
1637 for (i = 0; i < cc->num_palette; i++)
1639 dr = *red - cc->palette[i].red;
1640 dg = *green - cc->palette[i].green;
1641 db = *blue - cc->palette[i].blue;
1643 dif = dr * dr + dg * dg + db * db;
1649 pixel = cc->palette[i].pixel;
1659 /* we failed to map onto a color */
1674 gdk_color_context_get_index_from_palette (GdkColorContext *cc,
1680 gint dif, dr, dg, db, j = -1;
1681 gint mindif = 0x7fffffff;
1682 gint err = 0, erg = 0, erb = 0;
1685 g_assert (cc != NULL);
1686 g_assert (red != NULL);
1687 g_assert (green != NULL);
1688 g_assert (blue != NULL);
1689 g_assert (failed != NULL);
1693 for (i = 0; i < cc->num_palette; i++)
1695 dr = *red - cc->palette[i].red;
1696 dg = *green - cc->palette[i].green;
1697 db = *blue - cc->palette[i].blue;
1699 dif = dr * dr + dg * dg + db * db;
1714 /* we failed to map onto a color */
1723 /* return error fractions */