cairo_t * gsk_cairo_blur_finish_drawing (cairo_t *cr, float radius, const GdkRGBA *color, GskBlurFlags blur_flags) { cairo_t *original_cr; cairo_surface_t *surface; gdouble x_scale; if (!needs_blur (radius)) return cr; original_cr = cairo_get_user_data (cr, &original_cr_key); /* Blur the surface. */ surface = cairo_get_target (cr); x_scale = 1; cairo_surface_get_device_scale (cairo_get_target (cr), &x_scale, NULL); gsk_cairo_blur_surface (surface, x_scale * radius, blur_flags); gdk_cairo_set_source_rgba (original_cr, color); if (blur_flags & GSK_BLUR_REPEAT) mask_surface_repeat (original_cr, surface); else cairo_mask_surface (original_cr, surface, 0, 0); cairo_destroy (cr); cairo_surface_destroy (surface); return original_cr; }
static void get_surface_size (GtkIconHelper *self, GtkStyleContext *context, cairo_surface_t *surface, int *width, int *height) { double x_scale, y_scale; if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) { x_scale = y_scale = 1; #ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE cairo_surface_get_device_scale (surface, &x_scale, &y_scale); #endif /* Assume any set scaling is icon scale */ *width = ceil (cairo_image_surface_get_width (surface) / x_scale); *height = ceil (cairo_image_surface_get_height (surface) / y_scale); } else ensure_icon_size (self, context, width, height); }
cairo_t * gsk_cairo_blur_start_drawing (cairo_t *cr, float radius, GskBlurFlags blur_flags) { cairo_rectangle_int_t clip_rect; cairo_surface_t *surface; cairo_t *blur_cr; gdouble clip_radius; gdouble x_scale, y_scale; gboolean blur_x = (blur_flags & GSK_BLUR_X) != 0; gboolean blur_y = (blur_flags & GSK_BLUR_Y) != 0; if (!needs_blur (radius)) return cr; gdk_cairo_get_clip_rectangle (cr, &clip_rect); clip_radius = gsk_cairo_blur_compute_pixels (radius); x_scale = y_scale = 1; cairo_surface_get_device_scale (cairo_get_target (cr), &x_scale, &y_scale); if (blur_flags & GSK_BLUR_REPEAT) { if (!blur_x) clip_rect.width = 1; if (!blur_y) clip_rect.height = 1; } /* Create a larger surface to center the blur. */ surface = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_A8, x_scale * (clip_rect.width + (blur_x ? 2 * clip_radius : 0)), y_scale * (clip_rect.height + (blur_y ? 2 * clip_radius : 0))); cairo_surface_set_device_scale (surface, x_scale, y_scale); cairo_surface_set_device_offset (surface, x_scale * ((blur_x ? clip_radius : 0) - clip_rect.x), y_scale * ((blur_y ? clip_radius : 0) - clip_rect.y)); blur_cr = cairo_create (surface); cairo_set_user_data (blur_cr, &original_cr_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy); if (cairo_has_current_point (cr)) { double x, y; cairo_get_current_point (cr, &x, &y); cairo_move_to (blur_cr, x, y); } return blur_cr; }
static void gtk_css_image_surface_draw (GtkCssImage *image, cairo_t *cr, double width, double height) { GtkCssImageSurface *surface = GTK_CSS_IMAGE_SURFACE (image); int image_width, image_height; image_width = cairo_image_surface_get_width (surface->surface); image_height = cairo_image_surface_get_height (surface->surface); if (image_width == 0 || image_height == 0 || width <= 0 || height <= 0) return; /* Update cache image if size is different */ if (surface->cache == NULL || ABS (width - surface->width) > 0.001 || ABS (height - surface->height) > 0.001) { double xscale, yscale; cairo_t *cache; /* We need the device scale (HiDPI mode) to calculate the proper size in * pixels for the image surface and set the cache device scale */ cairo_surface_get_device_scale (cairo_get_target (cr), &xscale, &yscale); /* Save original size to preserve precision */ surface->width = width; surface->height = height; /* Destroy old cache if any */ g_clear_pointer (&surface->cache, cairo_surface_destroy); /* Image big enough to contain scaled image with subpixel precision */ surface->cache = cairo_surface_create_similar_image (surface->surface, CAIRO_FORMAT_ARGB32, ceil (width*xscale), ceil (height*yscale)); cairo_surface_set_device_scale (surface->cache, xscale, yscale); cache = cairo_create (surface->cache); cairo_rectangle (cache, 0, 0, width, height); cairo_scale (cache, width / image_width, height / image_height); cairo_set_source_surface (cache, surface->surface, 0, 0); cairo_fill (cache); cairo_destroy (cache); } cairo_rectangle (cr, 0, 0, width, height); cairo_set_source_surface (cr, surface->cache ? surface->cache : surface->surface, 0, 0); cairo_fill (cr); }
/** * gdk_cursor_get_image: * @cursor: a #GdkCursor * * Returns a #GdkPixbuf with the image used to display the cursor. * * Note that depending on the capabilities of the windowing system and * on the cursor, GDK may not be able to obtain the image data. In this * case, %NULL is returned. * * Returns: (transfer full): a #GdkPixbuf representing @cursor, or %NULL * * Since: 2.8 */ GdkPixbuf* gdk_cursor_get_image (GdkCursor *cursor) { int w, h; cairo_surface_t *surface; GdkPixbuf *pixbuf; gchar buf[32]; double x_hot, y_hot; double x_scale, y_scale; g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL); surface = gdk_cursor_get_surface (cursor, &x_hot, &y_hot); if (surface == NULL) return NULL; w = cairo_image_surface_get_width (surface); h = cairo_image_surface_get_height (surface); x_scale = y_scale = 1; #ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE cairo_surface_get_device_scale (surface, &x_scale, &y_scale); #endif pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, w, h); cairo_surface_destroy (surface); if (x_scale != 1) { GdkPixbuf *old; old = pixbuf; pixbuf = gdk_pixbuf_scale_simple (old, w / x_scale, h / y_scale, GDK_INTERP_HYPER); g_object_unref (old); } g_snprintf (buf, 32, "%d", (int)x_hot); gdk_pixbuf_set_option (pixbuf, "x_hot", buf); g_snprintf (buf, 32, "%d", (int)y_hot); gdk_pixbuf_set_option (pixbuf, "y_hot", buf); return pixbuf; }
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 text_to_glyphs (cairo_t *cr, const gchar *text, cairo_glyph_t **glyphs, int *num_glyphs) { PangoAttribute *fallback_attr; PangoAttrList *attr_list; PangoContext *context; PangoDirection base_dir; GList *items; GList *visual_items; FT_Face ft_face; hb_font_t *hb_font; gdouble x = 0, y = 0; gint i; gdouble x_scale, y_scale; *num_glyphs = 0; *glyphs = NULL; base_dir = pango_find_base_dir (text, -1); cairo_scaled_font_t *cr_font = cairo_get_scaled_font (cr); ft_face = cairo_ft_scaled_font_lock_face (cr_font); hb_font = hb_ft_font_create (ft_face, NULL); cairo_surface_t *target = cairo_get_target (cr); cairo_surface_get_device_scale (target, &x_scale, &y_scale); /* We abuse pango itemazation to split text into script and direction * runs, since we use our fonts directly no through pango, we don't * bother changing the default font, but we disable font fallback as * pango will split runs at font change */ context = pango_cairo_create_context (cr); attr_list = pango_attr_list_new (); fallback_attr = pango_attr_fallback_new (FALSE); pango_attr_list_insert (attr_list, fallback_attr); items = pango_itemize_with_base_dir (context, base_dir, text, 0, strlen (text), attr_list, NULL); g_object_unref (context); pango_attr_list_unref (attr_list); /* reorder the items in the visual order */ visual_items = pango_reorder_items (items); while (visual_items) { PangoItem *item; PangoAnalysis analysis; hb_buffer_t *hb_buffer; hb_glyph_info_t *hb_glyphs; hb_glyph_position_t *hb_positions; gint n; item = visual_items->data; analysis = item->analysis; hb_buffer = hb_buffer_create (); hb_buffer_add_utf8 (hb_buffer, text, -1, item->offset, item->length); hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis.script)); hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis.language), -1)); hb_buffer_set_direction (hb_buffer, analysis.level % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); hb_shape (hb_font, hb_buffer, NULL, 0); n = hb_buffer_get_length (hb_buffer); hb_glyphs = hb_buffer_get_glyph_infos (hb_buffer, NULL); hb_positions = hb_buffer_get_glyph_positions (hb_buffer, NULL); *glyphs = g_renew (cairo_glyph_t, *glyphs, *num_glyphs + n); for (i = 0; i < n; i++) { (*glyphs)[*num_glyphs + i].index = hb_glyphs[i].codepoint; (*glyphs)[*num_glyphs + i].x = x + (hb_positions[i].x_offset / (64. * x_scale)); (*glyphs)[*num_glyphs + i].y = y - (hb_positions[i].y_offset / (64. * y_scale)); x += (hb_positions[i].x_advance / (64. * x_scale)); y -= (hb_positions[i].y_advance / (64. * y_scale)); } *num_glyphs += n; hb_buffer_destroy (hb_buffer); visual_items = visual_items->next; } g_list_free_full (visual_items, (GDestroyNotify) pango_item_free); g_list_free_full (items, (GDestroyNotify) pango_item_free); hb_font_destroy (hb_font); cairo_ft_scaled_font_unlock_face (cr_font); }
/* This is always called with the paint context current */ void gdk_gl_texture_from_surface (cairo_surface_t *surface, cairo_region_t *region) { GdkGLContext *paint_context; cairo_surface_t *image; double device_x_offset, device_y_offset; cairo_rectangle_int_t rect, e; int n_rects, i; GdkWindow *window; int unscaled_window_height; unsigned int texture_id; int window_scale; double sx, sy; float umax, vmax; gboolean use_texture_rectangle; guint target; paint_context = gdk_gl_context_get_current (); if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_SURFACE) == 0 && paint_context && GDK_GL_CONTEXT_GET_CLASS (paint_context)->texture_from_surface && GDK_GL_CONTEXT_GET_CLASS (paint_context)->texture_from_surface (paint_context, surface, region)) return; /* Software fallback */ use_texture_rectangle = gdk_gl_context_use_texture_rectangle (paint_context); window = gdk_gl_context_get_window (paint_context); window_scale = gdk_window_get_scale_factor (window); gdk_window_get_unscaled_size (window, NULL, &unscaled_window_height); sx = sy = 1; cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy); cairo_surface_get_device_offset (surface, &device_x_offset, &device_y_offset); glGenTextures (1, &texture_id); if (use_texture_rectangle) target = GL_TEXTURE_RECTANGLE_ARB; else target = GL_TEXTURE_2D; glBindTexture (target, texture_id); glEnable (GL_SCISSOR_TEST); glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); n_rects = cairo_region_num_rectangles (region); #define FLIP_Y(_y) (unscaled_window_height - (_y)) for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rect); glScissor (rect.x * window_scale, FLIP_Y ((rect.y + rect.height) * window_scale), rect.width * window_scale, rect.height * window_scale); e = rect; e.x *= sx; e.y *= sy; e.x += (int)device_x_offset; e.y += (int)device_y_offset; e.width *= sx; e.height *= sy; image = cairo_surface_map_to_image (surface, &e); gdk_gl_context_upload_texture (paint_context, image, e.width, e.height, target); cairo_surface_unmap_image (surface, image); if (use_texture_rectangle) { umax = rect.width * sx; vmax = rect.height * sy; } else { umax = 1.0; vmax = 1.0; } { GdkTexturedQuad quad = { rect.x * window_scale, FLIP_Y(rect.y * window_scale), (rect.x + rect.width) * window_scale, FLIP_Y((rect.y + rect.height) * window_scale), 0, 0, umax, vmax, }; /* We don't want to combine the quads here, because they have different textures. * And we don't want to upload the unused source areas to make it one texture. */ gdk_gl_texture_quads (paint_context, target, 1, &quad); } } #undef FLIP_Y glDisable (GL_SCISSOR_TEST); glDeleteTextures (1, &texture_id); }
/** * gd_embed_surface_in_frame: * @source_image: * @frame_image_url: * @slice_width: * @border_width: * * Returns: (transfer full): */ cairo_surface_t * gd_embed_surface_in_frame (cairo_surface_t *source_image, const gchar *frame_image_url, GtkBorder *slice_width, GtkBorder *border_width) { cairo_surface_t *surface; cairo_t *cr; int source_width, source_height; gchar *css_str; GtkCssProvider *provider; GtkStyleContext *context; GError *error = NULL; GdkPixbuf *retval; GtkWidgetPath *path; gdouble scale_x, scale_y; cairo_surface_get_device_scale (source_image, &scale_x, &scale_y); source_width = cairo_image_surface_get_width (source_image) / (gint) floor (scale_x), source_height = cairo_image_surface_get_height (source_image) / (gint) floor (scale_y); css_str = g_strdup_printf (".embedded-image { border-image: url(\"%s\") %d %d %d %d / %dpx %dpx %dpx %dpx }", frame_image_url, slice_width->top, slice_width->right, slice_width->bottom, slice_width->left, border_width->top, border_width->right, border_width->bottom, border_width->left); provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (provider, css_str, -1, &error); if (error != NULL) { g_warning ("Unable to create the thumbnail frame image: %s", error->message); g_error_free (error); g_free (css_str); return g_object_ref (source_image); } surface = cairo_surface_create_similar (source_image, CAIRO_CONTENT_COLOR_ALPHA, source_width, source_height); cr = cairo_create (surface); context = gtk_style_context_new (); path = gtk_widget_path_new (); gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); gtk_style_context_set_path (context, path); gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), 600); cairo_save (cr); cairo_rectangle (cr, border_width->left, border_width->top, source_width - border_width->left - border_width->right, source_height - border_width->top - border_width->bottom); cairo_clip (cr); gtk_render_icon_surface (context, cr, source_image, 0, 0); cairo_restore (cr); gtk_style_context_save (context); gtk_style_context_add_class (context, "embedded-image"); gtk_render_frame (context, cr, 0, 0, source_width, source_height); gtk_style_context_restore (context); cairo_destroy (cr); gtk_widget_path_unref (path); g_object_unref (provider); g_object_unref (context); g_free (css_str); return surface; }