[mutter] Antialiased corners



commit dcfa6986c6aaa7f60d1aea45f04d3af5221e476b
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Aug 10 10:32:47 2011 -0400

    Antialiased corners
    
    Use a specially constructed cairo overlay to give us fully anti-aliased
    corners on the mask texture.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=628195

 src/compositor/meta-window-actor.c |  126 ++++++++++++++++++++++++++++++++---
 1 files changed, 115 insertions(+), 11 deletions(-)
---
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index a6f55d2..523a558 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -2,7 +2,6 @@
 
 #include <config.h>
 
-#define _ISOC99_SOURCE /* for roundf */
 #include <math.h>
 
 #include <X11/extensions/shape.h>
@@ -1697,13 +1696,8 @@ meta_window_actor_set_visible_region (MetaWindowActor *self,
   /* Get the area of the window texture that would be drawn if
    * we weren't obscured at all
    */
-  if (priv->shape_region)
-    texture_clip_region = cairo_region_copy (priv->shape_region);
-  else if (priv->bounding_region)
-    texture_clip_region = cairo_region_copy (priv->bounding_region);
-
-  if (!texture_clip_region)
-    texture_clip_region = cairo_region_create ();
+  texture_clip_region = meta_shaped_texture_get_visible_pixels_region (META_SHAPED_TEXTURE (priv->actor));
+  texture_clip_region = cairo_region_copy (texture_clip_region);
 
   /* Then intersect that with the visible region to get the region
    * that we actually need to redraw.
@@ -1993,12 +1987,120 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
     }
 }
 
+static inline void
+set_integral_bounding_rect (cairo_rectangle_int_t *rect,
+                            double x, double y,
+                            double width, double height)
+{
+  rect->x = floor(x);
+  rect->y = floor(y);
+  rect->width = ceil(x + width) - rect->x;
+  rect->height = ceil(y + height) - rect->y;
+}
+
+static void
+update_corners (MetaWindowActor   *self,
+                MetaFrameBorders  *borders)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+  MetaRectangle outer;
+  cairo_rectangle_int_t corner_rects[4];
+  cairo_region_t *corner_region;
+  cairo_path_t *corner_path;
+  float top_left, top_right, bottom_left, bottom_right;
+
+  /* need these to build a path */
+  cairo_t *cr;
+  cairo_surface_t *surface;
+
+  if (!priv->window->frame)
+    return;
+
+  meta_window_get_outer_rect (priv->window, &outer);
+
+  meta_frame_get_corner_radiuses (priv->window->frame,
+                                  &top_left,
+                                  &top_right,
+                                  &bottom_left,
+                                  &bottom_right);
+
+  /* Unfortunately, cairo does not allow us to create a context
+   * without a surface. Create a 0x0 image surface to "paint to"
+   * so we can get the path. */
+  surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
+                                        0, 0);
+
+  cr = cairo_create (surface);
+
+  /* top left */
+  set_integral_bounding_rect (&corner_rects[0],
+                              borders->invisible.left,
+                              borders->invisible.top,
+                              top_left, top_left);
+
+  cairo_arc (cr,
+             corner_rects[0].x + top_left,
+             corner_rects[0].y + top_left,
+             top_left,
+             0, M_PI*2);
+
+  /* top right */
+  set_integral_bounding_rect (&corner_rects[1],
+                              borders->invisible.left + outer.width - top_right,
+                              borders->invisible.top,
+                              top_right, top_right);
+
+  cairo_arc (cr,
+             corner_rects[1].x,
+             corner_rects[1].y + top_right,
+             top_right,
+             0, M_PI*2);
+
+  /* bottom left */
+  set_integral_bounding_rect (&corner_rects[2],
+                              borders->invisible.left,
+                              borders->invisible.top + outer.height - bottom_left,
+                              bottom_left, bottom_left);
+
+  cairo_arc (cr,
+             corner_rects[2].x + bottom_left,
+             corner_rects[2].y,
+             bottom_left,
+             0, M_PI*2);
+
+  /* bottom right */
+  set_integral_bounding_rect (&corner_rects[3],
+                              borders->invisible.left + outer.width - bottom_right,
+                              borders->invisible.top + outer.height - bottom_right,
+                              bottom_right, bottom_right);
+
+  cairo_arc (cr,
+             corner_rects[3].x,
+             corner_rects[3].y,
+             bottom_right,
+             0, M_PI*2);
+
+  corner_path = cairo_copy_path (cr);
+
+  cairo_surface_destroy (surface);
+  cairo_destroy (cr);
+
+  corner_region = cairo_region_create_rectangles (corner_rects, 4);
+
+  meta_shaped_texture_set_overlay_path (META_SHAPED_TEXTURE (priv->actor),
+                                        corner_region, corner_path);
+
+  cairo_region_destroy (corner_region);
+
+}
+
 static void
 check_needs_reshape (MetaWindowActor *self)
 {
   MetaWindowActorPrivate *priv = self->priv;
   MetaScreen *screen = priv->screen;
   MetaDisplay *display = meta_screen_get_display (screen);
+  MetaFrameBorders borders;
   cairo_region_t *region;
 
   if (!priv->needs_reshape)
@@ -2007,6 +2109,9 @@ check_needs_reshape (MetaWindowActor *self)
   meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), NULL);
   meta_window_actor_clear_shape_region (self);
 
+  if (priv->window->frame)
+    meta_frame_calc_borders (priv->window->frame, &borders);
+
   region = meta_window_get_frame_bounds (priv->window);
   if (region != NULL)
     {
@@ -2034,9 +2139,6 @@ check_needs_reshape (MetaWindowActor *self)
 
       if (priv->window->frame)
         {
-          MetaFrameBorders borders;
-          meta_frame_calc_borders (priv->window->frame, &borders);
-
           client_area.x = borders.total.left;
           client_area.y = borders.total.top;
         }
@@ -2080,6 +2182,8 @@ check_needs_reshape (MetaWindowActor *self)
 
   cairo_region_destroy (region);
 
+  update_corners (self, &borders);
+
   priv->needs_reshape = FALSE;
   meta_window_actor_invalidate_shadow (self);
 }



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