Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Color 4] Update color.same() and color equality #2232

Merged
merged 3 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions lib/src/functions/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -504,12 +504,37 @@ 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
) =>
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)
// Use [ColorSpace.convert] manually so that we can convert missing
// channels to 0 without having to create new intermediate color objects.
nex3 marked this conversation as resolved.
Show resolved Hide resolved
: toXyzNoMissing(color1) == toXyzNoMissing(color2));
}),

_function(
Expand Down
11 changes: 11 additions & 0 deletions lib/src/util/number.dart
Original file line number Diff line number Diff line change
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();
}
Goodwine marked this conversation as resolved.
Show resolved Hide resolved

/// 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
Original file line number Diff line number Diff line change
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
Loading