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

Update for oklab() tests #2094

Merged
merged 2 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 14 additions & 11 deletions lib/src/functions/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -476,11 +476,12 @@ final module = BuiltInModule("color", functions: <Callable>[

var channelInfo = color.space.channels[channelIndex];
var channelValue = color.channels[channelIndex];
var unit = channelInfo.associatedUnit;
if (unit == '%') {
channelValue = channelValue * 100 / (channelInfo as LinearChannel).max;
}

return channelInfo is LinearChannel
? SassNumber(channelValue,
channelInfo.min == 0 && channelInfo.max == 100 ? '%' : null)
: SassNumber(channelValue, 'deg');
return SassNumber(channelValue, unit);
}),

_function("same", r"$color1, $color2", (arguments) {
Expand Down Expand Up @@ -1198,7 +1199,8 @@ Value _parseChannels(String functionName, Value input,
var channelName =
space?.channels[channels.indexOf(channel)].name ?? 'channel';
throw SassScriptException(
'Expected $channelName $channel to be a number.', name);
'Expected $channelName channel to be a number, was $channel.',
name);
}
}

Expand Down Expand Up @@ -1346,14 +1348,15 @@ SassColor _colorFromChannels(ColorSpace space, SassNumber? channel0,
alpha,
fromRgbFunction ? ColorFormat.rgbFunction : null);

case ColorSpace.lab:
case ColorSpace.lch:
case ColorSpace.oklab:
case ColorSpace.oklch:
case ColorSpace.lab ||
ColorSpace.lch ||
ColorSpace.oklab ||
ColorSpace.oklch:
return SassColor.forSpaceInternal(
space,
_channelFromValue(space.channels[0], channel0)
.andThen((lightness) => fuzzyClamp(lightness, 0, 100)),
_channelFromValue(space.channels[0], channel0).andThen((lightness) =>
fuzzyClamp(
lightness, 0, (space.channels[0] as LinearChannel).max)),
_channelFromValue(space.channels[1], channel1),
_channelFromValue(space.channels[2], channel2),
alpha);
Expand Down
3 changes: 2 additions & 1 deletion lib/src/value/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,8 @@ class SassColor extends Value {
return SassColor.forSpaceInternal(
space,
clampChannel0
? channels[0].andThen((value) => fuzzyClamp(value, 0, 100))
? channels[0].andThen((value) => fuzzyClamp(
value, 0, (space.channels[0] as LinearChannel).max))
: channels[0],
clampChannel12
? channels[1].andThen((value) => fuzzyClamp(value, 0, 100))
Expand Down
28 changes: 25 additions & 3 deletions lib/src/value/color/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,21 @@ class ColorChannel {
/// This is true if and only if this is not a [LinearChannel].
final bool isPolarAngle;

/// The unit that's associated with this channel.
///
/// Some channels are typically written without units, while others have a
/// specific unit that is conventionally applied to their values. Although any
/// compatible unit or unitless value will work for input¹, this unit is used
/// when the value is serialized or returned from a Sass function.
///
/// 1: Unless [LinearChannel.requiresPercent] is set, in which case unitless
/// values are not allowed.
final String? associatedUnit;

/// @nodoc
@internal
const ColorChannel(this.name, {required this.isPolarAngle});
const ColorChannel(this.name,
{required this.isPolarAngle, this.associatedUnit});

/// Returns whether this channel is [analogous] to [other].
///
Expand Down Expand Up @@ -65,9 +77,19 @@ class LinearChannel extends ColorChannel {
/// forbids unitless values.
final bool requiresPercent;

/// Creates a linear color channel.
///
/// By default, [ColorChannel.associatedUnit] is set to `%` if and only if
/// [min] is 0 and [max] is 100. However, if [conventionallyPercent] is
/// true, it's set to `%`, and if it's false, it's set to null.
///
/// @nodoc
@internal
const LinearChannel(String name, this.min, this.max,
{this.requiresPercent = false})
: super(name, isPolarAngle: false);
{this.requiresPercent = false, bool? conventionallyPercent})
: super(name,
isPolarAngle: false,
associatedUnit: (conventionallyPercent ?? (min == 0 && max == 100))
? '%'
: null);
}
2 changes: 1 addition & 1 deletion lib/src/value/color/space/oklab.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class OklabColorSpace extends ColorSpace {

const OklabColorSpace()
: super('oklab', const [
LinearChannel('lightness', 0, 1),
LinearChannel('lightness', 0, 1, conventionallyPercent: true),
LinearChannel('a', -0.4, 0.4),
LinearChannel('b', -0.4, 0.4)
]);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/value/color/space/oklch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class OklchColorSpace extends ColorSpace {

const OklchColorSpace()
: super('oklch', const [
LinearChannel('lightness', 0, 1),
LinearChannel('lightness', 0, 1, conventionallyPercent: true),
LinearChannel('chroma', 0, 0.4),
hueChannel
]);
Expand Down
3 changes: 2 additions & 1 deletion lib/src/value/color/space/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const labKappa = 24389 / 27; // 29^3/3^3;
const labEpsilon = 216 / 24389; // 6^3/29^3;

/// The hue channel shared across all polar color spaces.
const hueChannel = ColorChannel('hue', isPolarAngle: true);
const hueChannel =
ColorChannel('hue', isPolarAngle: true, associatedUnit: 'deg');

/// The color channels shared across all RGB color spaces (except the legacy RGB space).
const rgbChannels = [
Expand Down
33 changes: 12 additions & 21 deletions lib/src/visitor/serialize.dart
Original file line number Diff line number Diff line change
Expand Up @@ -560,38 +560,29 @@ final class _SerializeVisitor
case ColorSpace.rgb || ColorSpace.hsl || ColorSpace.hwb:
_writeLegacyColor(value);

case ColorSpace.lab || ColorSpace.oklab:
case ColorSpace.lab ||
ColorSpace.oklab ||
ColorSpace.lch ||
ColorSpace.oklch:
_buffer
..write(value.space)
..writeCharCode($lparen);
_writeChannel(value.channel0OrNull);
if (!_isCompressed &&
value.space == ColorSpace.lab &&
!value.isChannel0Missing) {
if (!_isCompressed && !value.isChannel0Missing) {
var max = (value.space.channels[0] as LinearChannel).max;
_writeNumber(value.channel0 * 100 / max);
_buffer.writeCharCode($percent);
} else {
_writeChannel(value.channel0OrNull);
}
_buffer.writeCharCode($space);
_writeChannel(value.channel1OrNull);
_buffer.writeCharCode($space);
_writeChannel(value.channel2OrNull);
_maybeWriteSlashAlpha(value);
_buffer.writeCharCode($rparen);

case ColorSpace.lch || ColorSpace.oklch:
_buffer
..write(value.space)
..writeCharCode($lparen);
_writeChannel(value.channel0OrNull);
if (!_isCompressed &&
value.space == ColorSpace.lch &&
!value.isChannel0Missing) {
_buffer.writeCharCode($percent);
!value.isChannel2Missing &&
value.space.channels[2].isPolarAngle) {
_buffer.write('deg');
}
_buffer.writeCharCode($space);
_writeChannel(value.channel1OrNull);
_buffer.writeCharCode($space);
_writeChannel(value.channel2OrNull);
if (!_isCompressed && !value.isChannel2Missing) _buffer.write('deg');
_maybeWriteSlashAlpha(value);
_buffer.writeCharCode($rparen);

Expand Down