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