From fb0e358feccc45c7cd642e346d07f4f7f21b484b Mon Sep 17 00:00:00 2001 From: Phil Jones Date: Wed, 3 Nov 2021 01:22:20 +0000 Subject: Don't use Pango by default. Initialising Pango makes up a large portion of the startup time, and we can achieve neater rendering with pure Cairo if we're just drawing circles anyway. Therefore, this commit avoids loading Pango if no options which require it are specified (such as --font-name or --password-character). This reduces startup time with no background image to ~40ms on my machine (2015 MacBook Pro). --- src/entry.c | 118 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 40 deletions(-) (limited to 'src/entry.c') diff --git a/src/entry.c b/src/entry.c index fe2953c..95ab308 100644 --- a/src/entry.c +++ b/src/entry.c @@ -9,12 +9,34 @@ #include "log.h" #include "nelem.h" +#ifndef TWO_PI +#define TWO_PI 6.283185307179586f +#endif + static void calculate_font_extents(struct entry *entry, uint32_t scale); +static void draw_circles(struct entry *entry); void entry_init(struct entry *entry, uint32_t scale) { + entry->dot_radius = entry->font_size >> 3; + /* Calculate the size of the entry from our font and various widths. */ calculate_font_extents(entry, scale); - struct color color; + + entry->surface.width = entry->text_bounds.width; + entry->surface.height = entry->text_bounds.height; + entry->surface.width += 2 * ( + entry->border.width + + 2 * entry->border.outline_width + + entry->padding + ); + entry->surface.height += 2 * ( + entry->border.width + + 2 * entry->border.outline_width + + entry->padding + ); + entry->surface.width *= scale; + entry->surface.height *= scale; + /* * Cairo uses native 32 bit integers for pixels, so if this processor @@ -40,7 +62,7 @@ void entry_init(struct entry *entry, uint32_t scale) int32_t height = entry->surface.height / scale; /* Draw the outer outline */ - color = entry->border.outline_color; + struct color color = entry->border.outline_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); cairo_paint(cr); @@ -100,22 +122,25 @@ void entry_init(struct entry *entry, uint32_t scale) cairo_translate(cr, -entry->text_bounds.x, -entry->text_bounds.y); /* Setup Pango. */ - PangoContext *context = pango_cairo_create_context(cr); - PangoLayout *layout = pango_layout_new(context); - pango_layout_set_text(layout, "", -1); + if (entry->use_pango) { + PangoContext *context = pango_cairo_create_context(cr); + PangoLayout *layout = pango_layout_new(context); + pango_layout_set_text(layout, "", -1); - PangoFontDescription *font_description = - pango_font_description_from_string(entry->font_name); - pango_font_description_set_size( - font_description, - entry->font_size * PANGO_SCALE); - pango_layout_set_font_description(layout, font_description); - pango_font_description_free(font_description); + PangoFontDescription *font_description = + pango_font_description_from_string(entry->font_name); + pango_font_description_set_size( + font_description, + entry->font_size * PANGO_SCALE); + pango_layout_set_font_description(layout, font_description); + pango_font_description_free(font_description); + + entry->pango.context = context; + entry->pango.layout = layout; + } + entry->cairo.surface = surface; + entry->cairo.cr = cr; - entry->pangocairo.surface = surface; - entry->pangocairo.cr = cr; - entry->pangocairo.context = context; - entry->pangocairo.layout = layout; entry->image.width = entry->surface.width; entry->image.height = entry->surface.height; entry->image.buffer = cairo_image_surface_get_data(surface); @@ -123,25 +148,34 @@ void entry_init(struct entry *entry, uint32_t scale) void entry_destroy(struct entry *entry) { - g_object_unref(entry->pangocairo.layout); - g_object_unref(entry->pangocairo.context); - cairo_destroy(entry->pangocairo.cr); - cairo_surface_destroy(entry->pangocairo.surface); + if (entry->use_pango) { + g_object_unref(entry->pango.layout); + g_object_unref(entry->pango.context); + } + cairo_destroy(entry->cairo.cr); + cairo_surface_destroy(entry->cairo.surface); } void entry_update(struct entry *entry) { - cairo_t *cr = entry->pangocairo.cr; - PangoLayout *layout = entry->pangocairo.layout; + cairo_t *cr = entry->cairo.cr; + PangoLayout *layout = entry->pango.layout; + + entry->image.redraw = true; /* Redraw the background. */ struct color color = entry->background_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); cairo_paint(cr); - /* Draw our text with Pango. */ + /* Draw our text. */ color = entry->foreground_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); + + if (!entry->use_pango) { + draw_circles(entry); + return; + } size_t len = 0; for (unsigned int i = 0; i < entry->password_length; i++) { len += wcrtomb(entry->password_mb_print + len, entry->password_character, NULL); @@ -150,17 +184,21 @@ void entry_update(struct entry *entry) pango_layout_set_text(layout, entry->password_mb_print, -1); pango_cairo_update_layout(cr, layout); pango_cairo_show_layout(cr, layout); - - entry->image.redraw = true; } void entry_set_scale(struct entry *entry, uint32_t scale) { - cairo_surface_set_device_scale(entry->pangocairo.surface, scale, scale); + cairo_surface_set_device_scale(entry->cairo.surface, scale, scale); } void calculate_font_extents(struct entry *entry, uint32_t scale) { + if (!entry->use_pango) { + /* If we're not using pango, just do a simple calculation. */ + entry->text_bounds.height = 2 * entry->dot_radius; + entry->text_bounds.width = 3 * entry->num_characters * entry->dot_radius; + return; + } /* * To calculate the size of the password box, we do the following: * 1. Load the font we're going to use. @@ -219,22 +257,22 @@ void calculate_font_extents(struct entry *entry, uint32_t scale) rect.x -= 1; rect.y -= 1; - int width = rect.width; - int height = rect.height; - width += 2 * ( - entry->border.width - + 2 * entry->border.outline_width - + entry->padding - ); - height += 2 * ( - entry->border.width - + 2 * entry->border.outline_width - + entry->padding - ); - entry->surface.width = width * scale; - entry->surface.height = height * scale; entry->text_bounds = rect; g_object_unref(layout); g_object_unref(context); } + +void draw_circles(struct entry *entry) +{ + cairo_t *cr = entry->cairo.cr; + uint32_t radius = entry->dot_radius; + cairo_save(cr); + cairo_translate(cr, radius, radius); + for (uint32_t i = 0; i < entry->password_length && i < entry->num_characters; i++) { + /* Draw circles with a one-radius gap between them. */ + cairo_arc(cr, 3 * i * radius, 0, radius, 0, TWO_PI); + } + cairo_fill(cr); + cairo_restore(cr); +} -- cgit v1.2.3