From 3c6612a3f90fec47bde5f58dd61a63ba336b73b6 Mon Sep 17 00:00:00 2001 From: KenM76 Date: Tue, 27 Oct 2026 00:34:14 -0400 Subject: [PATCH] fix(forms-ui): measure auto-size text at no more than the screen-font bound An auto-size single-line field's size follows its height, up to about 12,500 pt for a 14,400 pt field. The editor measured the line's width by laying it out at that size, before `field_screen_font` clamps to `MAX_SCREEN_FONT`, and egui rasterizes every glyph it lays out: one such measurement took 1.2 s in a debug build, on every frame. The width is now measured at no more than `MAX_SCREEN_FONT` and scaled, which is exact up to the bound and linear above it. `tools::forms_ui::tests::a_line_is_never_laid_out_above_the_screen_font_bound` fails with the bound removed (laid out at 12,522 pt). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9 --- crates/ui-egui/src/tools/forms_ui.rs | 31 +++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/tools/forms_ui.rs b/crates/ui-egui/src/tools/forms_ui.rs index 4138f4e903..e5a1b36bc8 100644 --- a/crates/ui-egui/src/tools/forms_ui.rs +++ b/crates/ui-egui/src/tools/forms_ui.rs @@ -528,7 +528,9 @@ pub fn field_text_size(painter: &egui::Painter, f: &FormField, w: &FormWidget, t return pdfcraft_engine::field_comb_auto_text_size(height); } let font = |size: f64| egui::FontId::proportional(size as f32); - let line_width = |size: f64| f64::from(painter.layout_no_wrap(text.to_string(), font(size), Color32::BLACK).size().x); + let line_width = |size: f64| { + bounded_line_width(size, |at| painter.layout_no_wrap(text.to_string(), egui::FontId::proportional(at), Color32::BLACK).size().x) + }; // Wrapped as the editor and the page preview wrap it. let wrap = width.max(1.0) as f32; let wrapped_height = |size: f64| f64::from(painter.layout(text.to_string(), font(size), Color32::BLACK, wrap).size().y); @@ -537,6 +539,14 @@ pub fn field_text_size(painter: &egui::Painter, f: &FormField, w: &FormWidget, t size as f32 } +/// The width of a line at `size` points from `measure`, the width at a given size, called at no +/// more than [`MAX_SCREEN_FONT`] and scaled: egui rasterizes every glyph it lays out, and a tall +/// field's automatic size can be thousands of points. +fn bounded_line_width(size: f64, measure: impl Fn(f32) -> f32) -> f64 { + let at = size.min(f64::from(MAX_SCREEN_FONT)); + if at > 0.0 { f64::from(measure(at as f32)) * size / at } else { f64::from(measure(at as f32)) } +} + /// The largest font, in screen points, the on-page field editor draws with: a bound that keeps /// one rasterized glyph (font size times pixels per point) well inside egui's font atlas. pub const MAX_SCREEN_FONT: f32 = 256.0; @@ -960,3 +970,22 @@ pub fn field_screen_rect(view: &DocView, info: &DocInfo, f: &FormField, widget: let xf = view.page_xform(page)?; Some(widget_rect(&xf, info, page, w.rect)) } + +#[cfg(test)] +mod tests { + use super::{MAX_SCREEN_FONT, bounded_line_width}; + use std::cell::Cell; + + #[test] + fn a_line_is_never_laid_out_above_the_screen_font_bound() { + let largest = Cell::new(0.0f32); + let measure = |at: f32| { + largest.set(largest.get().max(at)); + at * 3.0 + }; + assert_eq!(bounded_line_width(12_522.0, measure), 12_522.0 * 3.0, "the width scales"); + assert_eq!(largest.get(), MAX_SCREEN_FONT, "laid out at the bound"); + assert_eq!(bounded_line_width(10.0, measure), 30.0, "below it, at the size itself"); + assert_eq!(largest.get(), MAX_SCREEN_FONT); + } +}