From b0160ec162e4d34a73307d02d41e073aa96e6987 Mon Sep 17 00:00:00 2001 From: Colomban Wendling Date: Thu, 4 Feb 2021 22:49:26 +0100 Subject: [PATCH 1/3] Avoid redundant margin computation when creating a new Scintilla widget Avoid recomputing margin widths 2 or 3 times when initially creating the editing widget. As computing the margin widths might be costly, this can make widget creation about twice as fast. Part of #2649. --- src/editor.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/editor.c b/src/editor.c index 055bbcfafc..54b41b2a33 100644 --- a/src/editor.c +++ b/src/editor.c @@ -4597,14 +4597,16 @@ void editor_ensure_final_newline(GeanyEditor *editor) } -void editor_set_font(GeanyEditor *editor, const gchar *font) +/* Similar to editor_set_font() but *only* sets the font, and doesn't take care + * of updating properties that might depend on the font */ +static void set_font(ScintillaObject *sci, const gchar *font) { gint style; gchar *font_name; PangoFontDescription *pfd; gdouble size; - g_return_if_fail(editor); + g_return_if_fail(sci); pfd = pango_font_description_from_string(font); size = pango_font_description_get_size(pfd) / (gdouble) PANGO_SCALE; @@ -4612,10 +4614,17 @@ void editor_set_font(GeanyEditor *editor, const gchar *font) pango_font_description_free(pfd); for (style = 0; style <= STYLE_MAX; style++) - sci_set_font_fractional(editor->sci, style, font_name, size); + sci_set_font_fractional(sci, style, font_name, size); g_free(font_name); +} + +void editor_set_font(GeanyEditor *editor, const gchar *font) +{ + g_return_if_fail(editor); + + set_font(editor->sci, font); update_margins(editor->sci); /* zoom to 100% to prevent confusion */ sci_zoom_off(editor->sci); @@ -4926,7 +4935,6 @@ static ScintillaObject *create_new_sci(GeanyEditor *editor) setup_sci_keys(sci); - sci_set_symbol_margin(sci, editor_prefs.show_markers_margin); sci_set_lines_wrapped(sci, editor->line_wrapping); sci_set_caret_policy_x(sci, CARET_JUMPS | CARET_EVEN, 0); /* Y policy is set in editor_apply_update_prefs() */ @@ -5000,7 +5008,7 @@ ScintillaObject *editor_create_widget(GeanyEditor *editor) editor->sci = sci; editor_set_indent(editor, iprefs->type, iprefs->width); - editor_set_font(editor, interface_prefs.editor_font); + set_font(editor->sci, interface_prefs.editor_font); editor_apply_update_prefs(editor); /* if editor already had a widget, restore it */ From b08ae0fe65c0942dca20281d6841dc83406d8b5e Mon Sep 17 00:00:00 2001 From: Colomban Wendling Date: Thu, 4 Feb 2021 22:54:13 +0100 Subject: [PATCH 2/3] Aggressively cache line height for computing margin sizes Computing the line height is a very costly operation that involves font loading and measuring, but the value stays mostly the same over time, as it depends on font, zoom and a couple other style settings which rarely change. As line height used to compute margin widths dominates startup timings, we now cache the latest result. This caching makes line height computation barely noticeable in startup times now. Fixes #2649. --- src/sciwrappers.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/sciwrappers.c b/src/sciwrappers.c index e2506c22d1..6fcb861c0d 100644 --- a/src/sciwrappers.c +++ b/src/sciwrappers.c @@ -144,10 +144,41 @@ void sci_set_mark_long_lines(ScintillaObject *sci, gint type, gint column, const } +/* Calls SCI_TEXTHEIGHT but tries very hard to cache the result as it's a very + * expensive operation */ +static gint sci_text_height_cached(ScintillaObject *sci) +{ + static guint cache_hash = 0; + static gint cache_value = 0; + guint hash; + gchar *font; + gint size; + + /* hash font, size and zoom factor using djb's algorithm which should be + * good enough for this use case. */ + font = sci_get_string(sci, SCI_STYLEGETFONT, 0); + hash = g_str_hash(font); + g_free(font); + size = SSM(sci, SCI_STYLEGETSIZEFRACTIONAL, 0, 0); + hash = hash * 33 + (gint) (size & 0x00FF); + hash = hash * 33 + (gint) ((size & 0xFF00) >> 8); + hash = hash * 33 + (gint) SSM(sci, SCI_GETZOOM, 0, 0); + hash = hash * 33 + (gint) SSM(sci, SCI_GETEXTRAASCENT, 0, 0); + hash = hash * 33 + (gint) SSM(sci, SCI_GETEXTRADESCENT, 0, 0); + + if (hash != cache_hash) + { + cache_hash = hash; + cache_value = SSM(sci, SCI_TEXTHEIGHT, 0, 0); + } + + return cache_value; +} + /* compute margin width based on ratio of line height */ static gint margin_width_from_line_height(ScintillaObject *sci, gdouble ratio, gint threshold) { - const gint line_height = SSM(sci, SCI_TEXTHEIGHT, 0, 0); + const gint line_height = sci_text_height_cached(sci); gint width; width = line_height * ratio; From f600937dd8f592ff00150867537166b2d86aa4dd Mon Sep 17 00:00:00 2001 From: Colomban Wendling Date: Fri, 5 Feb 2021 14:32:34 +0100 Subject: [PATCH 3/3] Use plain comparison instead of naive hashing It voids any kind of clashes, and is possibly easier to understand. It results in a slight memory overhead sorting a little more cache data, but it should not matter much here. --- src/sciwrappers.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/sciwrappers.c b/src/sciwrappers.c index 6fcb861c0d..804c0d91a7 100644 --- a/src/sciwrappers.c +++ b/src/sciwrappers.c @@ -148,27 +148,33 @@ void sci_set_mark_long_lines(ScintillaObject *sci, gint type, gint column, const * expensive operation */ static gint sci_text_height_cached(ScintillaObject *sci) { - static guint cache_hash = 0; + struct height_spec { + gchar *font; + gint size; + gint zoom; + gint extra; + }; + static struct height_spec cache = {0}; static gint cache_value = 0; - guint hash; - gchar *font; - gint size; - - /* hash font, size and zoom factor using djb's algorithm which should be - * good enough for this use case. */ - font = sci_get_string(sci, SCI_STYLEGETFONT, 0); - hash = g_str_hash(font); - g_free(font); - size = SSM(sci, SCI_STYLEGETSIZEFRACTIONAL, 0, 0); - hash = hash * 33 + (gint) (size & 0x00FF); - hash = hash * 33 + (gint) ((size & 0xFF00) >> 8); - hash = hash * 33 + (gint) SSM(sci, SCI_GETZOOM, 0, 0); - hash = hash * 33 + (gint) SSM(sci, SCI_GETEXTRAASCENT, 0, 0); - hash = hash * 33 + (gint) SSM(sci, SCI_GETEXTRADESCENT, 0, 0); - - if (hash != cache_hash) + struct height_spec current; + + current.font = sci_get_string(sci, SCI_STYLEGETFONT, 0); + current.size = SSM(sci, SCI_STYLEGETSIZEFRACTIONAL, 0, 0); + current.zoom = SSM(sci, SCI_GETZOOM, 0, 0); + current.extra = SSM(sci, SCI_GETEXTRAASCENT, 0, 0) + SSM(sci, SCI_GETEXTRADESCENT, 0, 0); + + if (g_strcmp0(current.font, cache.font) == 0 && + current.size == cache.size && + current.zoom == cache.zoom && + current.extra == cache.extra) + { + g_free(current.font); + } + else { - cache_hash = hash; + g_free(cache.font); + cache = current; + cache_value = SSM(sci, SCI_TEXTHEIGHT, 0, 0); }