Update decoration drawing to be less cairo path happy

This commit is contained in:
Kristian Høgsberg 2010-06-15 17:16:35 -04:00
parent 49e868cb05
commit dcb71b62a0
6 changed files with 220 additions and 85 deletions

View File

@ -114,4 +114,142 @@ blur_surface(cairo_surface_t *surface, int margin)
} }
free(dst); 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);
} }

View File

@ -26,4 +26,12 @@
void void
blur_surface(cairo_surface_t *surface, int margin); 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 #endif

View File

@ -11,12 +11,12 @@ all : $(egl_clients) $(cairo_clients)
clean : clean :
rm -f $(egl_clients) $(cairo_clients) *.o rm -f $(egl_clients) $(cairo_clients) *.o
flower : flower.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 gears : gears.o window.o wayland-glib.o ../cairo-util.o
screenshot : screenshot.o wayland-glib.o screenshot : screenshot.o wayland-glib.o ../cairo-util.o
terminal : terminal.o window.o wayland-glib.o terminal : terminal.o window.o wayland-glib.o ../cairo-util.o
image : image.o window.o wayland-glib.o image : image.o window.o wayland-glib.o ../cairo-util.o
view : view.o window.o wayland-glib.o view : view.o window.o wayland-glib.o ../cairo-util.o
terminal : LDLIBS += -lutil terminal : LDLIBS += -lutil
view : CFLAGS += $(POPPLER_CFLAGS) view : CFLAGS += $(POPPLER_CFLAGS)

View File

@ -136,7 +136,7 @@ terminal_draw_contents(struct terminal *terminal)
window_get_child_rectangle(terminal->window, &rectangle); 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); cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, cairo_set_source_rgba(cr,

View File

@ -61,6 +61,7 @@ struct display {
GSource *source; GSource *source;
struct wl_list window_list; struct wl_list window_list;
char *device_name; char *device_name;
cairo_surface_t *active_frame, *inactive_frame, *shadow;
}; };
struct window { struct window {
@ -125,11 +126,11 @@ surface_data_destroy(void *p)
} }
cairo_surface_t * cairo_surface_t *
window_create_surface(struct window *window, display_create_surface(struct display *display,
struct rectangle *rectangle) struct rectangle *rectangle)
{ {
struct surface_data *data; struct surface_data *data;
EGLDisplay dpy = window->display->dpy; EGLDisplay dpy = display->dpy;
cairo_surface_t *surface; cairo_surface_t *surface;
EGLint image_attribs[] = { EGLint image_attribs[] = {
@ -149,7 +150,7 @@ window_create_surface(struct window *window,
glBindTexture(GL_TEXTURE_2D, data->texture); glBindTexture(GL_TEXTURE_2D, data->texture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data->image); 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, CAIRO_CONTENT_COLOR_ALPHA,
data->texture, data->texture,
rectangle->width, rectangle->width,
@ -212,13 +213,16 @@ window_draw_decorations(struct window *window)
cairo_t *cr; cairo_t *cr;
int border = 2, radius = 5; int border = 2, radius = 5;
cairo_text_extents_t extents; cairo_text_extents_t extents;
cairo_pattern_t *gradient, *outline, *bright, *dim; cairo_pattern_t *pattern, *gradient, *outline, *bright, *dim;
int width, height; int width, height;
int shadow_dx = 4, shadow_dy = 4; int shadow_dx = 4, shadow_dy = 4;
cairo_matrix_t matrix;
window->cairo_surface = window->cairo_surface =
window_create_surface(window, &window->allocation); display_create_surface(window->display, &window->allocation);
window->surface_allocation = 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); outline = cairo_pattern_create_rgb(0.1, 0.1, 0.1);
bright = cairo_pattern_create_rgb(0.8, 0.8, 0.8); 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); 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_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_paint(cr); cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
cairo_translate(cr, window->margin + shadow_dx, tile_mask(cr, window->display->shadow, 3, 3, width, height, 32);
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 if (window->keyboard_device)
#ifdef SLOW_BUT_PWETTY tile_source(cr, window->display->active_frame,
/* FIXME: Aw, pretty drop shadows now have to fallback to sw. 0, 0, width, height, 96);
* Ideally we should have convolution filters in cairo, but we else
* can also fallback to compositing the shadow image a bunch tile_source(cr, window->display->inactive_frame,
* of times according to the blur kernel. */ 0, 0, width, height, 96);
{
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_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);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_font_size(cr, 14); cairo_set_font_size(cr, 14);
cairo_text_extents(cr, window->title, &extents); 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_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_width (cr, 4); cairo_set_line_width (cr, 4);
cairo_text_path(cr, window->title); if (window->keyboard_device)
if (window->keyboard_device) { cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_source_rgb(cr, 0.56, 0.56, 0.56); else
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
} else {
cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
cairo_fill(cr); cairo_show_text(cr, window->title);
}
cairo_destroy(cr); cairo_destroy(cr);
} }
@ -312,7 +264,7 @@ static void
window_draw_fullscreen(struct window *window) window_draw_fullscreen(struct window *window)
{ {
window->cairo_surface = window->cairo_surface =
window_create_surface(window, &window->allocation); display_create_surface(window->display, &window->allocation);
window->surface_allocation = 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 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 * struct display *
display_create(int *argc, char **argv[], const GOptionEntry *option_entries) 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; return NULL;
} }
display_render_frame(d);
d->loop = g_main_loop_new(NULL, FALSE); d->loop = g_main_loop_new(NULL, FALSE);
d->source = wl_glib_source_new(d->display); d->source = wl_glib_source_new(d->display);
g_source_attach(d->source, NULL); g_source_attach(d->source, NULL);

View File

@ -45,6 +45,10 @@ EGLDisplay
display_get_egl_display(struct display *d); display_get_egl_display(struct display *d);
#endif #endif
cairo_surface_t *
display_create_surface(struct display *display,
struct rectangle *rectangle);
void void
display_run(struct display *d); display_run(struct display *d);
@ -87,10 +91,6 @@ window_schedule_redraw(struct window *window);
void void
window_move(struct window *window, int32_t x, int32_t y); 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 * cairo_surface_t *
window_get_surface(struct window *window); window_get_surface(struct window *window);