source: trunk/third/gtk/gdk/gdkcc.c @ 14482

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