Skip to content

Commit

Permalink
Update specs for sass/sass#3497 (#1919)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Mar 23, 2023
1 parent e5aa642 commit 216ceb7
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 65 deletions.
17 changes: 12 additions & 5 deletions lib/src/functions/color.dart
Expand Up @@ -614,11 +614,6 @@ Value _invert(List<Value> arguments) {
}

if (fuzzyEquals(weight, 1)) return inverted;
if (!InterpolationMethod.supportedSpaces.contains(space)) {
throw SassScriptException(
"Color space $space can't be used for interpolation.", "space");
}

return color.interpolate(inverted, InterpolationMethod(space),
weight: 1 - weight);
}
Expand Down Expand Up @@ -1290,6 +1285,18 @@ SassColor _colorFromChannels(ColorSpace space, SassNumber? channel0,
alpha,
fromRgbFunction ? ColorFormat.rgbFunction : null);

case ColorSpace.lab:
case ColorSpace.lch:
case ColorSpace.oklab:
case ColorSpace.oklch:
return SassColor.forSpaceInternal(
space,
_channelFromValue(space.channels[0], channel0)
.andThen((lightness) => fuzzyClamp(lightness, 0, 100)),
_channelFromValue(space.channels[1], channel1),
_channelFromValue(space.channels[2], channel2),
alpha);

