diff options
-rw-r--r-- | src/entry.c | 79 | ||||
-rw-r--r-- | src/entry.h | 5 | ||||
-rw-r--r-- | src/entry_backend/harfbuzz.c | 35 | ||||
-rw-r--r-- | src/entry_backend/harfbuzz.h | 2 | ||||
-rw-r--r-- | src/entry_backend/pango.c | 10 | ||||
-rw-r--r-- | src/entry_backend/pango.h | 2 | ||||
-rw-r--r-- | src/image.h | 1 | ||||
-rw-r--r-- | src/main.c | 18 | ||||
-rw-r--r-- | src/surface.c | 11 | ||||
-rw-r--r-- | src/surface.h | 2 |
10 files changed, 110 insertions, 55 deletions
diff --git a/src/entry.c b/src/entry.c index 6b7c9e7..0348d06 100644 --- a/src/entry.c +++ b/src/entry.c @@ -5,26 +5,51 @@ #include "log.h" #include "nelem.h" -void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t scale) +void entry_init(struct entry *entry, uint8_t *restrict buffer, uint32_t width, uint32_t height, uint32_t scale) { entry->image.width = width; entry->image.height = height; entry->image.scale = scale; - width /= scale; - height /= scale; - /* - * Create the cairo surface and context we'll be using. + * Create the cairo surfaces and contexts we'll be using. + * + * In order to avoid an unnecessary copy when passing the image to the + * Wayland server, we accept a pointer to the mmap-ed file that our + * Wayland buffers are created from. This is assumed to be + * (width * height * (sizeof(uint32_t) == 4) * 2) bytes, + * to allow for double buffering. */ - cairo_surface_t *surface = cairo_image_surface_create( + cairo_surface_t *surface = cairo_image_surface_create_for_data( + buffer, CAIRO_FORMAT_ARGB32, - width * scale, - height * scale + width, + height, + width * sizeof(uint32_t) ); cairo_surface_set_device_scale(surface, scale, scale); cairo_t *cr = cairo_create(surface); + entry->cairo[0].surface = surface; + entry->cairo[0].cr = cr; + + entry->cairo[1].surface = cairo_image_surface_create_for_data( + &buffer[width * height * sizeof(uint32_t)], + CAIRO_FORMAT_ARGB32, + width, + height, + width * sizeof(uint32_t) + ); + cairo_surface_set_device_scale(entry->cairo[1].surface, scale, scale); + entry->cairo[1].cr = cairo_create(entry->cairo[1].surface); + + /* + * Cairo drawing operations take the scale into account, + * so we account for that here. + */ + width /= scale; + height /= scale; + /* Draw the outer outline */ struct color color = entry->border.outline_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); @@ -85,26 +110,43 @@ void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t s height -= 2 * entry->padding; cairo_rectangle(cr, 0, 0, width, height); cairo_clip(cr); - - entry->cairo.surface = surface; - entry->cairo.cr = cr; - entry->image.buffer = cairo_image_surface_get_data(surface); /* Setup the backend. */ - entry_backend_init(entry, width, height, scale); + entry_backend_init(entry, &width, &height, scale); + + /* + * To avoid performing all this drawing twice, we take a small + * shortcut. After performing all the drawing as normal on our first + * Cairo context, we can copy over just the important state (the + * transformation matrix and clip rectangle) and perform a memcpy() + * to initialise the other context. + */ + cairo_matrix_t mat; + cairo_get_matrix(cr, &mat); + cairo_set_matrix(entry->cairo[1].cr, &mat); + cairo_rectangle(entry->cairo[1].cr, 0, 0, width, height); + cairo_clip(entry->cairo[1].cr); + + memcpy( + cairo_image_surface_get_data(entry->cairo[1].surface), + cairo_image_surface_get_data(entry->cairo[0].surface), + entry->image.width * entry->image.height * sizeof(uint32_t) + ); } void entry_destroy(struct entry *entry) { entry_backend_destroy(entry); - cairo_destroy(entry->cairo.cr); - cairo_surface_destroy(entry->cairo.surface); + cairo_destroy(entry->cairo[0].cr); + cairo_destroy(entry->cairo[1].cr); + cairo_surface_destroy(entry->cairo[0].surface); + cairo_surface_destroy(entry->cairo[1].surface); } void entry_update(struct entry *entry) { log_debug("Start rendering entry.\n"); - cairo_t *cr = entry->cairo.cr; + cairo_t *cr = entry->cairo[entry->index].cr; cairo_save(cr); /* Clear the image. */ @@ -120,10 +162,13 @@ void entry_update(struct entry *entry) cairo_restore(cr); log_debug("Finish rendering entry.\n"); + + entry->index = !entry->index; } void entry_set_scale(struct entry *entry, uint32_t scale) { entry->image.scale = scale; - cairo_surface_set_device_scale(entry->cairo.surface, scale, scale); + cairo_surface_set_device_scale(entry->cairo[0].surface, scale, scale); + cairo_surface_set_device_scale(entry->cairo[1].surface, scale, scale); } diff --git a/src/entry.h b/src/entry.h index 341e340..95cab5d 100644 --- a/src/entry.h +++ b/src/entry.h @@ -22,7 +22,8 @@ struct entry { struct { cairo_surface_t *surface; cairo_t *cr; - } cairo; + } cairo[2]; + int index; wchar_t input[MAX_INPUT_LENGTH]; /* Assume maximum of 4 bytes per wchar_t (for UTF-8) */ @@ -50,7 +51,7 @@ struct entry { } border; }; -void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t scale); +void entry_init(struct entry *entry, uint8_t *restrict buffer, uint32_t width, uint32_t height, uint32_t scale); void entry_destroy(struct entry *entry); void entry_update(struct entry *entry); void entry_set_scale(struct entry *entry, uint32_t scale); diff --git a/src/entry_backend/harfbuzz.c b/src/entry_backend/harfbuzz.c index d1f54e9..779cbd8 100644 --- a/src/entry_backend/harfbuzz.c +++ b/src/entry_backend/harfbuzz.c @@ -1,4 +1,3 @@ -#include <assert.h> #include <cairo/cairo.h> #include <glib.h> #include <harfbuzz/hb-ft.h> @@ -12,6 +11,12 @@ #include "../nelem.h" #include "../xmalloc.h" +/* + * Cairo / FreeType use 72 Pts per inch, but Pango uses 96 DPI, so we have to + * rescale for consistency. + */ +#define PT_TO_DPI (96.0 / 72.0) + static void setup_hb_buffer(hb_buffer_t *buffer) { hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); @@ -69,17 +74,22 @@ static uint32_t render_hb_buffer(cairo_t *cr, hb_buffer_t *buffer, uint32_t scal return width; } -void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t scale) +void entry_backend_init(struct entry *entry, uint32_t *width, uint32_t *height, uint32_t scale) { - cairo_t *cr = entry->cairo.cr; + cairo_t *cr = entry->cairo[0].cr; /* Setup FreeType. */ log_debug("Creating FreeType library.\n"); - assert(!FT_Init_FreeType(&entry->backend.ft_library)); + FT_Init_FreeType(&entry->backend.ft_library); log_debug("Loading FreeType font.\n"); - assert(!FT_New_Face(entry->backend.ft_library, "font.ttf", 0, &entry->backend.ft_face)); - assert(!FT_Set_Char_Size(entry->backend.ft_face, entry->font_size * 64, entry->font_size * 64, 0, 0)); + FT_New_Face(entry->backend.ft_library, "font.ttf", 0, &entry->backend.ft_face); + FT_Set_Char_Size( + entry->backend.ft_face, + entry->font_size * 64 * scale * PT_TO_DPI, + entry->font_size * 64 * scale * PT_TO_DPI, + 0, + 0); log_debug("Creating Cairo font.\n"); entry->backend.cairo_face = cairo_ft_font_face_create_for_ft_face(entry->backend.ft_face, 0); @@ -87,10 +97,11 @@ void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, ui struct color color = entry->foreground_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); cairo_set_font_face(cr, entry->backend.cairo_face); - cairo_set_font_size(cr, entry->font_size * (96.0 / 72.0)); + cairo_set_font_size(cr, entry->font_size * PT_TO_DPI); - cairo_font_extents_t font_extents; - cairo_font_extents(cr, &font_extents); + /* We also need to set up the font for our other Cairo context. */ + cairo_set_font_face(entry->cairo[1].cr, entry->backend.cairo_face); + cairo_set_font_size(entry->cairo[1].cr, entry->font_size * PT_TO_DPI); log_debug("Creating Harfbuzz font.\n"); entry->backend.hb_font = hb_ft_font_create_referenced(entry->backend.ft_face); @@ -106,8 +117,8 @@ void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, ui /* Move and clip so we don't draw over the prompt */ uint32_t prompt_width = render_hb_buffer(cr, entry->backend.hb_buffer, scale); cairo_translate(cr, prompt_width, 0); - width -= prompt_width; - cairo_rectangle(cr, 0, 0, width, height); + *width -= prompt_width; + cairo_rectangle(cr, 0, 0, *width, *height); cairo_clip(cr); } @@ -121,7 +132,7 @@ void entry_backend_destroy(struct entry *entry) void entry_backend_update(struct entry *entry) { - cairo_t *cr = entry->cairo.cr; + cairo_t *cr = entry->cairo[entry->index].cr; hb_buffer_clear_contents(entry->backend.hb_buffer); setup_hb_buffer(entry->backend.hb_buffer); diff --git a/src/entry_backend/harfbuzz.h b/src/entry_backend/harfbuzz.h index 0b07538..52116a8 100644 --- a/src/entry_backend/harfbuzz.h +++ b/src/entry_backend/harfbuzz.h @@ -19,7 +19,7 @@ struct entry_backend { hb_buffer_t *hb_buffer; }; -void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t scale); +void entry_backend_init(struct entry *entry, uint32_t *width, uint32_t *height, uint32_t scale); void entry_backend_destroy(struct entry *entry); void entry_backend_update(struct entry *entry); diff --git a/src/entry_backend/pango.c b/src/entry_backend/pango.c index 569a706..4d43ce3 100644 --- a/src/entry_backend/pango.c +++ b/src/entry_backend/pango.c @@ -7,9 +7,9 @@ #include "../log.h" #include "../nelem.h" -void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t scale) +void entry_backend_init(struct entry *entry, uint32_t *width, uint32_t *height, uint32_t scale) { - cairo_t *cr = entry->cairo.cr; + cairo_t *cr = entry->cairo[0].cr; /* Setup Pango. */ log_debug("Creating Pango context.\n"); @@ -41,8 +41,8 @@ void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, ui /* Move and clip so we don't draw over the prompt */ cairo_translate(cr, prompt_width, 0); - width -= prompt_width; - cairo_rectangle(cr, 0, 0, width, height); + *width -= prompt_width; + cairo_rectangle(cr, 0, 0, *width, *height); cairo_clip(cr); log_debug("Creating Pango layout.\n"); @@ -70,7 +70,7 @@ void entry_backend_destroy(struct entry *entry) void entry_backend_update(struct entry *entry) { - cairo_t *cr = entry->cairo.cr; + cairo_t *cr = entry->cairo[entry->index].cr; pango_layout_set_text(entry->backend.entry_layout, entry->input_mb, -1); pango_cairo_update_layout(cr, entry->backend.entry_layout); diff --git a/src/entry_backend/pango.h b/src/entry_backend/pango.h index 08572ae..ef58be3 100644 --- a/src/entry_backend/pango.h +++ b/src/entry_backend/pango.h @@ -12,7 +12,7 @@ struct entry_backend { PangoLayout *result_layouts[5]; }; -void entry_backend_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t scale); +void entry_backend_init(struct entry *entry, uint32_t *width, uint32_t *height, uint32_t scale); void entry_backend_destroy(struct entry *entry); void entry_backend_update(struct entry *entry); diff --git a/src/image.h b/src/image.h index 81cb66a..090f32d 100644 --- a/src/image.h +++ b/src/image.h @@ -5,7 +5,6 @@ #include <stdint.h> struct image { - uint8_t *buffer; uint32_t width; uint32_t height; uint32_t scale; @@ -785,6 +785,15 @@ int main(int argc, char *argv[]) wl_display_roundtrip(tofi.wl_display); log_debug("Third roundtrip done.\n"); + + /* + * Create the various structures for our window surface. This needs to + * be done before calling entry_init as that performs some initial + * drawing, and surface_init allocates the buffers we'll be drawing to. + */ + log_debug("Initialising window surface.\n"); + surface_init(&tofi.window.surface, tofi.wl_shm); + /* * Initialise the structures for rendering the entry. * Cairo needs to know the size of the surface it's creating, and @@ -797,19 +806,14 @@ int main(int argc, char *argv[]) log_debug("Initialising renderer.\n"); entry_init( &tofi.window.entry, + tofi.window.surface.shm_pool_data, tofi.window.surface.width, tofi.window.surface.height, tofi.window.scale); entry_update(&tofi.window.entry); log_debug("Renderer initialised.\n"); - /* - * Create the various structures for each surface, and - * perform an initial render of everything. - */ - log_debug("Initialising main window surface.\n"); - - surface_initialise(&tofi.window.surface, tofi.wl_shm); + /* Perform an initial render. */ surface_draw( &tofi.window.surface, &tofi.window.entry.background_color, diff --git a/src/surface.c b/src/surface.c index d02fd4f..30a46cd 100644 --- a/src/surface.c +++ b/src/surface.c @@ -8,7 +8,7 @@ #undef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) -void surface_initialise( +void surface_init( struct surface *surface, struct wl_shm *wl_shm) { @@ -47,8 +47,6 @@ void surface_initialise( log_debug("Created shm file with size %d KiB.\n", surface->shm_pool_size / 1024); - - surface->index = 0; } void surface_destroy(struct surface *surface) @@ -66,12 +64,9 @@ void surface_draw( struct color *color, struct image *texture) { - surface->index = !surface->index; - int offset = surface->height * surface->stride * surface->index; - uint32_t *pixels = (uint32_t *)&surface->shm_pool_data[offset]; - memcpy(pixels, texture->buffer, surface->height * surface->stride); - wl_surface_attach(surface->wl_surface, surface->buffers[surface->index], 0, 0); wl_surface_damage_buffer(surface->wl_surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(surface->wl_surface); + + surface->index = !surface->index; } diff --git a/src/surface.h b/src/surface.h index 6016551..68f9a31 100644 --- a/src/surface.h +++ b/src/surface.h @@ -22,7 +22,7 @@ struct surface { bool redraw; }; -void surface_initialise( +void surface_init( struct surface *surface, struct wl_shm *wl_shm); void surface_destroy(struct surface *surface); |