aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2020-06-12 18:12:37 +0200
committerMattias EngdegÄrd2020-06-21 21:22:26 +0200
commit9fe2bdb88a4ebd4b2286c1c2a2a2ba7411af01b6 (patch)
tree0979ec4f38172e25a0420eca5b22650c249a80f4
parent0792f8e4f0de2328c57d552a5845bdf77265a971 (diff)
downloademacs-9fe2bdb88a4ebd4b2286c1c2a2a2ba7411af01b6.tar.gz
emacs-9fe2bdb88a4ebd4b2286c1c2a2a2ba7411af01b6.zip
Consolidate #RGB string parsers
Use a single parser of color strings in the #RGB, rgb:R/G/B and rgbi:R/G/B formats, replacing four existing ones. Previously, error-checking was spotty, handling of the rgbi: format not always present, and normalization of the result was sometimes incorrect. * src/dispextern.h: New prototype. * src/xfaces.c (parse_hex_color_comp, parse_float_color_comp) (parse_color_spec, Finternal-color_values_from_color_spec): New functions. * test/src/xfaces-tests.el (xfaces-internal-color-values-from-color-spec): New test. * lisp/term/tty-colors.el (tty-color-standard-values): Use internal-color-values-from-color-spec, replacing old parser. * src/nsterm.m (ns_get_color): * src/w32fns.c (x_to_w32_color): * src/xterm.c (x_parse_color): Use parse_color_spec, replacing old parsers. (HEX_COLOR_NAME_LENGTH): Remove #define.
-rw-r--r--lisp/term/tty-colors.el58
-rw-r--r--src/dispextern.h2
-rw-r--r--src/nsterm.m59
-rw-r--r--src/w32fns.c157
-rw-r--r--src/xfaces.c116
-rw-r--r--src/xterm.c51
-rw-r--r--test/src/xfaces-tests.el23
7 files changed, 180 insertions, 286 deletions
diff --git a/lisp/term/tty-colors.el b/lisp/term/tty-colors.el
index 39ca2d36276..73e2431822e 100644
--- a/lisp/term/tty-colors.el
+++ b/lisp/term/tty-colors.el
@@ -923,62 +923,8 @@ The returned value reflects the standard Emacs definition of
923COLOR (see the info node `(emacs) Colors'), regardless of whether 923COLOR (see the info node `(emacs) Colors'), regardless of whether
924the terminal can display it, so the return value should be the 924the terminal can display it, so the return value should be the
925same regardless of what display is being used." 925same regardless of what display is being used."
926 (let ((len (length color))) 926 (or (internal-color-values-from-color-spec color)
927 (cond ((and (>= len 4) ;; HTML/CSS/SVG-style "#XXYYZZ" color spec 927 (cdr (assoc color color-name-rgb-alist))))
928 (eq (aref color 0) ?#)
929 (member (aref color 1)
930 '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
931 ?a ?b ?c ?d ?e ?f
932 ?A ?B ?C ?D ?E ?F)))
933 ;; Translate the string "#XXYYZZ" into a list of numbers
934 ;; (XX YY ZZ), scaling each to the {0..65535} range. This
935 ;; follows the HTML color convention, where both "#fff" and
936 ;; "#ffffff" represent the same color, white.
937 (let* ((ndig (/ (- len 1) 3))
938 (maxval (1- (ash 1 (* 4 ndig))))
939 (i1 1)
940 (i2 (+ i1 ndig))
941 (i3 (+ i2 ndig))
942 (i4 (+ i3 ndig)))
943 (list
944 (/ (* (string-to-number
945 (substring color i1 i2) 16)
946 65535)
947 maxval)
948 (/ (* (string-to-number
949 (substring color i2 i3) 16)
950 65535)
951 maxval)
952 (/ (* (string-to-number
953 (substring color i3 i4) 16)
954 65535)
955 maxval))))
956 ((and (>= len 9) ;; X-style rgb:xx/yy/zz color spec
957 (string= (substring color 0 4) "rgb:"))
958 ;; Translate the string "rgb:XX/YY/ZZ" into a list of
959 ;; numbers (XX YY ZZ), scaling each to the {0..65535}
960 ;; range. "rgb:F/F/F" is white.
961 (let* ((ndig (/ (- len 3) 3))
962 (maxval (1- (ash 1 (* 4 (- ndig 1)))))
963 (i1 4)
964 (i2 (+ i1 ndig))
965 (i3 (+ i2 ndig))
966 (i4 (+ i3 ndig)))
967 (list
968 (/ (* (string-to-number
969 (substring color i1 (- i2 1)) 16)
970 65535)
971 maxval)
972 (/ (* (string-to-number
973 (substring color i2 (- i3 1)) 16)
974 65535)
975 maxval)
976 (/ (* (string-to-number
977 (substring color i3 (1- i4)) 16)
978 65535)
979 maxval))))
980 (t
981 (cdr (assoc color color-name-rgb-alist))))))
982 928
983(defun tty-color-translate (color &optional frame) 929(defun tty-color-translate (color &optional frame)
984 "Given a color COLOR, return the index of the corresponding TTY color. 930 "Given a color COLOR, return the index of the corresponding TTY color.
diff --git a/src/dispextern.h b/src/dispextern.h
index 0b1f3d14aeb..e1d6eddc419 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3514,6 +3514,8 @@ void update_face_from_frame_parameter (struct frame *, Lisp_Object,
3514 Lisp_Object); 3514 Lisp_Object);
3515extern bool tty_defined_color (struct frame *, const char *, Emacs_Color *, 3515extern bool tty_defined_color (struct frame *, const char *, Emacs_Color *,
3516 bool, bool); 3516 bool, bool);
3517bool parse_color_spec (const char *,
3518 unsigned short *, unsigned short *, unsigned short *);
3517 3519
3518Lisp_Object tty_color_name (struct frame *, int); 3520Lisp_Object tty_color_name (struct frame *, int);
3519void clear_face_cache (bool); 3521void clear_face_cache (bool);
diff --git a/src/nsterm.m b/src/nsterm.m
index 3dc7e1db7c9..0e405fc0175 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2341,9 +2341,6 @@ ns_get_color (const char *name, NSColor **col)
2341 See https://lists.gnu.org/r/emacs-devel/2009-07/msg01203.html. */ 2341 See https://lists.gnu.org/r/emacs-devel/2009-07/msg01203.html. */
2342{ 2342{
2343 NSColor *new = nil; 2343 NSColor *new = nil;
2344 static char hex[20];
2345 int scaling = 0;
2346 float r = -1.0, g, b;
2347 NSString *nsname = [NSString stringWithUTF8String: name]; 2344 NSString *nsname = [NSString stringWithUTF8String: name];
2348 2345
2349 NSTRACE ("ns_get_color(%s, **)", name); 2346 NSTRACE ("ns_get_color(%s, **)", name);
@@ -2386,51 +2383,31 @@ ns_get_color (const char *name, NSColor **col)
2386 } 2383 }
2387 2384
2388 /* First, check for some sort of numeric specification. */ 2385 /* First, check for some sort of numeric specification. */
2389 hex[0] = '\0'; 2386 unsigned short r16, g16, b16;
2390 2387 if (parse_color_spec (name, &r16, &g16, &b16))
2391 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2392 { 2388 {
2393 NSScanner *scanner = [NSScanner scannerWithString: nsname]; 2389 *col = [NSColor colorForEmacsRed: r16 / 65535.0
2394 [scanner scanFloat: &r]; 2390 green: g16 / 65535.0
2395 [scanner scanFloat: &g]; 2391 blue: b16 / 65535.0
2396 [scanner scanFloat: &b]; 2392 alpha: 1.0];
2397 } 2393 unblock_input ();
2398 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */ 2394 return 0;
2399 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2400 else if (name[0] == '#') /* An old X11 format; convert to newer */
2401 {
2402 int len = 0;
2403 while (isxdigit (name[len + 1]))
2404 len++;
2405 if (name[len + 1] == '\0' && len >= 1 && len <= 12 && len % 3 == 0)
2406 {
2407 scaling = len / 3;
2408 for (int i = 0; i < 3; i++)
2409 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2410 name + 1 + i * scaling);
2411 hex[3 * (scaling + 1) - 1] = '\0';
2412 }
2413 } 2395 }
2414 2396 else if (name[0] == '0' || name[0] == '1' || name[0] == '.')
2415 if (hex[0])
2416 { 2397 {
2417 unsigned int rr, gg, bb; 2398 /* RGB decimal */
2418 float fscale = (1 << (scaling * 4)) - 1; 2399 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2419 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb)) 2400 float r, g, b;
2401 if ( [scanner scanFloat: &r] && r >= 0 && r <= 1
2402 && [scanner scanFloat: &g] && g >= 0 && g <= 1
2403 && [scanner scanFloat: &b] && b >= 0 && b <= 1)
2420 { 2404 {
2421 r = rr / fscale; 2405 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2422 g = gg / fscale; 2406 unblock_input ();
2423 b = bb / fscale; 2407 return 0;
2424 } 2408 }
2425 } 2409 }
2426 2410
2427 if (r >= 0.0F)
2428 {
2429 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2430 unblock_input ();
2431 return 0;
2432 }
2433
2434 /* Otherwise, color is expected to be from a list */ 2411 /* Otherwise, color is expected to be from a list */
2435 { 2412 {
2436 NSEnumerator *lenum, *cenum; 2413 NSEnumerator *lenum, *cenum;
diff --git a/src/w32fns.c b/src/w32fns.c
index e595b0285a7..ab864332e78 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -864,161 +864,14 @@ x_to_w32_color (const char * colorname)
864 864
865 block_input (); 865 block_input ();
866 866
867 if (colorname[0] == '#') 867 unsigned short r, g, b;
868 if (parse_color_spec (colorname, &r, &g, &b))
868 { 869 {
869 /* Could be an old-style RGB Device specification. */ 870 unblock_input ();
870 int size = strlen (colorname + 1); 871 /* Throw away the low 8 bits and return 0xBBGGRR. */
871 char *color = alloca (size + 1); 872 return make_fixnum ((b & 0xff00) << 8 | (g & 0xff00) | r >> 8);
872
873 strcpy (color, colorname + 1);
874 if (size == 3 || size == 6 || size == 9 || size == 12)
875 {
876 UINT colorval;
877 int i, pos;
878 pos = 0;
879 size /= 3;
880 colorval = 0;
881
882 for (i = 0; i < 3; i++)
883 {
884 char *end;
885 char t;
886 unsigned long value;
887
888 /* The check for 'x' in the following conditional takes into
889 account the fact that strtol allows a "0x" in front of
890 our numbers, and we don't. */
891 if (!isxdigit (color[0]) || color[1] == 'x')
892 break;
893 t = color[size];
894 color[size] = '\0';
895 value = strtoul (color, &end, 16);
896 color[size] = t;
897 if (errno == ERANGE || end - color != size)
898 break;
899 switch (size)
900 {
901 case 1:
902 value = value * 0x10;
903 break;
904 case 2:
905 break;
906 case 3:
907 value /= 0x10;
908 break;
909 case 4:
910 value /= 0x100;
911 break;
912 }
913 colorval |= (value << pos);
914 pos += 0x8;
915 if (i == 2)
916 {
917 unblock_input ();
918 XSETINT (ret, colorval);
919 return ret;
920 }
921 color = end;
922 }
923 }
924 }
925 else if (strnicmp (colorname, "rgb:", 4) == 0)
926 {
927 const char *color;
928 UINT colorval;
929 int i, pos;
930 pos = 0;
931
932 colorval = 0;
933 color = colorname + 4;
934 for (i = 0; i < 3; i++)
935 {
936 char *end;
937 unsigned long value;
938
939 /* The check for 'x' in the following conditional takes into
940 account the fact that strtol allows a "0x" in front of
941 our numbers, and we don't. */
942 if (!isxdigit (color[0]) || color[1] == 'x')
943 break;
944 value = strtoul (color, &end, 16);
945 if (errno == ERANGE)
946 break;
947 switch (end - color)
948 {
949 case 1:
950 value = value * 0x10 + value;
951 break;
952 case 2:
953 break;
954 case 3:
955 value /= 0x10;
956 break;
957 case 4:
958 value /= 0x100;
959 break;
960 default:
961 value = ULONG_MAX;
962 }
963 if (value == ULONG_MAX)
964 break;
965 colorval |= (value << pos);
966 pos += 0x8;
967 if (i == 2)
968 {
969 if (*end != '\0')
970 break;
971 unblock_input ();
972 XSETINT (ret, colorval);
973 return ret;
974 }
975 if (*end != '/')
976 break;
977 color = end + 1;
978 }
979 } 873 }
980 else if (strnicmp (colorname, "rgbi:", 5) == 0)
981 {
982 /* This is an RGB Intensity specification. */
983 const char *color;
984 UINT colorval;
985 int i, pos;
986 pos = 0;
987
988 colorval = 0;
989 color = colorname + 5;
990 for (i = 0; i < 3; i++)
991 {
992 char *end;
993 double value;
994 UINT val;
995 874
996 value = strtod (color, &end);
997 if (errno == ERANGE)
998 break;
999 if (value < 0.0 || value > 1.0)
1000 break;
1001 val = (UINT)(0x100 * value);
1002 /* We used 0x100 instead of 0xFF to give a continuous
1003 range between 0.0 and 1.0 inclusive. The next statement
1004 fixes the 1.0 case. */
1005 if (val == 0x100)
1006 val = 0xFF;
1007 colorval |= (val << pos);
1008 pos += 0x8;
1009 if (i == 2)
1010 {
1011 if (*end != '\0')
1012 break;
1013 unblock_input ();
1014 XSETINT (ret, colorval);
1015 return ret;
1016 }
1017 if (*end != '/')
1018 break;
1019 color = end + 1;
1020 }
1021 }
1022 /* I am not going to attempt to handle any of the CIE color schemes 875 /* I am not going to attempt to handle any of the CIE color schemes
1023 or TekHVC, since I don't know the algorithms for conversion to 876 or TekHVC, since I don't know the algorithms for conversion to
1024 RGB. */ 877 RGB. */
diff --git a/src/xfaces.c b/src/xfaces.c
index cf155288bd1..308509a0267 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -220,6 +220,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
220#include "sysstdio.h" 220#include "sysstdio.h"
221#include <sys/types.h> 221#include <sys/types.h>
222#include <sys/stat.h> 222#include <sys/stat.h>
223#include <math.h>
223 224
224#include "lisp.h" 225#include "lisp.h"
225#include "character.h" 226#include "character.h"
@@ -819,6 +820,120 @@ load_pixmap (struct frame *f, Lisp_Object name)
819 Color Handling 820 Color Handling
820 ***********************************************************************/ 821 ***********************************************************************/
821 822
823/* Parse hex color component at S ending right before E.
824 Set *DST to the value normalized so that the maximum for the
825 number of digits given becomes 65535, and return true on success,
826 false otherwise. */
827static bool
828parse_hex_color_comp (const char *s, const char *e, unsigned short *dst)
829{
830 int n = e - s;
831 if (n <= 0 || n > 4)
832 return false;
833 int val = 0;
834 for (; s < e; s++)
835 {
836 int digit;
837 if (*s >= '0' && *s <= '9')
838 digit = *s - '0';
839 else if (*s >= 'A' && *s <= 'F')
840 digit = *s - 'A' + 10;
841 else if (*s >= 'a' && *s <= 'f')
842 digit = *s - 'a' + 10;
843 else
844 return false;
845 val = (val << 4) | digit;
846 }
847 int maxval = (1 << (n * 4)) - 1;
848 *dst = (unsigned)val * 65535 / maxval;
849 return true;
850}
851
852/* Parse floating-point color component at S ending right before E.
853 Return the number if in the range [0,1]; otherwise -1. */
854static double
855parse_float_color_comp (const char *s, const char *e)
856{
857 char *end;
858 double x = strtod (s, &end);
859 return (end == e && x >= 0 && x <= 1) ? x : -1;
860}
861
862/* Parse S as a numeric color specification and set *R, *G and *B.
863 Return true on success, false on failure.
864 Recognized formats:
865
866 "#RGB", with R, G and B hex strings of equal length, 1-4 digits each
867 "rgb:R/G/B", with R, G and B hex strings, 1-4 digits each
868 "rgbi:R/G/B", with R, G and B numbers in [0,1]
869
870 The result is normalized to a maximum value of 65535 per component. */
871bool
872parse_color_spec (const char *s,
873 unsigned short *r, unsigned short *g, unsigned short *b)
874{
875 int len = strlen (s);
876 if (s[0] == '#')
877 {
878 if ((len - 1) % 3 == 0)
879 {
880 int n = (len - 1) / 3;
881 return ( parse_hex_color_comp (s + 1 + 0 * n, s + 1 + 1 * n, r)
882 && parse_hex_color_comp (s + 1 + 1 * n, s + 1 + 2 * n, g)
883 && parse_hex_color_comp (s + 1 + 2 * n, s + 1 + 3 * n, b));
884 }
885 }
886 else if (strncmp (s, "rgb:", 4) == 0)
887 {
888 char *sep1, *sep2;
889 return ((sep1 = strchr (s + 4, '/')) != NULL
890 && (sep2 = strchr (sep1 + 1, '/')) != NULL
891 && parse_hex_color_comp (s + 4, sep1, r)
892 && parse_hex_color_comp (sep1 + 1, sep2, g)
893 && parse_hex_color_comp (sep2 + 1, s + len, b));
894 }
895 else if (strncmp (s, "rgbi:", 5) == 0)
896 {
897 char *sep1, *sep2;
898 double red, green, blue;
899 if ((sep1 = strchr (s + 5, '/')) != NULL
900 && (sep2 = strchr (sep1 + 1, '/')) != NULL
901 && (red = parse_float_color_comp (s + 5, sep1)) >= 0
902 && (green = parse_float_color_comp (sep1 + 1, sep2)) >= 0
903 && (blue = parse_float_color_comp (sep2 + 1, s + len)) >= 0)
904 {
905 *r = lrint (red * 65535);
906 *g = lrint (green * 65535);
907 *b = lrint (blue * 65535);
908 return true;
909 }
910 }
911 return false;
912}
913
914DEFUN ("internal-color-values-from-color-spec",
915 Finternal_color_values_from_color_spec,
916 Sinternal_color_values_from_color_spec,
917 1, 1, 0,
918 doc: /* Parse STRING as a numeric color and return (RED GREEN BLUE).
919Recognised formats for STRING are:
920
921 #RGB, where R, G and B are hex numbers of equal length, 1-4 digits each
922 rgb:R/G/B, where R, G, and B are hex numbers, 1-4 digits each
923 rgbi:R/G/B, where R, G and B are floating-point numbers in [0,1]
924
925The result is normalized to a maximum value of 65535 per component,
926forming a list of three integers in [0,65535].
927If STRING is not in one of the above forms, return nil. */)
928 (Lisp_Object string)
929{
930 CHECK_STRING (string);
931 unsigned short r, g, b;
932 return (parse_color_spec (SSDATA (string), &r, &g, &b)
933 ? list3i (r, g, b)
934 : Qnil);
935}
936
822/* Parse RGB_LIST, and fill in the RGB fields of COLOR. 937/* Parse RGB_LIST, and fill in the RGB fields of COLOR.
823 RGB_LIST should contain (at least) 3 lisp integers. 938 RGB_LIST should contain (at least) 3 lisp integers.
824 Return true iff RGB_LIST is OK. */ 939 Return true iff RGB_LIST is OK. */
@@ -7018,4 +7133,5 @@ clear the face cache, see `clear-face-cache'. */);
7018 defsubr (&Sinternal_face_x_get_resource); 7133 defsubr (&Sinternal_face_x_get_resource);
7019 defsubr (&Sx_family_fonts); 7134 defsubr (&Sx_family_fonts);
7020#endif 7135#endif
7136 defsubr (&Sinternal_color_values_from_color_spec);
7021} 7137}
diff --git a/src/xterm.c b/src/xterm.c
index 7989cecec7f..6340700cb89 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -2376,8 +2376,6 @@ x_query_frame_background_color (struct frame *f, XColor *bgcolor)
2376 x_query_colors (f, bgcolor, 1); 2376 x_query_colors (f, bgcolor, 1);
2377} 2377}
2378 2378
2379#define HEX_COLOR_NAME_LENGTH 32
2380
2381/* On frame F, translate the color name to RGB values. Use cached 2379/* On frame F, translate the color name to RGB values. Use cached
2382 information, if possible. 2380 information, if possible.
2383 2381
@@ -2389,44 +2387,23 @@ x_query_frame_background_color (struct frame *f, XColor *bgcolor)
2389Status x_parse_color (struct frame *f, const char *color_name, 2387Status x_parse_color (struct frame *f, const char *color_name,
2390 XColor *color) 2388 XColor *color)
2391{ 2389{
2390 /* Don't pass #RGB strings directly to XParseColor, because that
2391 follows the X convention of zero-extending each channel
2392 value: #f00 means #f00000. We want the convention of scaling
2393 channel values, so #f00 means #ff0000, just as it does for
2394 HTML, SVG, and CSS. */
2395 unsigned short r, g, b;
2396 if (parse_color_spec (color_name, &r, &g, &b))
2397 {
2398 color->red = r;
2399 color->green = g;
2400 color->blue = b;
2401 return 1;
2402 }
2403
2392 Display *dpy = FRAME_X_DISPLAY (f); 2404 Display *dpy = FRAME_X_DISPLAY (f);
2393 Colormap cmap = FRAME_X_COLORMAP (f); 2405 Colormap cmap = FRAME_X_COLORMAP (f);
2394 struct color_name_cache_entry *cache_entry; 2406 struct color_name_cache_entry *cache_entry;
2395
2396 if (color_name[0] == '#')
2397 {
2398 /* Don't pass #RGB strings directly to XParseColor, because that
2399 follows the X convention of zero-extending each channel
2400 value: #f00 means #f00000. We want the convention of scaling
2401 channel values, so #f00 means #ff0000, just as it does for
2402 HTML, SVG, and CSS.
2403
2404 So we translate #f00 to rgb:f/0/0, which X handles
2405 differently. */
2406 char rgb_color_name[HEX_COLOR_NAME_LENGTH];
2407 int len = strlen (color_name);
2408 int digits_per_channel;
2409 if (len == 4)
2410 digits_per_channel = 1;
2411 else if (len == 7)
2412 digits_per_channel = 2;
2413 else if (len == 10)
2414 digits_per_channel = 3;
2415 else if (len == 13)
2416 digits_per_channel = 4;
2417 else
2418 return 0;
2419
2420 snprintf (rgb_color_name, sizeof rgb_color_name, "rgb:%.*s/%.*s/%.*s",
2421 digits_per_channel, color_name + 1,
2422 digits_per_channel, color_name + digits_per_channel + 1,
2423 digits_per_channel, color_name + 2 * digits_per_channel + 1);
2424
2425 /* The rgb form is parsed directly by XParseColor without
2426 talking to the X server. No need for caching. */
2427 return XParseColor (dpy, cmap, rgb_color_name, color);
2428 }
2429
2430 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry; 2407 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
2431 cache_entry = cache_entry->next) 2408 cache_entry = cache_entry->next)
2432 { 2409 {
diff --git a/test/src/xfaces-tests.el b/test/src/xfaces-tests.el
index 5ed16c9e51d..34cda07e5b4 100644
--- a/test/src/xfaces-tests.el
+++ b/test/src/xfaces-tests.el
@@ -24,4 +24,27 @@
24 (should (equal (color-distance "#222222" "#ffffff") 24 (should (equal (color-distance "#222222" "#ffffff")
25 (color-distance "#ffffff" "#222222")))) 25 (color-distance "#ffffff" "#222222"))))
26 26
27(ert-deftest xfaces-internal-color-values-from-color-spec ()
28 (should (equal (internal-color-values-from-color-spec "#f05")
29 '(#xffff #x0000 #x5555)))
30 (should (equal (internal-color-values-from-color-spec "#1fb0C5")
31 '(#x1f1f #xb0b0 #xc5c5)))
32 (should (equal (internal-color-values-from-color-spec "#1f8b0AC5e")
33 '(#x1f81 #xb0aa #xc5eb)))
34 (should (equal (internal-color-values-from-color-spec "#1f83b0ADC5e2")
35 '(#x1f83 #xb0ad #xc5e2)))
36 (should (equal (internal-color-values-from-color-spec "#1f83b0ADC5e2g") nil))
37 (should (equal (internal-color-values-from-color-spec "#1f83b0ADC5e20") nil))
38 (should (equal (internal-color-values-from-color-spec "#12345") nil))
39 (should (equal (internal-color-values-from-color-spec "rgb:f/23/28a")
40 '(#xffff #x2323 #x28a2)))
41 (should (equal (internal-color-values-from-color-spec "rgb:1234/5678/09ab")
42 '(#x1234 #x5678 #x09ab)))
43 (should (equal (internal-color-values-from-color-spec "rgb:0//0") nil))
44 (should (equal (internal-color-values-from-color-spec "rgbi:0/0.5/0.1")
45 '(0 32768 6554)))
46 (should (equal (internal-color-values-from-color-spec "rgbi:1e-3/1.0e-2/1e0")
47 '(66 655 65535)))
48 (should (equal (internal-color-values-from-color-spec "rgbi:0/0.5/10") nil)))
49
27(provide 'xfaces-tests) 50(provide 'xfaces-tests)