Reset the overlay context for each draw request and use global font cache (#3231)
Some checks failed
Editor: Dev & CI / build (push) Has been cancelled
Editor: Dev & CI / cargo-deny (push) Has been cancelled

This commit is contained in:
Dennis Kobert 2025-09-28 17:36:08 +02:00 committed by GitHub
parent 84e44810d2
commit bc66148d2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 20 additions and 22 deletions

View file

@ -15,8 +15,6 @@ pub struct OverlaysMessageHandler {
canvas: Option<web_sys::HtmlCanvasElement>,
#[cfg(target_family = "wasm")]
context: Option<web_sys::CanvasRenderingContext2d>,
#[cfg(all(not(target_family = "wasm"), not(test)))]
context: Option<super::utility_types::OverlayContext>,
}
#[message_handler_data]
@ -82,11 +80,7 @@ impl MessageHandler<OverlaysMessage, OverlaysMessageContext<'_>> for OverlaysMes
let size = ipp.viewport_bounds.size();
if self.context.is_none() {
self.context = Some(OverlayContext::new(size, device_pixel_ratio, visibility_settings));
}
let overlay_context = self.context.as_mut().unwrap();
let overlay_context = OverlayContext::new(size, device_pixel_ratio, visibility_settings);
if visibility_settings.all() {
responses.add(DocumentMessage::GridOverlays { context: overlay_context.clone() });
@ -95,7 +89,7 @@ impl MessageHandler<OverlaysMessage, OverlaysMessageContext<'_>> for OverlaysMes
responses.add(provider(overlay_context.clone()));
}
}
responses.add(FrontendMessage::RenderOverlays { context: overlay_context.clone() });
responses.add(FrontendMessage::RenderOverlays { context: overlay_context });
}
#[cfg(all(not(target_family = "wasm"), test))]
OverlaysMessage::Draw => {

View file

@ -20,10 +20,22 @@ use graphene_std::vector::{PointId, SegmentId, Vector};
use kurbo::{self, BezPath, ParamCurve};
use kurbo::{Affine, PathSeg};
use std::collections::HashMap;
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::{Arc, LazyLock, Mutex, MutexGuard};
use vello::Scene;
use vello::peniko;
// Global lazy initialized font cache and text context
static GLOBAL_FONT_CACHE: LazyLock<FontCache> = LazyLock::new(|| {
let mut font_cache = FontCache::default();
// Initialize with the hardcoded font used by overlay text
const FONT_DATA: &[u8] = include_bytes!("source-sans-pro-regular.ttf");
let font = Font::new("Source Sans Pro".to_string(), "Regular".to_string());
font_cache.insert(font, String::new(), FONT_DATA.to_vec());
font_cache
});
static GLOBAL_TEXT_CONTEXT: LazyLock<Mutex<TextContext>> = LazyLock::new(|| Mutex::new(TextContext::default()));
pub type OverlayProvider = fn(OverlayContext) -> Message;
pub fn empty_provider() -> OverlayProvider {
@ -412,8 +424,6 @@ pub(super) struct OverlayContextInternal {
size: DVec2,
device_pixel_ratio: f64,
visibility_settings: OverlaysVisibilitySettings,
font_cache: FontCache,
thread_text: TextContext,
}
impl Default for OverlayContextInternal {
@ -424,19 +434,11 @@ impl Default for OverlayContextInternal {
impl OverlayContextInternal {
pub(super) fn new(size: DVec2, device_pixel_ratio: f64, visibility_settings: OverlaysVisibilitySettings) -> Self {
let mut font_cache = FontCache::default();
// Initialize with the hardcoded font used by overlay text
const FONT_DATA: &[u8] = include_bytes!("source-sans-pro-regular.ttf");
let font = Font::new("Source Sans Pro".to_string(), "Regular".to_string());
font_cache.insert(font, String::new(), FONT_DATA.to_vec());
Self {
scene: Scene::new(),
size,
device_pixel_ratio,
visibility_settings,
font_cache,
thread_text: TextContext::default(),
}
}
@ -1031,7 +1033,8 @@ impl OverlayContextInternal {
// TODO: Grab this from the node_modules folder (either with `include_bytes!` or ideally at runtime) instead of checking the font file into the repo.
// TODO: And maybe use the WOFF2 version (if it's supported) for its smaller, compressed file size.
let font = Font::new("Source Sans Pro".to_string(), "Regular".to_string());
let bounds = self.thread_text.bounding_box(text, &font, &self.font_cache, typesetting, false);
let mut text_context = GLOBAL_TEXT_CONTEXT.lock().expect("Failed to lock global text context");
let bounds = text_context.bounding_box(text, &font, &GLOBAL_FONT_CACHE, typesetting, false);
bounds.x
}
@ -1056,14 +1059,15 @@ impl OverlayContextInternal {
let font = Font::new("Source Sans Pro".to_string(), "Regular".to_string());
// Get text dimensions directly from layout
let text_size = self.thread_text.bounding_box(text, &font, &self.font_cache, typesetting, false);
let mut text_context = GLOBAL_TEXT_CONTEXT.lock().expect("Failed to lock global text context");
let text_size = text_context.bounding_box(text, &font, &GLOBAL_FONT_CACHE, typesetting, false);
let text_width = text_size.x;
let text_height = text_size.y;
// Create a rect from the size (assuming text starts at origin)
let text_bounds = kurbo::Rect::new(0.0, 0.0, text_width, text_height);
// Convert text to vector paths for rendering
let text_table = self.thread_text.to_path(text, &font, &self.font_cache, typesetting, false);
let text_table = text_context.to_path(text, &font, &GLOBAL_FONT_CACHE, typesetting, false);
// Calculate position based on pivot
let mut position = DVec2::ZERO;