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