Skip to content

Commit

Permalink
[Color 4] Update color.same() and color equality (#2232)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed May 9, 2024
1 parent f0dc4cd commit 2c92c89
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
38 changes: 32 additions & 6 deletions lib/src/functions/color.dart
Expand Up @@ -504,12 +504,38 @@ final module = BuiltInModule("color", functions: <Callable>[
var color1 = arguments[0].assertColor('color1');
var color2 = arguments[1].assertColor('color2');

// Convert both colors into the same space to compare them. Usually we
// just use color1's space, but since HSL and HWB can't represent
// out-of-gamut colors we use RGB for all legacy color spaces.
var targetSpace = color1.isLegacy ? ColorSpace.rgb : color1.space;
return SassBoolean(
color1.toSpace(targetSpace) == color2.toSpace(targetSpace));
/// Converts [color] to the xyz-d65 space without any mising channels.
SassColor toXyzNoMissing(SassColor color) => switch (color) {
SassColor(space: ColorSpace.xyzD65, hasMissingChannel: false) =>
color,
SassColor(
space: ColorSpace.xyzD65,
:var channel0,
:var channel1,
:var channel2,
:var alpha
) =>
SassColor.xyzD65(channel0, channel1, channel2, alpha),
SassColor(
:var space,
:var channel0,
:var channel1,
:var channel2,
:var alpha
) =>
// Use [ColorSpace.convert] manually so that we can convert missing
// channels to 0 without having to create new intermediate color
// objects.
space.convert(
ColorSpace.xyzD65, channel0, channel1, channel2, alpha)
};

return SassBoolean(color1.space == color2.space
? fuzzyEquals(color1.channel0, color2.channel0) &&
fuzzyEquals(color1.channel1, color2.channel1) &&
fuzzyEquals(color1.channel2, color2.channel2) &&
fuzzyEquals(color1.alpha, color2.alpha)
: toXyzNoMissing(color1) == toXyzNoMissing(color2));
}),

_function(
Expand Down
11 changes: 11 additions & 0 deletions lib/src/util/number.dart
Expand Up @@ -30,6 +30,17 @@ bool fuzzyEquals(num number1, num number2) {
(number2 * _inverseEpsilon).round();
}

/// Like [fuzzyEquals], but allows null values for [number1] and [number2].
///
/// null values are only equal to one another.
bool fuzzyEqualsNullable(num? number1, num? number2) {
if (number1 == number2) return true;
if (number1 == null || number2 == null) return false;
return (number1 - number2).abs() <= _epsilon &&
(number1 * _inverseEpsilon).round() ==
(number2 * _inverseEpsilon).round();
}

/// Returns a hash code for [number] that matches [fuzzyEquals].
int fuzzyHashCode(double number) {
if (!number.isFinite) return number.hashCode;
Expand Down
28 changes: 19 additions & 9 deletions lib/src/value/color.dart
Expand Up @@ -213,6 +213,16 @@ class SassColor extends Value {
_ => true
};

/// Whether this color has any missing channels.
///
/// @nodoc
@internal
bool get hasMissingChannel =>
isChannel0Missing ||
isChannel1Missing ||
isChannel2Missing ||
isAlphaMissing;

/// This color's red channel, between `0` and `255`.
///
/// **Note:** This is rounded to the nearest integer, which may be lossy. Use
Expand Down Expand Up @@ -953,21 +963,21 @@ class SassColor extends Value {

if (isLegacy) {
if (!other.isLegacy) return false;
if (!fuzzyEquals(alpha, other.alpha)) return false;
if (space == ColorSpace.rgb && other.space == ColorSpace.rgb) {
return fuzzyEquals(channel0, other.channel0) &&
fuzzyEquals(channel1, other.channel1) &&
fuzzyEquals(channel2, other.channel2);
if (!fuzzyEqualsNullable(alphaOrNull, other.alphaOrNull)) return false;
if (space == other.space) {
return fuzzyEqualsNullable(channel0OrNull, other.channel0OrNull) &&
fuzzyEqualsNullable(channel1OrNull, other.channel1OrNull) &&
fuzzyEqualsNullable(channel2OrNull, other.channel2OrNull);
} else {
return toSpace(ColorSpace.rgb) == other.toSpace(ColorSpace.rgb);
}
}

return space == other.space &&
fuzzyEquals(channel0, other.channel0) &&
fuzzyEquals(channel1, other.channel1) &&
fuzzyEquals(channel2, other.channel2) &&
fuzzyEquals(alpha, other.alpha);
fuzzyEqualsNullable(channel0OrNull, other.channel0OrNull) &&
fuzzyEqualsNullable(channel1OrNull, other.channel1OrNull) &&
fuzzyEqualsNullable(channel2OrNull, other.channel2OrNull) &&
fuzzyEqualsNullable(alphaOrNull, other.alphaOrNull);
}

int get hashCode {
Expand Down

0 comments on commit 2c92c89

Please sign in to comment.