Update decoration drawing to be less cairo path happy
authorKristian Høgsberg <krh@bitplanet.net>
Tue, 15 Jun 2010 21:16:35 +0000 (17:16 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Tue, 15 Jun 2010 21:16:35 +0000 (17:16 -0400)
cairo-util.c
cairo-util.h
clients/Makefile
clients/terminal.c
clients/window.c
clients/window.h

index 437098c..c4138dd 100644 (file)
@@ -114,4 +114,142 @@ blur_surface(cairo_surface_t *surface, int margin)
        }
 
        free(dst);
+       cairo_surface_mark_dirty(surface);
+}
+
+void
+tile_mask(cairo_t *cr, cairo_surface_t *surface,
+         int x, int y, int width, int height, int margin)
+{
+       cairo_pattern_t *pattern;
+       cairo_matrix_t matrix;
+       int i, fx, fy;
+
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       pattern = cairo_pattern_create_for_surface (surface);
+
+       for (i = 0; i < 4; i++) {
+               fx = i & 1;
+               fy = i >> 1;
+
+               cairo_matrix_init_translate(&matrix,
+                                           -x + fx * (128 - width),
+                                           -y + fy * (128 - height));
+               cairo_pattern_set_matrix(pattern, &matrix);
+
+               cairo_reset_clip(cr);
+               cairo_rectangle(cr,
+                               x + fx * (width - margin),
+                               y + fy * (height - margin),
+                               margin, margin);
+               cairo_clip (cr);
+               cairo_mask(cr, pattern);
+       }
+
+       /* Top strecth */
+       cairo_matrix_init_translate(&matrix, 64, 0);
+       cairo_matrix_scale(&matrix, 64.0 / (width - 2 * margin), 1);
+       cairo_matrix_translate(&matrix, -x - width / 2, -y);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_rectangle(cr, x + margin, y, width - 2 * margin, margin);
+
+       cairo_reset_clip(cr);
+       cairo_rectangle(cr,
+                       x + margin,
+                       y,
+                       width - 2 * margin, margin);
+       cairo_clip (cr);
+       cairo_mask(cr, pattern);
+
+       /* Bottom strecth */
+       cairo_matrix_translate(&matrix, 0, -height + 128);
+       cairo_pattern_set_matrix(pattern, &matrix);
+
+       cairo_reset_clip(cr);
+       cairo_rectangle(cr, x + margin, y + height - margin,
+                       width - 2 * margin, margin);
+       cairo_clip (cr);
+       cairo_mask(cr, pattern);
+
+       /* Left strecth */
+       cairo_matrix_init_translate(&matrix, 0, 64);
+       cairo_matrix_scale(&matrix, 1, 64.0 / (height - 2 * margin));
+       cairo_matrix_translate(&matrix, -x, -y - height / 2);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_reset_clip(cr);
+       cairo_rectangle(cr, x, y + margin, margin, height - 2 * margin);
+       cairo_clip (cr);
+       cairo_mask(cr, pattern);
+
+       /* Right strecth */
+       cairo_matrix_translate(&matrix, -width + 128, 0);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_rectangle(cr, x + width - margin, y + margin,
+                       margin, height - 2 * margin);
+       cairo_reset_clip(cr);
+       cairo_clip (cr);
+       cairo_mask(cr, pattern);
+
+       cairo_pattern_destroy(pattern);
+       cairo_reset_clip(cr);
+}
+
+void
+tile_source(cairo_t *cr, cairo_surface_t *surface,
+           int x, int y, int width, int height, int margin)
+{
+       cairo_pattern_t *pattern;
+       cairo_matrix_t matrix;
+       int i, fx, fy;
+
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       pattern = cairo_pattern_create_for_surface (surface);
+       cairo_set_source(cr, pattern);
+       cairo_pattern_destroy(pattern);
+
+       for (i = 0; i < 4; i++) {
+               fx = i & 1;
+               fy = i >> 1;
+
+               cairo_matrix_init_translate(&matrix,
+                                           -x + fx * (128 - width),
+                                           -y + fy * (128 - height));
+               cairo_pattern_set_matrix(pattern, &matrix);
+
+               cairo_rectangle(cr,
+                               x + fx * (width - margin),
+                               y + fy * (height - margin),
+                               margin, margin);
+               cairo_fill(cr);
+       }
+
+       /* Top strecth */
+       cairo_matrix_init_translate(&matrix, 64, 0);
+       cairo_matrix_scale(&matrix, 64.0 / (width - 2 * margin), 1);
+       cairo_matrix_translate(&matrix, -x - width / 2, -y);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_rectangle(cr, x + margin, y, width - 2 * margin, margin);
+       cairo_fill(cr);
+
+       /* Bottom strecth */
+       cairo_matrix_translate(&matrix, 0, -height + 128);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_rectangle(cr, x + margin, y + height - margin,
+                       width - 2 * margin, margin);
+       cairo_fill(cr);
+
+       /* Left strecth */
+       cairo_matrix_init_translate(&matrix, 0, 64);
+       cairo_matrix_scale(&matrix, 1, 64.0 / (height - 2 * margin));
+       cairo_matrix_translate(&matrix, -x, -y - height / 2);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_rectangle(cr, x, y + margin, margin, height - 2 * margin);
+       cairo_fill(cr);
+
+       /* Right strecth */
+       cairo_matrix_translate(&matrix, -width + 128, 0);
+       cairo_pattern_set_matrix(pattern, &matrix);
+       cairo_rectangle(cr, x + width - margin, y + margin,
+                       margin, height - 2 * margin);
+       cairo_fill(cr);
 }
