sass-embedded 1.77.5 → 1.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +18 -17
- data/README.md +1 -1
- data/exe/sass +2 -10
- data/ext/sass/Rakefile +162 -385
- data/ext/sass/file_utils.rb +75 -0
- data/ext/sass/package.json +1 -1
- data/ext/sass/platform.rb +44 -0
- data/ext/sass/sass-1.100.0.tgz +0 -0
- data/ext/sass/sass_config.rb +183 -0
- data/ext/sass/utils.rb +39 -0
- data/lib/sass/compiler/channel.rb +6 -4
- data/lib/sass/compiler/connection.rb +17 -21
- data/lib/sass/compiler/dispatcher.rb +27 -1
- data/lib/sass/compiler/host/function_registry.rb +6 -6
- data/lib/sass/compiler/host/importer_registry.rb +17 -11
- data/lib/sass/compiler/host/logger_registry.rb +17 -20
- data/lib/sass/compiler/host/protofier.rb +59 -73
- data/lib/sass/compiler/host/struct.rb +36 -0
- data/lib/sass/compiler/host.rb +2 -2
- data/lib/sass/compiler.rb +4 -3
- data/lib/sass/elf.rb +282 -172
- data/lib/sass/embedded/version.rb +1 -1
- data/lib/sass/embedded.rb +2 -41
- data/lib/sass/embedded_protocol.rb +1 -1
- data/{ext → lib}/sass/embedded_sass_pb.rb +3 -5
- data/lib/sass/exception.rb +7 -2
- data/lib/sass/fork_tracker.rb +36 -28
- data/lib/sass/gem_package_importer.rb +19 -0
- data/lib/sass/serializer.rb +5 -11
- data/lib/sass/value/argument_list.rb +0 -8
- data/lib/sass/value/color/channel.rb +79 -0
- data/lib/sass/value/color/conversions.rb +473 -0
- data/lib/sass/value/color/gamut_map_method/clip.rb +45 -0
- data/lib/sass/value/color/gamut_map_method/local_minde.rb +94 -0
- data/lib/sass/value/color/gamut_map_method.rb +45 -0
- data/lib/sass/value/color/interpolation_method.rb +51 -0
- data/lib/sass/value/color/space/a98_rgb.rb +57 -0
- data/lib/sass/value/color/space/display_p3.rb +72 -0
- data/lib/sass/value/color/space/display_p3_linear.rb +72 -0
- data/lib/sass/value/color/space/hsl.rb +65 -0
- data/lib/sass/value/color/space/hwb.rb +70 -0
- data/lib/sass/value/color/space/lab.rb +77 -0
- data/lib/sass/value/color/space/lch.rb +53 -0
- data/lib/sass/value/color/space/lms.rb +129 -0
- data/lib/sass/value/color/space/oklab.rb +66 -0
- data/lib/sass/value/color/space/oklch.rb +54 -0
- data/lib/sass/value/color/space/prophoto_rgb.rb +59 -0
- data/lib/sass/value/color/space/rec2020.rb +69 -0
- data/lib/sass/value/color/space/rgb.rb +52 -0
- data/lib/sass/value/color/space/srgb.rb +140 -0
- data/lib/sass/value/color/space/srgb_linear.rb +72 -0
- data/lib/sass/value/color/space/utils.rb +86 -0
- data/lib/sass/value/color/space/xyz_d50.rb +100 -0
- data/lib/sass/value/color/space/xyz_d65.rb +57 -0
- data/lib/sass/value/color/space.rb +201 -0
- data/lib/sass/value/color.rb +539 -162
- data/lib/sass/value/function.rb +9 -6
- data/lib/sass/value/fuzzy_math.rb +34 -30
- data/lib/sass/value/mixin.rb +5 -2
- data/lib/sass/value/null.rb +1 -1
- data/lib/sass/value/number/unit.rb +5 -4
- data/lib/sass/value/number.rb +15 -17
- data/lib/sass/value/string.rb +1 -1
- data/lib/sass/value.rb +1 -1
- metadata +42 -21
- data/ext/sass/expand-archive.ps1 +0 -1
- data/lib/sass/compiler/host/structifier.rb +0 -37
data/lib/sass/value/color.rb
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'color/channel'
|
|
4
|
+
require_relative 'color/conversions'
|
|
5
|
+
require_relative 'color/gamut_map_method'
|
|
6
|
+
require_relative 'color/interpolation_method'
|
|
7
|
+
require_relative 'color/space'
|
|
8
|
+
|
|
3
9
|
module Sass
|
|
4
10
|
module Value
|
|
5
11
|
# Sass's color type.
|
|
@@ -18,90 +24,150 @@ module Sass
|
|
|
18
24
|
# @param lightness [Numeric]
|
|
19
25
|
# @param whiteness [Numeric]
|
|
20
26
|
# @param blackness [Numeric]
|
|
27
|
+
# @param a [Numeric]
|
|
28
|
+
# @param b [Numeric]
|
|
29
|
+
# @param chroma [Numeric]
|
|
30
|
+
# @param x [Numeric]
|
|
31
|
+
# @param y [Numeric]
|
|
32
|
+
# @param z [Numeric]
|
|
21
33
|
# @param alpha [Numeric]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
# @param space [::String]
|
|
35
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'rgb')
|
|
36
|
+
# @overload initialize(hue: nil, saturation: nil, lightness: nil, alpha: nil, space: 'hsl')
|
|
37
|
+
# @overload initialize(hue: nil, whiteness: nil, blackness: nil, alpha: nil, space: 'hwb')
|
|
38
|
+
# @overload initialize(lightness: nil, a: nil, b: nil, alpha: nil, space: 'lab')
|
|
39
|
+
# @overload initialize(lightness: nil, a: nil, b: nil, alpha: nil, space: 'oklab')
|
|
40
|
+
# @overload initialize(lightness: nil, chroma: nil, hue: nil, alpha: nil, space: 'lch')
|
|
41
|
+
# @overload initialize(lightness: nil, chroma: nil, hue: nil, alpha: nil, space: 'oklch')
|
|
42
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'a98-rgb')
|
|
43
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'display-p3')
|
|
44
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'display-p3-linear')
|
|
45
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'prophoto-rgb')
|
|
46
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'rec2020')
|
|
47
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'srgb')
|
|
48
|
+
# @overload initialize(red: nil, green: nil, blue: nil, alpha: nil, space: 'srgb-linear')
|
|
49
|
+
# @overload initialize(x: nil, y: nil, z: nil, alpha: nil, space: 'xyz')
|
|
50
|
+
# @overload initialize(x: nil, y: nil, z: nil, alpha: nil, space: 'xyz-d50')
|
|
51
|
+
# @overload initialize(x: nil, y: nil, z: nil, alpha: nil, space: 'xyz-d65')
|
|
52
|
+
def initialize(**options)
|
|
53
|
+
unless options.key?(:space)
|
|
54
|
+
options[:space] = case options
|
|
55
|
+
in { red: _, green: _, blue: _ }
|
|
56
|
+
'rgb'
|
|
57
|
+
in { hue: _, saturation: _, lightness: _ }
|
|
58
|
+
'hsl'
|
|
59
|
+
in { hue: _, whiteness: _, blackness: _ }
|
|
60
|
+
'hwb'
|
|
61
|
+
else
|
|
62
|
+
raise Sass::ScriptError.new('No color space found', 'space')
|
|
63
|
+
end
|
|
48
64
|
end
|
|
49
|
-
end
|
|
50
65
|
|
|
51
|
-
|
|
52
|
-
def red
|
|
53
|
-
hsl_to_rgb unless defined?(@red)
|
|
66
|
+
space = Space.from_name(options[:space])
|
|
54
67
|
|
|
55
|
-
|
|
68
|
+
keys = _assert_options(space, options)
|
|
69
|
+
|
|
70
|
+
_initialize_for_space_internal(space,
|
|
71
|
+
options[keys[0]],
|
|
72
|
+
options[keys[1]],
|
|
73
|
+
options[keys[2]],
|
|
74
|
+
options.fetch(:alpha, 1))
|
|
56
75
|
end
|
|
57
76
|
|
|
58
|
-
# @return [
|
|
59
|
-
def
|
|
60
|
-
|
|
77
|
+
# @return [::String]
|
|
78
|
+
def space
|
|
79
|
+
_space.name
|
|
80
|
+
end
|
|
61
81
|
|
|
62
|
-
|
|
82
|
+
# @param space [::String]
|
|
83
|
+
# @return [Color]
|
|
84
|
+
def to_space(space)
|
|
85
|
+
_to_space(Space.from_name(space))
|
|
63
86
|
end
|
|
64
87
|
|
|
65
|
-
# @
|
|
66
|
-
|
|
67
|
-
|
|
88
|
+
# @param space [::String]
|
|
89
|
+
# @return [::Boolean]
|
|
90
|
+
def in_gamut?(space = nil)
|
|
91
|
+
return to_space(space)._in_gamut? unless space.nil?
|
|
68
92
|
|
|
69
|
-
|
|
93
|
+
_in_gamut?
|
|
70
94
|
end
|
|
71
95
|
|
|
72
|
-
# @
|
|
73
|
-
|
|
74
|
-
|
|
96
|
+
# @param method [::String]
|
|
97
|
+
# @param space [::String]
|
|
98
|
+
# @return [Color]
|
|
99
|
+
def to_gamut(method:, space: nil)
|
|
100
|
+
return to_space(space).to_gamut(method:)._to_space(_space) unless space.nil?
|
|
75
101
|
|
|
76
|
-
|
|
102
|
+
_to_gamut(GamutMapMethod.from_name(method, 'method'))
|
|
77
103
|
end
|
|
78
104
|
|
|
79
|
-
# @return [Numeric]
|
|
80
|
-
def
|
|
81
|
-
|
|
105
|
+
# @return [Array<Numeric, nil>]
|
|
106
|
+
def channels_or_nil
|
|
107
|
+
[channel0_or_nil, channel1_or_nil, channel2_or_nil].freeze
|
|
108
|
+
end
|
|
82
109
|
|
|
83
|
-
|
|
110
|
+
# @return [Array<Numeric>]
|
|
111
|
+
def channels
|
|
112
|
+
[channel0, channel1, channel2].freeze
|
|
84
113
|
end
|
|
85
114
|
|
|
115
|
+
# @param channel [::String]
|
|
116
|
+
# @param space [::String]
|
|
86
117
|
# @return [Numeric]
|
|
87
|
-
def
|
|
88
|
-
|
|
118
|
+
def channel(channel, space: nil)
|
|
119
|
+
return to_space(space).channel(channel) unless space.nil?
|
|
120
|
+
|
|
121
|
+
channels = _space.channels
|
|
122
|
+
return channel0 if channel == channels[0].name
|
|
123
|
+
return channel1 if channel == channels[1].name
|
|
124
|
+
return channel2 if channel == channels[2].name
|
|
125
|
+
return alpha if channel == 'alpha'
|
|
89
126
|
|
|
90
|
-
|
|
127
|
+
raise Sass::ScriptError.new("Color #{self} doesn't have a channel named \"#{channel}\".", channel)
|
|
91
128
|
end
|
|
92
129
|
|
|
93
|
-
# @
|
|
94
|
-
|
|
95
|
-
|
|
130
|
+
# @param channel [::String]
|
|
131
|
+
# @return [::Boolean]
|
|
132
|
+
def channel_missing?(channel)
|
|
133
|
+
channels = _space.channels
|
|
134
|
+
return channel0_missing? if channel == channels[0].name
|
|
135
|
+
return channel1_missing? if channel == channels[1].name
|
|
136
|
+
return channel2_missing? if channel == channels[2].name
|
|
137
|
+
return alpha_missing? if channel == 'alpha'
|
|
138
|
+
|
|
139
|
+
raise Sass::ScriptError.new("Color #{self} doesn't have a channel named \"#{channel}\".", channel)
|
|
96
140
|
end
|
|
97
141
|
|
|
98
|
-
# @
|
|
99
|
-
|
|
100
|
-
|
|
142
|
+
# @param channel [::String]
|
|
143
|
+
# @param space [::String]
|
|
144
|
+
# @return [::Boolean]
|
|
145
|
+
def channel_powerless?(channel, space: nil)
|
|
146
|
+
return to_space(space).channel_powerless?(channel) unless space.nil?
|
|
147
|
+
|
|
148
|
+
channels = _space.channels
|
|
149
|
+
return channel0_powerless? if channel == channels[0].name
|
|
150
|
+
return channel1_powerless? if channel == channels[1].name
|
|
151
|
+
return channel2_powerless? if channel == channels[2].name
|
|
152
|
+
return false if channel == 'alpha'
|
|
153
|
+
|
|
154
|
+
raise Sass::ScriptError.new("Color #{self} doesn't have a channel named \"#{channel}\".", channel)
|
|
101
155
|
end
|
|
102
156
|
|
|
103
|
-
# @
|
|
104
|
-
|
|
157
|
+
# @param other [Color]
|
|
158
|
+
# @param method [::String]
|
|
159
|
+
# @param weight [Numeric]
|
|
160
|
+
# @return [Color]
|
|
161
|
+
def interpolate(other, method: nil, weight: nil)
|
|
162
|
+
interpolation_method = if !method.nil?
|
|
163
|
+
InterpolationMethod.new(_space, HueInterpolationMethod.from_name(method))
|
|
164
|
+
elsif !_space.polar?
|
|
165
|
+
InterpolationMethod.new(_space)
|
|
166
|
+
else
|
|
167
|
+
InterpolationMethod.new(_space, :shorter)
|
|
168
|
+
end
|
|
169
|
+
_interpolate(other, interpolation_method, weight:)
|
|
170
|
+
end
|
|
105
171
|
|
|
106
172
|
# @param red [Numeric]
|
|
107
173
|
# @param green [Numeric]
|
|
@@ -111,52 +177,176 @@ module Sass
|
|
|
111
177
|
# @param lightness [Numeric]
|
|
112
178
|
# @param whiteness [Numeric]
|
|
113
179
|
# @param blackness [Numeric]
|
|
180
|
+
# @param a [Numeric]
|
|
181
|
+
# @param b [Numeric]
|
|
182
|
+
# @param chroma [Numeric]
|
|
183
|
+
# @param x [Numeric]
|
|
184
|
+
# @param y [Numeric]
|
|
185
|
+
# @param z [Numeric]
|
|
114
186
|
# @param alpha [Numeric]
|
|
187
|
+
# @param space [::String]
|
|
188
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'rgb')
|
|
189
|
+
# @overload change(hue: nil, saturation: nil, lightness: nil, alpha: nil, space: 'hsl')
|
|
190
|
+
# @overload change(hue: nil, whiteness: nil, blackness: nil, alpha: nil, space: 'hwb')
|
|
191
|
+
# @overload change(lightness: nil, a: nil, b: nil, alpha: nil, space: 'lab')
|
|
192
|
+
# @overload change(lightness: nil, a: nil, b: nil, alpha: nil, space: 'oklab')
|
|
193
|
+
# @overload change(lightness: nil, chroma: nil, hue: nil, alpha: nil, space: 'lch')
|
|
194
|
+
# @overload change(lightness: nil, chroma: nil, hue: nil, alpha: nil, space: 'oklch')
|
|
195
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'a98-rgb')
|
|
196
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'display-p3')
|
|
197
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'display-p3-linear')
|
|
198
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'prophoto-rgb')
|
|
199
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'rec2020')
|
|
200
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'srgb')
|
|
201
|
+
# @overload change(red: nil, green: nil, blue: nil, alpha: nil, space: 'srgb-linear')
|
|
202
|
+
# @overload change(x: nil, y: nil, z: nil, alpha: nil, space: 'xyz')
|
|
203
|
+
# @overload change(x: nil, y: nil, z: nil, alpha: nil, space: 'xyz-d50')
|
|
204
|
+
# @overload change(x: nil, y: nil, z: nil, alpha: nil, space: 'xyz-d65')
|
|
115
205
|
# @return [Color]
|
|
116
|
-
def change(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
alpha: alpha || self.alpha)
|
|
140
|
-
else
|
|
141
|
-
dup.instance_eval do
|
|
142
|
-
@alpha = FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
|
|
143
|
-
self
|
|
206
|
+
def change(**options)
|
|
207
|
+
space_set_explictly = !options[:space].nil?
|
|
208
|
+
space = space_set_explictly ? Space.from_name(options[:space]) : _space
|
|
209
|
+
|
|
210
|
+
if legacy? && !space_set_explictly
|
|
211
|
+
case options
|
|
212
|
+
in { whiteness: _ } | { blackness: _ }
|
|
213
|
+
space = Space::HWB
|
|
214
|
+
in { saturation: _ } | { lightness: _ }
|
|
215
|
+
space = Space::HSL
|
|
216
|
+
in { hue: _ }
|
|
217
|
+
space = if _space == Space::HWB
|
|
218
|
+
Space::HWB
|
|
219
|
+
else
|
|
220
|
+
Space::HSL
|
|
221
|
+
end
|
|
222
|
+
in { red: _ } | { blue: _ } | { green: _ }
|
|
223
|
+
space = Space::RGB
|
|
224
|
+
else
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
if space != _space
|
|
228
|
+
# deprecated
|
|
144
229
|
end
|
|
145
230
|
end
|
|
231
|
+
|
|
232
|
+
keys = _assert_options(space, options)
|
|
233
|
+
|
|
234
|
+
color = _to_space(space)
|
|
235
|
+
|
|
236
|
+
changed_color = if space_set_explictly
|
|
237
|
+
Color.send(:for_space_internal,
|
|
238
|
+
space,
|
|
239
|
+
options.fetch(keys[0], color.channel0_or_nil),
|
|
240
|
+
options.fetch(keys[1], color.channel1_or_nil),
|
|
241
|
+
options.fetch(keys[2], color.channel2_or_nil),
|
|
242
|
+
options.fetch(:alpha, color.alpha_or_nil))
|
|
243
|
+
else
|
|
244
|
+
changed_channel0_or_nil = options[keys[0]]
|
|
245
|
+
changed_channel1_or_nil = options[keys[1]]
|
|
246
|
+
changed_channel2_or_nil = options[keys[2]]
|
|
247
|
+
changed_alpha_or_nil = options[:alpha]
|
|
248
|
+
Color.send(:for_space_internal,
|
|
249
|
+
space,
|
|
250
|
+
changed_channel0_or_nil.nil? ? color.channel0_or_nil : changed_channel0_or_nil,
|
|
251
|
+
changed_channel1_or_nil.nil? ? color.channel1_or_nil : changed_channel1_or_nil,
|
|
252
|
+
changed_channel2_or_nil.nil? ? color.channel2_or_nil : changed_channel2_or_nil,
|
|
253
|
+
changed_alpha_or_nil.nil? ? color.alpha_or_nil : changed_alpha_or_nil)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
changed_color._to_space(_space)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# @return [Numeric]
|
|
260
|
+
def alpha
|
|
261
|
+
@alpha_or_nil.nil? ? 0 : @alpha_or_nil
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# @return [::Boolean]
|
|
265
|
+
def legacy?
|
|
266
|
+
_space.legacy?
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# @deprecated
|
|
270
|
+
# @return [Numeric]
|
|
271
|
+
def red
|
|
272
|
+
_to_space(Space::RGB).channel('red').round
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# @deprecated
|
|
276
|
+
# @return [Numeric]
|
|
277
|
+
def green
|
|
278
|
+
_to_space(Space::RGB).channel('green').round
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# @deprecated
|
|
282
|
+
# @return [Numeric]
|
|
283
|
+
def blue
|
|
284
|
+
_to_space(Space::RGB).channel('blue').round
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# @deprecated
|
|
288
|
+
# @return [Numeric]
|
|
289
|
+
def hue
|
|
290
|
+
_to_space(Space::HSL).channel('hue')
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# @deprecated
|
|
294
|
+
# @return [Numeric]
|
|
295
|
+
def saturation
|
|
296
|
+
_to_space(Space::HSL).channel('saturation')
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# @deprecated
|
|
300
|
+
# @return [Numeric]
|
|
301
|
+
def lightness
|
|
302
|
+
_to_space(Space::HSL).channel('lightness')
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# @deprecated
|
|
306
|
+
# @return [Numeric]
|
|
307
|
+
def whiteness
|
|
308
|
+
_to_space(Space::HWB).channel('whiteness')
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# @deprecated
|
|
312
|
+
# @return [Numeric]
|
|
313
|
+
def blackness
|
|
314
|
+
_to_space(Space::HWB).channel('blackness')
|
|
146
315
|
end
|
|
147
316
|
|
|
148
317
|
# @return [::Boolean]
|
|
149
318
|
def ==(other)
|
|
150
|
-
other.is_a?(Sass::Value::Color)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
other.
|
|
319
|
+
return false unless other.is_a?(Sass::Value::Color)
|
|
320
|
+
|
|
321
|
+
if legacy?
|
|
322
|
+
return false unless other.legacy?
|
|
323
|
+
return false unless FuzzyMath.equals_nilable?(other.alpha_or_nil, alpha_or_nil)
|
|
324
|
+
|
|
325
|
+
if _space == other._space
|
|
326
|
+
FuzzyMath.equals_nilable?(other.channel0_or_nil, channel0_or_nil) &&
|
|
327
|
+
FuzzyMath.equals_nilable?(other.channel1_or_nil, channel1_or_nil) &&
|
|
328
|
+
FuzzyMath.equals_nilable?(other.channel2_or_nil, channel2_or_nil)
|
|
329
|
+
else
|
|
330
|
+
_to_space(Space::RGB) == other._to_space(Space::RGB)
|
|
331
|
+
end
|
|
332
|
+
else
|
|
333
|
+
other._space == _space &&
|
|
334
|
+
FuzzyMath.equals_nilable?(other.channel0_or_nil, channel0_or_nil) &&
|
|
335
|
+
FuzzyMath.equals_nilable?(other.channel1_or_nil, channel1_or_nil) &&
|
|
336
|
+
FuzzyMath.equals_nilable?(other.channel2_or_nil, channel2_or_nil) &&
|
|
337
|
+
FuzzyMath.equals_nilable?(other.alpha_or_nil, alpha_or_nil)
|
|
338
|
+
end
|
|
155
339
|
end
|
|
156
340
|
|
|
157
341
|
# @return [Integer]
|
|
158
342
|
def hash
|
|
159
|
-
@hash ||= [
|
|
343
|
+
@hash ||= [
|
|
344
|
+
_space.name,
|
|
345
|
+
FuzzyMath._hash(channel0_or_nil),
|
|
346
|
+
FuzzyMath._hash(channel1_or_nil),
|
|
347
|
+
FuzzyMath._hash(channel2_or_nil),
|
|
348
|
+
FuzzyMath._hash(alpha_or_nil)
|
|
349
|
+
].hash
|
|
160
350
|
end
|
|
161
351
|
|
|
162
352
|
# @return [Color]
|
|
@@ -164,89 +354,276 @@ module Sass
|
|
|
164
354
|
self
|
|
165
355
|
end
|
|
166
356
|
|
|
357
|
+
protected
|
|
358
|
+
|
|
359
|
+
attr_reader :channel0_or_nil, :channel1_or_nil, :channel2_or_nil, :alpha_or_nil
|
|
360
|
+
|
|
361
|
+
def channel0
|
|
362
|
+
@channel0_or_nil.nil? ? 0 : @channel0_or_nil
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def channel0_missing?
|
|
366
|
+
@channel0_or_nil.nil?
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def channel0_powerless?
|
|
370
|
+
case _space
|
|
371
|
+
when Space::HSL
|
|
372
|
+
FuzzyMath.equals?(channel1, 0)
|
|
373
|
+
when Space::HWB
|
|
374
|
+
FuzzyMath.greater_than_or_equals?(channel1 + channel2, 100)
|
|
375
|
+
else
|
|
376
|
+
false
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def channel1
|
|
381
|
+
@channel1_or_nil.nil? ? 0 : @channel1_or_nil
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def channel1_missing?
|
|
385
|
+
@channel1_or_nil.nil?
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def channel1_powerless?
|
|
389
|
+
false
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def channel2
|
|
393
|
+
@channel2_or_nil.nil? ? 0 : @channel2_or_nil
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def channel2_missing?
|
|
397
|
+
@channel2_or_nil.nil?
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def channel2_powerless?
|
|
401
|
+
case _space
|
|
402
|
+
when Space::LCH, Space::OKLCH
|
|
403
|
+
FuzzyMath.equals?(channel1, 0)
|
|
404
|
+
else
|
|
405
|
+
false
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def alpha_missing?
|
|
410
|
+
@alpha_or_nil.nil?
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def _space
|
|
414
|
+
@space
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def _to_space(space)
|
|
418
|
+
return self if _space == space
|
|
419
|
+
|
|
420
|
+
_space.convert(space, channel0_or_nil, channel1_or_nil, channel2_or_nil, alpha)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def _in_gamut?
|
|
424
|
+
return true unless _space.bounded?
|
|
425
|
+
|
|
426
|
+
_is_channel_in_gamut?(channel0, _space.channels[0]) &&
|
|
427
|
+
_is_channel_in_gamut?(channel1, _space.channels[1]) &&
|
|
428
|
+
_is_channel_in_gamut?(channel2, _space.channels[2])
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def _to_gamut(method)
|
|
432
|
+
_in_gamut? ? self : method.map(self)
|
|
433
|
+
end
|
|
434
|
+
|
|
167
435
|
private
|
|
168
436
|
|
|
169
|
-
def
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
437
|
+
def _assert_options(space, options)
|
|
438
|
+
keys = space.channels.map do |channel|
|
|
439
|
+
channel.name.to_sym
|
|
440
|
+
end << :alpha << :space
|
|
441
|
+
options.each_key do |key|
|
|
442
|
+
unless keys.include?(key)
|
|
443
|
+
raise Sass::ScriptError.new("`#{key}` is not a valid channel in `#{space.name}`.", key)
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
keys
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def _initialize_for_space_internal(space, channel0, channel1, channel2, alpha = 1)
|
|
450
|
+
case space
|
|
451
|
+
when Space::HSL
|
|
452
|
+
_initialize_for_space(
|
|
453
|
+
space,
|
|
454
|
+
_normalize_hue(channel0, invert: !channel1.nil? && FuzzyMath.less_than?(channel1, 0)),
|
|
455
|
+
channel1&.abs,
|
|
456
|
+
channel2,
|
|
457
|
+
alpha
|
|
458
|
+
)
|
|
459
|
+
when Space::HWB
|
|
460
|
+
_initialize_for_space(space, _normalize_hue(channel0, invert: false), channel1, channel2, alpha)
|
|
461
|
+
when Space::LCH, Space::OKLCH
|
|
462
|
+
_initialize_for_space(
|
|
463
|
+
space,
|
|
464
|
+
channel0,
|
|
465
|
+
channel1&.abs,
|
|
466
|
+
_normalize_hue(channel2, invert: !channel1.nil? && FuzzyMath.less_than?(channel1, 0)),
|
|
467
|
+
alpha
|
|
468
|
+
)
|
|
469
|
+
else
|
|
470
|
+
_initialize_for_space(space, channel0, channel1, channel2, alpha)
|
|
186
471
|
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def _initialize_for_space(space, channel0_or_nil, channel1_or_nil, channel2_or_nil, alpha)
|
|
475
|
+
@space = space
|
|
476
|
+
@channel0_or_nil = channel0_or_nil
|
|
477
|
+
@channel1_or_nil = channel1_or_nil
|
|
478
|
+
@channel2_or_nil = channel2_or_nil
|
|
479
|
+
@alpha_or_nil = alpha
|
|
480
|
+
|
|
481
|
+
FuzzyMath.assert_between(@alpha_or_nil, 0, 1, 'alpha') unless @alpha_or_nil.nil?
|
|
482
|
+
end
|
|
187
483
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def hsl_to_rgb
|
|
200
|
-
scaled_hue = Rational(hue, 360)
|
|
201
|
-
scaled_saturation = Rational(saturation, 100)
|
|
202
|
-
scaled_lightness = Rational(lightness, 100)
|
|
203
|
-
|
|
204
|
-
tmp2 = if scaled_lightness <= 0.5
|
|
205
|
-
scaled_lightness * (scaled_saturation + 1)
|
|
206
|
-
else
|
|
207
|
-
scaled_lightness + scaled_saturation - (scaled_lightness * scaled_saturation)
|
|
208
|
-
end
|
|
209
|
-
tmp1 = (scaled_lightness * 2) - tmp2
|
|
210
|
-
@red = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue + Rational(1, 3)) * 255)
|
|
211
|
-
@green = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue) * 255)
|
|
212
|
-
@blue = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue - Rational(1, 3)) * 255)
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def hsl_hue_to_rgb(tmp1, tmp2, hue)
|
|
216
|
-
hue += 1 if hue.negative?
|
|
217
|
-
hue -= 1 if hue > 1
|
|
218
|
-
|
|
219
|
-
if hue < Rational(1, 6)
|
|
220
|
-
tmp1 + ((tmp2 - tmp1) * hue * 6)
|
|
221
|
-
elsif hue < Rational(1, 2)
|
|
222
|
-
tmp2
|
|
223
|
-
elsif hue < Rational(2, 3)
|
|
224
|
-
tmp1 + ((tmp2 - tmp1) * (Rational(2, 3) - hue) * 6)
|
|
484
|
+
def _normalize_hue(hue, invert:)
|
|
485
|
+
return hue if hue.nil?
|
|
486
|
+
|
|
487
|
+
((hue % 360) + 360 + (invert ? 180 : 0)) % 360
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
def _is_channel_in_gamut?(value, channel)
|
|
491
|
+
case channel
|
|
492
|
+
when LinearChannel
|
|
493
|
+
FuzzyMath.less_than_or_equals?(value, channel.max) && FuzzyMath.greater_than_or_equals?(value, channel.min)
|
|
225
494
|
else
|
|
226
|
-
|
|
495
|
+
true
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def _interpolate(other, method, weight: nil)
|
|
500
|
+
weight = 0.5 if weight.nil?
|
|
501
|
+
if weight.negative? || weight > 1
|
|
502
|
+
raise Sass::ScriptError.new("Expected #{wieght} to be within 0 and 1.", 'weight')
|
|
227
503
|
end
|
|
504
|
+
|
|
505
|
+
return other if FuzzyMath.equals?(weight, 0)
|
|
506
|
+
return self if FuzzyMath.equals?(weight, 1)
|
|
507
|
+
|
|
508
|
+
color1 = _to_space(method.space)
|
|
509
|
+
color2 = other._to_space(method.space)
|
|
510
|
+
|
|
511
|
+
c1_missing0 = _analogous_channel_missing?(self, color1, 0)
|
|
512
|
+
c1_missing1 = _analogous_channel_missing?(self, color1, 1)
|
|
513
|
+
c1_missing2 = _analogous_channel_missing?(self, color1, 2)
|
|
514
|
+
c2_missing0 = _analogous_channel_missing?(other, color2, 0)
|
|
515
|
+
c2_missing1 = _analogous_channel_missing?(other, color2, 1)
|
|
516
|
+
c2_missing2 = _analogous_channel_missing?(other, color2, 2)
|
|
517
|
+
c1_channel0 = (c1_missing0 ? color2 : color1).channel0
|
|
518
|
+
c1_channel1 = (c1_missing1 ? color2 : color1).channel1
|
|
519
|
+
c1_channel2 = (c1_missing2 ? color2 : color1).channel2
|
|
520
|
+
c2_channel0 = (c2_missing0 ? color1 : color2).channel0
|
|
521
|
+
c2_channel1 = (c2_missing1 ? color1 : color2).channel1
|
|
522
|
+
c2_channel2 = (c2_missing2 ? color1 : color2).channel2
|
|
523
|
+
c1_alpha = alpha_or_nil.nil? ? other.alpha : alpha_or_nil
|
|
524
|
+
c2_alpha = other.alpha_or_nil.nil? ? alpha : other.alpha_or_nil
|
|
525
|
+
|
|
526
|
+
c1_multiplier = (alpha_or_nil.nil? ? 1 : alpha_or_nil) * weight
|
|
527
|
+
c2_multiplier = (other.alpha_or_nil.nil? ? 1 : other.alpha_or_nil) * (1 - weight)
|
|
528
|
+
mixed_alpha = alpha_missing? && other.alpha_missing? ? nil : (c1_alpha * weight) + (c2_alpha * (1 - weight))
|
|
529
|
+
mixed0 = if c1_missing0 && c2_missing0
|
|
530
|
+
nil
|
|
531
|
+
else
|
|
532
|
+
((c1_channel0 * c1_multiplier) + (c2_channel0 * c2_multiplier)) /
|
|
533
|
+
(mixed_alpha.nil? ? 1 : mixed_alpha)
|
|
534
|
+
end
|
|
535
|
+
mixed1 = if c1_missing1 && c2_missing1
|
|
536
|
+
nil
|
|
537
|
+
else
|
|
538
|
+
((c1_channel1 * c1_multiplier) + (c2_channel1 * c2_multiplier)) /
|
|
539
|
+
(mixed_alpha.nil? ? 1 : mixed_alpha)
|
|
540
|
+
end
|
|
541
|
+
mixed2 = if c1_missing2 && c2_missing2
|
|
542
|
+
nil
|
|
543
|
+
else
|
|
544
|
+
((c1_channel2 * c1_multiplier) + (c2_channel2 * c2_multiplier)) /
|
|
545
|
+
(mixed_alpha.nil? ? 1 : mixed_alpha)
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
case method.space
|
|
549
|
+
when Space::HSL, Space::HWB
|
|
550
|
+
Color.send(:for_space_internal,
|
|
551
|
+
method.space,
|
|
552
|
+
c1_missing0 && c2_missing0 ? nil : _interpolate_hues(c1_channel0, c2_channel0, method.hue, weight),
|
|
553
|
+
mixed1,
|
|
554
|
+
mixed2,
|
|
555
|
+
mixed_alpha)
|
|
556
|
+
when Space::LCH, Space::OKLCH
|
|
557
|
+
Color.send(:for_space_internal,
|
|
558
|
+
method.space,
|
|
559
|
+
mixed0,
|
|
560
|
+
mixed1,
|
|
561
|
+
c1_missing2 && c2_missing2 ? nil : _interpolate_hues(c1_channel2, c2_channel2, method.hue, weight),
|
|
562
|
+
mixed_alpha)
|
|
563
|
+
else
|
|
564
|
+
Color.send(:_for_space,
|
|
565
|
+
method.space, mixed0, mixed1, mixed2, mixed_alpha)
|
|
566
|
+
end._to_space(_space)
|
|
228
567
|
end
|
|
229
568
|
|
|
230
|
-
def
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
569
|
+
def _analogous_channel_missing?(original, output, output_channel_index)
|
|
570
|
+
return true if output.channels_or_nil[output_channel_index].nil?
|
|
571
|
+
|
|
572
|
+
return false if original.equal?(output)
|
|
573
|
+
|
|
574
|
+
output_channel = output._space.channels[output_channel_index]
|
|
575
|
+
original_channel = original._space.channels.find do |channel|
|
|
576
|
+
output_channel.analogous?(channel)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
return false if original_channel.nil?
|
|
580
|
+
|
|
581
|
+
original.channel_missing?(original_channel.name)
|
|
582
|
+
end
|
|
234
583
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
584
|
+
def _interpolate_hues(hue1, hue2, method, weight)
|
|
585
|
+
case method
|
|
586
|
+
when :shorter
|
|
587
|
+
diff = hue2 - hue1
|
|
588
|
+
if diff > 180
|
|
589
|
+
hue1 += 360
|
|
590
|
+
elsif diff < -180
|
|
591
|
+
hue2 += 360
|
|
592
|
+
end
|
|
593
|
+
when :longer
|
|
594
|
+
diff = hue2 - hue1
|
|
595
|
+
if diff.positive? && diff < 180
|
|
596
|
+
hue2 += 360
|
|
597
|
+
elsif diff > -180 && diff <= 0
|
|
598
|
+
hue1 += 360
|
|
599
|
+
end
|
|
600
|
+
when :increasing
|
|
601
|
+
hue2 += 360 if hue2 < hue1
|
|
602
|
+
when :decreasing
|
|
603
|
+
hue1 += 360 if hue1 < hue2
|
|
239
604
|
end
|
|
240
605
|
|
|
241
|
-
|
|
242
|
-
@red = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue + Rational(1, 3))
|
|
243
|
-
@green = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
|
|
244
|
-
@blue = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue - Rational(1, 3))
|
|
606
|
+
(hue1 * weight) + (hue2 * (1 - weight))
|
|
245
607
|
end
|
|
246
608
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
609
|
+
class << self
|
|
610
|
+
private
|
|
611
|
+
|
|
612
|
+
def for_space(space, channel0_or_nil, channel1_or_nil, channel2_or_nil, alpha)
|
|
613
|
+
_for_space(Space.from_name(space), channel0_or_nil, channel1_or_nil, channel2_or_nil, alpha)
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def for_space_internal(space, channel0, channel1, channel2, alpha)
|
|
617
|
+
o = allocate
|
|
618
|
+
o.send(:_initialize_for_space_internal, space, channel0, channel1, channel2, alpha)
|
|
619
|
+
o
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
def _for_space(space, channel0_or_nil, channel1_or_nil, channel2_or_nil, alpha)
|
|
623
|
+
o = allocate
|
|
624
|
+
o.send(:_initialize_for_space, space, channel0_or_nil, channel1_or_nil, channel2_or_nil, alpha)
|
|
625
|
+
o
|
|
626
|
+
end
|
|
250
627
|
end
|
|
251
628
|
end
|
|
252
629
|
end
|