From 6078890268c1de46cb29b0cec77a725dd2ef883b Mon Sep 17 00:00:00 2001
From: Behdad Esfahbod <behdad@behdad.org>
Date: Tue, 1 Aug 2006 22:16:22 -0400
Subject: [PATCH] Implement a better one-minus-epsilon for color computations
using float.h if available.  Defining a macro CAIRO_ONE_MINUS_EPSILON
for internal use now.  (bug 7497)
---
 configure.in      |   14 +++++++++-----
 src/cairo-color.c |   18 ++++++++----------
 src/cairoint.h    |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+), 15 deletions(-)

diff --git a/configure.in b/configure.in
index 33fc8dc..8ba562d 100644
--- a/configure.in
+++ b/configure.in
@@ -446,11 +446,6 @@ fi
 
 dnl ===========================================================================
 
-AC_CHECK_HEADERS([pthread.h], have_pthread=yes, have_pthread=no)
-AM_CONDITIONAL(HAVE_PTHREAD, test "x$have_pthread" = "xyes")
-
-dnl ===========================================================================
-
 CAIRO_BACKEND_ENABLE(ps, PostScript, ps, PS_SURFACE, auto, [], [
   if test x"$have_ft_load_sfnt_table" != "xyes" ; then
     use_ps="no (requires FreeType 2.1.4 or newer)"
@@ -527,10 +522,19 @@ CAIRO_BACKEND_ENABLE(atsui, ATSUI font, 
 ])
 
 dnl ===========================================================================
+
 dnl Checks for precise integer types
 AC_CHECK_HEADERS([stdint.h inttypes.h sys/int_types.h])
 AC_CHECK_TYPES([uint64_t, uint128_t])
 
+dnl Check for misc headers
+
+AC_CHECK_HEADERS([float.h])
+
+AC_CHECK_HEADERS([pthread.h], have_pthread=yes, have_pthread=no)
+AM_CONDITIONAL(HAVE_PTHREAD, test "x$have_pthread" = "xyes")
+
+
 dnl Use lots of warning flags with GCC
 
 WARN_CFLAGS=""
diff --git a/src/cairo-color.c b/src/cairo-color.c
index e202af2..9cf060a 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -89,19 +89,17 @@ _cairo_color_init_rgb (cairo_color_t *co
     _cairo_color_init_rgba (color, red, green, blue, 1.0);
 }
 
-/* We multiply colors by (0x10000 - epsilon), such that we get a uniform
- * range even for 0xffff.  In other words, (1.0 - epsilon) would convert
- * to 0xffff, not 0xfffe.
- */
-#define CAIRO_COLOR_ONE_MINUS_EPSILON (65536.0 - 1e-5)
-
 static void
 _cairo_color_compute_shorts (cairo_color_t *color)
 {
-    color->red_short   = color->red   * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
-    color->green_short = color->green * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
-    color->blue_short  = color->blue  * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
-    color->alpha_short = color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
+    /* We multiply colors by (65536.0 * (1.0 - epsilon)), such that we get a
+     * uniform range even for 0xffff.  In other words, (1.0 - epsilon) will
+     * convert to 0xffff, not 0xfffe.
+     */
+    color->red_short   = floor (color->red   * color->alpha * (65536.0 * CAIRO_ONE_MINUS_EPSILON));
+    color->green_short = floor (color->green * color->alpha * (65536.0 * CAIRO_ONE_MINUS_EPSILON));
+    color->blue_short  = floor (color->blue  * color->alpha * (65536.0 * CAIRO_ONE_MINUS_EPSILON));
+    color->alpha_short = floor (color->alpha *                (65536.0 * CAIRO_ONE_MINUS_EPSILON));
 }
 
 void
diff --git a/src/cairoint.h b/src/cairoint.h
index 4eb0c3c..ee008e9 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -168,6 +168,53 @@ # define CAIRO_MUTEX_LOCK(name)
 # define CAIRO_MUTEX_UNLOCK(name)
 #endif
 
+#if HAVE_FLOAT_H
+# include <float.h>
+#endif
+#ifndef DBL_EPSILON
+/* 1e-7 is a conservative value.  it's less than 2^(1-24) which is
+ * the epsilon value for a 32-bit float.  The regular value for this
+ * with 64-bit doubles is 2^(1-53) or approximately 1e-16.
+ */
+# define DBL_EPSILON 1e-7
+#endif
+
+/* CAIRO_ONE_MINUS_EPSILON:
+ *
+ * DBL_EPSILON is the difference between 1 and the least value greater
+ * than 1 that is representable in the given floating-point type.  Then
+ * 1.0+DBL_EPSILON looks like:
+ *
+ *         1.00000000000...0000000001 * 2**0
+ *
+ * while 1.0-DBL_EPSILON looks like:
+ *
+ *         0.11111111111...1111111111 * 2**0
+ *
+ * and so represented as:
+ *
+ *         1.1111111111...11111111110 * 2**-1
+ *
+ * so, in fact, 1.0-(DBL_EPSILON*.5) works too, but I don't think it
+ * really matters.  So, I'll go with the simple 1.0-DBL_EPSILON here.
+ *
+ * The following python session shows these observations:
+ *
+ *         >>> 1.0 + 2**(1-53)
+ *         1.0000000000000002
+ *         >>> 1.0 + 2**(1-54)
+ *         1.0
+ *         >>> 1.0 - 2**(1-53)
+ *         0.99999999999999978
+ *         >>> 1.0 - 2**(1-54)
+ *         0.99999999999999989
+ *         >>> 1.0 - 2**(1-53)*.5
+ *         0.99999999999999989
+ *         >>> 1.0 - 2**(1-55)
+ *         1.0
+ */
+#define CAIRO_ONE_MINUS_EPSILON (1.0 - DBL_EPSILON)
+
 #undef MIN
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
-- 
1.4.0

