[gnome-shell] st: Use scaled surfaces for creating cairo background shadows



commit 5617ffc79ceb3acb291332879cbbe161cea0a316
Author: Marco Trevisan (Treviño) <mail 3v1n0 net>
Date:   Mon Feb 25 13:45:02 2019 +0100

    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

 src/st/st-private.c            | 39 +++++++++++++++++++++++++++++++++++++--
 src/st/st-theme-node-drawing.c | 19 +++++++++++++++----
 2 files changed, 52 insertions(+), 6 deletions(-)
---
diff --git a/src/st/st-private.c b/src/st/st-private.c
index 688b17b78..a74368709 100644
--- a/src/st/st-private.c
+++ b/src/st/st-private.c
@@ -536,9 +536,10 @@ _st_create_shadow_pipeline_from_actor (StShadow     *shadow_spec,
  * the offset.
  */
 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)
 {
+  g_autoptr(StShadow) shadow_spec = NULL;
   static cairo_user_data_key_t shadow_pattern_user_data;
   cairo_t *cr;
   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_out, height_out, rowstride_out;
   cairo_matrix_t   shadow_matrix;
+  double           xscale_in, yscale_in;
   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);
 
   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);
   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,
    * 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,
                                                      height_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,
                                pixels_out, (cairo_destroy_func_t) g_free);
 
@@ -616,6 +638,9 @@ _st_create_shadow_cairo_pattern (StShadow        *shadow_spec,
 
   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
        * applied to the original pattern, so all left to do is shift 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,
                               (width_out - width_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);
       return dst_pattern;
     }
@@ -636,6 +665,9 @@ _st_create_shadow_cairo_pattern (StShadow        *shadow_spec,
   /* 6. Invert the matrix back */
   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 */
   cairo_matrix_translate (&shadow_matrix,
                           shadow_spec->xoffset,
@@ -657,6 +689,9 @@ _st_create_shadow_cairo_pattern (StShadow        *shadow_spec,
                           - (width_out - width_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
    */
   cairo_matrix_invert (&shadow_matrix);
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index a94253f4e..7db928a0d 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -759,6 +759,7 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
     {
       cairo_surface_t *surface;
       int width, height;
+      double xscale, yscale;
       cairo_matrix_t matrix;
 
       cairo_save (cr);
@@ -775,11 +776,13 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
         /* Something went wrong previously */
         goto no_surface;
 
+      cairo_surface_get_device_scale (surface, &xscale, &yscale);
       width = cairo_image_surface_get_width  (surface);
       height = cairo_image_surface_get_height (surface);
 
       cairo_pattern_get_matrix (pattern, &matrix);
       cairo_matrix_invert (&matrix);
+      cairo_matrix_scale (&matrix, 1.0 / xscale, 1.0 / yscale);
       cairo_transform (cr, &matrix);
 
       cairo_rectangle (cr, 0, height, width, - height);
@@ -803,7 +806,8 @@ paint_background_image_shadow_to_cairo_context (StThemeNode     *node,
                                                 int              x,
                                                 int              y,
                                                 int              width,
-                                                int              height)
+                                                int              height,
+                                                float            resource_scale)
 {
   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,
        * 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);
+      cairo_surface_set_device_scale (clipped_surface, resource_scale, resource_scale);
       temp_cr = cairo_create (clipped_surface);
 
       cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
@@ -883,6 +890,7 @@ path_extents (cairo_path_t *path,
 static void
 paint_inset_box_shadow_to_cairo_context (StThemeNode     *node,
                                          StShadow        *shadow_spec,
+                                         float            resource_scale,
                                          cairo_t         *cr,
                                          cairo_path_t    *shadow_outline)
 {
@@ -923,8 +931,8 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode     *node,
       /* Bounds of temporary surface */
       int surface_x = floor (shrunk_extents_x1);
       int surface_y = floor (shrunk_extents_y1);
-      int surface_width = ceil (shrunk_extents_x2) - surface_x;
-      int surface_height = ceil (shrunk_extents_y2) - surface_y;
+      int surface_width = ceil ((shrunk_extents_x2 - surface_x) * resource_scale);
+      int surface_height = ceil ((shrunk_extents_y2 - surface_y) * resource_scale);
 
       /* Center of the original path */
       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;
 
       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);
 
       /* 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,
                                                       actor_box.x1,
                                                       actor_box.y1,
-                                                      width, height);
+                                                      width, height,
+                                                      resource_scale);
       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,
                                                box_shadow_spec,
+                                               resource_scale,
                                                cr,
                                                interior_path ? interior_path
                                                              : outline_path);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]