From 420697693b2f659fd7faccdc5c675f25494f00e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 11 May 2017 06:25:00 +0200 Subject: [PATCH] st-texture-cache: Separate 'scale' to 'paint_scale' and 'resource_scale' Instead of just passing a scale when getting a cached icon, pass both a 'paint_scale', the scale of which the icon will be painted on the stage, and a 'resource_scale', the scale of the resource used for painting. In effect, the texture size will use the scale 'paint_scale * resource_scale' in a ceiled value while the size of the actor will use 'paint_scale' when determining the size. this would load a bigger texture, but the downscaling would keep the visual quality. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5 https://bugzilla.gnome.org/show_bug.cgi?id=765011 --- js/gdm/loginDialog.js | 3 +- src/st/st-icon.c | 6 +- src/st/st-texture-cache.c | 112 ++++++++++++++++++++++----------- src/st/st-texture-cache.h | 15 +++-- src/st/st-theme-node-drawing.c | 37 +++++++---- 5 files changed, 117 insertions(+), 56 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 8ea1a86a2..bf7577c36 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -782,7 +782,8 @@ var LoginDialog = GObject.registerClass({ let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile, -1, _LOGO_ICON_HEIGHT, - scaleFactor)); + scaleFactor, + 1)); } } diff --git a/src/st/st-icon.c b/src/st/st-icon.c index b9c92c86c..9242d6b4e 100644 --- a/src/st/st-icon.c +++ b/src/st/st-icon.c @@ -393,14 +393,16 @@ st_icon_update (StIcon *icon) theme_node, priv->gicon, priv->icon_size, - scale); + scale, + 1); if (priv->pending_texture == NULL && priv->fallback_gicon != NULL) priv->pending_texture = st_texture_cache_load_gicon (cache, theme_node, priv->fallback_gicon, priv->icon_size, - scale); + scale, + 1); if (priv->pending_texture) { diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c index 967ad9e2e..0075845f8 100644 --- a/src/st/st-texture-cache.c +++ b/src/st/st-texture-cache.c @@ -25,6 +25,7 @@ #include "st-private.h" #include "st-settings.h" #include +#include #include #include @@ -284,7 +285,8 @@ typedef struct { guint width; guint height; - guint scale; + guint paint_scale; + gfloat resource_scale; GSList *actors; GtkIconInfo *icon_info; @@ -430,7 +432,8 @@ static GdkPixbuf * impl_load_pixbuf_file (GFile *file, int available_width, int available_height, - int scale, + int paint_scale, + float resource_scale, GError **error) { GdkPixbuf *pixbuf = NULL; @@ -439,6 +442,7 @@ impl_load_pixbuf_file (GFile *file, if (g_file_load_contents (file, NULL, &contents, &size, NULL, error)) { + int scale = ceilf (paint_scale * resource_scale); pixbuf = impl_load_pixbuf_data ((const guchar *) contents, size, available_width, available_height, scale, @@ -463,7 +467,9 @@ load_pixbuf_thread (GTask *result, g_assert (data != NULL); g_assert (data->file != NULL); - pixbuf = impl_load_pixbuf_file (data->file, data->width, data->height, data->scale, &error); + pixbuf = impl_load_pixbuf_file (data->file, data->width, data->height, + data->paint_scale, data->resource_scale, + &error); if (error != NULL) g_task_return_error (result, error); @@ -869,7 +875,8 @@ ensure_request (StTextureCache *cache, * if the icon must not be recolored * @icon: the #GIcon to load * @size: Size of themed - * @scale: Scale factor of display + * @paint_scale: Scale factor of display + * @resource_scale: Resource scale factor * * This method returns a new #ClutterActor for a given #GIcon. If the * icon isn't loaded already, the texture will be filled @@ -882,12 +889,15 @@ st_texture_cache_load_gicon (StTextureCache *cache, StThemeNode *theme_node, GIcon *icon, gint size, - gint scale) + gint paint_scale, + gfloat resource_scale) { AsyncTextureLoadData *request; ClutterActor *actor; + gint scale; char *gicon_string; char *key; + float actor_size; GtkIconTheme *theme; GtkIconInfo *info; StTextureCachePolicy policy; @@ -916,7 +926,10 @@ st_texture_cache_load_gicon (StTextureCache *cache, else lookup_flags |= GTK_ICON_LOOKUP_DIR_LTR; - info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, size, scale, lookup_flags); + scale = ceilf (paint_scale * resource_scale); + info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, + size, scale, + lookup_flags); if (info == NULL) return NULL; @@ -945,8 +958,8 @@ st_texture_cache_load_gicon (StTextureCache *cache, g_free (gicon_string); actor = create_invisible_actor (); - clutter_actor_set_size (actor, size * scale, size * scale); - + actor_size = size * paint_scale; + clutter_actor_set_size (actor, actor_size, actor_size); if (ensure_request (cache, key, policy, &request, actor)) { /* If there's an outstanding request, we've just added ourselves to it */ @@ -964,7 +977,8 @@ st_texture_cache_load_gicon (StTextureCache *cache, request->colors = colors ? st_icon_colors_ref (colors) : NULL; request->icon_info = info; request->width = request->height = size; - request->scale = scale; + request->paint_scale = paint_scale; + request->resource_scale = resource_scale; load_texture_async (cache, request); } @@ -1041,7 +1055,8 @@ ensure_monitor_for_file (StTextureCache *cache, typedef struct { GFile *gfile; gint grid_width, grid_height; - gint scale_factor; + gint paint_scale; + gfloat resource_scale; ClutterActor *actor; GFunc load_callback; gpointer load_callback_data; @@ -1097,9 +1112,9 @@ on_loader_size_prepared (GdkPixbufLoader *loader, gpointer user_data) { AsyncImageData *data = user_data; - gdk_pixbuf_loader_set_size (loader, - width * data->scale_factor, - height * data->scale_factor); + int scale = ceilf (data->paint_scale * data->resource_scale); + + gdk_pixbuf_loader_set_size (loader, width * scale, height * scale); } static void @@ -1112,6 +1127,7 @@ load_sliced_image (GTask *result, GList *res = NULL; GdkPixbuf *pix; gint width, height, y, x; + gint scale_factor; GdkPixbufLoader *loader; GError *error = NULL; gchar *buffer = NULL; @@ -1143,13 +1159,14 @@ load_sliced_image (GTask *result, pix = gdk_pixbuf_loader_get_pixbuf (loader); width = gdk_pixbuf_get_width (pix); height = gdk_pixbuf_get_height (pix); - for (y = 0; y < height; y += data->grid_height * data->scale_factor) + scale_factor = ceilf (data->paint_scale * data->resource_scale); + for (y = 0; y < height; y += data->grid_height * scale_factor) { - for (x = 0; x < width; x += data->grid_width * data->scale_factor) + for (x = 0; x < width; x += data->grid_width * scale_factor) { GdkPixbuf *pixbuf = gdk_pixbuf_new_subpixbuf (pix, x, y, - data->grid_width * data->scale_factor, - data->grid_height * data->scale_factor); + data->grid_width * scale_factor, + data->grid_height * scale_factor); g_assert (pixbuf != NULL); res = g_list_append (res, pixbuf); } @@ -1170,13 +1187,13 @@ load_sliced_image (GTask *result, * @file: A #GFile * @grid_width: Width in pixels * @grid_height: Height in pixels - * @scale: Scale factor of the display + * @paint_scale: Scale factor of the display * @load_callback: (scope async) (nullable): Function called when the image is loaded, or %NULL * @user_data: Data to pass to the load callback * * This function reads a single image file which contains multiple images internally. * The image file will be divided using @grid_width and @grid_height; - * note that the dimensions of the image loaded from @path + * note that the dimensions of the image loaded from @path * should be a multiple of the specified grid dimensions. * * Returns: (transfer none): A new #ClutterActor @@ -1186,7 +1203,8 @@ st_texture_cache_load_sliced_image (StTextureCache *cache, GFile *file, gint grid_width, gint grid_height, - gint scale, + gint paint_scale, + gfloat resource_scale, GFunc load_callback, gpointer user_data) { @@ -1194,10 +1212,15 @@ st_texture_cache_load_sliced_image (StTextureCache *cache, GTask *result; ClutterActor *actor = clutter_actor_new (); + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_assert (paint_scale > 0); + g_assert (resource_scale > 0); + data = g_new0 (AsyncImageData, 1); data->grid_width = grid_width; data->grid_height = grid_height; - data->scale_factor = scale; + data->paint_scale = paint_scale; + data->resource_scale = resource_scale; data->gfile = g_object_ref (file); data->actor = actor; data->load_callback = load_callback; @@ -1219,7 +1242,8 @@ st_texture_cache_load_sliced_image (StTextureCache *cache, * @file: a #GFile of the image file from which to create a pixbuf * @available_width: available width for the image, can be -1 if not limited * @available_height: available height for the image, can be -1 if not limited - * @scale: scale factor of the display + * @paint_scale: scale factor of the display + * @resource_scale: Resource scale factor * * Asynchronously load an image. Initially, the returned texture will have a natural * size of zero. At some later point, either the image will be loaded successfully @@ -1232,14 +1256,17 @@ st_texture_cache_load_file_async (StTextureCache *cache, GFile *file, int available_width, int available_height, - int scale) + int paint_scale, + gfloat resource_scale) { ClutterActor *actor; AsyncTextureLoadData *request; StTextureCachePolicy policy; gchar *key; + int scale; - key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file)); + scale = ceilf (paint_scale * resource_scale); + key = g_strdup_printf (CACHE_PREFIX_FILE "%u%d", g_file_hash (file), scale); policy = ST_TEXTURE_CACHE_POLICY_NONE; /* XXX */ @@ -1261,7 +1288,8 @@ st_texture_cache_load_file_async (StTextureCache *cache, request->policy = policy; request->width = available_width; request->height = available_height; - request->scale = scale; + request->paint_scale = paint_scale; + request->resource_scale = resource_scale; load_texture_async (cache, request); } @@ -1277,7 +1305,8 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache, GFile *file, int available_width, int available_height, - int scale, + int paint_scale, + gfloat resource_scale, GError **error) { ClutterContent *image; @@ -1285,14 +1314,15 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache, GdkPixbuf *pixbuf; char *key; - key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file)); + key = g_strdup_printf (CACHE_PREFIX_FILE "%u%f", g_file_hash (file), resource_scale); texdata = NULL; image = g_hash_table_lookup (cache->priv->keyed_cache, key); if (image == NULL) { - pixbuf = impl_load_pixbuf_file (file, available_width, available_height, scale, error); + pixbuf = impl_load_pixbuf_file (file, available_width, available_height, + paint_scale, resource_scale, error); if (!pixbuf) goto out; @@ -1325,20 +1355,22 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache, GFile *file, int available_width, int available_height, - int scale, + int paint_scale, + gfloat resource_scale, GError **error) { cairo_surface_t *surface; GdkPixbuf *pixbuf; char *key; - key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file)); + key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u%f", g_file_hash (file), resource_scale); surface = g_hash_table_lookup (cache->priv->keyed_surface_cache, key); if (surface == NULL) { - pixbuf = impl_load_pixbuf_file (file, available_width, available_height, scale, error); + pixbuf = impl_load_pixbuf_file (file, available_width, available_height, + paint_scale, resource_scale, error); if (!pixbuf) goto out; @@ -1366,7 +1398,8 @@ out: * st_texture_cache_load_file_to_cogl_texture: (skip) * @cache: A #StTextureCache * @file: A #GFile in supported image format - * @scale: Scale factor of the display + * @paint_scale: Scale factor of the display + * @resource_scale: Resource scale factor * * This function synchronously loads the given file path * into a COGL texture. On error, a warning is emitted @@ -1377,13 +1410,15 @@ out: CoglTexture * st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache, GFile *file, - gint scale) + gint paint_scale, + gfloat resource_scale) { CoglTexture *texture; GError *error = NULL; texture = st_texture_cache_load_file_sync_to_cogl_texture (cache, ST_TEXTURE_CACHE_POLICY_FOREVER, - file, -1, -1, scale, &error); + file, -1, -1, paint_scale, resource_scale, + &error); if (texture == NULL) { @@ -1400,7 +1435,8 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache, * st_texture_cache_load_file_to_cairo_surface: * @cache: A #StTextureCache * @file: A #GFile in supported image format - * @scale: Scale factor of the display + * @paint_scale: Scale factor of the display + * @resource_scale: Resource scale factor * * This function synchronously loads the given file path * into a cairo surface. On error, a warning is emitted @@ -1411,13 +1447,15 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache, cairo_surface_t * st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache, GFile *file, - gint scale) + gint paint_scale, + gfloat resource_scale) { cairo_surface_t *surface; GError *error = NULL; surface = st_texture_cache_load_file_sync_to_cairo_surface (cache, ST_TEXTURE_CACHE_POLICY_FOREVER, - file, -1, -1, scale, &error); + file, -1, -1, paint_scale, resource_scale, + &error); if (surface == NULL) { diff --git a/src/st/st-texture-cache.h b/src/st/st-texture-cache.h index 26f9c30ac..0e0202c50 100644 --- a/src/st/st-texture-cache.h +++ b/src/st/st-texture-cache.h @@ -58,7 +58,8 @@ st_texture_cache_load_sliced_image (StTextureCache *cache, GFile *file, gint grid_width, gint grid_height, - gint scale, + gint paint_scale, + gfloat resource_scale, GFunc load_callback, gpointer user_data); @@ -70,21 +71,25 @@ ClutterActor *st_texture_cache_load_gicon (StTextureCache *cache, StThemeNode *theme_node, GIcon *icon, gint size, - gint scale); + gint paint_scale, + gfloat resource_scale); ClutterActor *st_texture_cache_load_file_async (StTextureCache *cache, GFile *file, int available_width, int available_height, - int scale); + int paint_scale, + gfloat resource_scale); CoglTexture *st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache, GFile *file, - gint scale); + gint paint_scale, + gfloat resource_scale); cairo_surface_t *st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache, GFile *file, - gint scale); + gint paint_scale, + gfloat resource_scale); /** * StTextureCacheLoader: (skip) diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c index 3aaba3424..9877afdae 100644 --- a/src/st/st-theme-node-drawing.c +++ b/src/st/st-theme-node-drawing.c @@ -650,7 +650,9 @@ create_cairo_pattern_of_background_image (StThemeNode *node, texture_cache = st_texture_cache_get_default (); g_object_get (node->context, "scale-factor", &scale_factor, NULL); - surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file, scale_factor); + surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file, + scale_factor, + resource_scale); if (surface == NULL) return NULL; @@ -667,10 +669,18 @@ create_cairo_pattern_of_background_image (StThemeNode *node, cairo_matrix_init_identity (&matrix); + if (resource_scale != 1.0) + { + background_image_width /= resource_scale; + background_image_height /= resource_scale; + + cairo_matrix_scale (&matrix, resource_scale, resource_scale); + } + get_background_scale (node, width, height, background_image_width, background_image_height, - resource_scale, &scale_w, &scale_h); + &scale_w, &scale_h); if ((scale_w != 1) || (scale_h != 1)) cairo_matrix_scale (&matrix, 1.0/scale_w, 1.0/scale_h); @@ -1323,7 +1333,8 @@ st_theme_node_prerender_background (StThemeNode *node, if (interior_path != NULL) cairo_path_destroy (interior_path); - texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, texture_width, + texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, + texture_width, texture_height, CLUTTER_CAIRO_FORMAT_ARGB32, rowstride, @@ -1356,7 +1367,8 @@ st_theme_node_invalidate_border_image (StThemeNode *node) } static gboolean -st_theme_node_load_border_image (StThemeNode *node) +st_theme_node_load_border_image (StThemeNode *node, + gfloat resource_scale) { if (node->border_slices_texture == NULL) { @@ -1373,7 +1385,8 @@ st_theme_node_load_border_image (StThemeNode *node) g_object_get (node->context, "scale-factor", &scale_factor, NULL); node->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (), - file, scale_factor); + file, scale_factor, + resource_scale); if (node->border_slices_texture == NULL) goto out; @@ -1393,7 +1406,8 @@ st_theme_node_invalidate_background_image (StThemeNode *node) } static gboolean -st_theme_node_load_background_image (StThemeNode *node) +st_theme_node_load_background_image (StThemeNode *node, + gfloat resource_scale) { if (node->background_texture == NULL) { @@ -1409,7 +1423,8 @@ st_theme_node_load_background_image (StThemeNode *node) background_image_shadow_spec = st_theme_node_get_background_image_shadow (node); node->background_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (), - background_image, scale_factor); + background_image, scale_factor, + resource_scale); if (node->background_texture == NULL) goto out; @@ -1560,7 +1575,7 @@ st_theme_node_render_resources (StThemeNodePaintState *state, if (box_shadow_spec && !has_inset_box_shadow) { - if (st_theme_node_load_border_image (node)) + if (st_theme_node_load_border_image (node, resource_scale)) state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec, node->border_slices_texture, state->resource_scale); @@ -1634,7 +1649,7 @@ st_theme_node_update_resources (StThemeNodePaintState *state, for (corner_id = 0; corner_id < 4; corner_id++) if (state->corner_material[corner_id] == NULL) state->corner_material[corner_id] = - st_theme_node_lookup_corner (node, width, resource_scale, height, corner_id); + st_theme_node_lookup_corner (node, width, height, resource_scale, corner_id); } if (had_box_shadow) @@ -2635,7 +2650,7 @@ st_theme_node_paint (StThemeNode *node, } if (state->prerendered_pipeline != NULL || - st_theme_node_load_border_image (node)) + st_theme_node_load_border_image (node, resource_scale)) { if (state->prerendered_pipeline != NULL) { @@ -2663,7 +2678,7 @@ st_theme_node_paint (StThemeNode *node, st_theme_node_paint_outline (node, framebuffer, box, paint_opacity); if (state->prerendered_pipeline == NULL && - st_theme_node_load_background_image (node)) + st_theme_node_load_background_image (node, resource_scale)) { ClutterActorBox background_box; ClutterActorBox texture_coords;