forked from AuroraMiddleware/gtk
border-image: don't cache the cairo_surface_t in GtkBorderImage
It's not useful to cache these surfaces here, as the GtkBorderImage will be always generated on the fly, being a shorthand property. This also allows to get rid of the intermediate image surfaces for rendering the slices; we now use cairo_surface_create_for_rectangle() to proxy the slices from the source surface to the rendered area, which should also yield better performance.
This commit is contained in:
parent
a2a8d3e8f4
commit
052d6ef6da
@ -76,148 +76,8 @@ struct _GtkBorderImage {
|
||||
|
||||
gint ref_count;
|
||||
gboolean resolved;
|
||||
|
||||
cairo_surface_t *surfaces[BORDER_LAST][BORDER_LAST];
|
||||
};
|
||||
|
||||
static void
|
||||
_gtk_border_image_ensure_slices (GtkBorderImage *image,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
if (image->surfaces[0][0] != NULL)
|
||||
return;
|
||||
|
||||
if (cairo_pattern_get_type (image->source) != CAIRO_PATTERN_TYPE_SURFACE)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
cairo_matrix_init_scale (&matrix, 1 / width, 1 / height);
|
||||
cairo_pattern_set_matrix (image->source, &matrix);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source (cr, image->source);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_pattern_get_surface (image->source, &surface);
|
||||
cairo_surface_reference (surface);
|
||||
|
||||
width = cairo_image_surface_get_width (surface);
|
||||
height = cairo_image_surface_get_height (surface);
|
||||
}
|
||||
|
||||
/* Top /left corner */
|
||||
image->surfaces[BORDER_LEFT][BORDER_TOP] =
|
||||
cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
|
||||
image->slice.left, image->slice.top);
|
||||
cr = cairo_create (image->surfaces[BORDER_LEFT][BORDER_TOP]);
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
/* Top/right corner */
|
||||
image->surfaces[BORDER_RIGHT][BORDER_TOP] =
|
||||
cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
|
||||
image->slice.right, image->slice.top);
|
||||
cr = cairo_create (image->surfaces[BORDER_RIGHT][BORDER_TOP]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
- width + image->slice.right,
|
||||
0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
/* Bottom/left corner */
|
||||
image->surfaces[BORDER_LEFT][BORDER_BOTTOM] =
|
||||
cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
|
||||
image->slice.left, image->slice.bottom);
|
||||
cr = cairo_create (image->surfaces[BORDER_LEFT][BORDER_BOTTOM]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
0,
|
||||
- height + image->slice.bottom);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
/* Bottom/right corner */
|
||||
image->surfaces[BORDER_RIGHT][BORDER_BOTTOM] =
|
||||
cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
|
||||
image->slice.right, image->slice.bottom);
|
||||
cr = cairo_create (image->surfaces[BORDER_RIGHT][BORDER_BOTTOM]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
- width + image->slice.right,
|
||||
- height + image->slice.bottom);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
if ((image->slice.left + image->slice.right) < width)
|
||||
{
|
||||
/* Top side */
|
||||
image->surfaces[BORDER_MIDDLE][BORDER_TOP] =
|
||||
cairo_surface_create_similar (surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
width - image->slice.left - image->slice.right,
|
||||
image->slice.top);
|
||||
cr = cairo_create (image->surfaces[BORDER_MIDDLE][BORDER_TOP]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
- image->slice.left,
|
||||
0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
/* Bottom side */
|
||||
image->surfaces[BORDER_MIDDLE][BORDER_BOTTOM] =
|
||||
cairo_surface_create_similar (surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
width - image->slice.left - image->slice.right,
|
||||
image->slice.bottom);
|
||||
cr = cairo_create (image->surfaces[BORDER_MIDDLE][BORDER_BOTTOM]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
- image->slice.left,
|
||||
- height + image->slice.bottom);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
if ((image->slice.top + image->slice.bottom) < height)
|
||||
{
|
||||
/* Left side */
|
||||
image->surfaces[BORDER_LEFT][BORDER_MIDDLE] =
|
||||
cairo_surface_create_similar (surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
image->slice.left,
|
||||
height - image->slice.top - image->slice.bottom);
|
||||
cr = cairo_create (image->surfaces[BORDER_LEFT][BORDER_MIDDLE]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
0,
|
||||
- image->slice.top);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
/* Right side */
|
||||
image->surfaces[BORDER_RIGHT][BORDER_MIDDLE] =
|
||||
cairo_surface_create_similar (surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
image->slice.right,
|
||||
height - image->slice.top - image->slice.bottom);
|
||||
cr = cairo_create (image->surfaces[BORDER_RIGHT][BORDER_MIDDLE]);
|
||||
cairo_set_source_surface (cr, surface,
|
||||
- width + image->slice.right,
|
||||
- image->slice.top);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
GtkBorderImage *
|
||||
_gtk_border_image_new (cairo_pattern_t *pattern,
|
||||
GtkBorder *slice,
|
||||
@ -382,26 +242,23 @@ _gtk_border_image_pack (GValue *value,
|
||||
|
||||
static void
|
||||
render_corner (cairo_t *cr,
|
||||
gdouble corner_x,
|
||||
gdouble corner_y,
|
||||
gdouble corner_width,
|
||||
gdouble corner_height,
|
||||
cairo_surface_t *surface,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
gdouble image_width,
|
||||
gdouble image_height)
|
||||
{
|
||||
gint image_width, image_height;
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
if (corner_width == 0 || corner_height == 0)
|
||||
return;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
image_width = cairo_image_surface_get_width (surface);
|
||||
image_height = cairo_image_surface_get_height (surface);
|
||||
|
||||
cairo_translate (cr, x, y);
|
||||
cairo_translate (cr, corner_x, corner_y);
|
||||
cairo_scale (cr,
|
||||
width / image_width,
|
||||
height / image_height);
|
||||
corner_width / image_width,
|
||||
corner_height / image_height);
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
|
||||
/* use the nearest filter for scaling, to avoid color blending */
|
||||
@ -414,19 +271,17 @@ render_corner (cairo_t *cr,
|
||||
|
||||
static cairo_surface_t *
|
||||
create_spaced_surface (cairo_surface_t *tile,
|
||||
gdouble tile_width,
|
||||
gdouble tile_height,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
gint n_repeats, idx;
|
||||
gint tile_width, tile_height;
|
||||
gdouble avail_space, step;
|
||||
cairo_surface_t *retval;
|
||||
cairo_t *cr;
|
||||
|
||||
tile_width = cairo_image_surface_get_width (tile);
|
||||
tile_height = cairo_image_surface_get_height (tile);
|
||||
|
||||
n_repeats = (orientation == GTK_ORIENTATION_HORIZONTAL) ?
|
||||
(gint) floor (width / tile_width) :
|
||||
(gint) floor (height / tile_height);
|
||||
@ -465,16 +320,17 @@ create_spaced_surface (cairo_surface_t *tile,
|
||||
|
||||
static void
|
||||
render_border (cairo_t *cr,
|
||||
cairo_surface_t *surface,
|
||||
gdouble total_width,
|
||||
gdouble total_height,
|
||||
cairo_surface_t *surface,
|
||||
gdouble surface_width,
|
||||
gdouble surface_height,
|
||||
guint side,
|
||||
GtkBorder *border_area,
|
||||
GtkBorderImageRepeat *repeat)
|
||||
{
|
||||
gdouble target_x, target_y;
|
||||
gdouble target_width, target_height;
|
||||
gint original_width, original_height;
|
||||
GdkRectangle image_area;
|
||||
cairo_pattern_t *pattern;
|
||||
gboolean repeat_pattern;
|
||||
@ -485,18 +341,15 @@ render_border (cairo_t *cr,
|
||||
cairo_surface_reference (surface);
|
||||
repeat_pattern = FALSE;
|
||||
|
||||
original_width = cairo_image_surface_get_width (surface);
|
||||
original_height = cairo_image_surface_get_height (surface);
|
||||
|
||||
if (side == SIDE_TOP || side == SIDE_BOTTOM)
|
||||
{
|
||||
target_height = (side == SIDE_TOP) ? (border_area->top) : (border_area->bottom);
|
||||
target_width = original_width * (target_height / original_height);
|
||||
target_width = surface_width * (target_height / surface_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
target_width = (side == SIDE_LEFT) ? (border_area->left) : (border_area->right);
|
||||
target_height = original_height * (target_width / original_width);
|
||||
target_height = surface_height * (target_width / surface_width);
|
||||
}
|
||||
|
||||
if (side == SIDE_TOP || side == SIDE_BOTTOM)
|
||||
@ -526,7 +379,7 @@ render_border (cairo_t *cr,
|
||||
|
||||
repeat_pattern = TRUE;
|
||||
|
||||
n_repeats = (gint) floor (image_area.width / original_width);
|
||||
n_repeats = (gint) floor (image_area.width / surface_width);
|
||||
target_width = image_area.width / n_repeats;
|
||||
}
|
||||
else if (repeat->vrepeat == GTK_REPEAT_STYLE_SPACE)
|
||||
@ -534,13 +387,14 @@ render_border (cairo_t *cr,
|
||||
cairo_surface_t *spaced_surface;
|
||||
|
||||
spaced_surface = create_spaced_surface (surface,
|
||||
image_area.width, original_height,
|
||||
surface_width, surface_height,
|
||||
image_area.width, surface_height,
|
||||
GTK_ORIENTATION_HORIZONTAL);
|
||||
cairo_surface_destroy (surface);
|
||||
surface = spaced_surface;
|
||||
|
||||
/* short-circuit hscaling */
|
||||
target_width = original_width = cairo_image_surface_get_width (surface);
|
||||
target_width = surface_width = cairo_image_surface_get_width (spaced_surface);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -571,7 +425,7 @@ render_border (cairo_t *cr,
|
||||
|
||||
repeat_pattern = TRUE;
|
||||
|
||||
n_repeats = (gint) floor (image_area.height / original_height);
|
||||
n_repeats = (gint) floor (image_area.height / surface_height);
|
||||
target_height = image_area.height / n_repeats;
|
||||
}
|
||||
else if (repeat->hrepeat == GTK_REPEAT_STYLE_SPACE)
|
||||
@ -579,13 +433,14 @@ render_border (cairo_t *cr,
|
||||
cairo_surface_t *spaced_surface;
|
||||
|
||||
spaced_surface = create_spaced_surface (surface,
|
||||
original_width, image_area.height,
|
||||
surface_width, surface_height,
|
||||
surface_width, image_area.height,
|
||||
GTK_ORIENTATION_VERTICAL);
|
||||
cairo_surface_destroy (surface);
|
||||
surface = spaced_surface;
|
||||
|
||||
/* short-circuit vscaling */
|
||||
target_height = original_height = cairo_image_surface_get_height (surface);
|
||||
target_height = surface_height = cairo_image_surface_get_height (spaced_surface);
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,8 +464,8 @@ render_border (cairo_t *cr,
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
|
||||
cairo_scale (cr,
|
||||
target_width / original_width,
|
||||
target_height / original_height);
|
||||
target_width / surface_width,
|
||||
target_height / surface_height);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
@ -618,6 +473,7 @@ render_border (cairo_t *cr,
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
void
|
||||
@ -629,60 +485,177 @@ _gtk_border_image_render (GtkBorderImage *image,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
_gtk_border_image_ensure_slices (image, width, height);
|
||||
cairo_surface_t *surface, *slice;
|
||||
gdouble slice_width, slice_height, surface_width, surface_height;
|
||||
|
||||
if (cairo_pattern_get_type (image->source) != CAIRO_PATTERN_TYPE_SURFACE)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
cairo_t *surface_cr;
|
||||
|
||||
surface_width = width;
|
||||
surface_height = height;
|
||||
|
||||
cairo_matrix_init_scale (&matrix, 1 / width, 1 / height);
|
||||
cairo_pattern_set_matrix (image->source, &matrix);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
surface_cr = cairo_create (surface);
|
||||
cairo_set_source (surface_cr, image->source);
|
||||
cairo_paint (surface_cr);
|
||||
|
||||
cairo_destroy (surface_cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_pattern_get_surface (image->source, &surface);
|
||||
cairo_surface_reference (surface);
|
||||
|
||||
surface_width = cairo_image_surface_get_width (surface);
|
||||
surface_height = cairo_image_surface_get_height (surface);
|
||||
}
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, x, y);
|
||||
|
||||
/* Top side */
|
||||
surface = image->surfaces[BORDER_MIDDLE][BORDER_TOP];
|
||||
render_border (cr, surface,
|
||||
width, height, SIDE_TOP,
|
||||
border_width, &image->repeat);
|
||||
if ((image->slice.left + image->slice.right) < surface_width)
|
||||
{
|
||||
/* Top side */
|
||||
slice_width = surface_width - image->slice.left - image->slice.right;
|
||||
slice_height = image->slice.top;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
image->slice.left, 0,
|
||||
slice_width, slice_height);
|
||||
|
||||
/* Bottom side */
|
||||
surface = image->surfaces[BORDER_MIDDLE][BORDER_BOTTOM];
|
||||
render_border (cr, surface,
|
||||
width, height, SIDE_BOTTOM,
|
||||
border_width, &image->repeat);
|
||||
render_border (cr,
|
||||
width, height,
|
||||
slice,
|
||||
slice_width, slice_height,
|
||||
SIDE_TOP,
|
||||
border_width,
|
||||
&image->repeat);
|
||||
|
||||
/* Left side */
|
||||
surface = image->surfaces[BORDER_LEFT][BORDER_MIDDLE];
|
||||
render_border (cr, surface,
|
||||
width, height, SIDE_LEFT,
|
||||
border_width, &image->repeat);
|
||||
cairo_surface_destroy (slice);
|
||||
|
||||
/* Right side */
|
||||
surface = image->surfaces[BORDER_RIGHT][BORDER_MIDDLE];
|
||||
render_border (cr, surface,
|
||||
width, height, SIDE_RIGHT,
|
||||
border_width, &image->repeat);
|
||||
/* Bottom side */
|
||||
slice_height = image->slice.bottom;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
image->slice.left, surface_height - image->slice.bottom,
|
||||
slice_width, slice_height);
|
||||
|
||||
/* Top/Left corner */
|
||||
surface = image->surfaces[BORDER_LEFT][BORDER_TOP];
|
||||
render_corner (cr, surface,
|
||||
render_border (cr,
|
||||
width, height,
|
||||
slice,
|
||||
slice_width, slice_height,
|
||||
SIDE_BOTTOM,
|
||||
border_width,
|
||||
&image->repeat);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
}
|
||||
|
||||
if ((image->slice.top + image->slice.bottom) < surface_height)
|
||||
{
|
||||
/* Left side */
|
||||
slice_width = image->slice.left;
|
||||
slice_height = surface_height - image->slice.top - image->slice.bottom;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
0, image->slice.top,
|
||||
slice_width, slice_height);
|
||||
|
||||
render_border (cr,
|
||||
width, height,
|
||||
slice,
|
||||
slice_width, slice_height,
|
||||
SIDE_LEFT,
|
||||
border_width,
|
||||
&image->repeat);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
|
||||
/* Right side */
|
||||
slice_width = image->slice.right;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
surface_width - image->slice.right, image->slice.top,
|
||||
slice_width, slice_height);
|
||||
|
||||
render_border (cr,
|
||||
width, height,
|
||||
slice,
|
||||
slice_width, slice_height,
|
||||
SIDE_RIGHT,
|
||||
border_width,
|
||||
&image->repeat);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
}
|
||||
|
||||
/* Top/left corner */
|
||||
slice_width = image->slice.left;
|
||||
slice_height = image->slice.top;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
0, 0,
|
||||
slice_width, slice_height);
|
||||
|
||||
render_corner (cr,
|
||||
0, 0,
|
||||
border_width->left, border_width->top);
|
||||
border_width->left, border_width->top,
|
||||
slice,
|
||||
slice_width, slice_height);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
|
||||
/* Top/right corner */
|
||||
surface = image->surfaces[BORDER_RIGHT][BORDER_TOP];
|
||||
render_corner (cr, surface,
|
||||
slice_width = image->slice.right;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
surface_width - image->slice.right, 0,
|
||||
slice_width, slice_height);
|
||||
|
||||
render_corner (cr,
|
||||
width - border_width->right, 0,
|
||||
border_width->right, border_width->top);
|
||||
border_width->right, border_width->top,
|
||||
slice,
|
||||
slice_width, slice_height);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
|
||||
/* Bottom/left corner */
|
||||
surface = image->surfaces[BORDER_LEFT][BORDER_BOTTOM];
|
||||
render_corner (cr, surface,
|
||||
slice_width = image->slice.left;
|
||||
slice_height = image->slice.bottom;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
0, surface_height - image->slice.bottom,
|
||||
slice_width, slice_height);
|
||||
|
||||
render_corner (cr,
|
||||
0, height - border_width->bottom,
|
||||
border_width->left, border_width->bottom);
|
||||
border_width->left, border_width->bottom,
|
||||
slice,
|
||||
slice_width, slice_height);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
|
||||
/* Bottom/right corner */
|
||||
surface = image->surfaces[BORDER_RIGHT][BORDER_BOTTOM];
|
||||
render_corner (cr, surface,
|
||||
slice_width = image->slice.right;
|
||||
slice = cairo_surface_create_for_rectangle
|
||||
(surface,
|
||||
surface_width - image->slice.right,
|
||||
surface_height - image->slice.bottom,
|
||||
slice_width, slice_height);
|
||||
|
||||
render_corner (cr,
|
||||
width - border_width->right, height - border_width->bottom,
|
||||
border_width->right, border_width->bottom);
|
||||
border_width->right, border_width->bottom,
|
||||
slice,
|
||||
slice_width, slice_height);
|
||||
|
||||
cairo_surface_destroy (slice);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user