st/theme-node: Implement extensions for accent color

Add -st-accent-color and -st-fg-accent-color so that these colors can be
accessed from CSS.

Since they are often transformed in SCSS atm, add st-transparentize(),
st-mix(), st-lighten(), st-darken() that work in runtime.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2715>
This commit is contained in:
Alice Mikhaylenko 2023-03-22 00:02:51 +04:00 committed by Marge Bot
parent 1ce6193f4e
commit c593aecbde

View File

@ -502,6 +502,20 @@ term_is_transparent (CRTerm *term)
strcmp (term->content.str->stryng->str, "transparent") == 0);
}
static gboolean
term_is_accent_color (CRTerm *term)
{
return (term->type == TERM_IDENT &&
strcmp (term->content.str->stryng->str, "-st-accent-color") == 0);
}
static gboolean
term_is_accent_fg_color (CRTerm *term)
{
return (term->type == TERM_IDENT &&
strcmp (term->content.str->stryng->str, "-st-accent-fg-color") == 0);
}
static int
color_component_from_double (double component)
{
@ -594,6 +608,180 @@ get_color_from_rgba_term (CRTerm *term,
return VALUE_FOUND;
}
static GetFromTermResult get_color_from_term (StThemeNode *node,
CRTerm *term,
CoglColor *color);
static GetFromTermResult
get_color_from_transparentize_term (StThemeNode *node,
CRTerm *term,
CoglColor *color)
{
CRTerm *color_arg = term->ext_content.func_param;
CRTerm *amount_arg = color_arg->next;
CoglColor base_color;
CRNum *amount_num;
double amount;
if (!color_arg || !amount_arg)
return VALUE_NOT_FOUND;
if (get_color_from_term (node, color_arg, &base_color) != VALUE_FOUND)
return VALUE_NOT_FOUND;
if (amount_arg->type != TERM_NUMBER)
return VALUE_NOT_FOUND;
amount_num = amount_arg->content.num;
if (amount_num->type == NUM_PERCENTAGE)
amount = amount_num->val / 100;
else if (amount_num->type == NUM_GENERIC)
amount = amount_num->val;
else
return VALUE_NOT_FOUND;
color->red = base_color.red;
color->green = base_color.green;
color->blue = base_color.blue;
color->alpha = CLAMP (base_color.alpha - amount * 255, 0, 255);
return VALUE_FOUND;
}
#define LERP(a, b, t) (a + (b - a) * t)
static GetFromTermResult
get_color_from_mix_term (StThemeNode *node,
CRTerm *term,
CoglColor *color)
{
CRTerm *color1_arg = term->ext_content.func_param;
CRTerm *color2_arg = color1_arg->next;
CRTerm *factor_arg = color2_arg->next;
CoglColor color1, color2;
CRNum *factor_num;
double factor;
if (!color1_arg || !color2_arg || !factor_arg)
return VALUE_NOT_FOUND;
if (get_color_from_term (node, color1_arg, &color1) != VALUE_FOUND ||
get_color_from_term (node, color2_arg, &color2) != VALUE_FOUND)
return VALUE_NOT_FOUND;
if (factor_arg->type != TERM_NUMBER)
return VALUE_NOT_FOUND;
factor_num = factor_arg->content.num;
if (factor_num->type == NUM_PERCENTAGE)
factor = factor_num->val / 100;
else if (factor_num->type == NUM_GENERIC)
factor = factor_num->val;
else
return VALUE_NOT_FOUND;
/* SCSS mix() inverts the factor for some reason */
factor = 1 - factor;
color->alpha = CLAMP (LERP (color1.alpha, color2.alpha, factor), 0, 255);
if (color->alpha == 0)
{
color->red = color->green = color->blue = 0;
}
else
{
color->red = CLAMP (LERP (color1.red * color1.alpha, color2.red * color2.alpha, factor) / color->alpha, 0, 255);
color->green = CLAMP (LERP (color1.green * color1.alpha, color2.green * color2.alpha, factor) / color->alpha, 0, 255);
color->blue = CLAMP (LERP (color1.blue * color1.alpha, color2.blue * color2.alpha, factor) / color->alpha, 0, 255);
}
return VALUE_FOUND;
}
static GetFromTermResult
get_color_from_lighten_term (StThemeNode *node,
CRTerm *term,
CoglColor *color)
{
CRTerm *color_arg = term->ext_content.func_param;
CRTerm *factor_arg = color_arg->next;
CoglColor base_color;
CRNum *factor_num;
double factor;
float hue, luminance, saturation;
if (!color_arg || !factor_arg)
return VALUE_NOT_FOUND;
if (get_color_from_term (node, color_arg, &base_color) != VALUE_FOUND)
return VALUE_NOT_FOUND;
if (factor_arg->type != TERM_NUMBER)
return VALUE_NOT_FOUND;
factor_num = factor_arg->content.num;
if (factor_num->type == NUM_PERCENTAGE)
factor = factor_num->val / 100;
else if (factor_num->type == NUM_GENERIC)
factor = factor_num->val;
else
return VALUE_NOT_FOUND;
cogl_color_to_hsl (&base_color, &hue, &saturation, &luminance);
luminance = CLAMP (luminance + factor, 0, 1);
cogl_color_init_from_hsl (color, hue, saturation, luminance);
color->alpha = base_color.alpha;
return VALUE_FOUND;
}
static GetFromTermResult
get_color_from_darken_term (StThemeNode *node,
CRTerm *term,
CoglColor *color)
{
CRTerm *color_arg = term->ext_content.func_param;
CRTerm *factor_arg = color_arg->next;
CoglColor base_color;
CRNum *factor_num;
double factor;
float hue, luminance, saturation;
if (!color_arg || !factor_arg)
return VALUE_NOT_FOUND;
if (get_color_from_term (node, color_arg, &base_color) != VALUE_FOUND)
return VALUE_NOT_FOUND;
if (factor_arg->type != TERM_NUMBER)
return VALUE_NOT_FOUND;
factor_num = factor_arg->content.num;
if (factor_num->type == NUM_PERCENTAGE)
factor = factor_num->val / 100;
else if (factor_num->type == NUM_GENERIC)
factor = factor_num->val;
else
return VALUE_NOT_FOUND;
cogl_color_to_hsl (&base_color, &hue, &saturation, &luminance);
color->alpha = base_color.alpha;
luminance = CLAMP (luminance - factor, 0, 1);
cogl_color_init_from_hsl (color, hue, saturation, luminance);
color->alpha = base_color.alpha;
return VALUE_FOUND;
}
static GetFromTermResult
get_color_from_term (StThemeNode *node,
CRTerm *term,
@ -614,6 +802,18 @@ get_color_from_term (StThemeNode *node,
*color = TRANSPARENT_COLOR;
return VALUE_FOUND;
}
/* St-specific extension: -st-accent-color */
else if (term_is_accent_color (term))
{
st_theme_context_get_accent_color (node->context, color, NULL);
return VALUE_FOUND;
}
/* St-specific extension: -st-accent-fg-color */
else if (term_is_accent_fg_color (term))
{
st_theme_context_get_accent_color (node->context, NULL, color);
return VALUE_FOUND;
}
/* rgba () colors - a CSS3 addition, are not supported by libcroco,
* but they are parsed as a "function", so we can emulate the
* functionality.
@ -626,6 +826,42 @@ get_color_from_term (StThemeNode *node,
{
return get_color_from_rgba_term (term, color);
}
/* St-specific extension: st-transparentize() */
else if (term->type == TERM_FUNCTION &&
term->content.str &&
term->content.str->stryng &&
term->content.str->stryng->str &&
strcmp (term->content.str->stryng->str, "st-transparentize") == 0)
{
return get_color_from_transparentize_term (node, term, color);
}
/* St-specific extension: st-mix() */
else if (term->type == TERM_FUNCTION &&
term->content.str &&
term->content.str->stryng &&
term->content.str->stryng->str &&
strcmp (term->content.str->stryng->str, "st-mix") == 0)
{
return get_color_from_mix_term (node, term, color);
}
/* St-specific extension: st-lighten() */
else if (term->type == TERM_FUNCTION &&
term->content.str &&
term->content.str->stryng &&
term->content.str->stryng->str &&
strcmp (term->content.str->stryng->str, "st-lighten") == 0)
{
return get_color_from_lighten_term (node, term, color);
}
/* St-specific extension: st-darken() */
else if (term->type == TERM_FUNCTION &&
term->content.str &&
term->content.str->stryng &&
term->content.str->stryng->str &&
strcmp (term->content.str->stryng->str, "st-darken") == 0)
{
return get_color_from_darken_term (node, term, color);
}
status = cr_rgb_set_from_term (&rgb, term);
if (status != CR_OK)