1 | // sass.hpp must go before all system headers to get the |
2 | // __EXTENSIONS__ fix on Solaris. |
3 | #include "sass.hpp" |
4 | |
5 | #include <iomanip> |
6 | #include "ast.hpp" |
7 | #include "fn_utils.hpp" |
8 | #include "fn_colors.hpp" |
9 | #include "util.hpp" |
10 | #include "util_string.hpp" |
11 | |
12 | namespace Sass { |
13 | |
14 | namespace Functions { |
15 | |
16 | bool string_argument(AST_Node_Obj obj) { |
17 | String_Constant* s = Cast<String_Constant>(ptr: obj); |
18 | if (s == nullptr) return false; |
19 | const sass::string& str = s->value(); |
20 | return starts_with(str, prefix: "calc(" ) || |
21 | starts_with(str, prefix: "var(" ); |
22 | } |
23 | |
24 | void hsla_alpha_percent_deprecation(const SourceSpan& pstate, const sass::string val) |
25 | { |
26 | |
27 | sass::string msg("Passing a percentage as the alpha value to hsla() will be interpreted" ); |
28 | sass::string tail("differently in future versions of Sass. For now, use " + val + " instead." ); |
29 | |
30 | deprecated(msg, msg2: tail, with_column: false, pstate); |
31 | |
32 | } |
33 | |
34 | Signature rgb_sig = "rgb($red, $green, $blue)" ; |
35 | BUILT_IN(rgb) |
36 | { |
37 | if ( |
38 | string_argument(obj: env["$red" ]) || |
39 | string_argument(obj: env["$green" ]) || |
40 | string_argument(obj: env["$blue" ]) |
41 | ) { |
42 | return SASS_MEMORY_NEW(String_Constant, pstate, "rgb(" |
43 | + env["$red" ]->to_string() |
44 | + ", " |
45 | + env["$green" ]->to_string() |
46 | + ", " |
47 | + env["$blue" ]->to_string() |
48 | + ")" |
49 | ); |
50 | } |
51 | |
52 | return SASS_MEMORY_NEW(Color_RGBA, |
53 | pstate, |
54 | COLOR_NUM("$red" ), |
55 | COLOR_NUM("$green" ), |
56 | COLOR_NUM("$blue" )); |
57 | } |
58 | |
59 | Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)" ; |
60 | BUILT_IN(rgba_4) |
61 | { |
62 | if ( |
63 | string_argument(obj: env["$red" ]) || |
64 | string_argument(obj: env["$green" ]) || |
65 | string_argument(obj: env["$blue" ]) || |
66 | string_argument(obj: env["$alpha" ]) |
67 | ) { |
68 | return SASS_MEMORY_NEW(String_Constant, pstate, "rgba(" |
69 | + env["$red" ]->to_string() |
70 | + ", " |
71 | + env["$green" ]->to_string() |
72 | + ", " |
73 | + env["$blue" ]->to_string() |
74 | + ", " |
75 | + env["$alpha" ]->to_string() |
76 | + ")" |
77 | ); |
78 | } |
79 | |
80 | return SASS_MEMORY_NEW(Color_RGBA, |
81 | pstate, |
82 | COLOR_NUM("$red" ), |
83 | COLOR_NUM("$green" ), |
84 | COLOR_NUM("$blue" ), |
85 | ALPHA_NUM("$alpha" )); |
86 | } |
87 | |
88 | Signature rgba_2_sig = "rgba($color, $alpha)" ; |
89 | BUILT_IN(rgba_2) |
90 | { |
91 | if ( |
92 | string_argument(obj: env["$color" ]) |
93 | ) { |
94 | return SASS_MEMORY_NEW(String_Constant, pstate, "rgba(" |
95 | + env["$color" ]->to_string() |
96 | + ", " |
97 | + env["$alpha" ]->to_string() |
98 | + ")" |
99 | ); |
100 | } |
101 | |
102 | Color_RGBA_Obj c_arg = ARG("$color" , Color)->toRGBA(); |
103 | |
104 | if ( |
105 | string_argument(obj: env["$alpha" ]) |
106 | ) { |
107 | sass::ostream strm; |
108 | strm << "rgba(" |
109 | << (int)c_arg->r() << ", " |
110 | << (int)c_arg->g() << ", " |
111 | << (int)c_arg->b() << ", " |
112 | << env["$alpha" ]->to_string() |
113 | << ")" ; |
114 | return SASS_MEMORY_NEW(String_Constant, pstate, strm.str()); |
115 | } |
116 | |
117 | Color_RGBA_Obj new_c = SASS_MEMORY_COPY(c_arg); |
118 | new_c->a(ALPHA_NUM("$alpha" )); |
119 | new_c->disp(disp__: "" ); |
120 | return new_c.detach(); |
121 | } |
122 | |
123 | //////////////// |
124 | // RGB FUNCTIONS |
125 | //////////////// |
126 | |
127 | Signature red_sig = "red($color)" ; |
128 | BUILT_IN(red) |
129 | { |
130 | Color_RGBA_Obj color = ARG("$color" , Color)->toRGBA(); |
131 | return SASS_MEMORY_NEW(Number, pstate, color->r()); |
132 | } |
133 | |
134 | Signature green_sig = "green($color)" ; |
135 | BUILT_IN(green) |
136 | { |
137 | Color_RGBA_Obj color = ARG("$color" , Color)->toRGBA(); |
138 | return SASS_MEMORY_NEW(Number, pstate, color->g()); |
139 | } |
140 | |
141 | Signature blue_sig = "blue($color)" ; |
142 | BUILT_IN(blue) |
143 | { |
144 | Color_RGBA_Obj color = ARG("$color" , Color)->toRGBA(); |
145 | return SASS_MEMORY_NEW(Number, pstate, color->b()); |
146 | } |
147 | |
148 | Color_RGBA* colormix(Context& ctx, SourceSpan& pstate, Color* color1, Color* color2, double weight) { |
149 | Color_RGBA_Obj c1 = color1->toRGBA(); |
150 | Color_RGBA_Obj c2 = color2->toRGBA(); |
151 | double p = weight/100; |
152 | double w = 2*p - 1; |
153 | double a = c1->a() - c2->a(); |
154 | |
155 | double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0; |
156 | double w2 = 1 - w1; |
157 | |
158 | return SASS_MEMORY_NEW(Color_RGBA, |
159 | pstate, |
160 | Sass::round(w1*c1->r() + w2*c2->r(), ctx.c_options.precision), |
161 | Sass::round(w1*c1->g() + w2*c2->g(), ctx.c_options.precision), |
162 | Sass::round(w1*c1->b() + w2*c2->b(), ctx.c_options.precision), |
163 | c1->a()*p + c2->a()*(1-p)); |
164 | } |
165 | |
166 | Signature mix_sig = "mix($color1, $color2, $weight: 50%)" ; |
167 | BUILT_IN(mix) |
168 | { |
169 | Color_Obj color1 = ARG("$color1" , Color); |
170 | Color_Obj color2 = ARG("$color2" , Color); |
171 | double weight = DARG_U_PRCT("$weight" ); |
172 | return colormix(ctx, pstate, color1, color2, weight); |
173 | |
174 | } |
175 | |
176 | //////////////// |
177 | // HSL FUNCTIONS |
178 | //////////////// |
179 | |
180 | Signature hsl_sig = "hsl($hue, $saturation, $lightness)" ; |
181 | BUILT_IN(hsl) |
182 | { |
183 | if ( |
184 | string_argument(obj: env["$hue" ]) || |
185 | string_argument(obj: env["$saturation" ]) || |
186 | string_argument(obj: env["$lightness" ]) |
187 | ) { |
188 | return SASS_MEMORY_NEW(String_Constant, pstate, "hsl(" |
189 | + env["$hue" ]->to_string() |
190 | + ", " |
191 | + env["$saturation" ]->to_string() |
192 | + ", " |
193 | + env["$lightness" ]->to_string() |
194 | + ")" |
195 | ); |
196 | } |
197 | |
198 | return SASS_MEMORY_NEW(Color_HSLA, |
199 | pstate, |
200 | ARGVAL("$hue" ), |
201 | ARGVAL("$saturation" ), |
202 | ARGVAL("$lightness" ), |
203 | 1.0); |
204 | |
205 | } |
206 | |
207 | Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)" ; |
208 | BUILT_IN(hsla) |
209 | { |
210 | if ( |
211 | string_argument(obj: env["$hue" ]) || |
212 | string_argument(obj: env["$saturation" ]) || |
213 | string_argument(obj: env["$lightness" ]) || |
214 | string_argument(obj: env["$alpha" ]) |
215 | ) { |
216 | return SASS_MEMORY_NEW(String_Constant, pstate, "hsla(" |
217 | + env["$hue" ]->to_string() |
218 | + ", " |
219 | + env["$saturation" ]->to_string() |
220 | + ", " |
221 | + env["$lightness" ]->to_string() |
222 | + ", " |
223 | + env["$alpha" ]->to_string() |
224 | + ")" |
225 | ); |
226 | } |
227 | |
228 | Number* alpha = ARG("$alpha" , Number); |
229 | if (alpha && alpha->unit() == "%" ) { |
230 | Number_Obj val = SASS_MEMORY_COPY(alpha); |
231 | val->numerators.clear(); // convert |
232 | val->value(value__: val->value() / 100.0); |
233 | sass::string nr(val->to_string(opt: ctx.c_options)); |
234 | hsla_alpha_percent_deprecation(pstate, val: nr); |
235 | } |
236 | |
237 | return SASS_MEMORY_NEW(Color_HSLA, |
238 | pstate, |
239 | ARGVAL("$hue" ), |
240 | ARGVAL("$saturation" ), |
241 | ARGVAL("$lightness" ), |
242 | ARGVAL("$alpha" )); |
243 | |
244 | } |
245 | |
246 | ///////////////////////////////////////////////////////////////////////// |
247 | // Query functions |
248 | ///////////////////////////////////////////////////////////////////////// |
249 | |
250 | Signature hue_sig = "hue($color)" ; |
251 | BUILT_IN(hue) |
252 | { |
253 | Color_HSLA_Obj col = ARG("$color" , Color)->toHSLA(); |
254 | return SASS_MEMORY_NEW(Number, pstate, col->h(), "deg" ); |
255 | } |
256 | |
257 | Signature saturation_sig = "saturation($color)" ; |
258 | BUILT_IN(saturation) |
259 | { |
260 | Color_HSLA_Obj col = ARG("$color" , Color)->toHSLA(); |
261 | return SASS_MEMORY_NEW(Number, pstate, col->s(), "%" ); |
262 | } |
263 | |
264 | Signature lightness_sig = "lightness($color)" ; |
265 | BUILT_IN(lightness) |
266 | { |
267 | Color_HSLA_Obj col = ARG("$color" , Color)->toHSLA(); |
268 | return SASS_MEMORY_NEW(Number, pstate, col->l(), "%" ); |
269 | } |
270 | |
271 | ///////////////////////////////////////////////////////////////////////// |
272 | // HSL manipulation functions |
273 | ///////////////////////////////////////////////////////////////////////// |
274 | |
275 | Signature adjust_hue_sig = "adjust-hue($color, $degrees)" ; |
276 | BUILT_IN(adjust_hue) |
277 | { |
278 | Color* col = ARG("$color" , Color); |
279 | double degrees = ARGVAL("$degrees" ); |
280 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
281 | copy->h(h__: absmod(n: copy->h() + degrees, r: 360.0)); |
282 | return copy.detach(); |
283 | } |
284 | |
285 | Signature lighten_sig = "lighten($color, $amount)" ; |
286 | BUILT_IN(lighten) |
287 | { |
288 | Color* col = ARG("$color" , Color); |
289 | double amount = DARG_U_PRCT("$amount" ); |
290 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
291 | copy->l(l__: clip(n: copy->l() + amount, lower: 0.0, upper: 100.0)); |
292 | return copy.detach(); |
293 | |
294 | } |
295 | |
296 | Signature darken_sig = "darken($color, $amount)" ; |
297 | BUILT_IN(darken) |
298 | { |
299 | Color* col = ARG("$color" , Color); |
300 | double amount = DARG_U_PRCT("$amount" ); |
301 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
302 | copy->l(l__: clip(n: copy->l() - amount, lower: 0.0, upper: 100.0)); |
303 | return copy.detach(); |
304 | } |
305 | |
306 | Signature saturate_sig = "saturate($color, $amount: false)" ; |
307 | BUILT_IN(saturate) |
308 | { |
309 | // CSS3 filter function overload: pass literal through directly |
310 | if (!Cast<Number>(ptr: env["$amount" ])) { |
311 | return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color" ]->to_string(ctx.c_options) + ")" ); |
312 | } |
313 | |
314 | Color* col = ARG("$color" , Color); |
315 | double amount = DARG_U_PRCT("$amount" ); |
316 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
317 | copy->s(s__: clip(n: copy->s() + amount, lower: 0.0, upper: 100.0)); |
318 | return copy.detach(); |
319 | } |
320 | |
321 | Signature desaturate_sig = "desaturate($color, $amount)" ; |
322 | BUILT_IN(desaturate) |
323 | { |
324 | Color* col = ARG("$color" , Color); |
325 | double amount = DARG_U_PRCT("$amount" ); |
326 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
327 | copy->s(s__: clip(n: copy->s() - amount, lower: 0.0, upper: 100.0)); |
328 | return copy.detach(); |
329 | } |
330 | |
331 | Signature grayscale_sig = "grayscale($color)" ; |
332 | BUILT_IN(grayscale) |
333 | { |
334 | // CSS3 filter function overload: pass literal through directly |
335 | Number* amount = Cast<Number>(ptr: env["$color" ]); |
336 | if (amount) { |
337 | return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")" ); |
338 | } |
339 | |
340 | Color* col = ARG("$color" , Color); |
341 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
342 | copy->s(s__: 0.0); // just reset saturation |
343 | return copy.detach(); |
344 | } |
345 | |
346 | ///////////////////////////////////////////////////////////////////////// |
347 | // Misc manipulation functions |
348 | ///////////////////////////////////////////////////////////////////////// |
349 | |
350 | Signature complement_sig = "complement($color)" ; |
351 | BUILT_IN(complement) |
352 | { |
353 | Color* col = ARG("$color" , Color); |
354 | Color_HSLA_Obj copy = col->copyAsHSLA(); |
355 | copy->h(h__: absmod(n: copy->h() - 180.0, r: 360.0)); |
356 | return copy.detach(); |
357 | } |
358 | |
359 | Signature invert_sig = "invert($color, $weight: 100%)" ; |
360 | BUILT_IN(invert) |
361 | { |
362 | // CSS3 filter function overload: pass literal through directly |
363 | Number* amount = Cast<Number>(ptr: env["$color" ]); |
364 | double weight = DARG_U_PRCT("$weight" ); |
365 | if (amount) { |
366 | // TODO: does not throw on 100% manually passed as value |
367 | if (weight < 100.0) { |
368 | error(msg: "Only one argument may be passed to the plain-CSS invert() function." , pstate, traces); |
369 | } |
370 | return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")" ); |
371 | } |
372 | |
373 | Color* col = ARG("$color" , Color); |
374 | Color_RGBA_Obj inv = col->copyAsRGBA(); |
375 | inv->r(r__: clip(n: 255.0 - inv->r(), lower: 0.0, upper: 255.0)); |
376 | inv->g(g__: clip(n: 255.0 - inv->g(), lower: 0.0, upper: 255.0)); |
377 | inv->b(b__: clip(n: 255.0 - inv->b(), lower: 0.0, upper: 255.0)); |
378 | return colormix(ctx, pstate, color1: inv, color2: col, weight); |
379 | } |
380 | |
381 | ///////////////////////////////////////////////////////////////////////// |
382 | // Opacity functions |
383 | ///////////////////////////////////////////////////////////////////////// |
384 | |
385 | Signature alpha_sig = "alpha($color)" ; |
386 | Signature opacity_sig = "opacity($color)" ; |
387 | BUILT_IN(alpha) |
388 | { |
389 | String_Constant* ie_kwd = Cast<String_Constant>(ptr: env["$color" ]); |
390 | if (ie_kwd) { |
391 | return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")" ); |
392 | } |
393 | |
394 | // CSS3 filter function overload: pass literal through directly |
395 | Number* amount = Cast<Number>(ptr: env["$color" ]); |
396 | if (amount) { |
397 | return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")" ); |
398 | } |
399 | |
400 | return SASS_MEMORY_NEW(Number, pstate, ARG("$color" , Color)->a()); |
401 | } |
402 | |
403 | Signature opacify_sig = "opacify($color, $amount)" ; |
404 | Signature fade_in_sig = "fade-in($color, $amount)" ; |
405 | BUILT_IN(opacify) |
406 | { |
407 | Color* col = ARG("$color" , Color); |
408 | double amount = DARG_U_FACT("$amount" ); |
409 | Color_Obj copy = SASS_MEMORY_COPY(col); |
410 | copy->a(a__: clip(n: col->a() + amount, lower: 0.0, upper: 1.0)); |
411 | return copy.detach(); |
412 | } |
413 | |
414 | Signature transparentize_sig = "transparentize($color, $amount)" ; |
415 | Signature fade_out_sig = "fade-out($color, $amount)" ; |
416 | BUILT_IN(transparentize) |
417 | { |
418 | Color* col = ARG("$color" , Color); |
419 | double amount = DARG_U_FACT("$amount" ); |
420 | Color_Obj copy = SASS_MEMORY_COPY(col); |
421 | copy->a(a__: std::max(a: col->a() - amount, b: 0.0)); |
422 | return copy.detach(); |
423 | } |
424 | |
425 | //////////////////////// |
426 | // OTHER COLOR FUNCTIONS |
427 | //////////////////////// |
428 | |
429 | Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)" ; |
430 | BUILT_IN(adjust_color) |
431 | { |
432 | Color* col = ARG("$color" , Color); |
433 | Number* r = Cast<Number>(ptr: env["$red" ]); |
434 | Number* g = Cast<Number>(ptr: env["$green" ]); |
435 | Number* b = Cast<Number>(ptr: env["$blue" ]); |
436 | Number* h = Cast<Number>(ptr: env["$hue" ]); |
437 | Number* s = Cast<Number>(ptr: env["$saturation" ]); |
438 | Number* l = Cast<Number>(ptr: env["$lightness" ]); |
439 | Number* a = Cast<Number>(ptr: env["$alpha" ]); |
440 | |
441 | bool rgb = r || g || b; |
442 | bool hsl = h || s || l; |
443 | |
444 | if (rgb && hsl) { |
445 | error(msg: "Cannot specify HSL and RGB values for a color at the same time for `adjust-color'" , pstate, traces); |
446 | } |
447 | else if (rgb) { |
448 | Color_RGBA_Obj c = col->copyAsRGBA(); |
449 | if (r) c->r(r__: c->r() + DARG_R_BYTE("$red" )); |
450 | if (g) c->g(g__: c->g() + DARG_R_BYTE("$green" )); |
451 | if (b) c->b(b__: c->b() + DARG_R_BYTE("$blue" )); |
452 | if (a) c->a(a__: c->a() + DARG_R_FACT("$alpha" )); |
453 | return c.detach(); |
454 | } |
455 | else if (hsl) { |
456 | Color_HSLA_Obj c = col->copyAsHSLA(); |
457 | if (h) c->h(h__: c->h() + absmod(n: h->value(), r: 360.0)); |
458 | if (s) c->s(s__: c->s() + DARG_R_PRCT("$saturation" )); |
459 | if (l) c->l(l__: c->l() + DARG_R_PRCT("$lightness" )); |
460 | if (a) c->a(a__: c->a() + DARG_R_FACT("$alpha" )); |
461 | return c.detach(); |
462 | } |
463 | else if (a) { |
464 | Color_Obj c = SASS_MEMORY_COPY(col); |
465 | c->a(a__: c->a() + DARG_R_FACT("$alpha" )); |
466 | c->a(a__: clip(n: c->a(), lower: 0.0, upper: 1.0)); |
467 | return c.detach(); |
468 | } |
469 | error(msg: "not enough arguments for `adjust-color'" , pstate, traces); |
470 | // unreachable |
471 | return col; |
472 | } |
473 | |
474 | Signature scale_color_sig = "scale-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)" ; |
475 | BUILT_IN(scale_color) |
476 | { |
477 | Color* col = ARG("$color" , Color); |
478 | Number* r = Cast<Number>(ptr: env["$red" ]); |
479 | Number* g = Cast<Number>(ptr: env["$green" ]); |
480 | Number* b = Cast<Number>(ptr: env["$blue" ]); |
481 | Number* h = Cast<Number>(ptr: env["$hue" ]); |
482 | Number* s = Cast<Number>(ptr: env["$saturation" ]); |
483 | Number* l = Cast<Number>(ptr: env["$lightness" ]); |
484 | Number* a = Cast<Number>(ptr: env["$alpha" ]); |
485 | |
486 | bool rgb = r || g || b; |
487 | bool hsl = h || s || l; |
488 | |
489 | if (rgb && hsl) { |
490 | error(msg: "Cannot specify HSL and RGB values for a color at the same time for `scale-color'" , pstate, traces); |
491 | } |
492 | else if (rgb) { |
493 | Color_RGBA_Obj c = col->copyAsRGBA(); |
494 | double rscale = (r ? DARG_R_PRCT("$red" ) : 0.0) / 100.0; |
495 | double gscale = (g ? DARG_R_PRCT("$green" ) : 0.0) / 100.0; |
496 | double bscale = (b ? DARG_R_PRCT("$blue" ) : 0.0) / 100.0; |
497 | double ascale = (a ? DARG_R_PRCT("$alpha" ) : 0.0) / 100.0; |
498 | if (rscale) c->r(r__: c->r() + rscale * (rscale > 0.0 ? 255.0 - c->r() : c->r())); |
499 | if (gscale) c->g(g__: c->g() + gscale * (gscale > 0.0 ? 255.0 - c->g() : c->g())); |
500 | if (bscale) c->b(b__: c->b() + bscale * (bscale > 0.0 ? 255.0 - c->b() : c->b())); |
501 | if (ascale) c->a(a__: c->a() + ascale * (ascale > 0.0 ? 1.0 - c->a() : c->a())); |
502 | return c.detach(); |
503 | } |
504 | else if (hsl) { |
505 | Color_HSLA_Obj c = col->copyAsHSLA(); |
506 | double hscale = (h ? DARG_R_PRCT("$hue" ) : 0.0) / 100.0; |
507 | double sscale = (s ? DARG_R_PRCT("$saturation" ) : 0.0) / 100.0; |
508 | double lscale = (l ? DARG_R_PRCT("$lightness" ) : 0.0) / 100.0; |
509 | double ascale = (a ? DARG_R_PRCT("$alpha" ) : 0.0) / 100.0; |
510 | if (hscale) c->h(h__: c->h() + hscale * (hscale > 0.0 ? 360.0 - c->h() : c->h())); |
511 | if (sscale) c->s(s__: c->s() + sscale * (sscale > 0.0 ? 100.0 - c->s() : c->s())); |
512 | if (lscale) c->l(l__: c->l() + lscale * (lscale > 0.0 ? 100.0 - c->l() : c->l())); |
513 | if (ascale) c->a(a__: c->a() + ascale * (ascale > 0.0 ? 1.0 - c->a() : c->a())); |
514 | return c.detach(); |
515 | } |
516 | else if (a) { |
517 | Color_Obj c = SASS_MEMORY_COPY(col); |
518 | double ascale = DARG_R_PRCT("$alpha" ) / 100.0; |
519 | c->a(a__: c->a() + ascale * (ascale > 0.0 ? 1.0 - c->a() : c->a())); |
520 | c->a(a__: clip(n: c->a(), lower: 0.0, upper: 1.0)); |
521 | return c.detach(); |
522 | } |
523 | error(msg: "not enough arguments for `scale-color'" , pstate, traces); |
524 | // unreachable |
525 | return col; |
526 | } |
527 | |
528 | Signature change_color_sig = "change-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)" ; |
529 | BUILT_IN(change_color) |
530 | { |
531 | Color* col = ARG("$color" , Color); |
532 | Number* r = Cast<Number>(ptr: env["$red" ]); |
533 | Number* g = Cast<Number>(ptr: env["$green" ]); |
534 | Number* b = Cast<Number>(ptr: env["$blue" ]); |
535 | Number* h = Cast<Number>(ptr: env["$hue" ]); |
536 | Number* s = Cast<Number>(ptr: env["$saturation" ]); |
537 | Number* l = Cast<Number>(ptr: env["$lightness" ]); |
538 | Number* a = Cast<Number>(ptr: env["$alpha" ]); |
539 | |
540 | bool rgb = r || g || b; |
541 | bool hsl = h || s || l; |
542 | |
543 | if (rgb && hsl) { |
544 | error(msg: "Cannot specify HSL and RGB values for a color at the same time for `change-color'" , pstate, traces); |
545 | } |
546 | else if (rgb) { |
547 | Color_RGBA_Obj c = col->copyAsRGBA(); |
548 | if (r) c->r(DARG_U_BYTE("$red" )); |
549 | if (g) c->g(DARG_U_BYTE("$green" )); |
550 | if (b) c->b(DARG_U_BYTE("$blue" )); |
551 | if (a) c->a(DARG_U_FACT("$alpha" )); |
552 | return c.detach(); |
553 | } |
554 | else if (hsl) { |
555 | Color_HSLA_Obj c = col->copyAsHSLA(); |
556 | if (h) c->h(h__: absmod(n: h->value(), r: 360.0)); |
557 | if (s) c->s(DARG_U_PRCT("$saturation" )); |
558 | if (l) c->l(DARG_U_PRCT("$lightness" )); |
559 | if (a) c->a(DARG_U_FACT("$alpha" )); |
560 | return c.detach(); |
561 | } |
562 | else if (a) { |
563 | Color_Obj c = SASS_MEMORY_COPY(col); |
564 | c->a(a__: clip(DARG_U_FACT("$alpha" ), lower: 0.0, upper: 1.0)); |
565 | return c.detach(); |
566 | } |
567 | error(msg: "not enough arguments for `change-color'" , pstate, traces); |
568 | // unreachable |
569 | return col; |
570 | } |
571 | |
572 | Signature ie_hex_str_sig = "ie-hex-str($color)" ; |
573 | BUILT_IN(ie_hex_str) |
574 | { |
575 | Color* col = ARG("$color" , Color); |
576 | Color_RGBA_Obj c = col->toRGBA(); |
577 | double r = clip(n: c->r(), lower: 0.0, upper: 255.0); |
578 | double g = clip(n: c->g(), lower: 0.0, upper: 255.0); |
579 | double b = clip(n: c->b(), lower: 0.0, upper: 255.0); |
580 | double a = clip(n: c->a(), lower: 0.0, upper: 1.0) * 255.0; |
581 | |
582 | sass::ostream ss; |
583 | ss << '#' << std::setw(2) << std::setfill('0'); |
584 | ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(val: a, precision: ctx.c_options.precision)); |
585 | ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(val: r, precision: ctx.c_options.precision)); |
586 | ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(val: g, precision: ctx.c_options.precision)); |
587 | ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(val: b, precision: ctx.c_options.precision)); |
588 | |
589 | sass::string result = ss.str(); |
590 | Util::ascii_str_toupper(s: &result); |
591 | return SASS_MEMORY_NEW(String_Quoted, pstate, result); |
592 | } |
593 | |
594 | } |
595 | |
596 | } |
597 | |