Skip to content

Commit

Permalink
[css-color] move color interpolation from color-5 to color-4, see #5883
Browse files Browse the repository at this point in the history
  • Loading branch information
svgeesus committed Jan 28, 2021
1 parent dd01b5d commit 09bc009
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 162 deletions.
164 changes: 164 additions & 0 deletions css-color-4/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -4353,6 +4353,170 @@ Simple alpha compositing</h3>
When drawing, implementations must handle alpha
according to the rules in <a href="https://www.w3.org/TR/compositing-1/#simplealphacompositing">Section 5.1 Simple alpha compositing</a> of [[!Compositing]].

Interpolation {#interpolation}
===================================

Color interpolation happens with
gradients,
compositing,
filters,
transitions,
animations, and
color mixing and color modification functions.

In general, interpolation between <<color>> values of the same [=colorspace=]
occurs by linearly interpolating each component of the computed value of the color
separately, in that colorspace.
This provides Web compatibility; legacy sRGB content interpolates in the sRGB space by default.


Interpolating to or from ''<color>/currentcolor'' is possible.
The numerical value used for this purpose is the used value.

ISSUE: Computed value needs to be able to represent
combinations of ''currentColor'' and an actual color.
Consider the value of 'text-emphasis-color' in
<code>div { text-emphasis: circle; transition: all 2s; }<br>
div:hover { text-emphasis-color: lime; }<br>
em { color: red; }</code>
See <a href="https://github.com/w3c/csswg-drafts/issues/445">Issue 445</a>.

Color space for interpolation {#interpolation-space}
------------------------------

Issue: Should gamut mapping occur before or after interpolation?

If colors are not in the same color space,
they are first converted to Lab
and then interpolated as Lab colors.
Host syntax can override the interpolation color space and specify which color space is used for interpolation.
For example, 'color-mix' and 'color-adjust' override the default to LCH.


Interpolating with alpha {#interpolation-alpha}
------------------------

When the colors to be interpolated are not fully opaque,
they are transformed into <dfn export>premultiplied color values</dfn>
as follows:

* For [=rectangular orthogonal color=] coordinate systems,
all component values are multiplied by the alpha value
* For [=cylindrical polar color=] coordinate systems,
the hue angle is not premultiplied,
but the other two axes are premultiplied.

To obtain a color value from a premultipled color value,
each component which had been premultiplied
is divided by the interpolated alpha value.

<div class="example" id="ex-premultiplied-srgb">
For example, to interpolate the two sRGB colors
<span class="swatch" style="--color: rgb(24%, 12%, 98%, 0.4)"></span> rgb(24% 12% 98% / 0.4)
and
<span class="swatch" style="--color: rgb(62% 26% 64% / 0.6)"></span> rgb(62% 26% 64% / 0.6)
they would first be converted to premultiplied form
[9.6% 4.8% 39.2% ]
and
[37.2% 15.6% 38.4%]
before interpolation.

The midpoint of linearly interpolating these colors
would be [23.4% 10.2% 38.8%]
which, with an alpha value of 0.5,
is <span class="swatch" style="--color: rgb(46.8%, 21.4%, 77.6%, 0.5)"></span> rgb(46.8% 20.4% 77.6% / 0.5)
when premultiplication is undone.
</div>

<div class="example" id="ex-premultiplied-lab">
To interpolate two colors in lab
<span class="swatch" style="--color: rgb(76%, 62%, 03%, 0.4)"></span> rgb(76% 62% 03% / 0.4)
and
<span class="swatch" style="--color: rgb(91.56%, 3.87%, 74.09%, 0.6)"></span> color(display-p3 0.84 0.19 0.72 / 0.6)
they are first converted to lab
<span class="swatch" style="--color: rgb(76%, 62%, 03%, 0.4)"></span> lab(66.927% 4.873 68.622 / 0.4)
<span class="swatch" style="--color: rgb(91.56%, 3.87%, 74.09%, 0.6)"></span> lab(53.503% 82.672 -33.901 / 0.6)
then the L, a and b coordinates are premultiplied before interpolation
[26.771% 1.949 27.449]
and
[32.102% 49.603 -20.341].

The midpoint of linearly interpolating these would be
[29.4365% 25.776 3.554]
which, with an alpha value of 0.5,
is <span class="swatch" style="--color: rgb(87.604%, 38.956%, 51.753%, 0.5)"></span> lab(58.873% 51.552 7.108) / 0.5)
when premultiplication is undone.
</div>

Issue(445):

Hue interpolation {#hue-interpolation}
-------------------

Issue(4928): How to handle achromatic interpolation?

For color functions with a hue angle (LCH, HSL, HWB etc), there are multiple ways to interpolate.
We typically want to avoid arcs over 360 for the difference between the angles, as they are rarely desirable,
so in most cases angles are fixed up prior to interpolation so that per-component interpolation is done over less than 360 degrees, often less than 180.

Host syntax can specify any of the following algorithms for hue interpolation
(angles in the following are in degrees, but the logic is the same regardless of how they are specified).

Unless the type of hue interpolation is ''specified'', both angles need to be constrained to [0, 360) prior to interpolation.
One way to do this is <code><i>θ</i> = ((<i>θ</i> % 360) + 360) % 360</code>.

: ''shorter''
:: Angles are adjusted so that θ₂ - θ₁ ∈ [-180, 180]. In pseudo-Javascript:
<pre>
if (θ₂ - θ₁ > 180) {
θ₁ += 360;
}
else if (θ₂ - θ₁ < -180) {
θ₂ += 360;
}
</pre>

: ''longer''
:: Angles are adjusted so that |θ₂ - θ₁| ∈ {0, [180, 360)}. In pseudo-Javascript:
<pre>
if (0 < θ₂ - θ₁ < 180) {
θ₁ += 360;
}
else if (-180 < θ₂ - θ₁ < 0) {
θ₂ += 360;
}
</pre>

: ''increasing''
:: Angles are adjusted so that θ₂ - θ₁ ∈ [0, 360). In pseudo-Javascript:
<pre>
if (θ₂ < θ₁) {
θ₂ += 360;
}
</pre>

: ''decreasing''
:: Angles are adjusted so that θ₂ - θ₁ ∈ (-360, 0]. In pseudo-Javascript:
<pre>
if (θ₁ < θ₂) {
θ₁ += 360;
}
</pre>

: ''specified''
:: No fixup is performed. Angles are interpolated in the same way as every other component.

Unless otherwise specified, if no specific hue interpolation algorithm is selected by the host syntax, the default is ''shorter''.

If one of the angles has the value NaN,
then for interpolation, NaN is replaced
by the value of the other hue angle.
If both angles have the value NaN,
then for interpolation, NaN is replaced
by the value 0 for both angles.

Issue(5277): How do these work when interpolating between multiple colors?


<h2 id="sample">
Default Style Rules</h2>
Expand Down
162 changes: 0 additions & 162 deletions css-color-5/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -746,169 +746,7 @@ When an origin color is present, the following keywords can also be used in this
</pre>
</div>

Interpolation {#interpolation}
===================================

Color interpolation happens with
gradients,
compositing,
filters,
transitions,
animations, and
color mixing and color modification functions.

In general, interpolation between <<color>> values of the same [=colorspace=]
occurs by linearly interpolating each component of the computed value of the color
separately, in that colorspace.
This provides Web compatibility; legacy sRGB content interpolates in the sRGB space by default.


Interpolating to or from ''<color>/currentcolor'' is possible.
The numerical value used for this purpose is the used value.

ISSUE: Computed value needs to be able to represent
combinations of ''currentColor'' and an actual color.
Consider the value of 'text-emphasis-color' in
<code>div { text-emphasis: circle; transition: all 2s; }<br>
div:hover { text-emphasis-color: lime; }<br>
em { color: red; }</code>
See <a href="https://github.com/w3c/csswg-drafts/issues/445">Issue 445</a>.

Color space for interpolation {#interpolation-space}
------------------------------

Issue: Should gamut mapping occur before or after interpolation?

If colors are not in the same color space,
they are first converted to Lab
and then interpolated as Lab colors.
Host syntax can override the interpolation color space and specify which color space is used for interpolation.
For example, 'color-mix' and 'color-adjust' override the default to LCH.


Interpolating with alpha {#interpolation-alpha}
------------------------

When the colors to be interpolated are not fully opaque,
they are transformed into <dfn export>premultiplied color values</dfn>
as follows:

* For [=rectangular orthogonal color=] coordinate systems,
all component values are multiplied by the alpha value
* For [=cylindrical polar color=] coordinate systems,
the hue angle is not premultiplied,
but the other two axes are premultiplied.

To obtain a color value from a premultipled color value,
each component which had been premultiplied
is divided by the interpolated alpha value.

<div class="example" id="ex-premultiplied-srgb">
For example, to interpolate the two sRGB colors
<span class="swatch" style="--color: rgb(24%, 12%, 98%, 0.4)"></span> rgb(24% 12% 98% / 0.4)
and
<span class="swatch" style="--color: rgb(62% 26% 64% / 0.6)"></span> rgb(62% 26% 64% / 0.6)
they would first be converted to premultiplied form
[9.6% 4.8% 39.2% ]
and
[37.2% 15.6% 38.4%]
before interpolation.

The midpoint of linearly interpolating these colors
would be [23.4% 10.2% 38.8%]
which, with an alpha value of 0.5,
is <span class="swatch" style="--color: rgb(46.8%, 21.4%, 77.6%, 0.5)"></span> rgb(46.8% 20.4% 77.6% / 0.5)
when premultiplication is undone.
</div>

<div class="example" id="ex-premultiplied-lab">
To interpolate two colors in lab
<span class="swatch" style="--color: rgb(76%, 62%, 03%, 0.4)"></span> rgb(76% 62% 03% / 0.4)
and
<span class="swatch" style="--color: rgb(91.56%, 3.87%, 74.09%, 0.6)"></span> color(display-p3 0.84 0.19 0.72 / 0.6)
they are first converted to lab
<span class="swatch" style="--color: rgb(76%, 62%, 03%, 0.4)"></span> lab(66.927% 4.873 68.622 / 0.4)
<span class="swatch" style="--color: rgb(91.56%, 3.87%, 74.09%, 0.6)"></span> lab(53.503% 82.672 -33.901 / 0.6)
then the L, a and b coordinates are premultiplied before interpolation
[26.771% 1.949 27.449]
and
[32.102% 49.603 -20.341].

The midpoint of linearly interpolating these would be
[29.4365% 25.776 3.554]
which, with an alpha value of 0.5,
is <span class="swatch" style="--color: rgb(87.604%, 38.956%, 51.753%, 0.5)"></span> lab(58.873% 51.552 7.108) / 0.5)
when premultiplication is undone.
</div>

Issue(445):

Hue interpolation {#hue-interpolation}
-------------------

Issue(4928): How to handle achromatic interpolation?

For color functions with a hue angle (LCH, HSL, HWB etc), there are multiple ways to interpolate.
We typically want to avoid arcs over 360 for the difference between the angles, as they are rarely desirable,
so in most cases angles are fixed up prior to interpolation so that per-component interpolation is done over less than 360 degrees, often less than 180.

Host syntax can specify any of the following algorithms for hue interpolation
(angles in the following are in degrees, but the logic is the same regardless of how they are specified).

Unless the type of hue interpolation is ''specified'', both angles need to be constrained to [0, 360) prior to interpolation.
One way to do this is <code><i>θ</i> = ((<i>θ</i> % 360) + 360) % 360</code>.

: ''shorter''
:: Angles are adjusted so that θ₂ - θ₁ ∈ [-180, 180]. In pseudo-Javascript:
<pre>
if (θ₂ - θ₁ > 180) {
θ₁ += 360;
}
else if (θ₂ - θ₁ < -180) {
θ₂ += 360;
}
</pre>

: ''longer''
:: Angles are adjusted so that |θ₂ - θ₁| ∈ {0, [180, 360)}. In pseudo-Javascript:
<pre>
if (0 < θ₂ - θ₁ < 180) {
θ₁ += 360;
}
else if (-180 < θ₂ - θ₁ < 0) {
θ₂ += 360;
}
</pre>

: ''increasing''
:: Angles are adjusted so that θ₂ - θ₁ ∈ [0, 360). In pseudo-Javascript:
<pre>
if (θ₂ < θ₁) {
θ₂ += 360;
}
</pre>

: ''decreasing''
:: Angles are adjusted so that θ₂ - θ₁ ∈ (-360, 0]. In pseudo-Javascript:
<pre>
if (θ₁ < θ₂) {
θ₁ += 360;
}
</pre>

: ''specified''
:: No fixup is performed. Angles are interpolated in the same way as every other component.

Unless otherwise specified, if no specific hue interpolation algorithm is selected by the host syntax, the default is ''shorter''.

If one of the angles has the value NaN,
then for interpolation, NaN is replaced
by the value of the other hue angle.
If both angles have the value NaN,
then for interpolation, NaN is replaced
by the value 0 for both angles.

Issue(5277): How do these work when interpolating between multiple colors?

Security and Privacy Considerations {#SecPriv}
===================================
Expand Down

0 comments on commit 09bc009

Please sign in to comment.