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
This commit is contained in:
Marco Trevisan (Treviño) 2017-05-11 06:25:00 +02:00 committed by Jonas Ådahl
parent 37f53a42da
commit 420697693b
5 changed files with 117 additions and 56 deletions

View File

@ -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));
}
}

View File

@ -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)
{

View File

@ -25,6 +25,7 @@
#include "st-private.h"
#include "st-settings.h"
#include <gtk/gtk.h>
#include <math.h>
#include <string.h>
#include <glib.h>
@ -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)
{

View File

@ -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)

View File

@ -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;