st: Use scaled surfaces for creating cairo background shadows
Create the surfaces for background shadows at scaled sizes and then draw on them using logical coordinates, by setting the surface device scale accordingly. Use the said surface scale when generating the actual shadow cairo pattern but in such case, to reduce the number of code changes, is better to work in absolute coordinates, and to do so: 1) Create a temporary shadow-spec copy with scaled values to absolute sizes 2) Invert the scaling on the shadow matrix 3) Do the actual painting in absolute coordinates 4) Set the shadow matrix scaling back to the logical coordinates. Finally scale down the created shadow pattern surface size when painting it, applying again a reverse scale to the matrix. https://bugzilla.gnome.org/show_bug.cgi?id=765011 https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
This commit is contained in:
parent
ca4d86e9e5
commit
5617ffc79c
@ -536,9 +536,10 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
|||||||
* the offset.
|
* the offset.
|
||||||
*/
|
*/
|
||||||
cairo_pattern_t *
|
cairo_pattern_t *
|
||||||
_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
_st_create_shadow_cairo_pattern (StShadow *shadow_spec_in,
|
||||||
cairo_pattern_t *src_pattern)
|
cairo_pattern_t *src_pattern)
|
||||||
{
|
{
|
||||||
|
g_autoptr(StShadow) shadow_spec = NULL;
|
||||||
static cairo_user_data_key_t shadow_pattern_user_data;
|
static cairo_user_data_key_t shadow_pattern_user_data;
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
cairo_surface_t *src_surface;
|
cairo_surface_t *src_surface;
|
||||||
@ -549,9 +550,10 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
gint width_in, height_in, rowstride_in;
|
gint width_in, height_in, rowstride_in;
|
||||||
gint width_out, height_out, rowstride_out;
|
gint width_out, height_out, rowstride_out;
|
||||||
cairo_matrix_t shadow_matrix;
|
cairo_matrix_t shadow_matrix;
|
||||||
|
double xscale_in, yscale_in;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
g_return_val_if_fail (shadow_spec != NULL, NULL);
|
g_return_val_if_fail (shadow_spec_in != NULL, NULL);
|
||||||
g_return_val_if_fail (src_pattern != NULL, NULL);
|
g_return_val_if_fail (src_pattern != NULL, NULL);
|
||||||
|
|
||||||
if (cairo_pattern_get_surface (src_pattern, &src_surface) != CAIRO_STATUS_SUCCESS)
|
if (cairo_pattern_get_surface (src_pattern, &src_surface) != CAIRO_STATUS_SUCCESS)
|
||||||
@ -564,6 +566,25 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
width_in = cairo_image_surface_get_width (src_surface);
|
width_in = cairo_image_surface_get_width (src_surface);
|
||||||
height_in = cairo_image_surface_get_height (src_surface);
|
height_in = cairo_image_surface_get_height (src_surface);
|
||||||
|
|
||||||
|
cairo_surface_get_device_scale (src_surface, &xscale_in, &yscale_in);
|
||||||
|
|
||||||
|
if (xscale_in != 1.0 || yscale_in != 1.0)
|
||||||
|
{
|
||||||
|
/* Scale the shadow specifications in a temporary copy so that
|
||||||
|
* we can work everywhere in absolute surface coordinates */
|
||||||
|
double scale = (xscale_in + yscale_in) / 2.0;
|
||||||
|
shadow_spec = st_shadow_new (&shadow_spec_in->color,
|
||||||
|
shadow_spec_in->xoffset * xscale_in,
|
||||||
|
shadow_spec_in->yoffset * yscale_in,
|
||||||
|
shadow_spec_in->blur * scale,
|
||||||
|
shadow_spec_in->spread * scale,
|
||||||
|
shadow_spec_in->inset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shadow_spec = st_shadow_ref (shadow_spec_in);
|
||||||
|
}
|
||||||
|
|
||||||
/* We want the output to be a color agnostic alpha mask,
|
/* We want the output to be a color agnostic alpha mask,
|
||||||
* so we need to strip the color channels from the input
|
* so we need to strip the color channels from the input
|
||||||
*/
|
*/
|
||||||
@ -606,6 +627,7 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
width_out,
|
width_out,
|
||||||
height_out,
|
height_out,
|
||||||
rowstride_out);
|
rowstride_out);
|
||||||
|
cairo_surface_set_device_scale (surface_out, xscale_in, yscale_in);
|
||||||
cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
|
cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
|
||||||
pixels_out, (cairo_destroy_func_t) g_free);
|
pixels_out, (cairo_destroy_func_t) g_free);
|
||||||
|
|
||||||
@ -616,6 +638,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
|
|
||||||
if (shadow_spec->inset)
|
if (shadow_spec->inset)
|
||||||
{
|
{
|
||||||
|
/* Scale the matrix in surface absolute coordinates */
|
||||||
|
cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
|
||||||
|
|
||||||
/* For inset shadows, offsets and spread radius have already been
|
/* For inset shadows, offsets and spread radius have already been
|
||||||
* applied to the original pattern, so all left to do is shift the
|
* applied to the original pattern, so all left to do is shift the
|
||||||
* blurred image left, so that it aligns centered under the
|
* blurred image left, so that it aligns centered under the
|
||||||
@ -624,6 +649,10 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
cairo_matrix_translate (&shadow_matrix,
|
cairo_matrix_translate (&shadow_matrix,
|
||||||
(width_out - width_in) / 2.0,
|
(width_out - width_in) / 2.0,
|
||||||
(height_out - height_in) / 2.0);
|
(height_out - height_in) / 2.0);
|
||||||
|
|
||||||
|
/* Scale back the matrix in original coordinates */
|
||||||
|
cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
|
||||||
|
|
||||||
cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
|
cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
|
||||||
return dst_pattern;
|
return dst_pattern;
|
||||||
}
|
}
|
||||||
@ -636,6 +665,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
/* 6. Invert the matrix back */
|
/* 6. Invert the matrix back */
|
||||||
cairo_matrix_invert (&shadow_matrix);
|
cairo_matrix_invert (&shadow_matrix);
|
||||||
|
|
||||||
|
/* Scale the matrix in surface absolute coordinates */
|
||||||
|
cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
|
||||||
|
|
||||||
/* 5. Adjust based on specified offsets */
|
/* 5. Adjust based on specified offsets */
|
||||||
cairo_matrix_translate (&shadow_matrix,
|
cairo_matrix_translate (&shadow_matrix,
|
||||||
shadow_spec->xoffset,
|
shadow_spec->xoffset,
|
||||||
@ -657,6 +689,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
|||||||
- (width_out - width_in) / 2.0,
|
- (width_out - width_in) / 2.0,
|
||||||
- (height_out - height_in) / 2.0);
|
- (height_out - height_in) / 2.0);
|
||||||
|
|
||||||
|
/* Scale back the matrix in scaled coordinates */
|
||||||
|
cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
|
||||||
|
|
||||||
/* 1. Invert the matrix so we can work with it in pattern space
|
/* 1. Invert the matrix so we can work with it in pattern space
|
||||||
*/
|
*/
|
||||||
cairo_matrix_invert (&shadow_matrix);
|
cairo_matrix_invert (&shadow_matrix);
|
||||||
|
@ -759,6 +759,7 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
|
|||||||
{
|
{
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
double xscale, yscale;
|
||||||
cairo_matrix_t matrix;
|
cairo_matrix_t matrix;
|
||||||
|
|
||||||
cairo_save (cr);
|
cairo_save (cr);
|
||||||
@ -775,11 +776,13 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
|
|||||||
/* Something went wrong previously */
|
/* Something went wrong previously */
|
||||||
goto no_surface;
|
goto no_surface;
|
||||||
|
|
||||||
|
cairo_surface_get_device_scale (surface, &xscale, &yscale);
|
||||||
width = cairo_image_surface_get_width (surface);
|
width = cairo_image_surface_get_width (surface);
|
||||||
height = cairo_image_surface_get_height (surface);
|
height = cairo_image_surface_get_height (surface);
|
||||||
|
|
||||||
cairo_pattern_get_matrix (pattern, &matrix);
|
cairo_pattern_get_matrix (pattern, &matrix);
|
||||||
cairo_matrix_invert (&matrix);
|
cairo_matrix_invert (&matrix);
|
||||||
|
cairo_matrix_scale (&matrix, 1.0 / xscale, 1.0 / yscale);
|
||||||
cairo_transform (cr, &matrix);
|
cairo_transform (cr, &matrix);
|
||||||
|
|
||||||
cairo_rectangle (cr, 0, height, width, - height);
|
cairo_rectangle (cr, 0, height, width, - height);
|
||||||
@ -803,7 +806,8 @@ paint_background_image_shadow_to_cairo_context (StThemeNode *node,
|
|||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
int width,
|
int width,
|
||||||
int height)
|
int height,
|
||||||
|
float resource_scale)
|
||||||
{
|
{
|
||||||
cairo_pattern_t *shadow_pattern;
|
cairo_pattern_t *shadow_pattern;
|
||||||
|
|
||||||
@ -819,7 +823,10 @@ paint_background_image_shadow_to_cairo_context (StThemeNode *node,
|
|||||||
/* Prerender the pattern to a temporary surface,
|
/* Prerender the pattern to a temporary surface,
|
||||||
* so it's properly clipped before we create a shadow from it
|
* so it's properly clipped before we create a shadow from it
|
||||||
*/
|
*/
|
||||||
|
width = ceilf (width * resource_scale);
|
||||||
|
height = ceilf (height * resource_scale);
|
||||||
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||||
|
cairo_surface_set_device_scale (clipped_surface, resource_scale, resource_scale);
|
||||||
temp_cr = cairo_create (clipped_surface);
|
temp_cr = cairo_create (clipped_surface);
|
||||||
|
|
||||||
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
|
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
|
||||||
@ -883,6 +890,7 @@ path_extents (cairo_path_t *path,
|
|||||||
static void
|
static void
|
||||||
paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
||||||
StShadow *shadow_spec,
|
StShadow *shadow_spec,
|
||||||
|
float resource_scale,
|
||||||
cairo_t *cr,
|
cairo_t *cr,
|
||||||
cairo_path_t *shadow_outline)
|
cairo_path_t *shadow_outline)
|
||||||
{
|
{
|
||||||
@ -923,8 +931,8 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
|||||||
/* Bounds of temporary surface */
|
/* Bounds of temporary surface */
|
||||||
int surface_x = floor (shrunk_extents_x1);
|
int surface_x = floor (shrunk_extents_x1);
|
||||||
int surface_y = floor (shrunk_extents_y1);
|
int surface_y = floor (shrunk_extents_y1);
|
||||||
int surface_width = ceil (shrunk_extents_x2) - surface_x;
|
int surface_width = ceil ((shrunk_extents_x2 - surface_x) * resource_scale);
|
||||||
int surface_height = ceil (shrunk_extents_y2) - surface_y;
|
int surface_height = ceil ((shrunk_extents_y2 - surface_y) * resource_scale);
|
||||||
|
|
||||||
/* Center of the original path */
|
/* Center of the original path */
|
||||||
double x_center = (extents_x1 + extents_x2) / 2;
|
double x_center = (extents_x1 + extents_x2) / 2;
|
||||||
@ -935,6 +943,7 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
|||||||
cairo_matrix_t matrix;
|
cairo_matrix_t matrix;
|
||||||
|
|
||||||
shadow_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, surface_width, surface_height);
|
shadow_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, surface_width, surface_height);
|
||||||
|
cairo_surface_set_device_scale (shadow_surface, resource_scale, resource_scale);
|
||||||
temp_cr = cairo_create (shadow_surface);
|
temp_cr = cairo_create (shadow_surface);
|
||||||
|
|
||||||
/* Match the coordinates in the temporary context to the parent context */
|
/* Match the coordinates in the temporary context to the parent context */
|
||||||
@ -1284,7 +1293,8 @@ st_theme_node_prerender_background (StThemeNode *node,
|
|||||||
has_visible_outline? outline_path : NULL,
|
has_visible_outline? outline_path : NULL,
|
||||||
actor_box.x1,
|
actor_box.x1,
|
||||||
actor_box.y1,
|
actor_box.y1,
|
||||||
width, height);
|
width, height,
|
||||||
|
resource_scale);
|
||||||
cairo_append_path (cr, outline_path);
|
cairo_append_path (cr, outline_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1301,6 +1311,7 @@ st_theme_node_prerender_background (StThemeNode *node,
|
|||||||
{
|
{
|
||||||
paint_inset_box_shadow_to_cairo_context (node,
|
paint_inset_box_shadow_to_cairo_context (node,
|
||||||
box_shadow_spec,
|
box_shadow_spec,
|
||||||
|
resource_scale,
|
||||||
cr,
|
cr,
|
||||||
interior_path ? interior_path
|
interior_path ? interior_path
|
||||||
: outline_path);
|
: outline_path);
|
||||||
|
Loading…
Reference in New Issue
Block a user