From 0947765fc9a4f6fc4287acfcd2efcaf4fef1ffb8 Mon Sep 17 00:00:00 2001
From: M Stoeckl <code@mstoeckl.com>
Date: Thu, 31 Oct 2024 10:27:47 -0400
Subject: [PATCH] Only call render_menu once per frame

An actual surface is not needed to estimate font sizes; a 1x1 image
will do, as long as the cairo context has the same options.
---
 menu.c   | 5 ++++-
 menu.h   | 5 +++++
 render.c | 9 +++++++--
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/menu.c b/menu.c
index 52f0810..9bda76c 100644
--- a/menu.c
+++ b/menu.c
@@ -34,6 +34,8 @@ struct menu *menu_create(menu_callback callback) {
 	menu->selectionbg = 0x005577ff;
 	menu->selectionfg = 0xeeeeeeff;
 	menu->callback = callback;
+	menu->test_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
+	menu->test_cairo = cairo_create(menu->test_surface);
 	return menu;
 }
 
@@ -58,6 +60,8 @@ static void free_items(struct menu *menu) {
 void menu_destroy(struct menu *menu) {
 	free_pages(menu);
 	free_items(menu);
+	cairo_destroy(menu->test_cairo);
+	cairo_surface_destroy(menu->test_surface);
 	free(menu);
 }
 
@@ -374,7 +378,6 @@ static void match_items(struct menu *menu) {
 
 // Render menu items.
 void menu_render_items(struct menu *menu) {
-	render_menu(menu);
 	calc_widths(menu);
 	match_items(menu);
 	render_menu(menu);
diff --git a/menu.h b/menu.h
index 280cdd0..8dcd99c 100644
--- a/menu.h
+++ b/menu.h
@@ -1,6 +1,7 @@
 #ifndef WMENU_MENU_H
 #define WMENU_MENU_H
 
+#include <cairo/cairo.h>
 #include <stdbool.h>
 #include <sys/types.h>
 #include <xkbcommon/xkbcommon.h>
@@ -51,6 +52,10 @@ struct menu {
 
 	struct wl_context *context;
 
+	// 1x1 surface used estimate text sizes with pango
+	cairo_surface_t *test_surface;
+	cairo_t *test_cairo;
+
 	int width;
 	int height;
 	int line_height;
diff --git a/render.c b/render.c
index 070fad9..63dc4ab 100644
--- a/render.c
+++ b/render.c
@@ -13,8 +13,13 @@
 // Calculate text widths.
 void calc_widths(struct menu *menu) {
 	struct wl_context *context = menu->context;
-	struct pool_buffer *current = context_get_current_buffer(context);
-	cairo_t *cairo = current->cairo;
+	int scale = context_get_scale(context);
+	cairo_surface_set_device_scale(menu->test_surface, scale, scale);
+	cairo_set_antialias(menu->test_cairo, CAIRO_ANTIALIAS_BEST);
+	cairo_font_options_t *fo = cairo_font_options_create();
+	cairo_set_font_options(menu->test_cairo, fo);
+	cairo_font_options_destroy(fo);
+	cairo_t *cairo = menu->test_cairo;
 
 	// Calculate prompt width
 	if (menu->prompt) {