Commit 17e8846b authored by Alexander Larsson's avatar Alexander Larsson
Browse files

gtk: Use cairo surfaces rather than patterns for icons

cairo_pattern_t were used because they also support scaling
via the pattern matrix. However, patterns are not a great fit
for icons as they are potentially unbounded (i.e. for gradients).
So we switch to surfaces, using the device_scale for scaling.
parent e70de7a1
......@@ -75,7 +75,7 @@ enum {
PROP_PIXBUF,
PROP_PIXBUF_EXPANDER_OPEN,
PROP_PIXBUF_EXPANDER_CLOSED,
PROP_PATTERN,
PROP_SURFACE,
PROP_STOCK_ID,
PROP_STOCK_SIZE,
PROP_STOCK_DETAIL,
......@@ -171,11 +171,11 @@ gtk_cell_renderer_pixbuf_class_init (GtkCellRendererPixbufClass *class)
GDK_TYPE_PIXBUF,
GTK_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_PATTERN,
g_param_spec_boxed ("pattern",
P_("pattern"),
P_("The pattern to render"),
CAIRO_GOBJECT_TYPE_PATTERN,
PROP_SURFACE,
g_param_spec_boxed ("surface",
P_("surface"),
P_("The surface to render"),
CAIRO_GOBJECT_TYPE_SURFACE,
GTK_PARAM_READWRITE));
/**
......@@ -288,8 +288,8 @@ gtk_cell_renderer_pixbuf_get_property (GObject *object,
case PROP_PIXBUF_EXPANDER_CLOSED:
g_value_set_object (value, priv->pixbuf_expander_closed);
break;
case PROP_PATTERN:
g_value_set_boxed (value, _gtk_icon_helper_peek_pattern (priv->icon_helper));
case PROP_SURFACE:
g_value_set_boxed (value, _gtk_icon_helper_peek_surface (priv->icon_helper));
break;
case PROP_STOCK_ID:
g_value_set_string (value, _gtk_icon_helper_get_stock_id (priv->icon_helper));
......@@ -323,8 +323,8 @@ gtk_cell_renderer_pixbuf_reset (GtkCellRendererPixbuf *cellpixbuf)
switch (storage_type)
{
case GTK_IMAGE_PATTERN:
g_object_notify (G_OBJECT (cellpixbuf), "pattern");
case GTK_IMAGE_SURFACE:
g_object_notify (G_OBJECT (cellpixbuf), "surface");
break;
case GTK_IMAGE_PIXBUF:
g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
......@@ -371,9 +371,9 @@ gtk_cell_renderer_pixbuf_set_property (GObject *object,
g_object_unref (priv->pixbuf_expander_closed);
priv->pixbuf_expander_closed = (GdkPixbuf*) g_value_dup_object (value);
break;
case PROP_PATTERN:
case PROP_SURFACE:
gtk_cell_renderer_pixbuf_reset (cellpixbuf);
_gtk_icon_helper_set_pattern (priv->icon_helper, g_value_get_boxed (value));
_gtk_icon_helper_set_surface (priv->icon_helper, g_value_get_boxed (value));
break;
case PROP_STOCK_ID:
gtk_cell_renderer_pixbuf_reset (cellpixbuf);
......
......@@ -1321,7 +1321,6 @@ change_icon_theme_get_info_cb (GCancellable *cancellable,
gpointer user_data)
{
gboolean cancelled = g_cancellable_is_cancelled (cancellable);
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
struct ChangeIconThemeData *data = user_data;
......@@ -1335,13 +1334,8 @@ change_icon_theme_get_info_cb (GCancellable *cancellable,
goto out;
surface = _gtk_file_info_render_icon (info, GTK_WIDGET (data->button), data->button->priv->icon_size);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
if (pattern)
if (surface)
{
gint width = 0;
GtkTreeIter iter;
......@@ -1356,14 +1350,14 @@ change_icon_theme_get_info_cb (GCancellable *cancellable,
gtk_tree_path_free (path);
gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
-1);
g_object_set (data->button->priv->icon_cell,
"width", width,
NULL);
}
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
}
out:
......@@ -1405,7 +1399,6 @@ change_icon_theme (GtkFileChooserButton *button)
do
{
cairo_surface_t *surface = NULL;
cairo_pattern_t *pattern = NULL;
gchar type;
gpointer data;
......@@ -1442,7 +1435,7 @@ change_icon_theme (GtkFileChooserButton *button)
info);
button->priv->change_icon_theme_cancellables =
g_slist_append (button->priv->change_icon_theme_cancellables, cancellable);
pattern = NULL;
surface = NULL;
}
else
{
......@@ -1456,8 +1449,6 @@ change_icon_theme (GtkFileChooserButton *button)
gtk_widget_get_scale_factor (GTK_WIDGET (button)),
gtk_widget_get_window (GTK_WIDGET (button)),
0, NULL);
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
}
break;
......@@ -1468,11 +1459,6 @@ change_icon_theme (GtkFileChooserButton *button)
GTK_WIDGET (button),
priv->icon_size,
NULL);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
}
break;
......@@ -1481,15 +1467,15 @@ change_icon_theme (GtkFileChooserButton *button)
break;
}
if (pattern)
if (surface)
width = MAX (width, priv->icon_size);
gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
-1);
if (pattern)
cairo_pattern_destroy (pattern);
if (surface)
cairo_surface_destroy (surface);
}
while (gtk_tree_model_iter_next (priv->model, &iter));
......@@ -1548,7 +1534,6 @@ set_info_get_info_cb (GCancellable *cancellable,
gpointer callback_data)
{
gboolean cancelled = g_cancellable_is_cancelled (cancellable);
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
GtkTreePath *path;
GtkTreeIter iter;
......@@ -1584,11 +1569,6 @@ set_info_get_info_cb (GCancellable *cancellable,
goto out;
surface = _gtk_file_info_render_icon (info, GTK_WIDGET (data->button), data->button->priv->icon_size);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
if (!data->label)
data->label = g_strdup (g_file_info_get_display_name (info));
......@@ -1596,13 +1576,13 @@ set_info_get_info_cb (GCancellable *cancellable,
is_folder = _gtk_file_info_consider_as_directory (info);
gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
DISPLAY_NAME_COLUMN, data->label,
IS_FOLDER_COLUMN, is_folder,
-1);
if (pattern)
cairo_pattern_destroy (pattern);
if (surface)
cairo_surface_destroy (surface);
out:
g_object_unref (data->button);
......@@ -1744,7 +1724,6 @@ model_add_special_get_info_cb (GCancellable *cancellable,
gboolean cancelled = g_cancellable_is_cancelled (cancellable);
GtkTreeIter iter;
GtkTreePath *path;
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
GCancellable *model_cancellable = NULL;
struct ChangeIconThemeData *data = user_data;
......@@ -1777,17 +1756,11 @@ model_add_special_get_info_cb (GCancellable *cancellable,
surface = _gtk_file_info_render_icon (info, GTK_WIDGET (data->button), data->button->priv->icon_size);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
if (pattern)
{
gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
-1);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
}
gtk_tree_model_get (data->button->priv->model, &iter,
......@@ -1915,7 +1888,6 @@ model_add_volumes (GtkFileChooserButton *button,
{
GtkFileSystemVolume *volume;
GtkTreeIter iter;
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
gchar *display_name;
......@@ -1945,24 +1917,19 @@ model_add_volumes (GtkFileChooserButton *button,
GTK_WIDGET (button),
button->priv->icon_size,
NULL);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
display_name = _gtk_file_system_volume_get_display_name (volume);
gtk_list_store_insert (store, &iter, pos);
gtk_list_store_set (store, &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
DISPLAY_NAME_COLUMN, display_name,
TYPE_COLUMN, ROW_TYPE_VOLUME,
DATA_COLUMN, _gtk_file_system_volume_ref (volume),
IS_FOLDER_COLUMN, TRUE,
-1);
if (pattern)
cairo_pattern_destroy (pattern);
if (surface)
cairo_surface_destroy (surface);
g_free (display_name);
button->priv->n_volumes++;
......@@ -2011,7 +1978,6 @@ model_add_bookmarks (GtkFileChooserButton *button,
{
gchar *label;
GtkIconTheme *icon_theme;
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface = NULL;
if (local_only)
......@@ -2032,12 +1998,10 @@ model_add_bookmarks (GtkFileChooserButton *button,
gtk_widget_get_scale_factor (GTK_WIDGET (button)),
gtk_widget_get_window (GTK_WIDGET (button)),
0, NULL);
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
gtk_list_store_insert (store, &iter, pos);
gtk_list_store_set (store, &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
DISPLAY_NAME_COLUMN, label,
TYPE_COLUMN, ROW_TYPE_BOOKMARK,
DATA_COLUMN, g_object_ref (file),
......@@ -2045,8 +2009,8 @@ model_add_bookmarks (GtkFileChooserButton *button,
-1);
g_free (label);
if (pattern)
cairo_pattern_destroy (pattern);
if (surface)
cairo_surface_destroy (surface);
}
button->priv->n_bookmarks++;
......@@ -2124,7 +2088,6 @@ model_update_current_folder (GtkFileChooserButton *button,
{
gchar *label;
GtkIconTheme *icon_theme;
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
/* Don't call get_info for remote paths to avoid latency and
......@@ -2150,14 +2113,9 @@ model_update_current_folder (GtkFileChooserButton *button,
gtk_widget_get_scale_factor (GTK_WIDGET (button)),
gtk_widget_get_window (GTK_WIDGET (button)),
0, NULL);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
gtk_list_store_set (store, &iter,
ICON_COLUMN, pattern,
ICON_COLUMN, surface,
DISPLAY_NAME_COLUMN, label,
TYPE_COLUMN, ROW_TYPE_CURRENT_FOLDER,
DATA_COLUMN, g_object_ref (file),
......@@ -2165,8 +2123,8 @@ model_update_current_folder (GtkFileChooserButton *button,
-1);
g_free (label);
if (pattern)
cairo_pattern_destroy (pattern);
if (surface)
cairo_surface_destroy (surface);
}
}
......@@ -2502,7 +2460,6 @@ update_label_get_info_cb (GCancellable *cancellable,
gpointer data)
{
gboolean cancelled = g_cancellable_is_cancelled (cancellable);
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
GtkFileChooserButton *button = data;
GtkFileChooserButtonPrivate *priv = button->priv;
......@@ -2518,15 +2475,9 @@ update_label_get_info_cb (GCancellable *cancellable,
gtk_label_set_text (GTK_LABEL (priv->label), g_file_info_get_display_name (info));
surface = _gtk_file_info_render_icon (info, GTK_WIDGET (priv->image), priv->icon_size);
gtk_image_set_from_surface (GTK_IMAGE (priv->image), surface);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
gtk_image_set_from_pattern (GTK_IMAGE (priv->image), pattern);
if (pattern)
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
out:
emit_selection_changed_if_changing_selection (button);
......@@ -2566,7 +2517,6 @@ update_label_and_image (GtkFileChooserButton *button)
base_file = _gtk_file_system_volume_get_root (volume);
if (base_file && g_file_equal (base_file, file))
{
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
label_text = _gtk_file_system_volume_get_display_name (volume);
......@@ -2574,15 +2524,9 @@ update_label_and_image (GtkFileChooserButton *button)
GTK_WIDGET (button),
priv->icon_size,
NULL);
gtk_image_set_from_surface (GTK_IMAGE (priv->image), surface);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
gtk_image_set_from_pattern (GTK_IMAGE (priv->image), pattern);
if (pattern)
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
}
if (base_file)
......@@ -2607,7 +2551,6 @@ update_label_and_image (GtkFileChooserButton *button)
}
else
{
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface;
label_text = _gtk_bookmarks_manager_get_bookmark_label (button->priv->bookmarks_manager, file);
......@@ -2617,15 +2560,9 @@ update_label_and_image (GtkFileChooserButton *button)
gtk_widget_get_scale_factor (GTK_WIDGET (button)),
gtk_widget_get_window (GTK_WIDGET (button)),
0, NULL);
gtk_image_set_from_surface (GTK_IMAGE (priv->image), surface);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
gtk_image_set_from_pattern (GTK_IMAGE (priv->image), pattern);
if (pattern)
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
done_changing_selection = TRUE;
}
......@@ -2649,7 +2586,7 @@ out:
else
{
gtk_label_set_text (GTK_LABEL (priv->label), _(FALLBACK_DISPLAY_NAME));
gtk_image_set_from_pattern (GTK_IMAGE (priv->image), NULL);
gtk_image_set_from_surface (GTK_IMAGE (priv->image), NULL);
}
if (done_changing_selection)
......
......@@ -84,7 +84,7 @@
<child>
<object class="GtkCellRendererPixbuf" id="icon_cell"/>
<attributes>
<attribute name="pattern">0</attribute>
<attribute name="surface">0</attribute>
</attributes>
</child>
<child>
......@@ -104,7 +104,7 @@
<object class="GtkListStore" id="model">
<columns>
<!-- column-name icon -->
<column type="CairoPattern"/>
<column type="CairoSurface"/>
<!-- column-name display-name -->
<column type="gchararray"/>
<!-- column-name type -->
......
......@@ -365,7 +365,7 @@ enum {
MODEL_COL_NAME_COLLATED,
MODEL_COL_IS_FOLDER,
MODEL_COL_IS_SENSITIVE,
MODEL_COL_PATTERN,
MODEL_COL_SURFACE,
MODEL_COL_SIZE_TEXT,
MODEL_COL_MTIME_TEXT,
MODEL_COL_ELLIPSIZE,
......@@ -382,7 +382,7 @@ enum {
G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \
G_TYPE_BOOLEAN, /* MODEL_COL_IS_FOLDER */ \
G_TYPE_BOOLEAN, /* MODEL_COL_IS_SENSITIVE */ \
CAIRO_GOBJECT_TYPE_PATTERN, /* MODEL_COL_PATTERN */ \
CAIRO_GOBJECT_TYPE_SURFACE, /* MODEL_COL_SURFACE */ \
G_TYPE_STRING, /* MODEL_COL_SIZE_TEXT */ \
G_TYPE_STRING, /* MODEL_COL_MTIME_TEXT */ \
PANGO_TYPE_ELLIPSIZE_MODE /* MODEL_COL_ELLIPSIZE */
......@@ -3133,7 +3133,7 @@ change_icon_theme (GtkFileChooserDefault *impl)
set_icon_cell_renderer_fixed_size (impl);
if (priv->browse_files_model)
_gtk_file_system_model_clear_cache (priv->browse_files_model, MODEL_COL_PATTERN);
_gtk_file_system_model_clear_cache (priv->browse_files_model, MODEL_COL_SURFACE);
gtk_widget_queue_resize (priv->browse_files_tree_view);
profile_end ("end", NULL);
......@@ -4153,19 +4153,12 @@ file_system_model_set (GtkFileSystemModel *model,
else
g_value_set_boolean (value, TRUE);
break;
case MODEL_COL_PATTERN:
case MODEL_COL_SURFACE:
if (info)
{
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON))
{
cairo_pattern_t *pattern = NULL;
cairo_surface_t *surface = _gtk_file_info_render_icon (info, GTK_WIDGET (impl), priv->icon_size);
if (surface)
{
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
}
g_value_take_boxed (value, pattern);
g_value_take_boxed (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), priv->icon_size));
}
else
{
......@@ -7077,7 +7070,7 @@ update_cell_renderer_attributes (GtkFileChooserDefault *impl)
if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
{
gtk_tree_view_column_set_attributes (column, renderer,
"pattern", MODEL_COL_PATTERN,
"surface", MODEL_COL_SURFACE,
NULL);
}
else
......
......@@ -1582,7 +1582,7 @@ gtk_icon_set_render_icon_pixbuf (GtkIconSet *icon_set,
}
/**
* gtk_icon_set_render_icon_pattern:
* gtk_icon_set_render_icon_surface:
* @icon_set: a #GtkIconSet
* @context: a #GtkStyleContext
* @size: (type int): icon size. A size of (GtkIconSize)-1
......@@ -1591,18 +1591,18 @@ gtk_icon_set_render_icon_pixbuf (GtkIconSet *icon_set,
* @for_window: (allow-none): #GdkWindow to optimize drawing for, or %NULL
*
* Renders an icon using gtk_render_icon_pixbuf() and converts it to a
* cairo pattern.
* cairo surface.
*
* This function never returns %NULL; if the icon can't be rendered
* (perhaps because an image file fails to load), a default "missing
* image" icon will be returned instead.
*
* Return value: (transfer full): a #cairo_pattern_t to be displayed
* Return value: (transfer full): a #cairo_surface_t to be displayed
*
* Since: 3.10
*/
cairo_pattern_t *
gtk_icon_set_render_icon_pattern (GtkIconSet *icon_set,
cairo_surface_t *
gtk_icon_set_render_icon_surface (GtkIconSet *icon_set,
GtkStyleContext *context,
GtkIconSize size,
gint scale,
......@@ -1610,20 +1610,13 @@ gtk_icon_set_render_icon_pattern (GtkIconSet *icon_set,
{
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
pixbuf = gtk_icon_set_render_icon_pixbuf_for_scale (icon_set, context, size, scale);
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, for_window);
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, for_window);
g_object_unref (pixbuf);
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
cairo_matrix_init_scale (&matrix, scale, scale);
cairo_pattern_set_matrix (pattern, &matrix);
return pattern;
return surface;
}
/**
......
......@@ -36,7 +36,7 @@ struct _GtkIconHelperPrivate {
GtkIconSet *icon_set;
gchar *icon_name;
gchar *stock_id;
cairo_pattern_t *orig_pattern;
cairo_surface_t *orig_surface;
GtkIconSize icon_size;
gint pixel_size;
......@@ -47,11 +47,11 @@ struct _GtkIconHelperPrivate {
GdkPixbuf *rendered_pixbuf;
GtkStateFlags last_rendered_state;
cairo_pattern_t *rendered_pattern;
gint rendered_pattern_width;
gint rendered_pattern_height;
GtkStateFlags last_pattern_state;
gint last_pattern_scale;
cairo_surface_t *rendered_surface;
gint rendered_surface_width;
gint rendered_surface_height;
GtkStateFlags last_surface_state;
gint last_surface_scale;
};
void
......@@ -63,16 +63,16 @@ _gtk_icon_helper_clear (GtkIconHelper *self)
g_clear_object (&self->priv->rendered_pixbuf);
g_clear_object (&self->priv->window);
if (self->priv->orig_pattern)
if (self->priv->orig_surface)
{
cairo_pattern_destroy (self->priv->orig_pattern);
self->priv->orig_pattern = NULL;
cairo_surface_destroy (self->priv->orig_surface);
self->priv->orig_surface = NULL;
}
if (self->priv->rendered_pattern)
if (self->priv->rendered_surface)
{
cairo_pattern_destroy (self->priv->rendered_pattern);
self->priv->rendered_pattern = NULL;
cairo_surface_destroy (self->priv->rendered_surface);
self->priv->rendered_surface = NULL;
}
if (self->priv->icon_set != NULL)
......@@ -92,8 +92,8 @@ _gtk_icon_helper_clear (GtkIconHelper *self)
self->priv->storage_type = GTK_IMAGE_EMPTY;
self->priv->icon_size = GTK_ICON_SIZE_INVALID;
self->priv->last_rendered_state = GTK_STATE_FLAG_NORMAL;
self->priv->last_pattern_state = GTK_STATE_FLAG_NORMAL;
self->priv->last_pattern_scale = 0;
self->priv->last_surface_state = GTK_STATE_FLAG_NORMAL;
self->priv->last_surface_scale = 0;
}
void
......@@ -325,33 +325,34 @@ ensure_pixbuf_for_icon_set (GtkIconHelper *self,
}
static void
get_pattern_size (GtkIconHelper *self,
get_surface_size (GtkIconHelper *self,
GtkStyleContext *context,
cairo_pattern_t *pattern,
cairo_surface_t *surface,
int *width,
int *height)
{
cairo_surface_t *surface;
double x_scale, y_scale;
if(!cairo_pattern_get_surface (self->priv->rendered_pattern,
&surface) &&
cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
{
cairo_matrix_t matrix;
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 */
cairo_pattern_get_matrix (self->priv->rendered_pattern, &matrix);
*width =
ceil (cairo_image_surface_get_width (surface) / matrix.xx);
ceil (cairo_image_surface_get_width (surface) / x_scale);
*height =
ceil (cairo_image_surface_get_height (surface) / matrix.yy);
ceil (cairo_image_surface_get_height (surface) / y_scale);
}
else
ensure_icon_size (self, context, width, height);
}