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