Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* Cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2008 Red Hat, Inc.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it either under the terms of the GNU Lesser General Public
  7.  * License version 2.1 as published by the Free Software Foundation
  8.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  9.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  10.  * notice, a recipient may use your version of this file under either
  11.  * the MPL or the LGPL.
  12.  *
  13.  * You should have received a copy of the LGPL along with this library
  14.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  15.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  16.  * You should have received a copy of the MPL along with this library
  17.  * in the file COPYING-MPL-1.1
  18.  *
  19.  * The contents of this file are subject to the Mozilla Public License
  20.  * Version 1.1 (the "License"); you may not use this file except in
  21.  * compliance with the License. You may obtain a copy of the License at
  22.  * http://www.mozilla.org/MPL/
  23.  *
  24.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  25.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  26.  * the specific language governing rights and limitations.
  27.  *
  28.  * The Original Code is the cairo graphics library.
  29.  *
  30.  * The Initial Developer of the Original Code is Red Hat, Inc.
  31.  *
  32.  * Contributor(s):
  33.  *      Carl D. Worth <cworth@cworth.org>
  34.  */
  35.  
  36. #include "cairoint.h"
  37.  
  38. #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
  39.  
  40. #include "cairo-xlib-private.h"
  41.  
  42. #include "cairo-error-private.h"
  43. #include "cairo-list-inline.h"
  44.  
  45. /* A perceptual distance metric between two colors. No sqrt needed
  46.  * since the square of the distance is still a valid metric. */
  47.  
  48. /* XXX: This is currently using linear distance in RGB space which is
  49.  * decidedly not perceptually linear. If someone cared a lot about the
  50.  * quality, they might choose something else here. Then again, they
  51.  * might also choose not to use a PseudoColor visual... */
  52. static inline int
  53. _color_distance (unsigned short r1, unsigned short g1, unsigned short b1,
  54.                  unsigned short r2, unsigned short g2, unsigned short b2)
  55. {
  56.     r1 >>= 8; g1 >>= 8; b1 >>= 8;
  57.     r2 >>= 8; g2 >>= 8; b2 >>= 8;
  58.  
  59.     return ((r2 - r1) * (r2 - r1) +
  60.             (g2 - g1) * (g2 - g1) +
  61.             (b2 - b1) * (b2 - b1));
  62. }
  63.  
  64. cairo_status_t
  65. _cairo_xlib_visual_info_create (Display *dpy,
  66.                                 int screen,
  67.                                 VisualID visualid,
  68.                                 cairo_xlib_visual_info_t **out)
  69. {
  70.     cairo_xlib_visual_info_t *info;
  71.     Colormap colormap = DefaultColormap (dpy, screen);
  72.     XColor color;
  73.     int gray, red, green, blue;
  74.     int i, j, distance, min_distance = 0;
  75.     XColor colors[256];
  76.     unsigned short cube_index_to_short[CUBE_SIZE];
  77.     unsigned short ramp_index_to_short[RAMP_SIZE];
  78.     unsigned char  gray_to_pseudocolor[RAMP_SIZE];
  79.  
  80.     for (i = 0; i < CUBE_SIZE; i++)
  81.         cube_index_to_short[i] = (0xffff * i + ((CUBE_SIZE-1)>>1)) / (CUBE_SIZE-1);
  82.     for (i = 0; i < RAMP_SIZE; i++)
  83.         ramp_index_to_short[i] = (0xffff * i + ((RAMP_SIZE-1)>>1)) / (RAMP_SIZE-1);
  84.  
  85.     info = malloc (sizeof (cairo_xlib_visual_info_t));
  86.     if (unlikely (info == NULL))
  87.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  88.  
  89.     cairo_list_init (&info->link);
  90.     info->visualid = visualid;
  91.  
  92.     /* Allocate a gray ramp and a color cube.
  93.      * Give up as soon as failures start. */
  94.  
  95.     for (gray = 0; gray < RAMP_SIZE; gray++) {
  96.         color.red = color.green = color.blue = ramp_index_to_short[gray];
  97.         if (! XAllocColor (dpy, colormap, &color))
  98.             goto DONE_ALLOCATE;
  99.     }
  100.  
  101.     /* XXX: Could do this in a more clever order to have the best
  102.      * possible results from early failure. Could also choose a cube
  103.      * uniformly distributed in a better space than RGB. */
  104.     for (red = 0; red < CUBE_SIZE; red++) {
  105.         for (green = 0; green < CUBE_SIZE; green++) {
  106.             for (blue = 0; blue < CUBE_SIZE; blue++) {
  107.                 color.red = cube_index_to_short[red];
  108.                 color.green = cube_index_to_short[green];
  109.                 color.blue = cube_index_to_short[blue];
  110.                 color.pixel = 0;
  111.                 color.flags = 0;
  112.                 color.pad = 0;
  113.                 if (! XAllocColor (dpy, colormap, &color))
  114.                     goto DONE_ALLOCATE;
  115.             }
  116.         }
  117.     }
  118.   DONE_ALLOCATE:
  119.  
  120.     for (i = 0; i < ARRAY_LENGTH (colors); i++)
  121.         colors[i].pixel = i;
  122.     XQueryColors (dpy, colormap, colors, ARRAY_LENGTH (colors));
  123.  
  124.     /* Search for nearest colors within allocated colormap. */
  125.     for (gray = 0; gray < RAMP_SIZE; gray++) {
  126.         for (i = 0; i < 256; i++) {
  127.             distance = _color_distance (ramp_index_to_short[gray],
  128.                                         ramp_index_to_short[gray],
  129.                                         ramp_index_to_short[gray],
  130.                                         colors[i].red,
  131.                                         colors[i].green,
  132.                                         colors[i].blue);
  133.             if (i == 0 || distance < min_distance) {
  134.                 gray_to_pseudocolor[gray] = colors[i].pixel;
  135.                 min_distance = distance;
  136.                 if (!min_distance)
  137.                     break;
  138.             }
  139.         }
  140.     }
  141.     for (red = 0; red < CUBE_SIZE; red++) {
  142.         for (green = 0; green < CUBE_SIZE; green++) {
  143.             for (blue = 0; blue < CUBE_SIZE; blue++) {
  144.                 for (i = 0; i < 256; i++) {
  145.                     distance = _color_distance (cube_index_to_short[red],
  146.                                                 cube_index_to_short[green],
  147.                                                 cube_index_to_short[blue],
  148.                                                 colors[i].red,
  149.                                                 colors[i].green,
  150.                                                 colors[i].blue);
  151.                     if (i == 0 || distance < min_distance) {
  152.                         info->cube_to_pseudocolor[red][green][blue] = colors[i].pixel;
  153.                         min_distance = distance;
  154.                         if (!min_distance)
  155.                             break;
  156.                     }
  157.                 }
  158.             }
  159.         }
  160.     }
  161.  
  162.     for (i = 0, j = 0; i < 256; i++) {
  163.         if (j < CUBE_SIZE - 1 && (((i<<8)+i) - (int)cube_index_to_short[j]) > ((int)cube_index_to_short[j+1] - ((i<<8)+i)))
  164.             j++;
  165.         info->field8_to_cube[i] = j;
  166.  
  167.         info->dither8_to_cube[i] = ((int)i - 128) / (CUBE_SIZE - 1);
  168.     }
  169.     for (i = 0, j = 0; i < 256; i++) {
  170.         if (j < RAMP_SIZE - 1 && (((i<<8)+i) - (int)ramp_index_to_short[j]) > ((int)ramp_index_to_short[j+1] - ((i<<8)+i)))
  171.             j++;
  172.         info->gray8_to_pseudocolor[i] = gray_to_pseudocolor[j];
  173.     }
  174.  
  175.     for (i = 0; i < 256; i++) {
  176.         info->colors[i].a = 0xff;
  177.         info->colors[i].r = colors[i].red   >> 8;
  178.         info->colors[i].g = colors[i].green >> 8;
  179.         info->colors[i].b = colors[i].blue  >> 8;
  180.     }
  181.  
  182.     *out = info;
  183.     return CAIRO_STATUS_SUCCESS;
  184. }
  185.  
  186. void
  187. _cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info)
  188. {
  189.     /* No need for XFreeColors() whilst using DefaultColormap */
  190.     _cairo_list_del (&info->link);
  191.     free (info);
  192. }
  193.  
  194. #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
  195.