static void gtk_border_image_compute_border_size (GtkBorderImageSliceSize sizes[3], double offset, double area_size, double start_border_width, double end_border_width, const GtkCssValue *start_border, const GtkCssValue *end_border) { double start, end; if (gtk_css_number_value_get_dimension (start_border) == GTK_CSS_DIMENSION_NUMBER) start = start_border_width * _gtk_css_number_value_get (start_border, 100); else start = _gtk_css_number_value_get (start_border, area_size); if (gtk_css_number_value_get_dimension (end_border) == GTK_CSS_DIMENSION_NUMBER) end = end_border_width * _gtk_css_number_value_get (end_border, 100); else end = _gtk_css_number_value_get (end_border, area_size); /* XXX: reduce vertical and horizontal by the same factor */ if (start + end > area_size) { start = start * area_size / (start + end); end = end * area_size / (start + end); } sizes[0].offset = offset; sizes[0].size = start; sizes[1].offset = offset + start; sizes[1].size = area_size - start - end; sizes[2].offset = offset + area_size - end; sizes[2].size = end; }
static GtkCssImage * gtk_css_image_builtin_compute (GtkCssImage *image, guint property_id, GtkStyleProviderPrivate *provider, GtkCssStyle *style, GtkCssStyle *parent_style) { GtkCssImageBuiltin *result; GtkBorderStyle border_style; result = g_object_new (GTK_TYPE_CSS_IMAGE_BUILTIN, NULL); border_style = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_STYLE)); if (border_style == GTK_BORDER_STYLE_SOLID) { GtkBorder border; border.top = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border.right = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border.bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); border.left = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); result->border_width = MIN (MIN (border.top, border.bottom), MIN (border.left, border.right)); } result->fg_color = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_COLOR)); result->bg_color = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); result->border_color = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_COLOR)); return GTK_CSS_IMAGE (result); }
gboolean gtk_css_style_render_has_border (GtkCssStyle *style) { if (_gtk_css_image_value_get_image (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE))) return TRUE; return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100) > 0 || _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100) > 0 || _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100) > 0 || _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100) > 0; }
void gtk_css_style_render_border (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height, guint hidden_side, GtkJunctionSides junction) { GtkBorderImage border_image; double border_width[4]; border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border_width[1] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border_width[2] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); border_width[3] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); if (gtk_border_image_init (&border_image, style)) { gtk_border_image_render (&border_image, border_width, cr, x, y, width, height); } else { GtkBorderStyle border_style[4]; GtkRoundedBox border_box; GdkRGBA colors[4]; /* Optimize the most common case of "This widget has no border" */ if (border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0) return; border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_STYLE)); border_style[1] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE)); border_style[2] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE)); border_style[3] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_STYLE)); hide_border_sides (border_width, border_style, hidden_side); colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_COLOR)); colors[1] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR)); colors[2] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR)); colors[3] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_COLOR)); _gtk_rounded_box_init_rect (&border_box, x, y, width, height); _gtk_rounded_box_apply_border_radius_for_style (&border_box, style, junction); render_border (cr, &border_box, border_width, hidden_side, colors, border_style); } }
/* * gtk_render_content_path: * @context: style context to get style information from * @cr: cairo context to add path to * @x: x coordinate of CSS box * @y: y coordinate of CSS box * @width: width of CSS box * @height: height of CSS box * * Adds the path of the content box to @cr for a given border box. * This function respects rounded corners. * * This is useful if you are drawing content that is supposed to * fill the whole content area, like the color buttons in * #GtkColorChooserDialog. **/ void gtk_render_content_path (GtkStyleContext *context, cairo_t *cr, double x, double y, double width, double height) { GtkRoundedBox box; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); _gtk_rounded_box_init_rect (&box, x, y, width, height); _gtk_rounded_box_apply_border_radius_for_style (&box, gtk_style_context_lookup_style (context), 0); _gtk_rounded_box_shrink (&box, _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_TOP), 100), _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_RIGHT), 100), _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_BOTTOM), 100), _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100) + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_LEFT), 100)); _gtk_rounded_box_path (&box, cr); }
static void gtk_css_computed_values_create_css_transitions (GtkCssComputedValues *values, gint64 timestamp, GtkCssComputedValues *source) { TransitionInfo transitions[GTK_CSS_PROPERTY_N_PROPERTIES] = { { 0, } }; GtkCssValue *durations, *delays, *timing_functions; guint i; transition_infos_set (transitions, _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_TRANSITION_PROPERTY)); durations = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_TRANSITION_DURATION); delays = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_TRANSITION_DELAY); timing_functions = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION); for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++) { GtkStyleAnimation *animation; GtkCssValue *start, *end; double duration, delay; if (!transitions[i].pending) continue; duration = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (durations, transitions[i].index), 100); delay = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (delays, transitions[i].index), 100); if (duration + delay == 0.0) continue; start = _gtk_css_computed_values_get_intrinsic_value (source, i); end = _gtk_css_computed_values_get_intrinsic_value (values, i); if (_gtk_css_value_equal (start, end)) { animation = gtk_css_computed_values_find_transition (GTK_CSS_COMPUTED_VALUES (source), i); if (animation) values->animations = g_slist_prepend (values->animations, g_object_ref (animation)); } else { animation = _gtk_css_transition_new (i, _gtk_css_computed_values_get_value (source, i), _gtk_css_array_value_get_nth (timing_functions, i), timestamp + delay * G_USEC_PER_SEC, timestamp + (delay + duration) * G_USEC_PER_SEC); values->animations = g_slist_prepend (values->animations, animation); } } }
static double get_base_font_size (guint property_id, GtkStyleProviderPrivate *provider, GtkCssStyle *style, GtkCssStyle *parent_style) { if (property_id == GTK_CSS_PROPERTY_FONT_SIZE) { if (parent_style) return _gtk_css_number_value_get (gtk_css_style_get_value (parent_style, GTK_CSS_PROPERTY_FONT_SIZE), 100); else return _gtk_css_font_size_get_default (provider); } return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_SIZE), 100); }
void gtk_css_style_render_outline (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height) { GtkBorderStyle border_style[4]; GtkRoundedBox border_box; double border_width[4]; GdkRGBA colors[4]; border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_STYLE)); if (border_style[0] != GTK_BORDER_STYLE_NONE) { cairo_rectangle_t rect; compute_outline_rect (style, x, y, width, height, &rect); border_style[1] = border_style[2] = border_style[3] = border_style[0]; border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); border_width[3] = border_width[2] = border_width[1] = border_width[0]; colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_COLOR)); colors[3] = colors[2] = colors[1] = colors[0]; _gtk_rounded_box_init_rect (&border_box, rect.x, rect.y, rect.width, rect.height); _gtk_rounded_box_apply_outline_radius_for_style (&border_box, style, GTK_JUNCTION_NONE); render_border (cr, &border_box, border_width, 0, colors, border_style); } }
static gboolean int_value_parse (GtkCssParser *parser, GValue *value) { gint i; if (_gtk_css_parser_has_prefix (parser, "-gtk")) { GtkCssValue *cssvalue = gtk_css_win32_size_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_NUMBER_AS_PIXELS); if (cssvalue) { g_value_set_int (value, _gtk_css_number_value_get (cssvalue, 100)); _gtk_css_value_unref (cssvalue); return TRUE; } return FALSE; } if (!_gtk_css_parser_try_int (parser, &i)) { _gtk_css_parser_error (parser, "Expected a valid integer value"); return FALSE; } g_value_set_int (value, i); return TRUE; }
static void gtk_css_image_linear_print (GtkCssImage *image, GString *string) { GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image); guint i; if (linear->repeating) g_string_append (string, "repeating-linear-gradient("); else g_string_append (string, "linear-gradient("); if (_gtk_css_number_value_get_unit (linear->angle) == GTK_CSS_NUMBER) { guint side = _gtk_css_number_value_get (linear->angle, 100); if (side != (1 << GTK_CSS_BOTTOM)) { g_string_append (string, "to"); if (side & (1 << GTK_CSS_TOP)) g_string_append (string, " top"); else if (side & (1 << GTK_CSS_BOTTOM)) g_string_append (string, " bottom"); if (side & (1 << GTK_CSS_LEFT)) g_string_append (string, " left"); else if (side & (1 << GTK_CSS_RIGHT)) g_string_append (string, " right"); g_string_append (string, ", "); } } else { _gtk_css_value_print (linear->angle, string); g_string_append (string, ", "); } for (i = 0; i < linear->stops->len; i++) { GtkCssImageLinearColorStop *stop; if (i > 0) g_string_append (string, ", "); stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, i); _gtk_css_value_print (stop->color, string); if (stop->offset) { g_string_append (string, " "); _gtk_css_value_print (stop->offset, string); } } g_string_append (string, ")"); }
static double get_base_font_size (guint property_id, GtkStyleProviderPrivate *provider, GtkCssComputedValues *values, GtkCssComputedValues *parent_values, GtkCssDependencies *dependencies) { if (property_id == GTK_CSS_PROPERTY_FONT_SIZE) { *dependencies = GTK_CSS_DEPENDS_ON_PARENT; if (parent_values) return _gtk_css_number_value_get (_gtk_css_computed_values_get_value (parent_values, GTK_CSS_PROPERTY_FONT_SIZE), 100); else return _gtk_css_font_size_get_default (provider); } *dependencies = GTK_CSS_DEPENDS_ON_FONT_SIZE; return _gtk_css_number_value_get (_gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_FONT_SIZE), 100); }
int gtk_icon_helper_get_size (GtkIconHelper *self) { GtkCssStyle *style; if (self->pixel_size != -1) return self->pixel_size; style = gtk_css_node_get_style (self->node); return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SIZE), 100); }
static void gtk_css_image_linear_get_start_end (GtkCssImageLinear *linear, double length, double *start, double *end) { GtkCssImageLinearColorStop *stop; double pos; guint i; if (linear->repeating) { stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, 0); if (stop->offset == NULL) *start = 0; else *start = _gtk_css_number_value_get (stop->offset, length) / length; *end = *start; for (i = 0; i < linear->stops->len; i++) { stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, i); if (stop->offset == NULL) continue; pos = _gtk_css_number_value_get (stop->offset, length) / length; *end = MAX (pos, *end); } if (stop->offset == NULL) *end = MAX (*end, 1.0); } else { *start = 0; *end = 1; } }
static void gtk_css_image_radial_get_start_end (GtkCssImageRadial *radial, double radius, double *start, double *end) { GtkCssImageRadialColorStop *stop; double pos; guint i; if (radial->repeating) { stop = &g_array_index (radial->stops, GtkCssImageRadialColorStop, 0); if (stop->offset == NULL) *start = 0; else *start = _gtk_css_number_value_get (stop->offset, radius) / radius; *end = *start; for (i = 0; i < radial->stops->len; i++) { stop = &g_array_index (radial->stops, GtkCssImageRadialColorStop, i); if (stop->offset == NULL) continue; pos = _gtk_css_number_value_get (stop->offset, radius) / radius; *end = MAX (pos, *end); } if (stop->offset == NULL) *end = MAX (*end, 1.0); } else { *start = 0; *end = 1; } }
static gboolean border_value_parse (GtkCssParser *parser, GValue *value) { GtkBorder border = { 0, }; guint i; int numbers[4]; for (i = 0; i < G_N_ELEMENTS (numbers); i++) { if (_gtk_css_parser_has_prefix (parser, "-gtk")) { GtkCssValue *cssvalue = gtk_css_win32_size_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_NUMBER_AS_PIXELS); if (cssvalue) { numbers[i] = _gtk_css_number_value_get (cssvalue, 100); _gtk_css_value_unref (cssvalue); return TRUE; } return FALSE; } else { if (!_gtk_css_parser_try_length (parser, &numbers[i])) break; } } if (i == 0) { _gtk_css_parser_error (parser, "Expected valid border"); return FALSE; } border.top = numbers[0]; if (i > 1) border.right = numbers[1]; else border.right = border.top; if (i > 2) border.bottom = numbers[2]; else border.bottom = border.top; if (i > 3) border.left = numbers[3]; else border.left = border.right; g_value_set_boxed (value, &border); return TRUE; }
static void compute_outline_rect (GtkCssStyle *style, gdouble x, gdouble y, gdouble width, gdouble height, cairo_rectangle_t *out_rect) { double offset, owidth; owidth = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); offset = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 100); if (width <= -2 * offset) { x += width / 2; out_rect->x = x - owidth; out_rect->width = 2 * owidth; } else { out_rect->x = x - offset - owidth; out_rect->width = width + 2 * (offset + owidth); } if (height <= -2 * offset) { y += height / 2; out_rect->y = y - owidth; out_rect->height = 2 * owidth; } else { out_rect->y = y - offset - owidth; out_rect->height = height + 2 * (offset + owidth); } }
static gboolean gtk_css_image_cross_fade_parse (GtkCssImage *image, GtkCssParser *parser) { GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); if (!_gtk_css_parser_try (parser, "cross-fade(", TRUE)) { _gtk_css_parser_error (parser, "Expected 'cross-fade('"); return FALSE; } if (_gtk_css_parser_has_number (parser)) { GtkCssValue *number; number = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_PERCENT | GTK_CSS_POSITIVE_ONLY); if (number == NULL) return FALSE; cross_fade->progress = _gtk_css_number_value_get (number, 1); _gtk_css_value_unref (number); if (cross_fade->progress > 1.0) { _gtk_css_parser_error (parser, "Percentages over 100%% are not allowed"); return FALSE; } } else cross_fade->progress = 0.5; cross_fade->start = _gtk_css_image_new_parse (parser); if (cross_fade->start == NULL) return FALSE; if (_gtk_css_parser_try (parser, ",", TRUE)) { /* XXX: allow parsing colors here */ cross_fade->end = _gtk_css_image_new_parse (parser); if (cross_fade->end == NULL) return FALSE; } if (!_gtk_css_parser_try (parser, ")", TRUE)) { _gtk_css_parser_error (parser, "Missing closing bracket"); return FALSE; } return TRUE; }
void gtk_css_style_render_outline (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height) { GtkBorderStyle border_style[4]; GtkRoundedBox border_box; double border_width[4]; GdkRGBA colors[4]; border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_STYLE)); if (border_style[0] != GTK_BORDER_STYLE_NONE) { int offset; border_style[1] = border_style[2] = border_style[3] = border_style[0]; border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); border_width[3] = border_width[2] = border_width[1] = border_width[0]; colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_COLOR)); colors[3] = colors[2] = colors[1] = colors[0]; offset = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 100); _gtk_rounded_box_init_rect (&border_box, x, y, width, height); _gtk_rounded_box_shrink (&border_box, - border_width[GTK_CSS_TOP] - offset, - border_width[GTK_CSS_RIGHT] - offset, - border_width[GTK_CSS_LEFT] - offset, - border_width[GTK_CSS_BOTTOM] - offset); _gtk_rounded_box_apply_outline_radius_for_style (&border_box, style, GTK_JUNCTION_NONE); render_border (cr, &border_box, border_width, 0, colors, border_style); } }
static GSList * gtk_css_animated_style_create_css_transitions (GSList *animations, GtkCssStyle *base_style, gint64 timestamp, GtkCssStyle *source) { TransitionInfo transitions[GTK_CSS_PROPERTY_N_PROPERTIES] = { { 0, } }; GtkCssValue *durations, *delays, *timing_functions; guint i; transition_infos_set (transitions, gtk_css_style_get_value (base_style, GTK_CSS_PROPERTY_TRANSITION_PROPERTY)); durations = gtk_css_style_get_value (base_style, GTK_CSS_PROPERTY_TRANSITION_DURATION); delays = gtk_css_style_get_value (base_style, GTK_CSS_PROPERTY_TRANSITION_DELAY); timing_functions = gtk_css_style_get_value (base_style, GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION); for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++) { GtkStyleAnimation *animation; GtkCssValue *start, *end; double duration, delay; if (!transitions[i].pending) continue; duration = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (durations, transitions[i].index), 100); delay = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (delays, transitions[i].index), 100); if (duration + delay == 0.0) continue; if (GTK_IS_CSS_ANIMATED_STYLE (source)) { start = gtk_css_animated_style_get_intrinsic_value (GTK_CSS_ANIMATED_STYLE (source), i); end = gtk_css_style_get_value (base_style, i); if (_gtk_css_value_equal (start, end)) { animation = gtk_css_animated_style_find_transition (GTK_CSS_ANIMATED_STYLE (source), i); if (animation) { animation = _gtk_style_animation_advance (animation, timestamp); animations = g_slist_prepend (animations, animation); } continue; } } if (_gtk_css_value_equal (gtk_css_style_get_value (source, i), gtk_css_style_get_value (base_style, i))) continue; animation = _gtk_css_transition_new (i, gtk_css_style_get_value (source, i), _gtk_css_array_value_get_nth (timing_functions, i), timestamp, duration * G_USEC_PER_SEC, delay * G_USEC_PER_SEC); animations = g_slist_prepend (animations, animation); } return animations; }
gboolean gtk_css_style_render_has_outline (GtkCssStyle *style) { return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100) > 0; }
static void gtk_css_image_linear_snapshot (GtkCssImage *image, GtkSnapshot *snapshot, double width, double height) { GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image); GskColorStop *stops; GskRenderNode *node; double off_x, off_y; /* snapshot offset */ double angle; /* actual angle of the gradiant line in degrees */ double x, y; /* coordinates of start point */ double length; /* distance in pixels for 100% */ double start, end; /* position of first/last point on gradient line - with gradient line being [0, 1] */ double offset; int i, last; char *name; if (linear->side) { /* special casing the regular cases here so we don't get rounding errors */ switch (linear->side) { case 1 << GTK_CSS_RIGHT: angle = 90; break; case 1 << GTK_CSS_LEFT: angle = 270; break; case 1 << GTK_CSS_TOP: angle = 0; break; case 1 << GTK_CSS_BOTTOM: angle = 180; break; default: angle = atan2 (linear->side & 1 << GTK_CSS_TOP ? -width : width, linear->side & 1 << GTK_CSS_LEFT ? -height : height); angle = 180 * angle / G_PI + 90; break; } } else { angle = _gtk_css_number_value_get (linear->angle, 100); } gtk_css_image_linear_compute_start_point (angle, width, height, &x, &y); length = sqrt (x * x + y * y); gtk_css_image_linear_get_start_end (linear, length, &start, &end); if (start == end) { /* repeating gradients with all color stops sharing the same offset * get the color of the last color stop */ GtkCssImageLinearColorStop *stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, linear->stops->len - 1); gtk_snapshot_append_color_node (snapshot, _gtk_css_rgba_value_get_rgba (stop->color), &GRAPHENE_RECT_INIT (0, 0, width, height), "RepeatingLinearGradient<degenerate>"); return; } offset = start; last = -1; stops = g_newa (GskColorStop, linear->stops->len); for (i = 0; i < linear->stops->len; i++) { GtkCssImageLinearColorStop *stop; double pos, step; stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, i); if (stop->offset == NULL) { if (i == 0) pos = 0.0; else if (i + 1 == linear->stops->len) pos = 1.0; else continue; } else pos = _gtk_css_number_value_get (stop->offset, length) / length; pos = MAX (pos, offset); step = (pos - offset) / (i - last); for (last = last + 1; last <= i; last++) { stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, last); offset += step; stops[last].offset = (offset - start) / (end - start); stops[last].color = *_gtk_css_rgba_value_get_rgba (stop->color); } offset = pos; last = i; } gtk_snapshot_get_offset (snapshot, &off_x, &off_y); if (linear->repeating) { node = gsk_repeating_linear_gradient_node_new ( &GRAPHENE_RECT_INIT (off_x, off_y, width, height), &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)), &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5), off_y + height / 2 + y * (end - 0.5)), stops, linear->stops->len); } else { node = gsk_linear_gradient_node_new ( &GRAPHENE_RECT_INIT (off_x, off_y, width, height), &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)), &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5), off_y + height / 2 + y * (end - 0.5)), stops, linear->stops->len); } name = g_strdup_printf ("%sLinearGradient<%ustops>", linear->repeating ? "Repeating" : "", linear->stops->len); gsk_render_node_set_name (node, name); g_free (name); gtk_snapshot_append_node (snapshot, node); gsk_render_node_unref (node); }
static void gtk_border_image_render (GtkBorderImage *image, const double border_width[4], cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height) { cairo_surface_t *surface, *slice; GtkBorderImageSliceSize vertical_slice[3], horizontal_slice[3]; GtkBorderImageSliceSize vertical_border[3], horizontal_border[3]; double source_width, source_height; int h, v; _gtk_css_image_get_concrete_size (image->source, 0, 0, width, height, &source_width, &source_height); /* XXX: Optimize for (source_width == width && source_height == height) */ surface = _gtk_css_image_get_surface (image->source, cairo_get_target (cr), source_width, source_height); gtk_border_image_compute_slice_size (horizontal_slice, source_width, _gtk_css_number_value_get (_gtk_css_border_value_get_left (image->slice), source_width), _gtk_css_number_value_get (_gtk_css_border_value_get_right (image->slice), source_width)); gtk_border_image_compute_slice_size (vertical_slice, source_height, _gtk_css_number_value_get (_gtk_css_border_value_get_top (image->slice), source_height), _gtk_css_number_value_get (_gtk_css_border_value_get_bottom (image->slice), source_height)); gtk_border_image_compute_border_size (horizontal_border, x, width, border_width[GTK_CSS_LEFT], border_width[GTK_CSS_RIGHT], _gtk_css_border_value_get_left (image->width), _gtk_css_border_value_get_right (image->width)); gtk_border_image_compute_border_size (vertical_border, y, height, border_width[GTK_CSS_TOP], border_width[GTK_CSS_BOTTOM], _gtk_css_border_value_get_top (image->width), _gtk_css_border_value_get_bottom(image->width)); for (v = 0; v < 3; v++) { if (vertical_slice[v].size == 0 || vertical_border[v].size == 0) continue; for (h = 0; h < 3; h++) { if (horizontal_slice[h].size == 0 || horizontal_border[h].size == 0) continue; if (h == 1 && v == 1) continue; slice = cairo_surface_create_for_rectangle (surface, horizontal_slice[h].offset, vertical_slice[v].offset, horizontal_slice[h].size, vertical_slice[v].size); gtk_border_image_render_slice (cr, slice, horizontal_slice[h].size, vertical_slice[v].size, horizontal_border[h].offset, vertical_border[v].offset, horizontal_border[h].size, vertical_border[v].size, h == 1 ? _gtk_css_border_repeat_value_get_x (image->repeat) : GTK_CSS_REPEAT_STYLE_STRETCH, v == 1 ? _gtk_css_border_repeat_value_get_y (image->repeat) : GTK_CSS_REPEAT_STYLE_STRETCH); cairo_surface_destroy (slice); } } cairo_surface_destroy (surface); }
static void gtk_css_style_render_frame_gap (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height, GtkPositionType gap_side, gdouble xy0_gap, gdouble xy1_gap, GtkJunctionSides junction) { gint border_width; GtkCssValue *corner[4]; gdouble x0, y0, x1, y1, xc = 0.0, yc = 0.0, wc = 0.0, hc = 0.0; GtkBorder border; border.top = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border.right = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border.bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); border.left = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); corner[GTK_CSS_TOP_LEFT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS); corner[GTK_CSS_TOP_RIGHT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS); corner[GTK_CSS_BOTTOM_LEFT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS); corner[GTK_CSS_BOTTOM_RIGHT] = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS); border_width = MIN (MIN (border.top, border.bottom), MIN (border.left, border.right)); cairo_save (cr); switch (gap_side) { case GTK_POS_TOP: xc = x + xy0_gap + border_width; yc = y; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; if (xy0_gap < _gtk_css_corner_value_get_x (corner[GTK_CSS_TOP_LEFT], width)) junction |= GTK_JUNCTION_CORNER_TOPLEFT; if (xy1_gap > width - _gtk_css_corner_value_get_x (corner[GTK_CSS_TOP_RIGHT], width)) junction |= GTK_JUNCTION_CORNER_TOPRIGHT; break; case GTK_POS_BOTTOM: xc = x + xy0_gap + border_width; yc = y + height - border_width; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; if (xy0_gap < _gtk_css_corner_value_get_x (corner[GTK_CSS_BOTTOM_LEFT], width)) junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT; if (xy1_gap > width - _gtk_css_corner_value_get_x (corner[GTK_CSS_BOTTOM_RIGHT], width)) junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT; break; case GTK_POS_LEFT: xc = x; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); if (xy0_gap < _gtk_css_corner_value_get_y (corner[GTK_CSS_TOP_LEFT], height)) junction |= GTK_JUNCTION_CORNER_TOPLEFT; if (xy1_gap > height - _gtk_css_corner_value_get_y (corner[GTK_CSS_BOTTOM_LEFT], height)) junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT; break; case GTK_POS_RIGHT: xc = x + width - border_width; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); if (xy0_gap < _gtk_css_corner_value_get_y (corner[GTK_CSS_TOP_RIGHT], height)) junction |= GTK_JUNCTION_CORNER_TOPRIGHT; if (xy1_gap > height - _gtk_css_corner_value_get_y (corner[GTK_CSS_BOTTOM_RIGHT], height)) junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT; break; } cairo_clip_extents (cr, &x0, &y0, &x1, &y1); cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0); cairo_rectangle (cr, x0, yc, xc - x0, hc); cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc); cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc)); cairo_clip (cr); gtk_css_style_render_border (style, cr, x, y, width, height, 0, junction); cairo_restore (cr); }
static void gtk_css_computed_values_create_css_animations (GtkCssComputedValues *values, GtkCssComputedValues *parent_values, gint64 timestamp, GtkStyleProviderPrivate *provider, GtkCssComputedValues *source) { GtkCssValue *durations, *delays, *timing_functions, *animations; GtkCssValue *iteration_counts, *directions, *play_states, *fill_modes; guint i; animations = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_NAME); durations = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_DURATION); delays = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_DELAY); timing_functions = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION); iteration_counts = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT); directions = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_DIRECTION); play_states = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE); fill_modes = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_ANIMATION_FILL_MODE); for (i = 0; i < _gtk_css_array_value_get_n_values (animations); i++) { GtkStyleAnimation *animation; GtkCssKeyframes *keyframes; const char *name; name = _gtk_css_ident_value_get (_gtk_css_array_value_get_nth (animations, i)); if (g_ascii_strcasecmp (name, "none") == 0) continue; animation = gtk_css_computed_values_find_animation (values, name); if (animation) continue; if (source) animation = gtk_css_computed_values_find_animation (source, name); if (animation) { animation = _gtk_css_animation_copy (GTK_CSS_ANIMATION (animation), timestamp, _gtk_css_play_state_value_get (_gtk_css_array_value_get_nth (play_states, i))); } else { keyframes = _gtk_style_provider_private_get_keyframes (provider, name); if (keyframes == NULL) continue; keyframes = _gtk_css_keyframes_compute (keyframes, provider, values, parent_values); animation = _gtk_css_animation_new (name, keyframes, timestamp, _gtk_css_number_value_get (_gtk_css_array_value_get_nth (delays, i), 100) * G_USEC_PER_SEC, _gtk_css_number_value_get (_gtk_css_array_value_get_nth (durations, i), 100) * G_USEC_PER_SEC, _gtk_css_array_value_get_nth (timing_functions, i), _gtk_css_direction_value_get (_gtk_css_array_value_get_nth (directions, i)), _gtk_css_play_state_value_get (_gtk_css_array_value_get_nth (play_states, i)), _gtk_css_fill_mode_value_get (_gtk_css_array_value_get_nth (fill_modes, i)), _gtk_css_number_value_get (_gtk_css_array_value_get_nth (iteration_counts, i), 100)); _gtk_css_keyframes_unref (keyframes); } values->animations = g_slist_prepend (values->animations, animation); } }
static void gtk_css_image_linear_draw (GtkCssImage *image, cairo_t *cr, double width, double height) { GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image); cairo_pattern_t *pattern; double angle; /* actual angle of the gradiant line in degrees */ double x, y; /* coordinates of start point */ double length; /* distance in pixels for 100% */ double start, end; /* position of first/last point on gradient line - with gradient line being [0, 1] */ double offset; int i, last; if (linear->side) { /* special casing the regular cases here so we don't get rounding errors */ switch (linear->side) { case 1 << GTK_CSS_RIGHT: angle = 90; break; case 1 << GTK_CSS_LEFT: angle = 270; break; case 1 << GTK_CSS_TOP: angle = 0; break; case 1 << GTK_CSS_BOTTOM: angle = 180; break; default: angle = atan2 (linear->side & 1 << GTK_CSS_TOP ? -width : width, linear->side & 1 << GTK_CSS_LEFT ? -height : height); angle = 180 * angle / G_PI + 90; break; } } else { angle = _gtk_css_number_value_get (linear->angle, 100); } gtk_css_image_linear_compute_start_point (angle, width, height, &x, &y); length = sqrt (x * x + y * y); gtk_css_image_linear_get_start_end (linear, length, &start, &end); pattern = cairo_pattern_create_linear (x * (start - 0.5), y * (start - 0.5), x * (end - 0.5), y * (end - 0.5)); if (linear->repeating) cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); else cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); offset = start; last = -1; for (i = 0; i < linear->stops->len; i++) { GtkCssImageLinearColorStop *stop; double pos, step; stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, i); if (stop->offset == NULL) { if (i == 0) pos = 0.0; else if (i + 1 == linear->stops->len) pos = 1.0; else continue; } else pos = _gtk_css_number_value_get (stop->offset, length) / length; pos = MAX (pos, offset); step = (pos - offset) / (i - last); for (last = last + 1; last <= i; last++) { const GdkRGBA *rgba; stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, last); rgba = _gtk_css_rgba_value_get_rgba (stop->color); offset += step; cairo_pattern_add_color_stop_rgba (pattern, (offset - start) / (end - start), rgba->red, rgba->green, rgba->blue, rgba->alpha); } offset = pos; last = i; } cairo_rectangle (cr, 0, 0, width, height); cairo_translate (cr, width / 2, height / 2); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); }
static void gtk_css_image_radial_draw (GtkCssImage *image, cairo_t *cr, double width, double height) { GtkCssImageRadial *radial = GTK_CSS_IMAGE_RADIAL (image); cairo_pattern_t *pattern; cairo_matrix_t matrix; double x, y; double radius, yscale; double start, end; double r1, r2, r3, r4, r; double offset; int i, last; x = _gtk_css_position_value_get_x (radial->position, width); y = _gtk_css_position_value_get_y (radial->position, height); if (radial->circle) { switch (radial->size) { case GTK_CSS_EXPLICIT_SIZE: radius = _gtk_css_number_value_get (radial->sizes[0], width); break; case GTK_CSS_CLOSEST_SIDE: radius = MIN (MIN (x, width - x), MIN (y, height - y)); break; case GTK_CSS_FARTHEST_SIDE: radius = MAX (MAX (x, width - x), MAX (y, height - y)); break; case GTK_CSS_CLOSEST_CORNER: case GTK_CSS_FARTHEST_CORNER: r1 = x*x + y*y; r2 = x*x + (height - y)*(height - y); r3 = (width - x)*(width - x) + y*y; r4 = (width - x)*(width - x) + (height - y)*(height - y); if (radial->size == GTK_CSS_CLOSEST_CORNER) r = MIN ( MIN (r1, r2), MIN (r3, r4)); else r = MAX ( MAX (r1, r2), MAX (r3, r4)); radius = sqrt (r); break; default: g_assert_not_reached (); } radius = MAX (1.0, radius); yscale = 1.0; } else { double hradius, vradius; switch (radial->size) { case GTK_CSS_EXPLICIT_SIZE: hradius = _gtk_css_number_value_get (radial->sizes[0], width); vradius = _gtk_css_number_value_get (radial->sizes[1], height); break; case GTK_CSS_CLOSEST_SIDE: hradius = MIN (x, width - x); vradius = MIN (y, height - y); break; case GTK_CSS_FARTHEST_SIDE: hradius = MAX (x, width - x); vradius = MAX (y, height - y); break; case GTK_CSS_CLOSEST_CORNER: hradius = M_SQRT2 * MIN (x, width - x); vradius = M_SQRT2 * MIN (y, height - y); break; case GTK_CSS_FARTHEST_CORNER: hradius = M_SQRT2 * MAX (x, width - x); vradius = M_SQRT2 * MAX (y, height - y); break; default: g_assert_not_reached (); } hradius = MAX (1.0, hradius); vradius = MAX (1.0, vradius); radius = hradius; yscale = vradius / hradius; } gtk_css_image_radial_get_start_end (radial, radius, &start, &end); pattern = cairo_pattern_create_radial (0, 0, 0, 0, 0, radius); if (yscale != 1.0) { cairo_matrix_init_scale (&matrix, 1.0, 1.0 / yscale); cairo_pattern_set_matrix (pattern, &matrix); } if (radial->repeating) cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); else cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); offset = start; last = -1; for (i = 0; i < radial->stops->len; i++) { GtkCssImageRadialColorStop *stop; double pos, step; stop = &g_array_index (radial->stops, GtkCssImageRadialColorStop, i); if (stop->offset == NULL) { if (i == 0) pos = 0.0; else if (i + 1 == radial->stops->len) pos = 1.0; else continue; } else pos = _gtk_css_number_value_get (stop->offset, radius) / radius; pos = MAX (pos, 0); step = pos / (i - last); for (last = last + 1; last <= i; last++) { const GdkRGBA *rgba; stop = &g_array_index (radial->stops, GtkCssImageRadialColorStop, last); rgba = _gtk_css_rgba_value_get_rgba (stop->color); offset += step; cairo_pattern_add_color_stop_rgba (pattern, (offset - start) / (end - start), rgba->red, rgba->green, rgba->blue, rgba->alpha); } offset = pos; last = i; } cairo_rectangle (cr, 0, 0, width, height); cairo_translate (cr, x, y); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); }
static double get_dpi (GtkCssStyle *style) { return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_DPI), 96); }
static void gtk_css_style_render_frame_gap (GtkCssStyle *style, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height, GtkPositionType gap_side, gdouble xy0_gap, gdouble xy1_gap) { gint border_width; gdouble x0, y0, x1, y1, xc = 0.0, yc = 0.0, wc = 0.0, hc = 0.0; GtkBorder border; border.top = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border.right = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border.bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); border.left = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); border_width = MIN (MIN (border.top, border.bottom), MIN (border.left, border.right)); cairo_save (cr); switch (gap_side) { case GTK_POS_TOP: xc = x + xy0_gap + border_width; yc = y; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; break; case GTK_POS_BOTTOM: xc = x + xy0_gap + border_width; yc = y + height - border_width; wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); hc = border_width; break; case GTK_POS_LEFT: xc = x; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); break; case GTK_POS_RIGHT: xc = x + width - border_width; yc = y + xy0_gap + border_width; wc = border_width; hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0); break; } cairo_clip_extents (cr, &x0, &y0, &x1, &y1); cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0); cairo_rectangle (cr, x0, yc, xc - x0, hc); cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc); cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc)); cairo_clip (cr); gtk_css_style_render_border (style, cr, x, y, width, height); cairo_restore (cr); }