Skip to content

Commit

Permalink
Update for oklab() tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Sep 26, 2023
1 parent 3cf9a34 commit 00aa5e2
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 38 deletions.
22 changes: 12 additions & 10 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 @@ -1346,14 +1347,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 @@ -565,38 +565,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

0 comments on commit 00aa5e2

Please sign in to comment.