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 Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* Color Context module
20 * Copyright 1994,1995 John L. Cwikla
21 * Copyright (C) 1997 by Ripley Software Development
22 * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
25 /* Copyright 1994,1995 John L. Cwikla
27 * Permission to use, copy, modify, distribute, and sell this software
28 * and its documentation for any purpose is hereby granted without fee,
29 * provided that the above copyright notice appears in all copies and that
30 * both that copyright notice and this permission notice appear in
31 * supporting documentation, and that the name of John L. Cwikla or
32 * Wolfram Research, Inc not be used in advertising or publicity
33 * pertaining to distribution of the software without specific, written
34 * prior permission. John L. Cwikla and Wolfram Research, Inc make no
35 * representations about the suitability of this software for any
36 * purpose. It is provided "as is" without express or implied warranty.
38 * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
39 * regard to this software, including all implied warranties of
40 * merchantability and fitness, in no event shall John L. Cwikla or
41 * Wolfram Research, Inc be liable for any special, indirect or
42 * consequential damages or any damages whatsoever resulting from loss of
43 * use, data or profits, whether in an action of contract, negligence or
44 * other tortious action, arising out of or in connection with the use or
45 * performance of this software.
50 * Wolfram Research Inc.
57 * - When a CC is destroyed, remember to destroy the hash table properly.
65 #include "gdkprivate.h"
69 #define MAX_IMAGE_COLORS 256
73 hash_color(gpointer key)
75 GdkColor *color = key;
77 return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
81 compare_colors(gpointer a, gpointer b)
86 return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
90 free_hash_entry(gpointer key, gpointer value, gpointer user_data)
92 g_free(key); /* key and value are the same GdkColor */
96 pixel_sort(const void *a, const void *b)
98 return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
101 /* XXX: This function does an XQueryColors() the hard way, because there is
102 * no corresponding function in Gdk.
106 my_x_query_colors(GdkColormap *colormap,
113 xcolors = g_new(XColor, ncolors);
114 for (i = 0; i < ncolors; i++)
115 xcolors[i].pixel = colors[i].pixel;
117 XQueryColors(gdk_display, GDK_COLORMAP_XCOLORMAP(colormap), xcolors, ncolors);
119 for (i = 0; i < ncolors; i++) {
120 colors[i].red = xcolors[i].red;
121 colors[i].green = xcolors[i].green;
122 colors[i].blue = xcolors[i].blue;
129 query_colors(GdkColorContextPrivate *cc)
133 cc->cmap = g_new(GdkColor, cc->num_colors);
135 for (i = 0; i < cc->num_colors; i++)
136 cc->cmap[i].pixel = cc->clut ? cc->clut[i] : cc->std_cmap.base_pixel + i;
138 my_x_query_colors(cc->colormap, cc->cmap, cc->num_colors);
140 qsort(cc->cmap, cc->num_colors, sizeof(GdkColor), pixel_sort);
144 init_bw(GdkColorContextPrivate *cc)
148 g_warning("init_bw: failed to allocate colors, falling back to black and white");
150 cc->mode = GDK_CC_MODE_BW;
152 color.red = color.green = color.blue = 0;
153 if (!gdk_color_alloc(cc->colormap, &color))
156 cc->black_pixel = color.pixel;
158 color.red = color.green = color.blue = 0xffff;
159 if (!gdk_color_alloc(cc->colormap, &color))
160 cc->white_pixel = cc->black_pixel ? 0 : 1;
162 cc->white_pixel = color.pixel;
168 init_gray(GdkColorContextPrivate *cc)
170 GdkColor *clrs, *cstart;
174 cc->num_colors = GDK_VISUAL_XVISUAL(cc->visual)->map_entries;
176 cc->clut = g_new(gulong, cc->num_colors);
177 cstart = g_new(GdkColor, cc->num_colors);
181 dinc = 65535.0 / (cc->num_colors - 1);
185 for (i = 0; i < cc->num_colors; i++) {
186 clrs->red = clrs->green = clrs->blue = dinc * i;
188 if (!gdk_color_alloc(cc->colormap, clrs)) {
189 gdk_colors_free(cc->colormap, cc->clut, i, 0);
193 if (cc->num_colors > 1)
204 cc->clut[i] = clrs++->pixel;
209 /* XXX: is this the right thing to do? */
210 cc->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP(cc->colormap);
211 cc->std_cmap.base_pixel = 0;
212 cc->std_cmap.red_max = cc->num_colors - 1;
213 cc->std_cmap.green_max = 0;
214 cc->std_cmap.blue_max = 0;
215 cc->std_cmap.red_mult = 1;
216 cc->std_cmap.green_mult = 0;
217 cc->std_cmap.blue_mult = 0;
219 cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
220 cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
224 cc->mode = GDK_CC_MODE_MY_GRAY;
228 init_color(GdkColorContextPrivate *cc)
233 while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL(cc->visual)->map_entries)
237 cc->num_colors = cubeval * cubeval * cubeval;
239 cc->std_cmap.red_max = cubeval - 1;
240 cc->std_cmap.green_max = cubeval - 1;
241 cc->std_cmap.blue_max = cubeval - 1;
242 cc->std_cmap.red_mult = cubeval * cubeval;
243 cc->std_cmap.green_mult = cubeval;
244 cc->std_cmap.blue_mult = 1;
245 cc->std_cmap.base_pixel = 0;
247 cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
248 cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
249 cc->num_colors = DisplayCells(cc->xdisplay, gdk_screen);
251 /* a CLUT for storing allocated pixel indices */
253 cc->max_colors = cc->num_colors;
254 cc->clut = g_new(gulong, cc->max_colors);
256 for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
257 cc->clut[cubeval] = cubeval;
261 cc->mode = GDK_CC_MODE_STD_CMAP;
266 init_true_color(GdkColorContextPrivate *cc)
268 gulong rmask, gmask, bmask;
270 cc->mode = GDK_CC_MODE_TRUE;
274 rmask = cc->masks.red = cc->visual->red_mask;
279 while (!(rmask & 1)) {
291 gmask = cc->masks.green = cc->visual->green_mask;
293 cc->shifts.green = 0;
296 while (!(gmask & 1)) {
308 bmask = cc->masks.blue = cc->visual->blue_mask;
313 while (!(bmask & 1)) {
323 cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
324 cc->white_pixel = WhitePixel(cc->xdisplay, gdk_screen);
325 cc->black_pixel = BlackPixel(cc->xdisplay, gdk_screen);
329 init_direct_color(GdkColorContextPrivate *cc)
332 GdkColor *clrs, *cstart;
333 gulong rval, gval, bval;
339 init_true_color(cc); /* for shift stuff */
341 rval = cc->visual->red_mask >> cc->shifts.red;
342 gval = cc->visual->green_mask >> cc->shifts.green;
343 bval = cc->visual->blue_mask >> cc->shifts.blue;
345 rtable = g_new(gulong, rval + 1);
346 gtable = g_new(gulong, gval + 1);
347 btable = g_new(gulong, bval + 1);
349 cc->max_entry = MAX(rval, gval);
350 cc->max_entry = MAX(cc->max_entry, bval);
352 cstart = g_new(GdkColor, cc->max_entry + 1);
353 cc->clut = g_new(gulong, cc->max_entry + 1);
357 for (n = 0; n < rval; n++)
358 rtable[n] = rval ? (65535.0 / rval * n) : 0;
360 for (n = 0; n < gval; n++)
361 gtable[n] = gval ? (65535.0 / gval * n) : 0;
363 for (n = 0; n < bval; n++)
364 btable[n] = bval ? (65535.0 / bval * n) : 0;
366 cc->max_entry = MAX(rval, gval);
367 cc->max_entry = MAX(cc->max_entry, bval);
371 cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
373 for (n = 0; n < cc->max_entry; n++) {
374 dinc = (double) n / cc->max_entry;
376 clrs->red = rtable[(int) (dinc * rval)];
377 clrs->green = gtable[(int) (dinc * gval)];
378 clrs->blue = btable[(int) (dinc * bval)];
380 if (gdk_color_alloc(cc->colormap, clrs)) {
381 cc->clut[count++] = clrs->pixel;
384 gdk_colors_free(cc->colormap, cc->clut, count, 0);
390 cc->masks.red = (cc->masks.red >> 1) & cc->visual->red_mask;
391 cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
392 cc->masks.blue = (cc->masks.blue >> 1) & cc->visual->blue_mask;
402 cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
404 if (cc->num_colors >1)
415 /* Update allocated color count; original num_colors is max_entry, which
416 * is not necessarily the same as the really allocated number of colors.
419 cc->num_colors = count;
428 init_palette(GdkColorContextPrivate *cc)
430 /* restore correct mode for this cc */
432 switch (cc->visual->type) {
433 case GDK_VISUAL_STATIC_GRAY:
434 case GDK_VISUAL_GRAYSCALE:
435 if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
436 cc->mode = GDK_CC_MODE_BW;
438 cc->mode = GDK_CC_MODE_MY_GRAY;
441 case GDK_VISUAL_TRUE_COLOR:
442 case GDK_VISUAL_DIRECT_COLOR:
443 cc->mode = GDK_CC_MODE_TRUE;
446 case GDK_VISUAL_STATIC_COLOR:
447 case GDK_VISUAL_PSEUDO_COLOR:
448 cc->mode = GDK_CC_MODE_STD_CMAP;
452 cc->mode = GDK_CC_MODE_UNDEFINED;
456 /* previous palette */
462 g_free(cc->fast_dither);
464 /* clear hash table if present */
466 if (cc->color_hash) {
467 /* XXX: quick-and-dirty way to remove everything */
469 g_hash_table_destroy(cc->color_hash);
470 cc->color_hash = g_hash_table_new(hash_color, compare_colors);
475 cc->fast_dither = NULL;
479 gdk_color_context_new(GdkVisual *visual,
480 GdkColormap *colormap)
482 gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
483 GdkColorContextPrivate *cc;
485 GdkColormap *default_colormap;
487 g_assert(visual != NULL);
488 g_assert(colormap != NULL);
490 cc = g_new(GdkColorContextPrivate, 1);
492 cc->xdisplay = gdk_display;
494 cc->colormap = colormap;
497 cc->mode = GDK_CC_MODE_UNDEFINED;
498 cc->need_to_free_colormap = FALSE;
500 cc->color_hash = NULL;
503 cc->fast_dither = NULL;
505 default_colormap = gdk_colormap_get_system();
509 while (retry_count < 2) {
510 /* Only create a private colormap if the visual found isn't equal
511 * to the default visual and we don't have a private colormap,
512 * -or- if we are instructed to create a private colormap (which
513 * never is the case for XmHTML).
516 if (use_private_colormap
517 || ((cc->visual != gdk_visual_get_system()) /* default visual? */
518 && (GDK_COLORMAP_XCOLORMAP(colormap) == GDK_COLORMAP_XCOLORMAP(default_colormap)))) {
519 g_warning("gdk_color_context_new: non-default visual detected, "
520 "using private colormap");
522 cc->colormap = gdk_colormap_new(cc->visual, FALSE);
524 cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP(colormap)
525 != GDK_COLORMAP_XCOLORMAP(default_colormap));
528 switch (visual->type) {
529 case GDK_VISUAL_STATIC_GRAY:
530 case GDK_VISUAL_GRAYSCALE:
531 if (gdk_debug_level >= 1)
532 g_print("gdk_color_context_new: visual class is %s",
533 (visual->type == GDK_VISUAL_STATIC_GRAY) ?
534 "GDK_VISUAL_STATIC_GRAY" :
535 "GDK_VISUAL_GRAYSCALE");
537 if (GDK_VISUAL_XVISUAL(cc->visual)->map_entries == 2)
544 case GDK_VISUAL_TRUE_COLOR: /* shifts */
545 if (gdk_debug_level >= 1)
546 g_print("gdk_color_context_new: visual class is "
547 "GDK_VISUAL_TRUE_COLOR");
552 case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
553 if (gdk_debug_level >= 1)
554 g_print("gdk_color_context_new: visual class is "
555 "GDK_VISUAL_DIRECT_COLOR");
557 init_direct_color(cc);
560 case GDK_VISUAL_STATIC_COLOR:
561 case GDK_VISUAL_PSEUDO_COLOR:
562 if (gdk_debug_level >= 1)
563 g_print("gdk_color_context_new: visual class is %s",
564 (visual->type == GDK_VISUAL_STATIC_COLOR) ?
565 "GDK_VISUAL_STATIC_COLOR" :
566 "GDK_VISUAL_PSEUDO_COLOR");
572 g_assert_not_reached();
575 if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1)) {
576 use_private_colormap = TRUE;
582 /* no. of colors allocated yet */
584 cc->num_allocated = 0;
586 if (gdk_debug_level >= 1)
587 g_print("gdk_color_context_new: screen depth is %i, no. of colors is %i",
588 cc->visual->depth, cc->num_colors);
590 /* check if we need to initialize a hash table */
592 if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
593 cc->color_hash = g_hash_table_new(hash_color, compare_colors);
595 return (GdkColorContext *) cc;
599 gdk_color_context_new_mono(GdkVisual *visual,
600 GdkColormap *colormap)
602 GdkColorContextPrivate *cc;
604 g_assert(visual != NULL);
605 g_assert(colormap != NULL);
607 cc = g_new(GdkColorContextPrivate, 1);
609 cc->xdisplay = gdk_display;
611 cc->colormap = colormap;
614 cc->mode = GDK_CC_MODE_UNDEFINED;
615 cc->need_to_free_colormap = FALSE;
619 return (GdkColorContext *) cc;
622 /* This doesn't currently free black/white, hmm... */
625 gdk_color_context_free(GdkColorContext *cc)
627 GdkColorContextPrivate *ccp;
629 g_assert(cc != NULL);
631 ccp = (GdkColorContextPrivate *) cc;
633 if ((ccp->visual->type == GDK_VISUAL_STATIC_COLOR)
634 || (ccp->visual->type == GDK_VISUAL_PSEUDO_COLOR)) {
635 gdk_colors_free(ccp->colormap, ccp->clut, ccp->num_allocated, 0);
637 } else if (ccp->clut != NULL) {
638 gdk_colors_free(ccp->colormap, ccp->clut, ccp->num_colors, 0);
642 if (ccp->cmap != NULL)
645 if (ccp->need_to_free_colormap)
646 gdk_colormap_destroy(ccp->colormap);
648 /* free any palette that has been associated with this GdkColorContext */
652 if (ccp->color_hash) {
653 g_hash_table_foreach(ccp->color_hash,
656 g_hash_table_destroy(ccp->color_hash);
663 gdk_color_context_get_pixel(GdkColorContext *cc,
669 GdkColorContextPrivate *ccp;
671 g_assert(cc != NULL);
672 g_assert(failed != NULL);
674 ccp = (GdkColorContextPrivate *) cc;
679 case GDK_CC_MODE_BW: {
686 value = red / 65535.0 * 0.30
687 + green / 65535.0 * 0.59
688 + blue / 65535.0 * 0.11;
691 return ccp->white_pixel;
693 return ccp->black_pixel;
696 case GDK_CC_MODE_MY_GRAY: {
697 gulong ired, igreen, iblue;
703 red = red * 0.30 + green * 0.59 + blue * 0.11;
707 if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff)
708 > ccp->std_cmap.red_max)
709 ired = ccp->std_cmap.red_max;
711 ired *= ccp->std_cmap.red_mult;
713 if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff)
714 > ccp->std_cmap.green_max)
715 igreen = ccp->std_cmap.green_max;
717 igreen *= ccp->std_cmap.green_mult;
719 if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff)
720 > ccp->std_cmap.blue_max)
721 iblue = ccp->std_cmap.blue_max;
723 iblue *= ccp->std_cmap.blue_mult;
725 if (ccp->clut != NULL)
726 return ccp->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
728 return ccp->std_cmap.base_pixel + ired + igreen + iblue;
731 case GDK_CC_MODE_TRUE: {
732 gulong ired, igreen, iblue;
738 if (ccp->clut == NULL) {
739 red >>= 16 - ccp->bits.red;
740 green >>= 16 - ccp->bits.green;
741 blue >>= 16 - ccp->bits.blue;
743 ired = (red << ccp->shifts.red) & ccp->masks.red;
744 igreen = (green << ccp->shifts.green) & ccp->masks.green;
745 iblue = (blue << ccp->shifts.blue) & ccp->masks.blue;
747 return ired | igreen | iblue;
750 ired = ccp->clut[red * ccp->max_entry / 65535] & ccp->masks.red;
751 igreen = ccp->clut[green * ccp->max_entry / 65535] & ccp->masks.green;
752 iblue = ccp->clut[blue * ccp->max_entry / 65535] & ccp->masks.blue;
754 return ired | igreen | iblue;
757 case GDK_CC_MODE_PALETTE:
758 return gdk_color_context_get_pixel_from_palette(cc, &red, &green, &blue, failed);
760 case GDK_CC_MODE_STD_CMAP:
773 result = g_hash_table_lookup(ccp->color_hash, &color);
781 if (!gdk_color_alloc(ccp->colormap, &color))
786 /* XXX: the following comment comes directly from
787 * XCC.c. I don't know if it is relevant for
788 * gdk_color_alloc() as it is for XAllocColor()
792 * I can't figure this out entirely, but it *is* possible
793 * that XAllocColor succeeds, even if the number of
794 * allocations we've made exceeds the number of available
795 * colors in the current colormap. And therefore it
796 * might be necessary for us to resize the CLUT.
799 if (ccp->num_allocated == ccp->max_colors) {
800 ccp->max_colors *= 2;
802 if (gdk_debug_level >= 1)
803 g_print("gdk_color_context_get_pixel: "
804 "resizing CLUT to %i entries",
807 ccp->clut = g_realloc(ccp->clut,
808 ccp->max_colors * sizeof(gulong));
811 /* Key and value are the same color structure */
813 cnew = g_new(GdkColor, 1);
815 g_hash_table_insert(ccp->color_hash, cnew, cnew);
817 ccp->clut[ccp->num_allocated] = color.pixel;
818 ccp->num_allocated++;
823 return result->pixel;
829 gdk_color_context_get_pixels(GdkColorContext *cc,
837 GdkColorContextPrivate *ccp;
839 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
840 gint bad_alloc = FALSE;
841 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
842 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
843 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
845 g_assert(cc != NULL);
846 g_assert(reds != NULL);
847 g_assert(greens != NULL);
848 g_assert(blues != NULL);
849 g_assert(colors != NULL);
850 g_assert(nallocated != NULL);
852 ccp = (GdkColorContextPrivate *) cc;
854 memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
855 memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
856 memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
858 /* Will only have a value if used by the progressive image loader */
864 /* First allocate all pixels */
866 for (i = 0; i < ncolors; i++) {
867 /* colors[i] is only zero if the pixel at that location hasn't
868 * been allocated yet. This is a sanity check required for proper
869 * color allocation by the progressive image loader
872 if (colors[i] == 0) {
873 defs[i].red = reds[i];
874 defs[i].green = greens[i];
875 defs[i].blue = blues[i];
877 colors[i] = gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i],
880 /* successfully allocated, store it */
883 defs[i].pixel = colors[i];
884 allocated[ncols++] = colors[i];
892 /* all colors available, all done */
894 if ((ncols == ncolors) || (nopen == 0)) {
895 if (gdk_debug_level >= 1)
896 g_print("gdk_color_context_get_pixels: got all %i colors; "
897 "(%i colors allocated so far", ncolors, ccp->num_allocated);
902 /* The fun part. We now try to allocate the colors we couldn't allocate
903 * directly. The first step will map a color onto its nearest color
904 * that has been allocated (either by us or someone else). If any colors
905 * remain unallocated, we map these onto the colors that we have allocated
909 /* read up to MAX_IMAGE_COLORS colors of the current colormap */
911 cmapsize = MIN(ccp->num_colors, MAX_IMAGE_COLORS);
913 /* see if the colormap has any colors to read */
916 g_warning("gdk_color_context_get_pixels: oops! no colors available, "
917 "your images will look *really* ugly.");
926 /* initialize pixels */
928 for (i = 0; i < cmapsize; i++) {
930 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
933 /* read the colormap */
935 my_x_query_colors(ccp->colormap, cmap, cmapsize);
937 /* speedup: downscale here instead of in the matching code */
939 for (i = 0; i < cmapsize; i++) {
945 /* get a close match for any unallocated colors */
952 gint d, j, mdist, close, ri, gi, bi;
960 /* Store these vals. Small performance increase as this skips three
961 * indexing operations in the loop code.
968 /* Walk all colors in the colormap and see which one is the
969 * closest. Uses plain least squares.
972 for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
973 rd = ri - cmap[j].red;
974 gd = gi - cmap[j].green;
975 bd = bi - cmap[j].blue;
977 d = rd * rd + gd * gd + bd * bd;
986 rd = cmap[close].red;
987 gd = cmap[close].green;
988 bd = cmap[close].blue;
992 colors[i] = gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
997 defs[i] = cmap[close];
998 defs[i].pixel = colors[i];
999 allocated[ncols++] = colors[i];
1004 failed[nopen++] = i;
1006 failed[nopen++] = i;
1007 /* deal with in next stage if allocation failed */
1008 } while (++idx < counter);
1010 *nallocated = ncols;
1012 /* This is the maximum no. of allocated colors. See also the nopen == 0
1016 if ((ncols == ncolors) || (nopen == 0)) {
1017 if (gdk_debug_level >= 1)
1018 g_print("gdk_color_context_get_pixels: got %i colors, %i exact and "
1019 "%i close (%i colors allocated so far)",
1020 ncolors, exact_col, close_col, ccp->num_allocated);
1025 /* Now map any remaining unallocated pixels into the colors we did get */
1030 gint d, mdist, close, ri, gi, bi;
1044 /* search allocated colors */
1046 for (j = 0; (j < ncols) && (mdist != 0); j++) {
1049 rd = ri - defs[k].red;
1050 gd = gi - defs[k].green;
1051 bd = bi - defs[k].blue;
1053 d = rd * rd + gd * gd + bd * bd;
1062 /* too bad, map to black */
1064 defs[i].pixel = ccp->black_pixel;
1065 defs[i].red = defs[i].green = defs[i].blue = 0;
1070 defs[i] = defs[close];
1076 colors[i] = defs[i].pixel;
1077 } while (++idx < nopen);
1079 if (gdk_debug_level >= 1)
1080 g_print("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
1081 "%i substituted, %i to black (%i colors allocated so far)",
1082 ncolors, exact_col, close_col, subst_col, black_col, ccp->num_allocated);
1086 gdk_color_context_get_pixels_incremental(GdkColorContext *cc,
1095 GdkColorContextPrivate *ccp;
1097 gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1098 gint bad_alloc = FALSE;
1099 gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1100 GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1101 gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1103 g_assert(cc != NULL);
1104 g_assert(reds != NULL);
1105 g_assert(greens != NULL);
1106 g_assert(blues != NULL);
1107 g_assert(used != NULL);
1108 g_assert(colors != NULL);
1109 g_assert(nallocated != NULL);
1111 ccp = (GdkColorContextPrivate *) cc;
1113 memset(defs, 0, MAX_IMAGE_COLORS * sizeof(GdkColor));
1114 memset(failed, 0, MAX_IMAGE_COLORS * sizeof(gint));
1115 memset(allocated, 0, MAX_IMAGE_COLORS * sizeof(gint));
1117 /* Will only have a value if used by the progressive image loader */
1119 ncols = *nallocated;
1123 /* First allocate all pixels */
1125 for (i = 0; i < ncolors; i++) {
1126 /* used[i] is only -1 if the pixel at that location hasn't
1127 * been allocated yet. This is a sanity check required for proper
1128 * color allocation by the progressive image loader.
1129 * When colors[i] == 0 it indicates the slot is available for
1133 if (used[i] != FALSE) {
1134 if (colors[i] == 0) {
1135 defs[i].red = reds[i];
1136 defs[i].green = greens[i];
1137 defs[i].blue = blues[i];
1139 colors[i] = gdk_color_context_get_pixel(cc, reds[i], greens[i], blues[i], &bad_alloc);
1141 /* successfully allocated, store it */
1144 defs[i].pixel = colors[i];
1145 allocated[ncols++] = colors[i];
1147 failed[nopen++] = i;
1151 if (gdk_debug_level >= 1)
1152 g_print("gdk_color_context_get_pixels_incremental: "
1153 "pixel at slot %i already allocated, skipping", i);
1158 *nallocated = ncols;
1160 if ((ncols == ncolors) || (nopen == 0)) {
1161 if (gdk_debug_level >= 1)
1162 g_print("gdk_color_context_get_pixels_incremental: got all %i colors "
1163 "(%i colors allocated so far)",
1164 ncolors, ccp->num_allocated);
1169 cmapsize = MIN(ccp->num_colors, MAX_IMAGE_COLORS);
1172 g_warning("gdk_color_context_get_pixels_incremental: oops! "
1173 "No colors available images will look *really* ugly.");
1181 /* initialize pixels */
1183 for (i = 0; i < cmapsize; i++) {
1185 cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1188 /* read and downscale */
1190 my_x_query_colors(ccp->colormap, cmap, cmapsize);
1192 for (i = 0; i < cmapsize; i++) {
1194 cmap[i].green >>= 8;
1198 /* now match any unallocated colors */
1205 gint d, j, mdist, close, ri, gi, bi;
1219 for (j = 0; (j < cmapsize) && (mdist != 0); j++) {
1220 rd = ri - cmap[j].red;
1221 gd = gi - cmap[j].green;
1222 bd = bi - cmap[j].blue;
1224 d = rd * rd + gd * gd + bd * bd;
1233 rd = cmap[close].red;
1234 gd = cmap[close].green;
1235 bd = cmap[close].blue;
1239 colors[i] = gdk_color_context_get_pixel(cc, rd, gd, bd, &bad_alloc);
1244 defs[i] = cmap[close];
1245 defs[i].pixel = colors[i];
1246 allocated[ncols++] = colors[i];
1251 failed[nopen++] = i;
1253 failed[nopen++] = i;
1254 /* deal with in next stage if allocation failed */
1255 } while (++idx < counter);
1257 *nallocated = ncols;
1259 if ((ncols == ncolors) || (nopen == 0)) {
1260 if (gdk_debug_level >= 1)
1261 g_print("gdk_color_context_get_pixels_incremental: "
1262 "got %i colors, %i exact and %i close "
1263 "(%i colors allocated so far)",
1264 ncolors, exact_col, close_col, ccp->num_allocated);
1269 /* map remaining unallocated pixels into colors we did get */
1274 gint d, mdist, close, ri, gi, bi;
1286 /* search allocated colors */
1288 for (j = 0; (j < ncols) && (mdist != 0); j++) {
1293 rd = ri - defs[k].red;
1294 gd = gi - defs[k].green;
1295 bd = bi - defs[k].blue;
1297 d = rd * rd + gd * gd + bd * bd;
1306 /* too bad, map to black */
1308 defs[i].pixel = ccp->black_pixel;
1309 defs[i].red = defs[i].green = defs[i].blue = 0;
1314 defs[i] = defs[close];
1320 colors[i] = defs[i].pixel;
1321 } while (++idx < nopen);
1323 if (gdk_debug_level >= 1)
1324 g_print("gdk_color_context_get_pixels_incremental: "
1325 "got %i colors, %i exact, %i close, %i substituted, %i to black "
1326 "(%i colors allocated so far)",
1327 ncolors, exact_col, close_col, subst_col, black_col, ccp->num_allocated);
1331 gdk_color_context_get_num_colors(GdkColorContext *cc)
1333 g_assert(cc != NULL);
1335 return ((GdkColorContextPrivate *) cc)->num_colors;
1339 gdk_color_context_get_depth(GdkColorContext *cc)
1341 GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
1343 g_assert(cc != NULL);
1345 return ccp->visual->depth;
1349 gdk_color_context_get_mode(GdkColorContext *cc)
1351 g_assert(cc != NULL);
1353 return ((GdkColorContextPrivate *) cc)->mode;
1358 gdk_color_context_get_visual(GdkColorContext *cc)
1360 g_assert(cc != NULL);
1362 return ((GdkColorContextPrivate *) cc)->visual;
1366 gdk_color_context_query_color(GdkColorContext *cc,
1369 return gdk_color_context_query_colors(cc, color, 1);
1373 gdk_color_context_query_colors(GdkColorContext *cc,
1377 GdkColorContextPrivate *ccp;
1381 g_assert(cc != NULL);
1382 g_assert(colors != NULL);
1384 ccp = (GdkColorContextPrivate *) cc;
1386 switch (ccp->mode) {
1387 case GDK_CC_MODE_BW:
1388 for (i = 0, tc = colors; i < num_colors; i++, tc++) {
1389 if (tc->pixel == ccp->white_pixel)
1390 tc->red = tc->green = tc->blue = 65535;
1392 tc->red = tc->green = tc->blue = 0;
1396 case GDK_CC_MODE_TRUE:
1397 if (ccp->clut == NULL)
1398 for (i = 0, tc = colors; i < num_colors; i++, tc++) {
1399 tc->red = (tc->pixel & ccp->masks.red) * 65535 / ccp->masks.red;
1400 tc->green = (tc->pixel & ccp->masks.green) * 65535 / ccp->masks.green;
1401 tc->blue = (tc->pixel & ccp->masks.blue) * 65535 / ccp->masks.blue;
1404 my_x_query_colors(ccp->colormap, colors, num_colors);
1409 case GDK_CC_MODE_STD_CMAP:
1411 if (ccp->cmap == NULL) {
1412 my_x_query_colors(ccp->colormap, colors, num_colors);
1415 gint first, last, half;
1418 for (i = 0, tc = colors; i < num_colors; i++) {
1420 last = ccp->num_colors - 1;
1422 while (first <= last) {
1423 half = (first + last) / 2;
1424 half_pixel = ccp->cmap[half].pixel;
1426 if (tc->pixel == half_pixel) {
1427 tc->red = ccp->cmap[half].red;
1428 tc->green = ccp->cmap[half].green;
1429 tc->blue = ccp->cmap[half].blue;
1430 first = last + 1; /* false break */
1432 if (tc->pixel > half_pixel)
1447 gdk_color_context_add_palette(GdkColorContext *cc,
1451 GdkColorContextPrivate *ccp;
1456 g_assert(cc != NULL);
1458 ccp = (GdkColorContextPrivate *) cc;
1460 /* initialize this palette (will also erase previous palette as well) */
1464 /* restore previous mode if we aren't adding a new palette */
1466 if (num_palette == 0) {
1467 /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
1469 /* XXX: here, the hash table is already initialized */
1474 /* Initialize a hash table for this palette (we need one for allocating
1475 * the pixels in the palette using the current settings)
1478 if (ccp->color_hash == NULL)
1479 ccp->color_hash = g_hash_table_new(hash_color, compare_colors);
1481 /* copy incoming palette */
1483 ccp->palette = g_new0(GdkColor, num_palette);
1487 for (i = 0; i < num_palette; i++) {
1491 /* try to allocate this color */
1494 g = palette[i].green;
1495 b = palette[i].blue;
1497 gdk_color_context_get_pixels(cc, &r, &g, &b, 1, pixel, &erg);
1499 /* only store if we succeed */
1502 /* store in palette */
1504 ccp->palette[j].red = r;
1505 ccp->palette[j].green = g;
1506 ccp->palette[j].blue = b;
1507 ccp->palette[j].pixel = pixel[0];
1509 /* move to next slot */
1517 if (j != num_palette)
1518 ccp->palette = g_realloc(ccp->palette, j * sizeof(GdkColor));
1520 /* clear the hash table, we don't use it when dithering */
1522 if (ccp->color_hash) {
1523 g_hash_table_destroy(ccp->color_hash);
1524 ccp->color_hash = NULL;
1527 /* store real palette size */
1529 ccp->num_palette = j;
1531 /* switch to palette mode */
1533 ccp->mode = GDK_CC_MODE_PALETTE;
1537 qsort(ccp->palette, ccp->num_palette, sizeof(GdkColor), pixel_sort);
1539 ccp->fast_dither = NULL;
1545 gdk_color_context_init_dither(GdkColorContext *cc)
1547 GdkColorContextPrivate *ccp;
1548 gint rr, gg, bb, err, erg, erb;
1549 gint success = FALSE;
1551 g_assert(cc != NULL);
1553 ccp = (GdkColorContextPrivate *) cc;
1555 /* now we can initialize the fast dither matrix */
1557 if(ccp->fast_dither == NULL)
1558 ccp->fast_dither = g_new(GdkColorContextDither, 1);
1560 /* Fill it. We ignore unsuccessful allocations, they are just mapped
1561 * to black instead */
1563 for (rr = 0; rr < 32; rr++)
1564 for (gg = 0; gg < 32; gg++)
1565 for (bb = 0; bb < 32; bb++) {
1566 err = (rr << 3) | (rr >> 2);
1567 erg = (gg << 3) | (gg >> 2);
1568 erb = (bb << 3) | (bb >> 2);
1570 ccp->fast_dither->fast_rgb[rr][gg][bb] =
1571 gdk_color_context_get_index_from_palette(cc, &err, &erg, &erb, &success);
1572 ccp->fast_dither->fast_err[rr][gg][bb] = err;
1573 ccp->fast_dither->fast_erg[rr][gg][bb] = erg;
1574 ccp->fast_dither->fast_erb[rr][gg][bb] = erb;
1579 gdk_color_context_free_dither(GdkColorContext *cc)
1581 GdkColorContextPrivate *ccp;
1583 g_assert(cc != NULL);
1585 ccp = (GdkColorContextPrivate *) cc;
1587 if (ccp->fast_dither)
1588 g_free(ccp->fast_dither);
1590 ccp->fast_dither = NULL;
1594 gdk_color_context_get_pixel_from_palette(GdkColorContext *cc,
1600 GdkColorContextPrivate *ccp;
1602 gint dif, dr, dg, db, j = -1;
1603 gint mindif = 0x7fffffff;
1604 gint err = 0, erg = 0, erb = 0;
1607 g_assert(cc != NULL);
1608 g_assert(red != NULL);
1609 g_assert(green != NULL);
1610 g_assert(blue != NULL);
1611 g_assert(failed != NULL);
1613 ccp = (GdkColorContextPrivate *) cc;
1617 for (i = 0; i < ccp->num_palette; i++) {
1618 dr = *red - ccp->palette[i].red;
1619 dg = *green - ccp->palette[i].green;
1620 db = *blue - ccp->palette[i].blue;
1622 dif = dr * dr + dg * dg + db * db;
1627 pixel = ccp->palette[i].pixel;
1637 /* we failed to map onto a color */
1651 gdk_color_context_get_index_from_palette(GdkColorContext *cc,
1657 GdkColorContextPrivate *ccp;
1658 gint dif, dr, dg, db, j = -1;
1659 gint mindif = 0x7fffffff;
1660 gint err = 0, erg = 0, erb = 0;
1663 g_assert(cc != NULL);
1664 g_assert(red != NULL);
1665 g_assert(green != NULL);
1666 g_assert(blue != NULL);
1667 g_assert(failed != NULL);
1669 ccp = (GdkColorContextPrivate *) cc;
1673 for (i = 0; i < ccp->num_palette; i++) {
1674 dr = *red - ccp->palette[i].red;
1675 dg = *green - ccp->palette[i].green;
1676 db = *blue - ccp->palette[i].blue;
1678 dif = dr * dr + dg * dg + db * db;
1692 /* we failed to map onto a color */
1698 /* return error fractions */