From 0c2af63b4ee6ca3607d1aefeb3df93122812df75 Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Sat, 20 Jun 2026 20:29:41 +0800 Subject: [PATCH] fix(canvas): resolve named draw family in caret measurement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement Painter::measure_text_family on the native skia backend (NativeBackend::measure_text_family_styled segments per-codepoint against the real family, exactly like draw_text) and forward it through NativeFrameBackend + BaselineAdjustingBackend so the family-aware measure reaches skia through the wrappers. Fixes the ~6px caret drift in every TextInputView/TextArea chrome input (property pills, chat, git, settings) — measure now uses the same typeface paint does. Bumps vendor/jian to 19fb00b (Painter::measure_text_family). --- .../src/widgets/text_input_backend.rs | 4 +++ .../src/backend/frame_backend.rs | 4 +++ .../op-host-native/src/backend/skia/text.rs | 25 ++++++++++++++++++- vendor/jian | 2 +- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/op-editor-ui/src/widgets/text_input_backend.rs b/crates/op-editor-ui/src/widgets/text_input_backend.rs index 8494a0d29..d994c42e5 100644 --- a/crates/op-editor-ui/src/widgets/text_input_backend.rs +++ b/crates/op-editor-ui/src/widgets/text_input_backend.rs @@ -267,4 +267,8 @@ impl RenderBackend for BaselineAdjustingBackend<'_> { self.inner .measure_text_styled(text, font_size, weight, italic) } + + fn measure_text_family(&mut self, text: &str, font_size: f32, family: &str) -> f32 { + self.inner.measure_text_family(text, font_size, family) + } } diff --git a/crates/op-host-native/src/backend/frame_backend.rs b/crates/op-host-native/src/backend/frame_backend.rs index 15f8b8dc5..4d0aa8360 100644 --- a/crates/op-host-native/src/backend/frame_backend.rs +++ b/crates/op-host-native/src/backend/frame_backend.rs @@ -284,4 +284,8 @@ impl<'a> RenderBackend for NativeFrameBackend<'a> { self.inner .measure_text_styled(text, font_size, weight, italic) } + + fn measure_text_family(&mut self, text: &str, font_size: f32, family: &str) -> f32 { + self.inner.measure_text_family(text, font_size, family) + } } diff --git a/crates/op-host-native/src/backend/skia/text.rs b/crates/op-host-native/src/backend/skia/text.rs index 935febfad..cef1fd5ac 100644 --- a/crates/op-host-native/src/backend/skia/text.rs +++ b/crates/op-host-native/src/backend/skia/text.rs @@ -249,7 +249,24 @@ impl NativeBackend { weight: u16, italic: bool, ) -> f32 { - let segments = self.segment_text_styled(text, "", weight, italic); + self.measure_text_family_styled(text, font_size, "", weight, italic) + } + + /// Like [`Self::measure_text_styled`] but resolves the per-codepoint + /// typeface against `family` — exactly as `draw_text` does for a run + /// carrying that family. The family-blind `measure_text*` pass `""` + /// (bundled Roboto); chrome inputs that DRAW in a named family (e.g. + /// "Inter") must measure with that same family so their caret / + /// selection geometry lines up with the painted glyphs. + pub fn measure_text_family_styled( + &mut self, + text: &str, + font_size: f32, + family: &str, + weight: u16, + italic: bool, + ) -> f32 { + let segments = self.segment_text_styled(text, family, weight, italic); if segments.is_empty() { return 0.0; } @@ -262,6 +279,12 @@ impl NativeBackend { advance } + /// Family-aware width at the default weight/upright — the measurement + /// backing `Painter::measure_text_family` for caret positioning. + pub fn measure_text_family(&mut self, text: &str, font_size: f32, family: &str) -> f32 { + self.measure_text_family_styled(text, font_size, family, 400, false) + } + /// Render every shaped run in the layout via cached typefaces + /// `Canvas::draw_str` (Step 4 perf fix — see comment on the /// `typeface` / `cjk_typeface` fields). diff --git a/vendor/jian b/vendor/jian index ce19bed8a..19fb00ba8 160000 --- a/vendor/jian +++ b/vendor/jian @@ -1 +1 @@ -Subproject commit ce19bed8a086cd18541c4715cdc308a2cfb5e2fb +Subproject commit 19fb00ba88a5be0e15f7d2b5468337cdb0037984