default:
return SassColor.forSpaceInternal(
space,
Expand Down
75 changes: 53 additions & 22 deletions lib/src/value/color.dart
Expand Up @@ -123,7 +123,7 @@ class SassColor extends Value {
case ColorSpace.oklab:
case ColorSpace.lch:
case ColorSpace.oklch:
return fuzzyEquals(channel0, 0);
return fuzzyEquals(channel0, 0) || fuzzyEquals(channel0, 100);

default:
return false;
Expand Down Expand Up @@ -156,11 +156,13 @@ class SassColor extends Value {
switch (space) {
case ColorSpace.lab:
case ColorSpace.oklab:
return fuzzyEquals(channel0, 0);
return fuzzyEquals(channel0, 0) || fuzzyEquals(channel0, 100);

case ColorSpace.lch:
case ColorSpace.oklch:
return fuzzyEquals(channel0, 0) || fuzzyEquals(channel1, 0);
return fuzzyEquals(channel0, 0) ||
fuzzyEquals(channel0, 100) ||
fuzzyEquals(channel1, 0);

default:
return false;
Expand Down Expand Up @@ -285,7 +287,7 @@ class SassColor extends Value {
[num? alpha]) =>
SassColor.forSpaceInternal(
ColorSpace.hsl,
hue?.toDouble(),
_normalizeHue(hue?.toDouble()),
saturation.andThen((saturation) =>
fuzzyAssertRange(saturation.toDouble(), 0, 100, "saturation")),
lightness.andThen((lightness) =>
Expand All @@ -299,7 +301,7 @@ class SassColor extends Value {
[num? alpha]) =>
SassColor.forSpaceInternal(
ColorSpace.hwb,
hue?.toDouble(),
_normalizeHue(hue?.toDouble()),
whiteness.andThen((whiteness) =>
fuzzyAssertRange(whiteness.toDouble(), 0, 100, "whiteness")),
blackness.andThen((blackness) =>
Expand Down Expand Up @@ -367,29 +369,52 @@ class SassColor extends Value {
/// Throws a [RangeError] if [alpha] isn't between `0` and `1`.
factory SassColor.lab(double? lightness, double? a, double? b,
[double? alpha]) =>
SassColor.forSpaceInternal(ColorSpace.lab, lightness, a, b, alpha);
SassColor.forSpaceInternal(
ColorSpace.lab,
lightness.andThen(
(lightness) => fuzzyAssertRange(lightness, 0, 100, "lightness")),
a,
b,
alpha);

/// Creates a color in [ColorSpace.lch].
///
/// Throws a [RangeError] if [alpha] isn't between `0` and `1`.
factory SassColor.lch(double? lightness, double? chroma, double? hue,
[double? alpha]) =>
SassColor.forSpaceInternal(ColorSpace.lch, lightness, chroma, hue, alpha);
SassColor.forSpaceInternal(
ColorSpace.lch,
lightness.andThen(
(lightness) => fuzzyAssertRange(lightness, 0, 100, "lightness")),
chroma,
_normalizeHue(hue),
alpha);

/// Creates a color in [ColorSpace.oklab].
///
/// Throws a [RangeError] if [alpha] isn't between `0` and `1`.
factory SassColor.oklab(double? lightness, double? a, double? b,
[double? alpha]) =>
SassColor.forSpaceInternal(ColorSpace.oklab, lightness, a, b, alpha);
SassColor.forSpaceInternal(
ColorSpace.oklab,
lightness.andThen(
(lightness) => fuzzyAssertRange(lightness, 0, 100, "lightness")),
a,
b,
alpha);

/// Creates a color in [ColorSpace.oklch].
///
/// Throws a [RangeError] if [alpha] isn't between `0` and `1`.
factory SassColor.oklch(double? lightness, double? chroma, double? hue,
[double? alpha]) =>
SassColor.forSpaceInternal(
ColorSpace.oklch, lightness, chroma, hue, alpha);
ColorSpace.oklch,
lightness.andThen(
(lightness) => fuzzyAssertRange(lightness, 0, 100, "lightness")),
chroma,
_normalizeHue(hue),
alpha);

/// Creates a color in the color space named [space].
///
Expand All @@ -401,14 +426,17 @@ class SassColor extends Value {
throw RangeError.value(channels.length, "channels.length",
'must be exactly ${space.channels.length} for color space "$space"');
} else {
var clampChannels = space == ColorSpace.hsl || space == ColorSpace.hwb;
var clampChannel0 = space.channels[0].name == "lightness";
var clampChannel12 = space == ColorSpace.hsl || space == ColorSpace.hwb;
return SassColor.forSpaceInternal(
space,
channels[0],
clampChannels
clampChannel0
? channels[0].andThen((value) => fuzzyClamp(value, 0, 100))
: channels[0],
clampChannel12
? channels[1].andThen((value) => fuzzyClamp(value, 0, 100))
: channels[1],
clampChannels
clampChannel12
? channels[2].andThen((value) => fuzzyClamp(value, 0, 100))
: channels[2],
alpha);
Expand All @@ -432,6 +460,12 @@ class SassColor extends Value {
"[BUG] Tried to create "
"$_space(${channel0OrNull ?? 'none'}, ${channel1OrNull ?? 'none'}, "
"${channel2OrNull ?? 'none'})");
assert(
space.channels[0].name != "lightness" ||
fuzzyCheckRange(channel0, 0, 100) != null,
"[BUG] Tried to create "
"$_space(${channel0OrNull ?? 'none'}, ${channel1OrNull ?? 'none'}, "
"${channel2OrNull ?? 'none'})");
assert(space != ColorSpace.lms);

_checkChannel(channel0OrNull, space.channels[0].name);
Expand All @@ -449,6 +483,12 @@ class SassColor extends Value {
}
}

/// If [hue] isn't null, normalizes it to the range `[0, 360)`.
static double? _normalizeHue(double? hue) {
if (hue == null) return hue;
return (hue % 360 + 360) % 360;
}

/// @nodoc
@internal
T accept<T>(ValueVisitor<T> visitor) => visitor.visitColor(this);
Expand Down Expand Up @@ -894,11 +934,6 @@ class SassColor extends Value {
double _interpolateHues(
double hue1, double hue2, HueInterpolationMethod method, double weight) {
// Algorithms from https://www.w3.org/TR/css-color-4/#hue-interpolation
if (method != HueInterpolationMethod.specified) {
hue1 = (hue1 % 360 + 360) % 360;
hue2 = (hue2 % 360 + 360) % 360;
}

switch (method) {
case HueInterpolationMethod.shorter:
var difference = hue2 - hue1;
Expand All @@ -925,10 +960,6 @@ class SassColor extends Value {
case HueInterpolationMethod.decreasing:
if (hue1 < hue2) hue1 += 360;
break;

case HueInterpolationMethod.specified:
// Use the hues as-is.
break;
}

return hue1 * weight + hue2 * (1 - weight);
Expand Down
40 changes: 2 additions & 38 deletions lib/src/value/color/interpolation_method.dart
Expand Up @@ -2,8 +2,6 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'package:meta/meta.dart';

import '../../exception.dart';
import '../../value.dart';

Expand All @@ -14,23 +12,6 @@ import '../../value.dart';
///
/// {@category Value}
class InterpolationMethod {
/// The set of color spaces that can be used for color interpolation.
///
/// @nodoc
@internal
static const supportedSpaces = {
ColorSpace.srgb,
ColorSpace.srgbLinear,
ColorSpace.lab,
ColorSpace.oklab,
ColorSpace.xyzD50,
ColorSpace.xyzD65,
ColorSpace.hsl,
ColorSpace.hwb,
ColorSpace.lch,
ColorSpace.oklch
};

/// The color space in which to perform the interpolation.
final ColorSpace space;

Expand All @@ -41,10 +22,7 @@ class InterpolationMethod {

InterpolationMethod(this.space, [HueInterpolationMethod? hue])
: hue = space.isPolar ? hue ?? HueInterpolationMethod.shorter : null {
if (!supportedSpaces.contains(space)) {
throw ArgumentError(
"Color space $space can't be used for interpolation.");
} else if (!space.isPolar && hue != null) {
if (!space.isPolar && hue != null) {
throw ArgumentError(
"Hue interpolation method may not be set for rectangular color space "
"$space.");
Expand All @@ -66,11 +44,6 @@ class InterpolationMethod {

var space = ColorSpace.fromName(
(list.first.assertString(name)..assertUnquoted(name)).text, name);
if (!supportedSpaces.contains(space)) {
throw SassScriptException(
"Color space $space can't be used for interpolation.", name);
}

if (list.length == 1) return InterpolationMethod(space);

var hueMethod = HueInterpolationMethod._fromValue(list[1], name);
Expand Down Expand Up @@ -124,14 +97,7 @@ enum HueInterpolationMethod {
/// Angles are adjusted so that `θ₂ - θ₁ ∈ (-360, 0]`.
///
/// https://www.w3.org/TR/css-color-4/#hue-decreasing
decreasing,

/// No fixup is performed.
///
/// Angles are interpolated in the same way as every other component.
///
/// https://www.w3.org/TR/css-color-4/#hue-specified
specified;
decreasing;

/// Parses a SassScript value representing a hue interpolation method, not
/// ending with "hue".
Expand All @@ -150,8 +116,6 @@ enum HueInterpolationMethod {
return HueInterpolationMethod.increasing;
case 'decreasing':
return HueInterpolationMethod.decreasing;
case 'specified':
return HueInterpolationMethod.specified;
default:
throw SassScriptException(
'Unknown hue interpolation method $value.', name);
Expand Down

0 comments on commit 216ceb7

Please sign in to comment.