static void gtk_css_image_cross_fade_draw (GtkCssImage *image, cairo_t *cr, double width, double height) { GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); if (cross_fade->progress <= 0.0) { if (cross_fade->start) _gtk_css_image_draw (cross_fade->start, cr, width, height); } else if (cross_fade->progress >= 1.0) { if (cross_fade->end) _gtk_css_image_draw (cross_fade->end, cr, width, height); } else { if (cross_fade->start && cross_fade->end) { /* to reduce the group size */ cairo_rectangle (cr, 0, 0, ceil (width), ceil (height)); cairo_clip (cr); cairo_push_group (cr); /* performance trick */ cairo_reset_clip (cr); _gtk_css_image_draw (cross_fade->start, cr, width, height); cairo_push_group (cr); _gtk_css_image_draw (cross_fade->end, cr, width, height); cairo_pop_group_to_source (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint_with_alpha (cr, cross_fade->progress); cairo_pop_group_to_source (cr); cairo_paint (cr); } else if (cross_fade->start || cross_fade->end) { cairo_push_group (cr); _gtk_css_image_draw (cross_fade->start ? cross_fade->start : cross_fade->end, cr, width, height); cairo_pop_group_to_source (cr); cairo_paint_with_alpha (cr, cross_fade->start ? 1.0 - cross_fade->progress : cross_fade->progress); } } }
cairo_surface_t * _gtk_css_image_get_surface (GtkCssImage *image, cairo_surface_t *target, int surface_width, int surface_height) { cairo_surface_t *result; cairo_t *cr; g_return_val_if_fail (GTK_IS_CSS_IMAGE (image), NULL); g_return_val_if_fail (surface_width > 0, NULL); g_return_val_if_fail (surface_height > 0, NULL); if (target) result = cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR_ALPHA, surface_width, surface_height); else result = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, surface_width, surface_height); cr = cairo_create (result); _gtk_css_image_draw (image, cr, surface_width, surface_height); cairo_destroy (cr); return result; }
static void gtk_css_image_url_draw (GtkCssImage *image, cairo_t *cr, double width, double height) { GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image); _gtk_css_image_draw (gtk_css_image_url_load_image (url), cr, width, height); }
cairo_surface_t * _gtk_css_image_get_surface (GtkCssImage *image, cairo_surface_t *target, int surface_width, int surface_height) { cairo_surface_t *result; cairo_t *cr; double sx, sy; g_return_val_if_fail (GTK_IS_CSS_IMAGE (image), NULL); g_return_val_if_fail (surface_width > 0, NULL); g_return_val_if_fail (surface_height > 0, NULL); if (target) { #ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE cairo_surface_get_device_scale (target, &sx, &sy); #else sx = sy = 1; #endif result = cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR_ALPHA, surface_width*sx, surface_height*sy); #ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE cairo_surface_set_device_scale (result, sx, sy); #endif } else result = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, surface_width, surface_height); cr = cairo_create (result); _gtk_css_image_draw (image, cr, surface_width, surface_height); cairo_destroy (cr); return result; }
static void gtk_css_image_fallback_draw (GtkCssImage *image, cairo_t *cr, double width, double height) { GtkCssImageFallback *fallback = GTK_CSS_IMAGE_FALLBACK (image); if (fallback->used < 0) { if (fallback->color) gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (fallback->color)); else cairo_set_source_rgb (cr, 1, 0, 9); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); } else _gtk_css_image_draw (fallback->images[fallback->used], cr, width, height); }
static void _gtk_theming_background_paint_layer (GtkThemingBackground *bg, guint idx, cairo_t *cr) { GtkCssRepeatStyle hrepeat, vrepeat; const GtkCssValue *pos, *repeat; GtkCssImage *image; const GtkRoundedBox *origin; double image_width, image_height; double width, height; pos = _gtk_css_array_value_get_nth (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_POSITION), idx); repeat = _gtk_css_array_value_get_nth (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_REPEAT), idx); hrepeat = _gtk_css_background_repeat_value_get_x (repeat); vrepeat = _gtk_css_background_repeat_value_get_y (repeat); image = _gtk_css_image_value_get_image ( _gtk_css_array_value_get_nth ( _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_IMAGE), idx)); origin = &bg->boxes[ _gtk_css_area_value_get ( _gtk_css_array_value_get_nth ( _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_ORIGIN), idx))]; width = origin->box.width; height = origin->box.height; if (image == NULL || width <= 0 || height <= 0) return; _gtk_css_bg_size_value_compute_size (_gtk_css_array_value_get_nth (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_SIZE), idx), image, width, height, &image_width, &image_height); if (image_width <= 0 || image_height <= 0) return; /* optimization */ if (image_width == width) hrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT; if (image_height == height) vrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT; cairo_save (cr); _gtk_rounded_box_path ( &bg->boxes[ _gtk_css_area_value_get ( _gtk_css_array_value_get_nth ( _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_CLIP), idx))], cr); cairo_clip (cr); cairo_translate (cr, origin->box.x, origin->box.y); if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT && vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT) { cairo_translate (cr, _gtk_css_position_value_get_x (pos, width - image_width), _gtk_css_position_value_get_y (pos, height - image_height)); /* shortcut for normal case */ _gtk_css_image_draw (image, cr, image_width, image_height); } else { int surface_width, surface_height; cairo_rectangle_t fill_rect; cairo_surface_t *surface; cairo_t *cr2; /* If ‘background-repeat’ is ‘round’ for one (or both) dimensions, * there is a second step. The UA must scale the image in that * dimension (or both dimensions) so that it fits a whole number of * times in the background positioning area. In the case of the width * (height is analogous): * * If X ≠ 0 is the width of the image after step one and W is the width * of the background positioning area, then the rounded width * X' = W / round(W / X) where round() is a function that returns the * nearest natural number (integer greater than zero). * * If ‘background-repeat’ is ‘round’ for one dimension only and if * ‘background-size’ is ‘auto’ for the other dimension, then there is * a third step: that other dimension is scaled so that the original * aspect ratio is restored. */ if (hrepeat == GTK_CSS_REPEAT_STYLE_ROUND) { double n = round (width / image_width); n = MAX (1, n); if (vrepeat != GTK_CSS_REPEAT_STYLE_ROUND /* && vsize == auto (it is by default) */) image_height *= width / (image_width * n); image_width = width / n; } if (vrepeat == GTK_CSS_REPEAT_STYLE_ROUND) { double n = round (height / image_height); n = MAX (1, n); if (hrepeat != GTK_CSS_REPEAT_STYLE_ROUND /* && hsize == auto (it is by default) */) image_width *= height / (image_height * n); image_height = height / n; } /* if hrepeat or vrepeat is 'space', we create a somewhat larger surface * to store the extra space. */ if (hrepeat == GTK_CSS_REPEAT_STYLE_SPACE) { double n = floor (width / image_width); surface_width = n ? round (width / n) : 0; } else surface_width = round (image_width); if (vrepeat == GTK_CSS_REPEAT_STYLE_SPACE) { double n = floor (height / image_height); surface_height = n ? round (height / n) : 0; } else surface_height = round (image_height); surface = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR_ALPHA, surface_width, surface_height); cr2 = cairo_create (surface); cairo_translate (cr2, 0.5 * (surface_width - image_width), 0.5 * (surface_height - image_height)); _gtk_css_image_draw (image, cr2, image_width, image_height); cairo_destroy (cr2); cairo_set_source_surface (cr, surface, _gtk_css_position_value_get_x (pos, width - image_width), _gtk_css_position_value_get_y (pos, height - image_height)); cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); cairo_surface_destroy (surface); if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT) { fill_rect.x = _gtk_css_position_value_get_x (pos, width - image_width); fill_rect.width = image_width; } else { fill_rect.x = 0; fill_rect.width = width; } if (vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT) { fill_rect.y = _gtk_css_position_value_get_y (pos, height - image_height); fill_rect.height = image_height; } else { fill_rect.y = 0; fill_rect.height = height; } cairo_rectangle (cr, fill_rect.x, fill_rect.y, fill_rect.width, fill_rect.height); cairo_fill (cr); } cairo_restore (cr); }
void gtk_css_image_builtin_draw (GtkCssImage *image, cairo_t *cr, double width, double height, GtkCssImageBuiltinType image_type) { if (!GTK_IS_CSS_IMAGE_BUILTIN (image)) { _gtk_css_image_draw (image, cr, width, height); return; } switch (image_type) { default: g_assert_not_reached (); break; case GTK_CSS_IMAGE_BUILTIN_NONE: break; case GTK_CSS_IMAGE_BUILTIN_CHECK: case GTK_CSS_IMAGE_BUILTIN_CHECK_CHECKED: case GTK_CSS_IMAGE_BUILTIN_CHECK_INCONSISTENT: gtk_css_image_builtin_draw_check (image, cr, width, height, image_type == GTK_CSS_IMAGE_BUILTIN_CHECK_CHECKED, image_type == GTK_CSS_IMAGE_BUILTIN_CHECK_INCONSISTENT); break; case GTK_CSS_IMAGE_BUILTIN_OPTION: case GTK_CSS_IMAGE_BUILTIN_OPTION_CHECKED: case GTK_CSS_IMAGE_BUILTIN_OPTION_INCONSISTENT: gtk_css_image_builtin_draw_option (image, cr, width, height, image_type == GTK_CSS_IMAGE_BUILTIN_OPTION_CHECKED, image_type == GTK_CSS_IMAGE_BUILTIN_OPTION_INCONSISTENT); break; case GTK_CSS_IMAGE_BUILTIN_ARROW_UP: case GTK_CSS_IMAGE_BUILTIN_ARROW_DOWN: case GTK_CSS_IMAGE_BUILTIN_ARROW_LEFT: case GTK_CSS_IMAGE_BUILTIN_ARROW_RIGHT: gtk_css_image_builtin_draw_arrow (image, cr, width, height, image_type); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL_LEFT: gtk_css_image_builtin_draw_expander (image, cr, width, height, TRUE, FALSE, FALSE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL_LEFT: gtk_css_image_builtin_draw_expander (image, cr, width, height, FALSE, FALSE, FALSE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL_RIGHT: gtk_css_image_builtin_draw_expander (image, cr, width, height, TRUE, TRUE, FALSE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL_RIGHT: gtk_css_image_builtin_draw_expander (image, cr, width, height, FALSE, TRUE, FALSE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL_LEFT_EXPANDED: gtk_css_image_builtin_draw_expander (image, cr, width, height, TRUE, FALSE, TRUE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL_LEFT_EXPANDED: gtk_css_image_builtin_draw_expander (image, cr, width, height, FALSE, FALSE, TRUE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_HORIZONTAL_RIGHT_EXPANDED: gtk_css_image_builtin_draw_expander (image, cr, width, height, TRUE, TRUE, TRUE); break; case GTK_CSS_IMAGE_BUILTIN_EXPANDER_VERTICAL_RIGHT_EXPANDED: gtk_css_image_builtin_draw_expander (image, cr, width, height, FALSE, TRUE, TRUE); break; case GTK_CSS_IMAGE_BUILTIN_GRIP_TOPLEFT: case GTK_CSS_IMAGE_BUILTIN_GRIP_TOP: case GTK_CSS_IMAGE_BUILTIN_GRIP_TOPRIGHT: case GTK_CSS_IMAGE_BUILTIN_GRIP_RIGHT: case GTK_CSS_IMAGE_BUILTIN_GRIP_BOTTOMRIGHT: case GTK_CSS_IMAGE_BUILTIN_GRIP_BOTTOM: case GTK_CSS_IMAGE_BUILTIN_GRIP_BOTTOMLEFT: case GTK_CSS_IMAGE_BUILTIN_GRIP_LEFT: gtk_css_image_builtin_draw_grip (image, cr, width, height, image_type); break; case GTK_CSS_IMAGE_BUILTIN_PANE_SEPARATOR: gtk_css_image_builtin_draw_pane_separator (image, cr, width, height); break; case GTK_CSS_IMAGE_BUILTIN_HANDLE: gtk_css_image_builtin_draw_handle (image, cr, width, height); break; case GTK_CSS_IMAGE_BUILTIN_SPINNER: gtk_css_image_builtin_draw_spinner (image, cr, width, height); break; } }