Use the CSS convention for #RGB colors (bug#36304)
* src/xterm.c (x_parse_color): Change interpretation of #RGB color triplets to match CSS rather than X conventions. * lisp/term/tty-colors.el (tty-color-standard-values): Change interpretation of #RGB color triplets to match CSS rather than X conventions. Allow upper-case digits. Fix rgb:R/G/B interpretation. * doc/emacs/display.texi (Colors): Specify the convention used for "#RGB" color triplets. * test/lisp/tty-colors-tests.el: New file. * etc/NEWS: Mention the change.
This commit is contained in:
parent
e310843d9d
commit
357399014a
4 changed files with 88 additions and 44 deletions
|
@ -556,14 +556,14 @@ Font Lock mode.
|
|||
|
||||
@node Colors
|
||||
@section Colors for Faces
|
||||
@cindex color name
|
||||
@cindex RGB triplet
|
||||
|
||||
Faces can have various foreground and background colors. When you
|
||||
specify a color for a face---for instance, when customizing the face
|
||||
(@pxref{Face Customization})---you can use either a @dfn{color name}
|
||||
or an @dfn{RGB triplet}.
|
||||
|
||||
@subsection Color Names
|
||||
@cindex color name
|
||||
@findex list-colors-display
|
||||
@vindex list-colors-sort
|
||||
A color name is a pre-defined name, such as @samp{dark orange} or
|
||||
|
@ -578,12 +578,16 @@ such terminals. However, Emacs understands X11 color names even on
|
|||
text terminals; if a face is given a color specified by an X11 color
|
||||
name, it is displayed using the closest-matching terminal color.
|
||||
|
||||
@subsection RGB Triplets
|
||||
@cindex RGB triplet
|
||||
An RGB triplet is a string of the form @samp{#RRGGBB}. Each of the
|
||||
R, G, and B components is a hexadecimal number specifying the
|
||||
component's relative intensity, one to four digits long (usually two
|
||||
digits are used). The components must have the same number of digits.
|
||||
For hexadecimal values A to F, either upper or lower case are
|
||||
acceptable.
|
||||
primary color components is represented by a hexadecimal number
|
||||
between @samp{00} (intensity 0) and @samp{FF} (the maximum intensity).
|
||||
It is also possible to use one, three, or four hex digits for each
|
||||
component, so @samp{red} can be represented as @samp{#F00},
|
||||
@samp{#fff000000}, or @samp{#ffff00000000}. The components must have
|
||||
the same number of digits. For hexadecimal values A to F, either
|
||||
upper or lower case are acceptable.
|
||||
|
||||
The @kbd{M-x list-colors-display} command also shows the equivalent
|
||||
RGB triplet for each named color. For instance, @samp{medium sea
|
||||
|
|
7
etc/NEWS
7
etc/NEWS
|
@ -407,6 +407,12 @@ names in xref buffers.
|
|||
|
||||
** New variable `file-size-function' controls how file sizes are displayed.
|
||||
|
||||
+++
|
||||
** Emacs now interprets RGB triplets like HTML, SVG, and CSS do.
|
||||
|
||||
The X convention previously used differed slightly, particularly for
|
||||
RGB triplets with a single hexadecimal digit per component.
|
||||
|
||||
|
||||
* Editing Changes in Emacs 27.1
|
||||
|
||||
|
@ -1509,7 +1515,6 @@ automatically updates. In the buffer, you can use 's q' or 's e' to
|
|||
signal a thread with quit or error respectively, or get a snapshot
|
||||
backtrace with 'b'.
|
||||
|
||||
|
||||
** thingatpt.el
|
||||
|
||||
---
|
||||
|
|
|
@ -919,57 +919,63 @@ FRAME defaults to the selected frame."
|
|||
The result is a list of integer RGB values--(RED GREEN BLUE).
|
||||
These values range from 0 to 65535; white is (65535 65535 65535).
|
||||
|
||||
The returned value reflects the standard X definition of COLOR,
|
||||
regardless of whether the terminal can display it, so the return value
|
||||
should be the same regardless of what display is being used."
|
||||
The returned value reflects the standard Emacs definition of
|
||||
COLOR (see the info node `(emacs) Colors'), regardless of whether
|
||||
the terminal can display it, so the return value should be the
|
||||
same regardless of what display is being used."
|
||||
(let ((len (length color)))
|
||||
(cond ((and (>= len 4) ;; X-style "#XXYYZZ" color spec
|
||||
(cond ((and (>= len 4) ;; HTML/CSS/SVG-style "#XXYYZZ" color spec
|
||||
(eq (aref color 0) ?#)
|
||||
(member (aref color 1)
|
||||
'(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
|
||||
?a ?b ?c ?d ?e ?f)))
|
||||
;; Translate the string "#XXYYZZ" into a list
|
||||
;; of numbers (XX YY ZZ). If the primary colors
|
||||
;; are specified with less than 4 hex digits,
|
||||
;; the used digits represent the most significant
|
||||
;; bits of the value (e.g. #XYZ = #X000Y000Z000).
|
||||
?a ?b ?c ?d ?e ?f
|
||||
?A ?B ?C ?D ?E ?F)))
|
||||
;; Translate the string "#XXYYZZ" into a list of numbers
|
||||
;; (XX YY ZZ), scaling each to the {0..65535} range. This
|
||||
;; follows the HTML color convention, where both "#fff" and
|
||||
;; "#ffffff" represent the same color, white.
|
||||
(let* ((ndig (/ (- len 1) 3))
|
||||
(maxval (1- (ash 1 (* 4 ndig))))
|
||||
(i1 1)
|
||||
(i2 (+ i1 ndig))
|
||||
(i3 (+ i2 ndig)))
|
||||
(i3 (+ i2 ndig))
|
||||
(i4 (+ i3 ndig)))
|
||||
(list
|
||||
(ash
|
||||
(string-to-number (substring color i1 i2) 16)
|
||||
(* 4 (- 4 ndig)))
|
||||
(ash
|
||||
(string-to-number (substring color i2 i3) 16)
|
||||
(* 4 (- 4 ndig)))
|
||||
(ash
|
||||
(string-to-number (substring color i3) 16)
|
||||
(* 4 (- 4 ndig))))))
|
||||
((and (>= len 9) ;; X-style RGB:xx/yy/zz color spec
|
||||
(/ (* (string-to-number
|
||||
(substring color i1 i2) 16)
|
||||
65535)
|
||||
maxval)
|
||||
(/ (* (string-to-number
|
||||
(substring color i2 i3) 16)
|
||||
65535)
|
||||
maxval)
|
||||
(/ (* (string-to-number
|
||||
(substring color i3 i4) 16)
|
||||
65535)
|
||||
maxval))))
|
||||
((and (>= len 9) ;; X-style rgb:xx/yy/zz color spec
|
||||
(string= (substring color 0 4) "rgb:"))
|
||||
;; Translate the string "RGB:XX/YY/ZZ" into a list
|
||||
;; of numbers (XX YY ZZ). If fewer than 4 hex
|
||||
;; digits are used, they represent the fraction
|
||||
;; of the maximum value (RGB:X/Y/Z = #XXXXYYYYZZZZ).
|
||||
;; Translate the string "rgb:XX/YY/ZZ" into a list of
|
||||
;; numbers (XX YY ZZ), scaling each to the {0..65535}
|
||||
;; range. "rgb:F/F/F" is white.
|
||||
(let* ((ndig (/ (- len 3) 3))
|
||||
(maxval (1- (ash 1 (* 4 (- ndig 1)))))
|
||||
(i1 4)
|
||||
(i2 (+ i1 ndig))
|
||||
(i3 (+ i2 ndig)))
|
||||
(i3 (+ i2 ndig))
|
||||
(i4 (+ i3 ndig)))
|
||||
(list
|
||||
(/ (* (string-to-number
|
||||
(substring color i1 (- i2 1)) 16)
|
||||
255)
|
||||
65535)
|
||||
maxval)
|
||||
(/ (* (string-to-number
|
||||
(substring color i2 (- i3 1)) 16)
|
||||
255)
|
||||
65535)
|
||||
maxval)
|
||||
(/ (* (string-to-number
|
||||
(substring color i3) 16)
|
||||
255)
|
||||
(substring color i3 (1- i4)) 16)
|
||||
65535)
|
||||
maxval))))
|
||||
(t
|
||||
(cdr (assoc color color-name-rgb-alist))))))
|
||||
|
@ -977,9 +983,9 @@ should be the same regardless of what display is being used."
|
|||
(defun tty-color-translate (color &optional frame)
|
||||
"Given a color COLOR, return the index of the corresponding TTY color.
|
||||
|
||||
COLOR must be a string that is either the color's name, or its X-style
|
||||
specification like \"#RRGGBB\" or \"RGB:rr/gg/bb\", where each primary.
|
||||
color can be given with 1 to 4 hex digits.
|
||||
COLOR must be a string that is either the color's name, or its
|
||||
color triplet specification like \"#RRGGBB\" or \"rgb:RR/GG/BB\",
|
||||
where each primary color can be given with 1 to 4 hex digits.
|
||||
|
||||
If COLOR is a color name that is found among supported colors in
|
||||
`tty-color-alist', the associated index is returned. Otherwise, the
|
||||
|
@ -987,7 +993,7 @@ RGB values of the color, either as given by the argument or from
|
|||
looking up the name in `color-name-rgb-alist', are used to find the
|
||||
supported color that is the best approximation for COLOR in the RGB
|
||||
space.
|
||||
If COLOR is neither a valid X RGB specification of the color, nor a
|
||||
If COLOR is neither a valid RGB specification of the color, nor a
|
||||
name of a color in `color-name-rgb-alist', the returned value is nil.
|
||||
|
||||
If FRAME is unspecified or nil, it defaults to the selected frame."
|
||||
|
|
33
src/xterm.c
33
src/xterm.c
|
@ -2381,6 +2381,8 @@ x_query_frame_background_color (struct frame *f, XColor *bgcolor)
|
|||
x_query_colors (f, bgcolor, 1);
|
||||
}
|
||||
|
||||
#define HEX_COLOR_NAME_LENGTH 32
|
||||
|
||||
/* On frame F, translate the color name to RGB values. Use cached
|
||||
information, if possible.
|
||||
|
||||
|
@ -2398,9 +2400,36 @@ Status x_parse_color (struct frame *f, const char *color_name,
|
|||
|
||||
if (color_name[0] == '#')
|
||||
{
|
||||
/* The hex form is parsed directly by XParseColor without
|
||||
/* Don't pass #RGB strings directly to XParseColor, because that
|
||||
follows the X convention of zero-extending each channel
|
||||
value: #f00 means #f00000. We want the convention of scaling
|
||||
channel values, so #f00 means #ff0000, just as it does for
|
||||
HTML, SVG, and CSS.
|
||||
|
||||
So we translate #f00 to rgb:f/0/0, which X handles
|
||||
differently. */
|
||||
char rgb_color_name[HEX_COLOR_NAME_LENGTH];
|
||||
int len = strlen (color_name);
|
||||
int digits_per_channel;
|
||||
if (len == 4)
|
||||
digits_per_channel = 1;
|
||||
else if (len == 7)
|
||||
digits_per_channel = 2;
|
||||
else if (len == 10)
|
||||
digits_per_channel = 3;
|
||||
else if (len == 13)
|
||||
digits_per_channel = 4;
|
||||
else
|
||||
return 0;
|
||||
|
||||
snprintf (rgb_color_name, sizeof rgb_color_name, "rgb:%.*s/%.*s/%.*s",
|
||||
digits_per_channel, color_name + 1,
|
||||
digits_per_channel, color_name + digits_per_channel + 1,
|
||||
digits_per_channel, color_name + 2 * digits_per_channel + 1);
|
||||
|
||||
/* The rgb form is parsed directly by XParseColor without
|
||||
talking to the X server. No need for caching. */
|
||||
return XParseColor (dpy, cmap, color_name, color);
|
||||
return XParseColor (dpy, cmap, rgb_color_name, color);
|
||||
}
|
||||
|
||||
for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
|
||||
|
|
Loading…
Add table
Reference in a new issue