]> Pileus Git - ~andy/gtk/blob - gdk/gdkcc.c
Try to guess if we can use the mb* functions safely. (For glibc, they do
[~andy/gtk] / gdk / gdkcc.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
17  */
18
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)
23  */
24
25 /* Copyright 1994,1995 John L. Cwikla
26  *
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.
37  *
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.
46  *
47  * Author:
48  *  John L. Cwikla
49  *  X Programmer
50  *  Wolfram Research Inc.
51  *
52  *  cwikla@wri.com
53  */
54
55
56 #include <X11/Xlib.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include "gdk.h"
60 #include "gdkprivate.h"
61 #include "gdkx.h"
62
63
64 #define MAX_IMAGE_COLORS 256
65
66
67 static guint
68 hash_color (gpointer key)
69 {
70   GdkColor *color = key;
71
72   return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
73 }
74
75 static gint
76 compare_colors (gpointer a,
77                 gpointer b)
78 {
79   GdkColor *aa = a;
80   GdkColor *bb = b;
81
82   return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
83 }
84
85 static void
86 free_hash_entry (gpointer key,
87                  gpointer value,
88                  gpointer user_data)
89 {
90   g_free (key); /* key and value are the same GdkColor */
91 }
92
93 static int
94 pixel_sort (const void *a, const void *b)
95 {
96   return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
97 }
98
99 /* XXX: This function does an XQueryColors() the hard way, because there is
100  * no corresponding function in Gdk.
101  */
102
103 static void
104 my_x_query_colors (GdkColormap *colormap,
105                    GdkColor    *colors,
106                    gint         ncolors)
107 {
108   XColor *xcolors;
109   gint    i;
110
111   xcolors = g_new (XColor, ncolors);
112   for (i = 0; i < ncolors; i++)
113     xcolors[i].pixel = colors[i].pixel;
114
115   XQueryColors (gdk_display, GDK_COLORMAP_XCOLORMAP (colormap), xcolors, ncolors);
116
117   for (i = 0; i < ncolors; i++)
118     {
119       colors[i].red   = xcolors[i].red;
120       colors[i].green = xcolors[i].green;
121       colors[i].blue  = xcolors[i].blue;
122     }
123
124   g_free (xcolors);
125 }
126
127 static void
128 query_colors (GdkColorContext *cc)
129 {
130   gint i;
131   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
132   cc->cmap = g_new (GdkColor, cc->num_colors);
133
134   for (i = 0; i < cc->num_colors; i++)
135     cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
136
137   my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors);
138         
139   qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort);
140 }
141
142 static void
143 init_bw (GdkColorContext *cc)
144 {
145   GdkColor color;
146
147   g_warning ("init_bw: failed to allocate colors, falling back to black and white");
148
149   cc->mode = GDK_CC_MODE_BW;
150
151   color.red = color.green = color.blue = 0;
152   
153   if (!gdk_color_alloc (cc->colormap, &color))
154     cc->black_pixel = 0;
155   else
156     cc->black_pixel = color.pixel;
157
158   color.red = color.green = color.blue = 0xffff;
159   
160   if (!gdk_color_alloc (cc->colormap, &color))
161     cc->white_pixel = cc->black_pixel ? 0 : 1;
162   else
163     cc->white_pixel = color.pixel;
164
165   cc->num_colors = 2;
166 }
167
168 static void
169 init_gray (GdkColorContext *cc)
170 {
171   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
172   GdkColor *clrs, *cstart;
173   gint i;
174   gdouble dinc;
175         
176   cc->num_colors = GDK_VISUAL_XVISUAL (cc->visual)->map_entries;
177
178   cc->clut = g_new (gulong, cc->num_colors);
179   cstart = g_new (GdkColor, cc->num_colors);
180
181 retrygray:
182
183   dinc = 65535.0 / (cc->num_colors - 1);
184
185   clrs = cstart;
186
187   for (i = 0; i < cc->num_colors; i++)
188     {
189       clrs->red = clrs->green = clrs->blue = dinc * i;
190
191       if (!gdk_color_alloc (cc->colormap, clrs))
192         {
193           gdk_colors_free (cc->colormap, cc->clut, i, 0);
194
195           cc->num_colors /= 2;
196
197           if (cc->num_colors > 1)
198             goto retrygray;
199           else
200             {
201               g_free (cc->clut);
202               cc->clut = NULL;
203               init_bw (cc);
204               g_free (cstart);
205               return;
206             }
207         }
208
209       cc->clut[i] = clrs++->pixel;
210     }
211
212   g_free (cstart);
213
214   /* XXX: is this the right thing to do? */
215   ccp->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP (cc->colormap);
216   ccp->std_cmap.base_pixel = 0;
217   ccp->std_cmap.red_max = cc->num_colors - 1;
218   ccp->std_cmap.green_max = 0;
219   ccp->std_cmap.blue_max = 0;
220   ccp->std_cmap.red_mult = 1;
221   ccp->std_cmap.green_mult = 0;
222   ccp->std_cmap.blue_mult = 0;
223
224   cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
225   cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
226
227   query_colors (cc);
228
229   cc->mode = GDK_CC_MODE_MY_GRAY;
230 }
231
232 static void
233 init_color (GdkColorContext *cc)
234 {
235   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
236   gint cubeval;
237
238   cubeval = 1;
239   while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL (cc->visual)->map_entries)
240     cubeval++;
241   cubeval--;
242
243   cc->num_colors = cubeval * cubeval * cubeval;
244
245   ccp->std_cmap.red_max    = cubeval - 1;
246   ccp->std_cmap.green_max  = cubeval - 1;
247   ccp->std_cmap.blue_max   = cubeval - 1;
248   ccp->std_cmap.red_mult   = cubeval * cubeval;
249   ccp->std_cmap.green_mult = cubeval;
250   ccp->std_cmap.blue_mult  = 1;
251   ccp->std_cmap.base_pixel = 0;
252
253   cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
254   cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
255   cc->num_colors = DisplayCells (ccp->xdisplay, gdk_screen);
256
257   /* a CLUT for storing allocated pixel indices */
258
259   cc->max_colors = cc->num_colors;
260   cc->clut = g_new (gulong, cc->max_colors);
261
262   for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
263     cc->clut[cubeval] = cubeval;
264
265   query_colors (cc);
266
267   cc->mode = GDK_CC_MODE_STD_CMAP;
268 }
269
270
271 static void
272 init_true_color (GdkColorContext *cc)
273 {
274   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
275   gulong rmask, gmask, bmask;
276
277   cc->mode = GDK_CC_MODE_TRUE;
278
279   /* Red */
280
281   rmask = cc->masks.red = cc->visual->red_mask;
282
283   cc->shifts.red = 0;
284   cc->bits.red = 0;
285
286   while (!(rmask & 1))
287     {
288       rmask >>= 1;
289       cc->shifts.red++;
290     }
291
292   while (rmask & 1)
293     {
294       rmask >>= 1;
295       cc->bits.red++;
296     }
297
298   /* Green */
299
300   gmask = cc->masks.green = cc->visual->green_mask;
301
302   cc->shifts.green = 0;
303   cc->bits.green = 0;
304
305   while (!(gmask & 1))
306     {
307       gmask >>= 1;
308       cc->shifts.green++;
309     }
310
311   while (gmask & 1)
312     {
313       gmask >>= 1;
314       cc->bits.green++;
315     }
316
317   /* Blue */
318
319   bmask = cc->masks.blue = cc->visual->blue_mask;
320
321   cc->shifts.blue = 0;
322   cc->bits.blue = 0;
323
324   while (!(bmask & 1))
325     {
326       bmask >>= 1;
327       cc->shifts.blue++;
328     }
329
330   while (bmask & 1)
331     {
332       bmask >>= 1;
333       cc->bits.blue++;
334     }
335
336   cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
337   cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
338   cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
339 }
340
341 static void
342 init_direct_color (GdkColorContext *cc)
343 {
344   gint n, count;
345   GdkColor *clrs, *cstart;
346   gulong rval, gval, bval;
347   gulong *rtable;
348   gulong *gtable;
349   gulong *btable;
350   gdouble dinc;
351
352   init_true_color (cc); /* for shift stuff */
353
354   rval = cc->visual->red_mask >> cc->shifts.red;
355   gval = cc->visual->green_mask >> cc->shifts.green;
356   bval = cc->visual->blue_mask >> cc->shifts.blue;
357
358   rtable = g_new (gulong, rval + 1);
359   gtable = g_new (gulong, gval + 1);
360   btable = g_new (gulong, bval + 1);
361
362   cc->max_entry = MAX (rval, gval);
363   cc->max_entry = MAX (cc->max_entry, bval);
364
365   cstart = g_new (GdkColor, cc->max_entry + 1);
366   cc->clut = g_new (gulong, cc->max_entry + 1);
367
368 retrydirect:
369
370   for (n = 0; n < rval; n++)
371     rtable[n] = rval ? (65535.0 / rval * n) : 0;
372
373   for (n = 0; n < gval; n++)
374     gtable[n] = gval ? (65535.0 / gval * n) : 0;
375
376   for (n = 0; n < bval; n++)
377     btable[n] = bval ? (65535.0 / bval * n) : 0;
378
379   cc->max_entry = MAX (rval, gval);
380   cc->max_entry = MAX (cc->max_entry, bval);
381
382   count = 0;
383   clrs = cstart;
384   cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
385
386   for (n = 0; n < cc->max_entry; n++)
387     {
388       dinc = (double) n / cc->max_entry;
389
390       clrs->red   = rtable[(int) (dinc * rval)];
391       clrs->green = gtable[(int) (dinc * gval)];
392       clrs->blue  = btable[(int) (dinc * bval)];
393
394       if (gdk_color_alloc (cc->colormap, clrs))
395         {
396           cc->clut[count++] = clrs->pixel;
397           clrs++;
398         }
399       else
400         {
401           gdk_colors_free (cc->colormap, cc->clut, count, 0);
402
403           rval >>= 1;
404           gval >>= 1;
405           bval >>= 1;
406
407           cc->masks.red   = (cc->masks.red >> 1) & cc->visual->red_mask;
408           cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
409           cc->masks.blue  = (cc->masks.blue >> 1) & cc->visual->blue_mask;
410
411           cc->shifts.red++;
412           cc->shifts.green++;
413           cc->shifts.blue++;
414
415           cc->bits.red--;
416           cc->bits.green--;
417           cc->bits.blue--;
418
419           cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
420
421           if (cc->num_colors >1)
422             goto retrydirect;
423           else
424             {
425               g_free (cc->clut);
426               cc->clut = NULL;
427               init_bw (cc);
428               break;
429             }
430         }
431     }
432
433   /* Update allocated color count; original num_colors is max_entry, which
434    * is not necessarily the same as the really allocated number of colors.
435    */
436
437   cc->num_colors = count;
438
439   g_free (rtable);
440   g_free (gtable);
441   g_free (btable);
442   g_free (cstart);
443 }
444
445 static void
446 init_palette (GdkColorContext *cc)
447 {
448   /* restore correct mode for this cc */
449         
450   switch (cc->visual->type)
451     {
452     case GDK_VISUAL_STATIC_GRAY:
453     case GDK_VISUAL_GRAYSCALE:
454       if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
455         cc->mode = GDK_CC_MODE_BW;
456       else
457         cc->mode = GDK_CC_MODE_MY_GRAY;
458       break;
459
460     case GDK_VISUAL_TRUE_COLOR:
461     case GDK_VISUAL_DIRECT_COLOR:
462       cc->mode = GDK_CC_MODE_TRUE;
463       break;
464
465     case GDK_VISUAL_STATIC_COLOR:
466     case GDK_VISUAL_PSEUDO_COLOR:
467       cc->mode = GDK_CC_MODE_STD_CMAP;
468       break;
469
470     default:
471       cc->mode = GDK_CC_MODE_UNDEFINED;
472       break;
473     }
474
475   /* previous palette */
476
477   if (cc->num_palette)
478     g_free (cc->palette);
479
480   if (cc->fast_dither)
481     g_free (cc->fast_dither);
482
483   /* clear hash table if present */
484
485   if (cc->color_hash)
486     {
487       /* XXX: quick-and-dirty way to remove everything */
488
489       g_hash_table_destroy (cc->color_hash);
490       cc->color_hash = g_hash_table_new (hash_color, compare_colors);
491     }
492
493   cc->palette = NULL;
494   cc->num_palette = 0;
495   cc->fast_dither = NULL;
496 }
497
498 GdkColorContext *
499 gdk_color_context_new (GdkVisual   *visual,
500                        GdkColormap *colormap)
501 {
502   GdkColorContextPrivate *ccp;
503   gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
504   GdkColorContext *cc;
505   gint retry_count;
506   GdkColormap *default_colormap;
507
508   g_assert (visual != NULL);
509   g_assert (colormap != NULL);
510
511   ccp = g_new (GdkColorContextPrivate, 1);
512   cc = (GdkColorContext *) ccp;
513   ccp->xdisplay = gdk_display;
514   cc->visual = visual;
515   cc->colormap = colormap;
516   cc->clut = NULL;
517   cc->cmap = NULL;
518   cc->mode = GDK_CC_MODE_UNDEFINED;
519   cc->need_to_free_colormap = FALSE;
520
521   cc->color_hash = NULL;
522   cc->palette = NULL;
523   cc->num_palette = 0;
524   cc->fast_dither = NULL;
525
526   default_colormap = gdk_colormap_get_system ();
527
528   retry_count = 0;
529
530   while (retry_count < 2)
531     {
532       /* Only create a private colormap if the visual found isn't equal
533        * to the default visual and we don't have a private colormap,
534        * -or- if we are instructed to create a private colormap (which
535        * never is the case for XmHTML).
536        */
537
538       if (use_private_colormap
539           || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
540               && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
541         {
542           g_warning ("gdk_color_context_new: non-default visual detected, "
543                      "using private colormap");
544
545           cc->colormap = gdk_colormap_new (cc->visual, FALSE);
546
547           cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
548                                        != GDK_COLORMAP_XCOLORMAP (default_colormap));
549         }
550
551       switch (visual->type)
552         {
553         case GDK_VISUAL_STATIC_GRAY:
554         case GDK_VISUAL_GRAYSCALE:
555           GDK_NOTE (COLOR_CONTEXT,
556             g_print ("gdk_color_context_new: visual class is %s\n",
557                      (visual->type == GDK_VISUAL_STATIC_GRAY) ?
558                      "GDK_VISUAL_STATIC_GRAY" :
559                      "GDK_VISUAL_GRAYSCALE"));
560
561           if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
562             init_bw (cc);
563           else
564             init_gray (cc);
565
566           break;
567
568         case GDK_VISUAL_TRUE_COLOR: /* shifts */
569           GDK_NOTE (COLOR_CONTEXT,
570             g_print ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
571
572           init_true_color (cc);
573           break;
574
575         case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
576           GDK_NOTE (COLOR_CONTEXT,
577             g_print ("gdk_color_context_new: visual class is GDK_VISUAL_DIRECT_COLOR\n"));
578
579           init_direct_color (cc);
580           break;
581
582         case GDK_VISUAL_STATIC_COLOR:
583         case GDK_VISUAL_PSEUDO_COLOR:
584           GDK_NOTE (COLOR_CONTEXT,
585             g_print ("gdk_color_context_new: visual class is %s\n",
586                      (visual->type == GDK_VISUAL_STATIC_COLOR) ?
587                      "GDK_VISUAL_STATIC_COLOR" :
588                      "GDK_VISUAL_PSEUDO_COLOR"));
589
590           init_color (cc);
591           break;
592
593         default:
594           g_assert_not_reached ();
595         }
596
597       if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
598         {
599           use_private_colormap = TRUE;
600           retry_count++;
601         }
602       else
603         break;
604     }
605
606   /* no. of colors allocated yet */
607
608   cc->num_allocated = 0;
609
610   GDK_NOTE (COLOR_CONTEXT,
611     g_print ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
612              cc->visual->depth, cc->num_colors));
613
614   /* check if we need to initialize a hash table */
615
616   if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
617     cc->color_hash = g_hash_table_new (hash_color, compare_colors);
618
619   return (GdkColorContext *) cc;
620 }
621
622 GdkColorContext *
623 gdk_color_context_new_mono (GdkVisual   *visual,
624                             GdkColormap *colormap)
625 {
626   GdkColorContextPrivate *ccp;
627   GdkColorContext *cc;
628
629   g_assert (visual != NULL);
630   g_assert (colormap != NULL);
631
632   cc = g_new (GdkColorContext, 1);
633   ccp = (GdkColorContextPrivate *) cc;
634   ccp->xdisplay = gdk_display;
635   cc->visual = visual;
636   cc->colormap = colormap;
637   cc->clut = NULL;
638   cc->cmap = NULL;
639   cc->mode = GDK_CC_MODE_UNDEFINED;
640   cc->need_to_free_colormap = FALSE;
641
642   init_bw (cc);
643
644   return (GdkColorContext *) cc;
645 }
646
647 /* This doesn't currently free black/white, hmm... */
648
649 void
650 gdk_color_context_free (GdkColorContext *cc)
651 {
652   g_assert (cc != NULL);
653
654   if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
655       || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
656     {
657       gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
658       g_free (cc->clut);
659     }
660   else if (cc->clut != NULL)
661     {
662       gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
663       g_free (cc->clut);
664     }
665
666   if (cc->cmap != NULL)
667     g_free (cc->cmap);
668
669   if (cc->need_to_free_colormap)
670     gdk_colormap_unref (cc->colormap);
671
672   /* free any palette that has been associated with this GdkColorContext */
673
674   init_palette (cc);
675
676   if (cc->color_hash)
677     {
678       g_hash_table_foreach (cc->color_hash,
679                             free_hash_entry,
680                             NULL);
681       g_hash_table_destroy (cc->color_hash);
682     }
683
684   g_free (cc);
685 }
686
687 gulong
688 gdk_color_context_get_pixel (GdkColorContext *cc,
689                              gushort          red,
690                              gushort          green,
691                              gushort          blue,
692                              gint            *failed)
693 {
694   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
695   g_assert (cc != NULL);
696   g_assert (failed != NULL);
697
698   *failed = FALSE;
699
700   switch (cc->mode)
701     {
702     case GDK_CC_MODE_BW:
703       {
704         gdouble value;
705
706         value = (red / 65535.0 * 0.30
707                  + green / 65535.0 * 0.59
708                  + blue / 65535.0 * 0.11);
709
710         if (value > 0.5)
711           return cc->white_pixel;
712
713         return cc->black_pixel;
714       }
715
716     case GDK_CC_MODE_MY_GRAY:
717       {
718         gulong ired, igreen, iblue;
719
720         red   = red * 0.30 + green * 0.59 + blue * 0.11;
721         green = 0;
722         blue  = 0;
723
724         if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
725           ired = ccp->std_cmap.red_max;
726
727         ired *= ccp->std_cmap.red_mult;
728
729         if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
730           igreen = ccp->std_cmap.green_max;
731
732         igreen *= ccp->std_cmap.green_mult;
733
734         if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
735           iblue = ccp->std_cmap.blue_max;
736
737         iblue *= ccp->std_cmap.blue_mult;
738
739         if (cc->clut != NULL)
740           return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
741
742         return ccp->std_cmap.base_pixel + ired + igreen + iblue;
743       }
744
745     case GDK_CC_MODE_TRUE:
746       {
747         gulong ired, igreen, iblue;
748
749         if (cc->clut == NULL)
750           {
751             red   >>= 16 - cc->bits.red;
752             green >>= 16 - cc->bits.green;
753             blue  >>= 16 - cc->bits.blue;
754
755             ired   = (red << cc->shifts.red) & cc->masks.red;
756             igreen = (green << cc->shifts.green) & cc->masks.green;
757             iblue  = (blue << cc->shifts.blue) & cc->masks.blue;
758
759             return ired | igreen | iblue;
760           }
761
762         ired   = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
763         igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
764         iblue  = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
765
766         return ired | igreen | iblue;
767       }
768
769     case GDK_CC_MODE_PALETTE:
770       return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
771
772     case GDK_CC_MODE_STD_CMAP:
773     default:
774       {
775         GdkColor color;
776         GdkColor *result;
777
778         color.red   = red;
779         color.green = green;
780         color.blue  = blue;
781
782         result = g_hash_table_lookup (cc->color_hash, &color);
783
784         if (!result)
785           {
786             color.red   = red;
787             color.green = green;
788             color.blue  = blue;
789             color.pixel = 0;
790
791             if (!gdk_color_alloc (cc->colormap, &color))
792               *failed = TRUE;
793             else
794               {
795                 GdkColor *cnew;
796                                         
797                 /* XXX: the following comment comes directly from
798                  * XCC.c.  I don't know if it is relevant for
799                  * gdk_color_alloc() as it is for XAllocColor()
800                  * - Federico
801                  */
802                 /*
803                  * I can't figure this out entirely, but it *is* possible
804                  * that XAllocColor succeeds, even if the number of
805                  * allocations we've made exceeds the number of available
806                  * colors in the current colormap. And therefore it
807                  * might be necessary for us to resize the CLUT.
808                  */
809
810                 if (cc->num_allocated == cc->max_colors)
811                   {
812                     cc->max_colors *= 2;
813
814                     GDK_NOTE (COLOR_CONTEXT,
815                       g_print ("gdk_color_context_get_pixel: "
816                                "resizing CLUT to %i entries\n",
817                                cc->max_colors));
818
819                     cc->clut = g_realloc (cc->clut,
820                                           cc->max_colors * sizeof (gulong));
821                   }
822
823                 /* Key and value are the same color structure */
824
825                 cnew = g_new (GdkColor, 1);
826                 *cnew = color;
827                 g_hash_table_insert (cc->color_hash, cnew, cnew);
828
829                 cc->clut[cc->num_allocated] = color.pixel;
830                 cc->num_allocated++;
831                 return color.pixel;
832               }
833           }
834                         
835         return result->pixel;
836       }
837     }
838 }
839
840 void
841 gdk_color_context_get_pixels (GdkColorContext *cc,
842                               gushort         *reds,
843                               gushort         *greens,
844                               gushort         *blues,
845                               gint             ncolors,
846                               gulong          *colors,
847                               gint            *nallocated)
848 {
849   gint i, k, idx;
850   gint cmapsize, ncols = 0, nopen = 0, counter = 0;
851   gint bad_alloc = FALSE;
852   gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
853   GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
854 #ifdef G_ENABLE_DEBUG  
855   gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
856 #endif
857   g_assert (cc != NULL);
858   g_assert (reds != NULL);
859   g_assert (greens != NULL);
860   g_assert (blues != NULL);
861   g_assert (colors != NULL);
862   g_assert (nallocated != NULL);
863
864   memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
865   memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
866   memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
867
868   /* Will only have a value if used by the progressive image loader */
869
870   ncols = *nallocated;
871
872   *nallocated = 0;
873
874   /* First allocate all pixels */
875
876   for (i = 0; i < ncolors; i++)
877     {
878       /* colors[i] is only zero if the pixel at that location hasn't
879        * been allocated yet.  This is a sanity check required for proper
880        * color allocation by the progressive image loader
881        */
882
883       if (colors[i] == 0)
884         {
885           defs[i].red   = reds[i];
886           defs[i].green = greens[i];
887           defs[i].blue  = blues[i];
888
889           colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
890                                                    &bad_alloc);
891
892           /* successfully allocated, store it */
893
894           if (!bad_alloc)
895             {
896               defs[i].pixel = colors[i];
897               allocated[ncols++] = colors[i];
898             }
899           else
900             failed[nopen++] = i;
901         }
902     }
903
904   *nallocated = ncols;
905
906   /* all colors available, all done */
907
908   if ((ncols == ncolors) || (nopen == 0))
909     {
910       GDK_NOTE (COLOR_CONTEXT,
911         g_print ("gdk_color_context_get_pixels: got all %i colors; "
912                  "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
913
914       return;
915     }
916
917   /* The fun part.  We now try to allocate the colors we couldn't allocate
918    * directly.  The first step will map a color onto its nearest color
919    * that has been allocated (either by us or someone else).  If any colors
920    * remain unallocated, we map these onto the colors that we have allocated
921    * ourselves.
922    */
923
924   /* read up to MAX_IMAGE_COLORS colors of the current colormap */
925
926   cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
927
928   /* see if the colormap has any colors to read */
929
930   if (cmapsize < 0)
931     {
932       g_warning ("gdk_color_context_get_pixels: oops!  no colors available, "
933                  "your images will look *really* ugly.");
934
935       return;
936     }
937
938 #ifdef G_ENABLE_DEBUG
939   exact_col = ncols;
940 #endif
941
942   /* initialize pixels */
943
944   for (i = 0; i < cmapsize; i++)
945     {
946       cmap[i].pixel = i;
947       cmap[i].red = cmap[i].green = cmap[i].blue = 0;
948     }
949
950   /* read the colormap */
951
952   my_x_query_colors (cc->colormap, cmap, cmapsize);
953
954   /* get a close match for any unallocated colors */
955
956   counter = nopen;
957   nopen = 0;
958   idx = 0;
959
960   do
961     {
962       gint d, j, mdist, close, ri, gi, bi;
963       gint rd, gd, bd;
964
965       i = failed[idx];
966
967       mdist = 0x1000000;
968       close = -1;
969
970       /* Store these vals.  Small performance increase as this skips three
971        * indexing operations in the loop code.
972        */
973
974       ri = reds[i];
975       gi = greens[i];
976       bi = blues[i];
977
978       /* Walk all colors in the colormap and see which one is the
979        * closest.  Uses plain least squares.
980        */
981
982       for (j = 0; (j < cmapsize) && (mdist != 0); j++)
983         {
984           /* Don't replace these by shifts; the sign may get clobbered */
985
986           rd = (ri - cmap[j].red) / 256;
987           gd = (gi - cmap[j].green) / 256;
988           bd = (bi - cmap[j].blue) / 256;
989
990           d = rd * rd + gd * gd + bd * bd;
991
992           if (d < mdist)
993             {
994               close = j;
995               mdist = d;
996             }
997         }
998
999       if (close != -1)
1000         {
1001           rd = cmap[close].red;
1002           gd = cmap[close].green;
1003           bd = cmap[close].blue;
1004
1005           /* allocate */
1006
1007           colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1008
1009           /* store */
1010
1011           if (!bad_alloc)
1012             {
1013               defs[i] = cmap[close];
1014               defs[i].pixel = colors[i];
1015               allocated[ncols++] = colors[i];
1016 #ifdef G_ENABLE_DEBUG
1017               close_col++;
1018 #endif
1019             } else
1020               failed[nopen++] = i;
1021         } else
1022           failed[nopen++] = i;
1023       /* deal with in next stage if allocation failed */
1024     }
1025   while (++idx < counter);
1026
1027   *nallocated = ncols;
1028
1029   /* This is the maximum no. of allocated colors.  See also the nopen == 0
1030    * note above.
1031    */
1032
1033   if ((ncols == ncolors) || (nopen == 0))
1034     {
1035       GDK_NOTE (COLOR_CONTEXT,
1036         g_print ("gdk_color_context_get_pixels: got %i colors, %i exact and "
1037                  "%i close (%i colors allocated so far)\n",
1038                  ncolors, exact_col, close_col, cc->num_allocated));
1039
1040       return;
1041     }
1042
1043   /* Now map any remaining unallocated pixels into the colors we did get */
1044
1045   idx = 0;
1046
1047   do
1048     {
1049       gint d, mdist, close, ri, gi, bi;
1050       gint j, rd, gd, bd;
1051
1052       i = failed[idx];
1053
1054       mdist = 0x1000000;
1055       close = -1;
1056
1057       /* store */
1058
1059       ri = reds[i];
1060       gi = greens[i];
1061       bi = blues[i];
1062
1063       /* search allocated colors */
1064
1065       for (j = 0; (j < ncols) && (mdist != 0); j++)
1066         {
1067           k = allocated[j];
1068
1069           /* Don't replace these by shifts; the sign may get clobbered */
1070
1071           rd = (ri - defs[k].red) / 256;
1072           gd = (gi - defs[k].green) / 256;
1073           bd = (bi - defs[k].blue) / 256;
1074
1075           d = rd * rd + gd * gd + bd * bd;
1076
1077           if (d < mdist)
1078             {
1079               close = k;
1080               mdist = d;
1081             }
1082         }
1083
1084       if (close < 0)
1085         {
1086           /* too bad, map to black */
1087
1088           defs[i].pixel = cc->black_pixel;
1089           defs[i].red = defs[i].green = defs[i].blue = 0;
1090 #ifdef G_ENABLE_DEBUG
1091           black_col++;
1092 #endif
1093         }
1094       else
1095         {
1096           defs[i] = defs[close];
1097 #ifdef G_ENABLE_DEBUG
1098           subst_col++;
1099 #endif
1100         }
1101
1102       colors[i] = defs[i].pixel;
1103     }
1104   while (++idx < nopen);
1105
1106   GDK_NOTE (COLOR_CONTEXT,
1107     g_print ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
1108              "%i substituted, %i to black (%i colors allocated so far)\n",
1109              ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1110 }
1111
1112 void
1113 gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
1114                                           gushort         *reds,
1115                                           gushort         *greens,
1116                                           gushort         *blues,
1117                                           gint             ncolors,
1118                                           gint            *used,
1119                                           gulong          *colors,
1120                                           gint            *nallocated)
1121 {
1122   gint i, k, idx;
1123   gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1124   gint bad_alloc = FALSE;
1125   gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1126   GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1127 #ifdef G_ENABLE_DEBUG  
1128   gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1129 #endif  
1130
1131   g_assert (cc != NULL);
1132   g_assert (reds != NULL);
1133   g_assert (greens != NULL);
1134   g_assert (blues != NULL);
1135   g_assert (used != NULL);
1136   g_assert (colors != NULL);
1137   g_assert (nallocated != NULL);
1138
1139   memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
1140   memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
1141   memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
1142
1143   /* Will only have a value if used by the progressive image loader */
1144
1145   ncols = *nallocated;
1146
1147   *nallocated = 0;
1148
1149   /* First allocate all pixels */
1150
1151   for (i = 0; i < ncolors; i++)
1152     {
1153       /* used[i] is only -1 if the pixel at that location hasn't
1154        * been allocated yet.  This is a sanity check required for proper
1155        * color allocation by the progressive image loader.
1156        * When colors[i] == 0 it indicates the slot is available for
1157        * allocation.
1158        */
1159
1160       if (used[i] != FALSE)
1161         {
1162           if (colors[i] == 0)
1163             {
1164               defs[i].red   = reds[i];
1165               defs[i].green = greens[i];
1166               defs[i].blue  = blues[i];
1167
1168               colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
1169
1170               /* successfully allocated, store it */
1171
1172               if (!bad_alloc)
1173                 {
1174                   defs[i].pixel = colors[i];
1175                   allocated[ncols++] = colors[i];
1176                 }
1177               else
1178                 failed[nopen++] = i;
1179             }
1180 #ifdef DEBUG
1181           else
1182             GDK_NOTE (COLOR_CONTEXT,
1183               g_print ("gdk_color_context_get_pixels_incremental: "
1184                        "pixel at slot %i already allocated, skipping\n", i));
1185 #endif
1186         }
1187     }
1188
1189   *nallocated = ncols;
1190
1191   if ((ncols == ncolors) || (nopen == 0))
1192     {
1193       GDK_NOTE (COLOR_CONTEXT,
1194         g_print ("gdk_color_context_get_pixels_incremental: got all %i colors "
1195                  "(%i colors allocated so far)\n",
1196                  ncolors, cc->num_allocated));
1197
1198       return;
1199     }
1200
1201   cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
1202
1203   if (cmapsize < 0)
1204     {
1205       g_warning ("gdk_color_context_get_pixels_incremental: oops!  "
1206                  "No colors available images will look *really* ugly.");
1207       return;
1208     }
1209
1210 #ifdef G_ENABLE_DEBUG
1211   exact_col = ncols;
1212 #endif
1213
1214   /* initialize pixels */
1215
1216   for (i = 0; i < cmapsize; i++)
1217     {
1218       cmap[i].pixel = i;
1219       cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1220     }
1221
1222   /* read */
1223
1224   my_x_query_colors (cc->colormap, cmap, cmapsize);
1225
1226   /* now match any unallocated colors */
1227
1228   counter = nopen;
1229   nopen = 0;
1230   idx = 0;
1231
1232   do
1233     {
1234       gint d, j, mdist, close, ri, gi, bi;
1235       gint rd, gd, bd;
1236
1237       i = failed[idx];
1238
1239       mdist = 0x1000000;
1240       close = -1;
1241
1242       /* store */
1243
1244       ri = reds[i];
1245       gi = greens[i];
1246       bi = blues[i];
1247
1248       for (j = 0; (j < cmapsize) && (mdist != 0); j++)
1249         {
1250           /* Don't replace these by shifts; the sign may get clobbered */
1251
1252           rd = (ri - cmap[j].red) / 256;
1253           gd = (gi - cmap[j].green) / 256;
1254           bd = (bi - cmap[j].blue) / 256;
1255
1256           d = rd * rd + gd * gd + bd * bd;
1257
1258           if (d < mdist)
1259             {
1260               close = j;
1261               mdist = d;
1262             }
1263         }
1264
1265       if (close != -1)
1266         {
1267           rd = cmap[close].red;
1268           gd = cmap[close].green;
1269           bd = cmap[close].blue;
1270
1271           /* allocate */
1272
1273           colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1274
1275           /* store */
1276
1277           if (!bad_alloc)
1278             {
1279               defs[i] = cmap[close];
1280               defs[i].pixel = colors[i];
1281               allocated[ncols++] = colors[i];
1282 #ifdef G_ENABLE_DEBUG
1283               close_col++;
1284 #endif
1285             }
1286           else
1287             failed[nopen++] = i;
1288         }
1289       else
1290         failed[nopen++] = i;
1291       /* deal with in next stage if allocation failed */
1292     }
1293   while (++idx < counter);
1294
1295   *nallocated = ncols;
1296
1297   if ((ncols == ncolors) || (nopen == 0))
1298     {
1299       GDK_NOTE (COLOR_CONTEXT,
1300         g_print ("gdk_color_context_get_pixels_incremental: "
1301                  "got %i colors, %i exact and %i close "
1302                  "(%i colors allocated so far)\n",
1303                  ncolors, exact_col, close_col, cc->num_allocated));
1304
1305       return;
1306     }
1307
1308   /* map remaining unallocated pixels into colors we did get */
1309
1310   idx = 0;
1311
1312   do
1313     {
1314       gint d, mdist, close, ri, gi, bi;
1315       gint j, rd, gd, bd;
1316
1317       i = failed[idx];
1318
1319       mdist = 0x1000000;
1320       close = -1;
1321
1322       ri = reds[i];
1323       gi = greens[i];
1324       bi = blues[i];
1325
1326       /* search allocated colors */
1327
1328       for (j = 0; (j < ncols) && (mdist != 0); j++)
1329         {
1330           k = allocated[j];
1331
1332           /* downscale */
1333           /* Don't replace these by shifts; the sign may get clobbered */
1334
1335           rd = (ri - defs[k].red) / 256;
1336           gd = (gi - defs[k].green) / 256;
1337           bd = (bi - defs[k].blue) / 256;
1338
1339           d = rd * rd + gd * gd + bd * bd;
1340
1341           if (d < mdist)
1342             {
1343               close = k;
1344               mdist = d;
1345             }
1346         }
1347
1348       if (close < 0)
1349         {
1350           /* too bad, map to black */
1351
1352           defs[i].pixel = cc->black_pixel;
1353           defs[i].red = defs[i].green = defs[i].blue = 0;
1354 #ifdef G_ENABLE_DEBUG
1355           black_col++;
1356 #endif
1357         }
1358       else
1359         {
1360           defs[i] = defs[close];
1361 #ifdef G_ENABLE_DEBUG
1362           subst_col++;
1363 #endif
1364         }
1365
1366       colors[i] = defs[i].pixel;
1367     }
1368   while (++idx < nopen);
1369
1370   GDK_NOTE (COLOR_CONTEXT,
1371     g_print ("gdk_color_context_get_pixels_incremental: "
1372              "got %i colors, %i exact, %i close, %i substituted, %i to black "
1373              "(%i colors allocated so far)\n",
1374              ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1375 }
1376
1377 gint
1378 gdk_color_context_query_color (GdkColorContext *cc,
1379                                GdkColor        *color)
1380 {
1381   return gdk_color_context_query_colors (cc, color, 1);
1382 }
1383
1384 gint
1385 gdk_color_context_query_colors (GdkColorContext *cc,
1386                                 GdkColor        *colors,
1387                                 gint             num_colors)
1388 {
1389   gint i;
1390   GdkColor *tc;
1391         
1392   g_assert (cc != NULL);
1393   g_assert (colors != NULL);
1394
1395   switch (cc->mode)
1396     {
1397     case GDK_CC_MODE_BW:
1398       for (i = 0, tc = colors; i < num_colors; i++, tc++)
1399         {
1400           if (tc->pixel == cc->white_pixel)
1401             tc->red = tc->green = tc->blue = 65535;
1402           else
1403             tc->red = tc->green = tc->blue = 0;
1404         }
1405       break;
1406
1407     case GDK_CC_MODE_TRUE:
1408       if (cc->clut == NULL)
1409         for (i = 0, tc = colors; i < num_colors; i++, tc++)
1410           {
1411             tc->red   = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
1412             tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
1413             tc->blue  = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
1414           }
1415       else
1416         {
1417           my_x_query_colors (cc->colormap, colors, num_colors);
1418           return 1;
1419         }
1420       break;
1421
1422     case GDK_CC_MODE_STD_CMAP:
1423     default:
1424       if (cc->cmap == NULL)
1425         {
1426           my_x_query_colors (cc->colormap, colors, num_colors);
1427           return 1;
1428         }
1429       else
1430         {
1431           gint first, last, half;
1432           gulong half_pixel;
1433
1434           for (i = 0, tc = colors; i < num_colors; i++)
1435             {
1436               first = 0;
1437               last = cc->num_colors - 1;
1438
1439               while (first <= last)
1440                 {
1441                   half = (first + last) / 2;
1442                   half_pixel = cc->cmap[half].pixel;
1443
1444                   if (tc->pixel == half_pixel)
1445                     {
1446                       tc->red   = cc->cmap[half].red;
1447                       tc->green = cc->cmap[half].green;
1448                       tc->blue  = cc->cmap[half].blue;
1449                       first = last + 1; /* false break */
1450                     }
1451                   else
1452                     {
1453                       if (tc->pixel > half_pixel)
1454                         first = half + 1;
1455                       else
1456                         last = half - 1;
1457                     }
1458                 }
1459             }
1460           return 1;
1461         }
1462       break;
1463     }
1464   return 1;
1465 }
1466
1467 gint
1468 gdk_color_context_add_palette (GdkColorContext *cc,
1469                                GdkColor        *palette,
1470                                gint             num_palette)
1471 {
1472   gint i, j, erg;
1473   gushort r, g, b;
1474   gulong pixel[1];
1475
1476   g_assert (cc != NULL);
1477
1478   /* initialize this palette (will also erase previous palette as well) */
1479
1480   init_palette (cc);
1481
1482   /* restore previous mode if we aren't adding a new palette */
1483
1484   if (num_palette == 0)
1485     {
1486       /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
1487
1488       /* XXX: here, the hash table is already initialized */
1489
1490       return 0;
1491     }
1492
1493   /* Initialize a hash table for this palette (we need one for allocating
1494    * the pixels in the palette using the current settings)
1495    */
1496
1497   if (cc->color_hash == NULL)
1498     cc->color_hash = g_hash_table_new (hash_color, compare_colors);
1499
1500   /* copy incoming palette */
1501
1502   cc->palette = g_new0(GdkColor, num_palette);
1503
1504   j = 0;
1505
1506   for (i = 0; i < num_palette; i++)
1507     {
1508       erg = 0;
1509       pixel[0] = 0;
1510
1511       /* try to allocate this color */
1512
1513       r = palette[i].red;
1514       g = palette[i].green;
1515       b = palette[i].blue;
1516
1517       gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
1518
1519       /* only store if we succeed */
1520
1521       if (erg)
1522         {
1523           /* store in palette */
1524
1525           cc->palette[j].red   = r;
1526           cc->palette[j].green = g;
1527           cc->palette[j].blue  = b;
1528           cc->palette[j].pixel = pixel[0];
1529
1530           /* move to next slot */
1531
1532           j++;
1533         }
1534     }
1535
1536   /* resize to fit */
1537
1538   if (j != num_palette)
1539     cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
1540
1541   /* clear the hash table, we don't use it when dithering */
1542
1543   if (cc->color_hash)
1544     {
1545       g_hash_table_destroy (cc->color_hash);
1546       cc->color_hash = NULL;
1547     }
1548
1549   /* store real palette size */
1550
1551   cc->num_palette = j;
1552
1553   /* switch to palette mode */
1554
1555   cc->mode = GDK_CC_MODE_PALETTE;
1556
1557   /* sort palette */
1558
1559   qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
1560
1561   cc->fast_dither = NULL;
1562
1563   return j;
1564 }
1565
1566 void
1567 gdk_color_context_init_dither (GdkColorContext *cc)
1568 {
1569   gint rr, gg, bb, err, erg, erb;
1570   gint success = FALSE;
1571
1572   g_assert (cc != NULL);
1573
1574   /* now we can initialize the fast dither matrix */
1575
1576   if (cc->fast_dither == NULL)
1577     cc->fast_dither = g_new (GdkColorContextDither, 1);
1578
1579   /* Fill it.  We ignore unsuccessful allocations, they are just mapped
1580    * to black instead */
1581
1582   for (rr = 0; rr < 32; rr++)
1583     for (gg = 0; gg < 32; gg++)
1584       for (bb = 0; bb < 32; bb++)
1585         {
1586           err = (rr << 3) | (rr >> 2);
1587           erg = (gg << 3) | (gg >> 2);
1588           erb = (bb << 3) | (bb >> 2);
1589
1590           cc->fast_dither->fast_rgb[rr][gg][bb] =
1591             gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
1592           cc->fast_dither->fast_err[rr][gg][bb] = err;
1593           cc->fast_dither->fast_erg[rr][gg][bb] = erg;
1594           cc->fast_dither->fast_erb[rr][gg][bb] = erb;
1595         }
1596 }
1597
1598 void
1599 gdk_color_context_free_dither (GdkColorContext *cc)
1600 {
1601   g_assert (cc != NULL);
1602
1603   if (cc->fast_dither)
1604     g_free (cc->fast_dither);
1605
1606   cc->fast_dither = NULL;
1607 }
1608
1609 gulong
1610 gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
1611                                           gushort         *red,
1612                                           gushort         *green,
1613                                           gushort         *blue,
1614                                           gint            *failed)
1615 {
1616   gulong pixel = 0;
1617   gint dif, dr, dg, db, j = -1;
1618   gint mindif = 0x7fffffff;
1619   gint err = 0, erg = 0, erb = 0;
1620   gint i;
1621
1622   g_assert (cc != NULL);
1623   g_assert (red != NULL);
1624   g_assert (green != NULL);
1625   g_assert (blue != NULL);
1626   g_assert (failed != NULL);
1627
1628   *failed = FALSE;
1629
1630   for (i = 0; i < cc->num_palette; i++)
1631     {
1632       dr = *red - cc->palette[i].red;
1633       dg = *green - cc->palette[i].green;
1634       db = *blue - cc->palette[i].blue;
1635
1636       dif = dr * dr + dg * dg + db * db;
1637                 
1638       if (dif < mindif)
1639         {
1640           mindif = dif;
1641           j = i;
1642           pixel = cc->palette[i].pixel;
1643           err = dr;
1644           erg = dg;
1645           erb = db;
1646
1647           if (mindif == 0)
1648             break;
1649         }
1650     }
1651
1652   /* we failed to map onto a color */
1653
1654   if (j == -1)
1655     *failed = TRUE;
1656   else
1657     {
1658       *red   = ABS (err);
1659       *green = ABS (erg);
1660       *blue  = ABS (erb);
1661     }
1662
1663   return pixel;
1664 }
1665
1666 guchar
1667 gdk_color_context_get_index_from_palette (GdkColorContext *cc,
1668                                           gint            *red,
1669                                           gint            *green,
1670                                           gint            *blue,
1671                                           gint            *failed)
1672 {
1673   gint dif, dr, dg, db, j = -1;
1674   gint mindif = 0x7fffffff;
1675   gint err = 0, erg = 0, erb = 0;
1676   gint i;
1677
1678   g_assert (cc != NULL);
1679   g_assert (red != NULL);
1680   g_assert (green != NULL);
1681   g_assert (blue != NULL);
1682   g_assert (failed != NULL);
1683
1684   *failed = FALSE;
1685
1686   for (i = 0; i < cc->num_palette; i++)
1687     {
1688       dr = *red - cc->palette[i].red;
1689       dg = *green - cc->palette[i].green;
1690       db = *blue - cc->palette[i].blue;
1691
1692       dif = dr * dr + dg * dg + db * db;
1693
1694       if (dif < mindif)
1695         {
1696           mindif = dif;
1697           j = i;
1698           err = dr;
1699           erg = dg;
1700           erb = db;
1701
1702           if (mindif == 0)
1703             break;
1704         }
1705     }
1706
1707   /* we failed to map onto a color */
1708
1709   if (j == -1)
1710     {
1711       *failed = TRUE;
1712       j = 0;
1713     }
1714   else
1715     {
1716       /* return error fractions */
1717
1718       *red   = err;
1719       *green = erg;
1720       *blue  = erb;
1721     }
1722
1723   return j;
1724 }