static GtkGradient * gtk_gradient_fade (GtkGradient *gradient, double opacity) { GtkGradient *faded; guint i; faded = g_slice_new (GtkGradient); faded->stops = g_array_new (FALSE, FALSE, sizeof (ColorStop)); faded->x0 = gradient->x0; faded->y0 = gradient->y0; faded->x1 = gradient->x1; faded->y1 = gradient->y1; faded->radius0 = gradient->radius0; faded->radius1 = gradient->radius1; faded->ref_count = 1; for (i = 0; i < gradient->stops->len; i++) { GtkSymbolicColor *color; ColorStop *stop; stop = &g_array_index (gradient->stops, ColorStop, i); color = gtk_symbolic_color_new_alpha (stop->color, opacity); gtk_gradient_add_color_stop (faded, stop->offset, color); gtk_symbolic_color_unref (color); } return faded; }
GtkGradient * _gtk_gradient_transition (GtkGradient *start, GtkGradient *end, guint property_id, double progress) { GtkGradient *gradient; guint i; g_return_val_if_fail (start != NULL, NULL); if (end == NULL) return gtk_gradient_fade (start, 1.0 - CLAMP (progress, 0.0, 1.0)); if (start->stops->len != end->stops->len) return NULL; /* check both are radial/linear */ if ((start->radius0 == 0 && start->radius1 == 0) != (end->radius0 == 0 && end->radius1 == 0)) return NULL; gradient = g_slice_new (GtkGradient); gradient->stops = g_array_new (FALSE, FALSE, sizeof (ColorStop)); gradient->x0 = (1 - progress) * start->x0 + progress * end->x0; gradient->y0 = (1 - progress) * start->y0 + progress * end->y0; gradient->x1 = (1 - progress) * start->x1 + progress * end->x1; gradient->y1 = (1 - progress) * start->y1 + progress * end->y1; gradient->radius0 = (1 - progress) * start->radius0 + progress * end->radius0; gradient->radius1 = (1 - progress) * start->radius1 + progress * end->radius1; gradient->ref_count = 1; for (i = 0; i < start->stops->len; i++) { ColorStop *start_stop, *end_stop; GtkSymbolicColor *color; double offset; start_stop = &g_array_index (start->stops, ColorStop, i); end_stop = &g_array_index (end->stops, ColorStop, i); offset = (1 - progress) * start_stop->offset + progress * end_stop->offset; color = gtk_symbolic_color_new_mix (start_stop->color, end_stop->color, progress); gtk_gradient_add_color_stop (gradient, offset, color); gtk_symbolic_color_unref (color); } return gradient; }
GtkGradient * _gtk_gradient_parse (GtkCssParser *parser) { GtkGradient *gradient; cairo_pattern_type_t type; gdouble coords[6]; guint i; g_return_val_if_fail (parser != NULL, NULL); if (!_gtk_css_parser_try (parser, "-gtk-gradient", TRUE)) { _gtk_css_parser_error (parser, "Expected '-gtk-gradient'"); return NULL; } if (!_gtk_css_parser_try (parser, "(", TRUE)) { _gtk_css_parser_error (parser, "Expected '(' after '-gtk-gradient'"); return NULL; } /* Parse gradient type */ if (_gtk_css_parser_try (parser, "linear", TRUE)) type = CAIRO_PATTERN_TYPE_LINEAR; else if (_gtk_css_parser_try (parser, "radial", TRUE)) type = CAIRO_PATTERN_TYPE_RADIAL; else { _gtk_css_parser_error (parser, "Gradient type must be 'radial' or 'linear'"); return NULL; } /* Parse start/stop position parameters */ for (i = 0; i < 2; i++) { if (! _gtk_css_parser_try (parser, ",", TRUE)) { _gtk_css_parser_error (parser, "Expected ','"); return NULL; } if (_gtk_css_parser_try (parser, "left", TRUE)) coords[i * 3] = 0; else if (_gtk_css_parser_try (parser, "right", TRUE)) coords[i * 3] = 1; else if (_gtk_css_parser_try (parser, "center", TRUE)) coords[i * 3] = 0.5; else if (!_gtk_css_parser_try_double (parser, &coords[i * 3])) { _gtk_css_parser_error (parser, "Expected a valid X coordinate"); return NULL; } if (_gtk_css_parser_try (parser, "top", TRUE)) coords[i * 3 + 1] = 0; else if (_gtk_css_parser_try (parser, "bottom", TRUE)) coords[i * 3 + 1] = 1; else if (_gtk_css_parser_try (parser, "center", TRUE)) coords[i * 3 + 1] = 0.5; else if (!_gtk_css_parser_try_double (parser, &coords[i * 3 + 1])) { _gtk_css_parser_error (parser, "Expected a valid Y coordinate"); return NULL; } if (type == CAIRO_PATTERN_TYPE_RADIAL) { /* Parse radius */ if (! _gtk_css_parser_try (parser, ",", TRUE)) { _gtk_css_parser_error (parser, "Expected ','"); return NULL; } if (! _gtk_css_parser_try_double (parser, &coords[(i * 3) + 2])) { _gtk_css_parser_error (parser, "Expected a numer for the radius"); return NULL; } } } if (type == CAIRO_PATTERN_TYPE_LINEAR) gradient = gtk_gradient_new_linear (coords[0], coords[1], coords[3], coords[4]); else gradient = gtk_gradient_new_radial (coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); while (_gtk_css_parser_try (parser, ",", TRUE)) { GtkSymbolicColor *color; gdouble position; if (_gtk_css_parser_try (parser, "from", TRUE)) { position = 0; if (!_gtk_css_parser_try (parser, "(", TRUE)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected '('"); return NULL; } } else if (_gtk_css_parser_try (parser, "to", TRUE)) { position = 1; if (!_gtk_css_parser_try (parser, "(", TRUE)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected '('"); return NULL; } } else if (_gtk_css_parser_try (parser, "color-stop", TRUE)) { if (!_gtk_css_parser_try (parser, "(", TRUE)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected '('"); return NULL; } if (!_gtk_css_parser_try_double (parser, &position)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected a valid number"); return NULL; } if (!_gtk_css_parser_try (parser, ",", TRUE)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected a comma"); return NULL; } } else { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Not a valid color-stop definition"); return NULL; } color = _gtk_css_parser_read_symbolic_color (parser); if (color == NULL) { gtk_gradient_unref (gradient); return NULL; } gtk_gradient_add_color_stop (gradient, position, color); gtk_symbolic_color_unref (color); if (!_gtk_css_parser_try (parser, ")", TRUE)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected ')'"); return NULL; } } if (!_gtk_css_parser_try (parser, ")", TRUE)) { gtk_gradient_unref (gradient); _gtk_css_parser_error (parser, "Expected ')'"); return NULL; } return gradient; }