index d74b27d..18fa2b7 100644 (file)
 void
 blur_surface(cairo_surface_t *surface, int margin);
 
+void
+tile_mask(cairo_t *cr, cairo_surface_t *surface,
+         int x, int y, int width, int height, int margin);
+
+void
+tile_source(cairo_t *cr, cairo_surface_t *surface,
+           int x, int y, int width, int height, int margin);
+
 #endif
index 81e8792..458100f 100644 (file)
@@ -11,12 +11,12 @@ all : $(egl_clients) $(cairo_clients)
 clean :
        rm -f $(egl_clients) $(cairo_clients) *.o
 
-flower : flower.o window.o wayland-glib.o
-gears : gears.o window.o wayland-glib.o
-screenshot : screenshot.o wayland-glib.o
-terminal : terminal.o window.o wayland-glib.o
-image : image.o window.o wayland-glib.o
-view : view.o window.o wayland-glib.o
+flower : flower.o window.o wayland-glib.o ../cairo-util.o
+gears : gears.o window.o wayland-glib.o ../cairo-util.o
+screenshot : screenshot.o wayland-glib.o ../cairo-util.o
+terminal : terminal.o window.o wayland-glib.o ../cairo-util.o
+image : image.o window.o wayland-glib.o ../cairo-util.o
+view : view.o window.o wayland-glib.o ../cairo-util.o
 
 terminal : LDLIBS += -lutil
 view : CFLAGS += $(POPPLER_CFLAGS)
index e0702e5..df217b6 100644 (file)
@@ -136,7 +136,7 @@ terminal_draw_contents(struct terminal *terminal)
 
        window_get_child_rectangle(terminal->window, &rectangle);
 
