diff options
| author | Eli Zaretskii | 2020-06-22 18:32:01 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2020-06-22 18:32:01 +0300 |
| commit | 30ff2433b16dba2c4e36c6eda6f808c6f2cb46d1 (patch) | |
| tree | fae44fdb6ed9e62a20c0bdb047441bc55f23c771 | |
| parent | bea5eb77b3170203424179274bf26b9ce70de807 (diff) | |
| download | emacs-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/NEWS | 5 | ||||
| -rw-r--r-- | lisp/term/tty-colors.el | 2 | ||||
| -rw-r--r-- | src/xfaces.c | 90 | ||||
| -rw-r--r-- | test/src/xfaces-tests.el | 26 |
4 files changed, 68 insertions, 55 deletions
| @@ -624,6 +624,11 @@ In order for the two functions to behave more consistently, | |||
| 624 | length, and also supports format specifications that include a | 624 | length, and also supports format specifications that include a |
| 625 | truncating precision field, such as '%.2a'. | 625 | truncating precision field, such as '%.2a'. |
| 626 | 626 | ||
| 627 | --- | ||
| 628 | ** New function 'color-values-from-color-spec'. | ||
| 629 | This can be used to parse RGB color specs in several formats and | ||
| 630 | convert 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 | |||
| 923 | COLOR (see the info node `(emacs) Colors'), regardless of whether | 923 | COLOR (see the info node `(emacs) Colors'), regardless of whether |
| 924 | the terminal can display it, so the return value should be the | 924 | the terminal can display it, so the return value should be the |
| 925 | same regardless of what display is being used." | 925 | same 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. */ |
| 827 | static bool | 827 | static bool |
| 828 | parse_hex_color_comp (const char *s, const char *e, unsigned short *dst) | 828 | parse_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. */ | ||
| 854 | static double | 855 | static double |
| 855 | parse_float_color_comp (const char *s, const char *e) | 856 | parse_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. */ | ||
| 871 | bool | 875 | bool |
| 872 | parse_color_spec (const char *s, | 876 | parse_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 | ||
| 914 | DEFUN ("internal-color-values-from-color-spec", | 921 | DEFUN ("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). |
| 919 | Recognised formats for STRING are: | 926 | This 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 | 932 | If 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 | ||
| 925 | The result is normalized to a maximum value of 65535 per component, | 934 | Each of the 3 integer members of the resulting list, RED, GREEN, and BLUE, |
| 926 | forming a list of three integers in [0,65535]. | 935 | is normalized to have its value in [0,65535]. */) |
| 927 | If 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) |