aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2020-06-22 18:32:01 +0300
committerEli Zaretskii2020-06-22 18:32:01 +0300
commit30ff2433b16dba2c4e36c6eda6f808c6f2cb46d1 (patch)
treefae44fdb6ed9e62a20c0bdb047441bc55f23c771
parentbea5eb77b3170203424179274bf26b9ce70de807 (diff)
downloademacs-30ff2433b16dba2c4e36c6eda6f808c6f2cb46d1.tar.gz
emacs-30ff2433b16dba2c4e36c6eda6f808c6f2cb46d1.zip
Minor improvements as followup to recent RGB string-parsing change
* src/xfaces.c (Finternal_color_values_from_color_spec): Rename to... (Fcolor_values_from_color_spec): ...this. Callers changed. Rename the argument to SPEC and improve the doc string. (parse_color_spec, parse_float_color_comp, parse_hex_color_comp): Improve commentary. (parse_color_spec): Rename the argument S to SPEC. * etc/NEWS: Mention 'color-values-from-color-spec'.
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/term/tty-colors.el2
-rw-r--r--src/xfaces.c90
-rw-r--r--test/src/xfaces-tests.el26
4 files changed, 68 insertions, 55 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 6bfecd68139..d501c2ad872 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -624,6 +624,11 @@ In order for the two functions to behave more consistently,
624length, and also supports format specifications that include a 624length, and also supports format specifications that include a
625truncating precision field, such as '%.2a'. 625truncating precision field, such as '%.2a'.
626 626
627---
628** New function 'color-values-from-color-spec'.
629This can be used to parse RGB color specs in several formats and
630convert them to a list (R G B) of primary color values.
631
627 632
628* Changes in Emacs 28.1 on Non-Free Operating Systems 633* Changes in Emacs 28.1 on Non-Free Operating Systems
629 634
diff --git a/lisp/term/tty-colors.el b/lisp/term/tty-colors.el
index 73e2431822e..dda7fcc3691 100644
--- a/lisp/term/tty-colors.el
+++ b/lisp/term/tty-colors.el
@@ -923,7 +923,7 @@ 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 (or (internal-color-values-from-color-spec color) 926 (or (color-values-from-color-spec color)
927 (cdr (assoc color color-name-rgb-alist)))) 927 (cdr (assoc color color-name-rgb-alist))))
928 928
929(defun tty-color-translate (color &optional frame) 929(defun tty-color-translate (color &optional frame)
diff --git a/src/xfaces.c b/src/xfaces.c
index 308509a0267..c4a4e1c94f3 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -820,10 +820,10 @@ load_pixmap (struct frame *f, Lisp_Object name)
820 Color Handling 820 Color Handling
821 ***********************************************************************/ 821 ***********************************************************************/
822 822
823/* Parse hex color component at S ending right before E. 823/* Parse hex color component specification that starts at S and ends
824 Set *DST to the value normalized so that the maximum for the 824 right before E. Set *DST to the parsed value normalized so that
825 number of digits given becomes 65535, and return true on success, 825 the maximum value for the number of hex digits given becomes 65535,
826 false otherwise. */ 826 and return true on success, false otherwise. */
827static bool 827static bool
828parse_hex_color_comp (const char *s, const char *e, unsigned short *dst) 828parse_hex_color_comp (const char *s, const char *e, unsigned short *dst)
829{ 829{
@@ -849,8 +849,9 @@ parse_hex_color_comp (const char *s, const char *e, unsigned short *dst)
849 return true; 849 return true;
850} 850}
851 851
852/* Parse floating-point color component at S ending right before E. 852/* Parse floating-point color component specification that starts at S
853 Return the number if in the range [0,1]; otherwise -1. */ 853 and ends right before E. Return the parsed number if in the range
854 [0,1]; otherwise return -1. */
854static double 855static double
855parse_float_color_comp (const char *s, const char *e) 856parse_float_color_comp (const char *s, const char *e)
856{ 857{
@@ -859,48 +860,54 @@ parse_float_color_comp (const char *s, const char *e)
859 return (end == e && x >= 0 && x <= 1) ? x : -1; 860 return (end == e && x >= 0 && x <= 1) ? x : -1;
860} 861}
861 862
862/* Parse S as a numeric color specification and set *R, *G and *B. 863/* Parse SPEC as a numeric color specification and set *R, *G and *B.
863 Return true on success, false on failure. 864 Return true on success, false on failure.
864 Recognized formats:
865 865
866 "#RGB", with R, G and B hex strings of equal length, 1-4 digits each 866 Recognized formats of SPEC:
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 867
870 The result is normalized to a maximum value of 65535 per component. */ 868 "#RGB", with R, G and B hex strings of equal length, 1-4 digits each.
869 "rgb:R/G/B", with R, G and B hex strings, 1-4 digits each.
870 "rgbi:R/G/B", with R, G and B numbers in [0,1].
871
872 If the function succeeds, it assigns to each of the components *R,
873 *G, and *B a value normalized to be in the [0, 65535] range. If
874 the function fails, some or all of the components remain unassigned. */
871bool 875bool
872parse_color_spec (const char *s, 876parse_color_spec (const char *spec,
873 unsigned short *r, unsigned short *g, unsigned short *b) 877 unsigned short *r, unsigned short *g, unsigned short *b)
874{ 878{
875 int len = strlen (s); 879 int len = strlen (spec);
876 if (s[0] == '#') 880 if (spec[0] == '#')
877 { 881 {
878 if ((len - 1) % 3 == 0) 882 if ((len - 1) % 3 == 0)
879 { 883 {
880 int n = (len - 1) / 3; 884 int n = (len - 1) / 3;
881 return ( parse_hex_color_comp (s + 1 + 0 * n, s + 1 + 1 * n, r) 885 return ( parse_hex_color_comp (spec + 1 + 0 * n,
882 && parse_hex_color_comp (s + 1 + 1 * n, s + 1 + 2 * n, g) 886 spec + 1 + 1 * n, r)
883 && parse_hex_color_comp (s + 1 + 2 * n, s + 1 + 3 * n, b)); 887 && parse_hex_color_comp (spec + 1 + 1 * n,
888 spec + 1 + 2 * n, g)
889 && parse_hex_color_comp (spec + 1 + 2 * n,
890 spec + 1 + 3 * n, b));
884 } 891 }
885 } 892 }
886 else if (strncmp (s, "rgb:", 4) == 0) 893 else if (strncmp (spec, "rgb:", 4) == 0)
887 { 894 {
888 char *sep1, *sep2; 895 char *sep1, *sep2;
889 return ((sep1 = strchr (s + 4, '/')) != NULL 896 return ((sep1 = strchr (spec + 4, '/')) != NULL
890 && (sep2 = strchr (sep1 + 1, '/')) != NULL 897 && (sep2 = strchr (sep1 + 1, '/')) != NULL
891 && parse_hex_color_comp (s + 4, sep1, r) 898 && parse_hex_color_comp (spec + 4, sep1, r)
892 && parse_hex_color_comp (sep1 + 1, sep2, g) 899 && parse_hex_color_comp (sep1 + 1, sep2, g)
893 && parse_hex_color_comp (sep2 + 1, s + len, b)); 900 && parse_hex_color_comp (sep2 + 1, spec + len, b));
894 } 901 }
895 else if (strncmp (s, "rgbi:", 5) == 0) 902 else if (strncmp (spec, "rgbi:", 5) == 0)
896 { 903 {
897 char *sep1, *sep2; 904 char *sep1, *sep2;
898 double red, green, blue; 905 double red, green, blue;
899 if ((sep1 = strchr (s + 5, '/')) != NULL 906 if ((sep1 = strchr (spec + 5, '/')) != NULL
900 && (sep2 = strchr (sep1 + 1, '/')) != NULL 907 && (sep2 = strchr (sep1 + 1, '/')) != NULL
901 && (red = parse_float_color_comp (s + 5, sep1)) >= 0 908 && (red = parse_float_color_comp (spec + 5, sep1)) >= 0
902 && (green = parse_float_color_comp (sep1 + 1, sep2)) >= 0 909 && (green = parse_float_color_comp (sep1 + 1, sep2)) >= 0
903 && (blue = parse_float_color_comp (sep2 + 1, s + len)) >= 0) 910 && (blue = parse_float_color_comp (sep2 + 1, spec + len)) >= 0)
904 { 911 {
905 *r = lrint (red * 65535); 912 *r = lrint (red * 65535);
906 *g = lrint (green * 65535); 913 *g = lrint (green * 65535);
@@ -911,25 +918,26 @@ parse_color_spec (const char *s,
911 return false; 918 return false;
912} 919}
913 920
914DEFUN ("internal-color-values-from-color-spec", 921DEFUN ("color-values-from-color-spec",
915 Finternal_color_values_from_color_spec, 922 Fcolor_values_from_color_spec,
916 Sinternal_color_values_from_color_spec, 923 Scolor_values_from_color_spec,
917 1, 1, 0, 924 1, 1, 0,
918 doc: /* Parse STRING as a numeric color and return (RED GREEN BLUE). 925 doc: /* Parse color SPEC as a numeric color and return (RED GREEN BLUE).
919Recognised formats for STRING are: 926This function recognises the following formats for SPEC:
927
928 #RGB, where R, G and B are hex numbers of equal length, 1-4 digits each.
929 rgb:R/G/B, where R, G, and B are hex numbers, 1-4 digits each.
930 rgbi:R/G/B, where R, G and B are floating-point numbers in [0,1].
920 931
921 #RGB, where R, G and B are hex numbers of equal length, 1-4 digits each 932If SPEC is not in one of the above forms, return nil.
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 933
925The result is normalized to a maximum value of 65535 per component, 934Each of the 3 integer members of the resulting list, RED, GREEN, and BLUE,
926forming a list of three integers in [0,65535]. 935is normalized to have its value in [0,65535]. */)
927If STRING is not in one of the above forms, return nil. */) 936 (Lisp_Object spec)
928 (Lisp_Object string)
929{ 937{
930 CHECK_STRING (string); 938 CHECK_STRING (spec);
931 unsigned short r, g, b; 939 unsigned short r, g, b;
932 return (parse_color_spec (SSDATA (string), &r, &g, &b) 940 return (parse_color_spec (SSDATA (spec), &r, &g, &b)
933 ? list3i (r, g, b) 941 ? list3i (r, g, b)
934 : Qnil); 942 : Qnil);
935} 943}
@@ -7133,5 +7141,5 @@ clear the face cache, see `clear-face-cache'. */);
7133 defsubr (&Sinternal_face_x_get_resource); 7141 defsubr (&Sinternal_face_x_get_resource);
7134 defsubr (&Sx_family_fonts); 7142 defsubr (&Sx_family_fonts);
7135#endif 7143#endif
7136 defsubr (&Sinternal_color_values_from_color_spec); 7144 defsubr (&Scolor_values_from_color_spec);
7137} 7145}
diff --git a/test/src/xfaces-tests.el b/test/src/xfaces-tests.el
index 34cda07e5b4..bde3a354229 100644
--- a/test/src/xfaces-tests.el
+++ b/test/src/xfaces-tests.el
@@ -25,26 +25,26 @@
25 (color-distance "#ffffff" "#222222")))) 25 (color-distance "#ffffff" "#222222"))))
26 26
27(ert-deftest xfaces-internal-color-values-from-color-spec () 27(ert-deftest xfaces-internal-color-values-from-color-spec ()
28 (should (equal (internal-color-values-from-color-spec "#f05") 28 (should (equal (color-values-from-color-spec "#f05")
29 '(#xffff #x0000 #x5555))) 29 '(#xffff #x0000 #x5555)))
30 (should (equal (internal-color-values-from-color-spec "#1fb0C5") 30 (should (equal (color-values-from-color-spec "#1fb0C5")
31 '(#x1f1f #xb0b0 #xc5c5))) 31 '(#x1f1f #xb0b0 #xc5c5)))
32 (should (equal (internal-color-values-from-color-spec "#1f8b0AC5e") 32 (should (equal (color-values-from-color-spec "#1f8b0AC5e")
33 '(#x1f81 #xb0aa #xc5eb))) 33 '(#x1f81 #xb0aa #xc5eb)))
34 (should (equal (internal-color-values-from-color-spec "#1f83b0ADC5e2") 34 (should (equal (color-values-from-color-spec "#1f83b0ADC5e2")
35 '(#x1f83 #xb0ad #xc5e2))) 35 '(#x1f83 #xb0ad #xc5e2)))
36 (should (equal (internal-color-values-from-color-spec "#1f83b0ADC5e2g") nil)) 36 (should (equal (color-values-from-color-spec "#1f83b0ADC5e2g") nil))
37 (should (equal (internal-color-values-from-color-spec "#1f83b0ADC5e20") nil)) 37 (should (equal (color-values-from-color-spec "#1f83b0ADC5e20") nil))
38 (should (equal (internal-color-values-from-color-spec "#12345") nil)) 38 (should (equal (color-values-from-color-spec "#12345") nil))
39 (should (equal (internal-color-values-from-color-spec "rgb:f/23/28a") 39 (should (equal (color-values-from-color-spec "rgb:f/23/28a")
40 '(#xffff #x2323 #x28a2))) 40 '(#xffff #x2323 #x28a2)))
41 (should (equal (internal-color-values-from-color-spec "rgb:1234/5678/09ab") 41 (should (equal (color-values-from-color-spec "rgb:1234/5678/09ab")
42 '(#x1234 #x5678 #x09ab))) 42 '(#x1234 #x5678 #x09ab)))
43 (should (equal (internal-color-values-from-color-spec "rgb:0//0") nil)) 43 (should (equal (color-values-from-color-spec "rgb:0//0") nil))
44 (should (equal (internal-color-values-from-color-spec "rgbi:0/0.5/0.1") 44 (should (equal (color-values-from-color-spec "rgbi:0/0.5/0.1")
45 '(0 32768 6554))) 45 '(0 32768 6554)))
46 (should (equal (internal-color-values-from-color-spec "rgbi:1e-3/1.0e-2/1e0") 46 (should (equal (color-values-from-color-spec "rgbi:1e-3/1.0e-2/1e0")
47 '(66 655 65535))) 47 '(66 655 65535)))
48 (should (equal (internal-color-values-from-color-spec "rgbi:0/0.5/10") nil))) 48 (should (equal (color-values-from-color-spec "rgbi:0/0.5/10") nil)))
49 49
50(provide 'xfaces-tests) 50(provide 'xfaces-tests)