-       surface = window_create_surface(terminal->window, &rectangle);
+       surface = display_create_surface(terminal->display, &rectangle);
        cr = cairo_create(surface);
        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
        cairo_set_source_rgba(cr,
index c1cc2dd..214d0d5 100644 (file)
@@ -61,6 +61,7 @@ struct display {
        GSource *source;
        struct wl_list window_list;
        char *device_name;
+       cairo_surface_t *active_frame, *inactive_frame, *shadow;
 };
 
 struct window {
@@ -125,11 +126,11 @@ surface_data_destroy(void *p)
 }
 
 cairo_surface_t *
-window_create_surface(struct window *window,
-                     struct rectangle *rectangle)
+display_create_surface(struct display *display,
+                      struct rectangle *rectangle)
 {
        struct surface_data *data;
-       EGLDisplay dpy = window->display->dpy;
+       EGLDisplay dpy = display->dpy;
        cairo_surface_t *surface;
 
        EGLint image_attribs[] = {
@@ -149,7 +150,7 @@ window_create_surface(struct window *window,
        glBindTexture(GL_TEXTURE_2D, data->texture);
        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data->image);
 
-       surface = cairo_gl_surface_create_for_texture(window->display->device,
+       surface = cairo_gl_surface_create_for_texture(display->device,
                                                      CAIRO_CONTENT_COLOR_ALPHA,
                                                      data->texture,
                                                      rectangle->width,
@@ -212,13 +213,16 @@ window_draw_decorations(struct window *window)
        cairo_t *cr;
        int border = 2, radius = 5;
        cairo_text_extents_t extents;
-       cairo_pattern_t *gradient, *outline, *bright, *dim;
+       cairo_pattern_t *pattern, *gradient, *outline, *bright, *dim;
        int width, height;
        int shadow_dx = 4, shadow_dy = 4;
+       cairo_matrix_t matrix;
 
        window->cairo_surface =
-               window_create_surface(window, &window->allocation);
+               display_create_surface(window->display, &window->allocation);
        window->surface_allocation = window->allocation;
+       width = window->allocation.width;
+       height = window->allocation.height;
 
        outline = cairo_pattern_create_rgb(0.1, 0.1, 0.1);
        bright = cairo_pattern_create_rgb(0.8, 0.8, 0.8);
@@ -226,85 +230,33 @@ window_draw_decorations(struct window *window)
 
        cr = cairo_create(window->cairo_surface);
 
-       width = window->allocation.width - window->margin * 2;
-       height = window->allocation.height - window->margin * 2;
-
-       cairo_set_source_rgba(cr, 0, 0, 0, 0);
        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+       cairo_set_source_rgba(cr, 0, 0, 0, 0);
        cairo_paint(cr);
 
-       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-       cairo_translate(cr, window->margin + shadow_dx,
-                       window->margin + shadow_dy);
-       cairo_set_line_width (cr, border);
-       cairo_set_source_rgba(cr, 0, 0, 0, 0.7);
-       rounded_rect(cr, -1, -1, width + 1, height + 1, radius);
-       cairo_fill(cr);
-
-#define SLOW_BUT_PWETTY_not_right_now
-#ifdef SLOW_BUT_PWETTY
-       /* FIXME: Aw, pretty drop shadows now have to fallback to sw.
-        * Ideally we should have convolution filters in cairo, but we
-        * can also fallback to compositing the shadow image a bunch
-        * of times according to the blur kernel. */
-       {
-               cairo_surface_t *map;
-
-               map = cairo_drm_surface_map(window->cairo_surface);
-               blur_surface(map, 32);
-               cairo_drm_surface_unmap(window->cairo_surface, map);
-       }
-#endif
-
-       cairo_translate(cr, -shadow_dx, -shadow_dy);
-       if (window->keyboard_device) {
-               rounded_rect(cr, 0, 0, width, height, radius);
-               gradient = cairo_pattern_create_linear (0, 0, 0, 100);
-               cairo_pattern_add_color_stop_rgb(gradient, 0, 0.6, 0.6, 0.6);
-               cairo_pattern_add_color_stop_rgb(gradient, 1, 0.8, 0.8, 0.8);
-               cairo_set_source(cr, gradient);
-               cairo_fill(cr);
-               cairo_pattern_destroy(gradient);
-       } else {
-               rounded_rect(cr, 0, 0, width, height, radius);
-               cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1);
-               cairo_fill(cr);
-       }
-
-       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-       cairo_move_to(cr, 10, 50);
-       cairo_line_to(cr, width - 10, 50);
-       cairo_line_to(cr, width - 10, height - 10);
-       cairo_line_to(cr, 10, height - 10);
-       cairo_close_path(cr);
-       cairo_set_source(cr, dim);
-       cairo_stroke(cr);
+       cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
+       tile_mask(cr, window->display->shadow, 3, 3, width, height, 32);
 
-       cairo_move_to(cr, 11, 51);
-       cairo_line_to(cr, width - 10, 51);
-       cairo_line_to(cr, width - 10, height - 10);
-       cairo_line_to(cr, 11, height - 10);
-       cairo_close_path(cr);
-       cairo_set_source(cr, bright);
-       cairo_stroke(cr);
+       if (window->keyboard_device)
+               tile_source(cr, window->display->active_frame,
+                           0, 0, width, height, 96);
+       else
+               tile_source(cr, window->display->inactive_frame,
+                           0, 0, width, height, 96);
 
        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
        cairo_set_font_size(cr, 14);
        cairo_text_extents(cr, window->title, &extents);
-       cairo_move_to(cr, (width - extents.width) / 2, 10 - extents.y_bearing);
+       cairo_move_to(cr, (width - extents.width) / 2, 32 - extents.y_bearing);
        cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
        cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
        cairo_set_line_width (cr, 4);
-       cairo_text_path(cr, window->title);
-       if (window->keyboard_device) {
-               cairo_set_source_rgb(cr, 0.56, 0.56, 0.56);
-               cairo_stroke_preserve(cr);
-               cairo_set_source_rgb(cr, 1, 1, 1);
-               cairo_fill(cr);
-       } else {
+       if (window->keyboard_device)
+               cairo_set_source_rgb(cr, 0, 0, 0);
+       else
                cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
-               cairo_fill(cr);
-       }
+       cairo_show_text(cr, window->title);
+
        cairo_destroy(cr);
 }
 
@@ -312,7 +264,7 @@ static void
 window_draw_fullscreen(struct window *window)
 {
        window->cairo_surface =
-               window_create_surface(window, &window->allocation);
+               display_create_surface(window->display, &window->allocation);
        window->surface_allocation = window->allocation;
 }
 
@@ -907,6 +859,41 @@ display_handle_global(struct wl_display *display,
 
 static const char socket_name[] = "\0wayland";
 
+static void
+display_render_frame(struct display *d)
+{
+       struct rectangle r = { 0, 0, 128, 128 };
+       int radius = 8;
+       cairo_t *cr;
+
+       d->shadow = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
+       cr = cairo_create(d->shadow);
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       cairo_set_source_rgba(cr, 0, 0, 0, 1);
+       rounded_rect(cr, 16, 16, 112, 112, radius);
+       cairo_fill(cr);
+       cairo_destroy(cr);
+       blur_surface(d->shadow, 64);
+
+       d->active_frame =
+               cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
+       cr = cairo_create(d->active_frame);
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       cairo_set_source_rgba(cr, 0.8, 0.8, 0.4, 1);
+       rounded_rect(cr, 16, 16, 112, 112, radius);
+       cairo_fill(cr);
+       cairo_destroy(cr);
+
+       d->inactive_frame =
+               cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
+       cr = cairo_create(d->inactive_frame);
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1);
+       rounded_rect(cr, 16, 16, 112, 112, radius);
+       cairo_fill(cr);
+       cairo_destroy(cr);
+}
+
 struct display *
 display_create(int *argc, char **argv[], const GOptionEntry *option_entries)
 {
@@ -998,6 +985,8 @@ display_create(int *argc, char **argv[], const GOptionEntry *option_entries)
                return NULL;
        }
 
+       display_render_frame(d);
+
        d->loop = g_main_loop_new(NULL, FALSE);
        d->source = wl_glib_source_new(d->display);
        g_source_attach(d->source, NULL);
index 511f703..041d35d 100644 (file)
@@ -45,6 +45,10 @@ EGLDisplay
 display_get_egl_display(struct display *d);
 #endif
 
+cairo_surface_t *
+display_create_surface(struct display *display,
+                      struct rectangle *rectangle);
+
 void
 display_run(struct display *d);
 
@@ -88,10 +92,6 @@ void
 window_move(struct window *window, int32_t x, int32_t y);
 
 cairo_surface_t *
-window_create_surface(struct window *window,
-                     struct rectangle *rectangle);
-
-cairo_surface_t *
 window_get_surface(struct window *window);
 
 void