summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2013-10-09 15:53:16 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2013-10-22 14:27:43 -0400
commit98fef3cef2d0f7f463a2e4f9f1b35b09f7b6ea77 (patch)
treedadc80d6826ef32fb9a8ad281e813444f69404fd
parent6f05ecf488314e4b0c6c6b0110963c449bebe7d7 (diff)
_cairo_color_double_to_short(): Use standard rounding algorithm
The _cairo_color_double_to_short() function converts a double precision floating point value in the range of [0.0, 1.0] to a uint16_t integer by dividing the [0.0, 1.0] range into 65536 equal-sized intervals and then associating each interval with an integer. Under the assumption that an integer i corresponds to the real value i / 65535.0 this algorithm introduces more error than necessary as can be seen from the following picture showing the analogous transformation for two-bit integers: +-----------+-----------+-----------+-----------+ 0b00 | 0b01 | 0b10 | 0b11 +-----------+-----------+-----------+-----------+ which shows that some floating point values are not converted to the integer that would minimize the error in value that that integer corresponds to. Instead, this patch uses standard rounding, which makes the diagram look like this: +-------+---------------+---------------+-------+ 0b00 | 0b01 | 0b10 | 0b11 +-------+---------------+---------------+-------+ It's clear that if the values corresponding to the given integers are fixed, then it's not possible to decrease the resulting error by moving any of the interval boundaries. See this thread for more information: http://lists.freedesktop.org/archives/cairo/2013-October/024691.html Reference images updated: pthread-similar.ref.png record-paint-alpha.ref.png record90-paint-alpha.argb32.ref record90-paint-alpha.rgb24.ref.png xcb-huge-image-shm.ref.png xcb-huge-subimage.ref.png All of these have only one-step differences to the old images.
-rw-r--r--src/cairo-color.c193
-rw-r--r--test/reference/pthread-similar.ref.pngbin140728321541552 -> 176 bytes
-rw-r--r--test/reference/record-paint-alpha.ref.pngbin140728321541552 -> 245 bytes
-rw-r--r--test/reference/record90-paint-alpha.argb32.ref.pngbin105 -> 105 bytes
-rw-r--r--test/reference/record90-paint-alpha.rgb24.ref.pngbin105 -> 105 bytes
-rw-r--r--test/reference/xcb-huge-image-shm.ref.pngbin105 -> 97 bytes
-rw-r--r--test/reference/xcb-huge-subimage.ref.pngbin105 -> 97 bytes
7 files changed, 193 insertions, 0 deletions
diff --git a/src/cairo-color.c b/src/cairo-color.c
index 9c85255..c2a11a1 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -0,0 +1,193 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairoint.h"
+
+static cairo_color_t const cairo_color_white = {
+ 1.0, 1.0, 1.0, 1.0,
+ 0xffff, 0xffff, 0xffff, 0xffff
+};
+
+static cairo_color_t const cairo_color_black = {
+ 0.0, 0.0, 0.0, 1.0,
+ 0x0, 0x0, 0x0, 0xffff
+};
+
+static cairo_color_t const cairo_color_transparent = {
+ 0.0, 0.0, 0.0, 0.0,
+ 0x0, 0x0, 0x0, 0x0
+};
+
+static cairo_color_t const cairo_color_magenta = {
+ 1.0, 0.0, 1.0, 1.0,
+ 0xffff, 0x0, 0xffff, 0xffff
+};
+
+const cairo_color_t *
+_cairo_stock_color (cairo_stock_t stock)
+{
+ switch (stock) {
+ case CAIRO_STOCK_WHITE:
+ return &cairo_color_white;
+ case CAIRO_STOCK_BLACK:
+ return &cairo_color_black;
+ case CAIRO_STOCK_TRANSPARENT:
+ return &cairo_color_transparent;
+
+ case CAIRO_STOCK_NUM_COLORS:
+ default:
+ ASSERT_NOT_REACHED;
+ /* If the user can get here somehow, give a color that indicates a
+ * problem. */
+ return &cairo_color_magenta;
+ }
+}
+
+/* Convert a double in [0.0, 1.0] to an integer in [0, 65535]
+ * The conversion is designed to choose the integer i such that
+ * i / 65535.0 is as close as possible to the input value.
+ */
+uint16_t
+_cairo_color_double_to_short (double d)
+{
+ return d * 65535.0 + 0.5;
+}
+
+static void
+_cairo_color_compute_shorts (cairo_color_t *color)
+{
+ color->red_short = _cairo_color_double_to_short (color->red * color->alpha);
+ color->green_short = _cairo_color_double_to_short (color->green * color->alpha);
+ color->blue_short = _cairo_color_double_to_short (color->blue * color->alpha);
+ color->alpha_short = _cairo_color_double_to_short (color->alpha);
+}
+
+void
+_cairo_color_init_rgba (cairo_color_t *color,
+ double red, double green, double blue,
+ double alpha)
+{
+ color->red = red;
+ color->green = green;
+ color->blue = blue;
+ color->alpha = alpha;
+
+ _cairo_color_compute_shorts (color);
+}
+
+void
+_cairo_color_multiply_alpha (cairo_color_t *color,
+ double alpha)
+{
+ color->alpha *= alpha;
+
+ _cairo_color_compute_shorts (color);
+}
+
+void
+_cairo_color_get_rgba (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha)
+{
+ *red = color->red;
+ *green = color->green;
+ *blue = color->blue;
+ *alpha = color->alpha;
+}
+
+void
+_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha)
+{
+ *red = color->red * color->alpha;
+ *green = color->green * color->alpha;
+ *blue = color->blue * color->alpha;
+ *alpha = color->alpha;
+}
+
+/* NB: This function works both for unmultiplied and premultiplied colors */
+cairo_bool_t
+_cairo_color_equal (const cairo_color_t *color_a,
+ const cairo_color_t *color_b)
+{
+ if (color_a == color_b)
+ return TRUE;
+
+ if (color_a->alpha_short != color_b->alpha_short)
+ return FALSE;
+
+ if (color_a->alpha_short == 0)
+ return TRUE;
+
+ return color_a->red_short == color_b->red_short &&
+ color_a->green_short == color_b->green_short &&
+ color_a->blue_short == color_b->blue_short;
+}
+
+cairo_bool_t
+_cairo_color_stop_equal (const cairo_color_stop_t *color_a,
+ const cairo_color_stop_t *color_b)
+{
+ if (color_a == color_b)
+ return TRUE;
+
+ return color_a->alpha_short == color_b->alpha_short &&
+ color_a->red_short == color_b->red_short &&
+ color_a->green_short == color_b->green_short &&
+ color_a->blue_short == color_b->blue_short;
+}
+
+cairo_content_t
+_cairo_color_get_content (const cairo_color_t *color)
+{
+ if (CAIRO_COLOR_IS_OPAQUE (color))
+ return CAIRO_CONTENT_COLOR;
+
+ if (color->red_short == 0 &&
+ color->green_short == 0 &&
+ color->blue_short == 0)
+ {
+ return CAIRO_CONTENT_ALPHA;
+ }
+
+ return CAIRO_CONTENT_COLOR_ALPHA;
+}
diff --git a/test/reference/pthread-similar.ref.png b/test/reference/pthread-similar.ref.png
index a22210d..c8763ba 100644
--- a/test/reference/pthread-similar.ref.png
+++ b/test/reference/pthread-similar.ref.png
Binary files differ
diff --git a/test/reference/record-paint-alpha.ref.png b/test/reference/record-paint-alpha.ref.png
index ab7ce3e..487b8b6 100644
--- a/test/reference/record-paint-alpha.ref.png
+++ b/test/reference/record-paint-alpha.ref.png
Binary files differ
diff --git a/test/reference/record90-paint-alpha.argb32.ref.png b/test/reference/record90-paint-alpha.argb32.ref.png
index 57aa95d..5e9cb58 100644
--- a/test/reference/record90-paint-alpha.argb32.ref.png
+++ b/test/reference/record90-paint-alpha.argb32.ref.png
Binary files differ
diff --git a/test/reference/record90-paint-alpha.rgb24.ref.png b/test/reference/record90-paint-alpha.rgb24.ref.png
index 57aa95d..5e9cb58 100644
--- a/test/reference/record90-paint-alpha.rgb24.ref.png
+++ b/test/reference/record90-paint-alpha.rgb24.ref.png
Binary files differ
diff --git a/test/reference/xcb-huge-image-shm.ref.png b/test/reference/xcb-huge-image-shm.ref.png
index a0b24c8..5c274f8 100644
--- a/test/reference/xcb-huge-image-shm.ref.png
+++ b/test/reference/xcb-huge-image-shm.ref.png
Binary files differ
diff --git a/test/reference/xcb-huge-subimage.ref.png b/test/reference/xcb-huge-subimage.ref.png
index a0b24c8..5c274f8 100644
--- a/test/reference/xcb-huge-subimage.ref.png
+++ b/test/reference/xcb-huge-subimage.ref.png
Binary files differ