From 7d589fd2ac38ea35fe2d5c2316688ee6b5d86e87 Mon Sep 17 00:00:00 2001 From: jkds Date: Sat, 3 Jan 2026 06:36:44 +0100 Subject: [PATCH] app/edit: improve perf of editing selection. only recalc rect when editing text itself (not select changes) --- .../src/android/textinput/gametextinput.rs | 8 +----- bin/app/src/android/util.rs | 2 ++ bin/app/src/text2/editor/android.rs | 2 +- bin/app/src/ui/chatview/mod.rs | 2 +- bin/app/src/ui/edit/mod.rs | 27 +++++++++++-------- bin/app/src/ui/mod.rs | 2 ++ 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/bin/app/src/android/textinput/gametextinput.rs b/bin/app/src/android/textinput/gametextinput.rs index e63e27301..e3294c8f2 100644 --- a/bin/app/src/android/textinput/gametextinput.rs +++ b/bin/app/src/android/textinput/gametextinput.rs @@ -185,13 +185,7 @@ impl GameTextInput { unsafe { let env = android::attach_jni_env(); let jstate = self.state_to_java(state); - call_void_method!( - env, - input_connection, - "setState", - "(Ltextinput/State;)V", - jstate - ); + call_void_method!(env, input_connection, "setState", "(Ltextinput/State;)V", jstate); let delete_local_ref = (**env).DeleteLocalRef.unwrap(); delete_local_ref(env, jstate); diff --git a/bin/app/src/android/util.rs b/bin/app/src/android/util.rs index b77cc482d..6738fc3c0 100644 --- a/bin/app/src/android/util.rs +++ b/bin/app/src/android/util.rs @@ -32,5 +32,7 @@ unsafe fn check_except(env: *mut ndk_sys::JNIEnv, context: &str) { let exception_clear = (**env).ExceptionClear.unwrap(); exception_clear(env); + + panic!("Java exception detected in {context}"); } } diff --git a/bin/app/src/text2/editor/android.rs b/bin/app/src/text2/editor/android.rs index 6a4fc7321..33f7d99ff 100644 --- a/bin/app/src/text2/editor/android.rs +++ b/bin/app/src/text2/editor/android.rs @@ -199,7 +199,7 @@ impl Editor { } pub fn selection(&self, side: isize) -> parley::Selection { assert!(side.abs() == 1); - t!("selection({side}) [state={:?}]", self.state); + //t!("selection({side}) [state={:?}]", self.state); let (start, end) = (self.state.select.0, self.state.select.1); let (anchor, focus) = match side { diff --git a/bin/app/src/ui/chatview/mod.rs b/bin/app/src/ui/chatview/mod.rs index bdcc99cf5..d2e3f3a86 100644 --- a/bin/app/src/ui/chatview/mod.rs +++ b/bin/app/src/ui/chatview/mod.rs @@ -1003,7 +1003,7 @@ impl UIObject for ChatView { } let rect = self.rect.get(); - t!("handle_touch({phase:?}, {id},{id}, {touch_pos:?})"); + //t!("handle_touch({phase:?}, {id},{id}, {touch_pos:?})"); let atom = &mut self.render_api.make_guard(gfxtag!("ChatView::handle_touch")); let touch_y = touch_pos.y; diff --git a/bin/app/src/ui/edit/mod.rs b/bin/app/src/ui/edit/mod.rs index 9f4f17f06..1411bb3f5 100644 --- a/bin/app/src/ui/edit/mod.rs +++ b/bin/app/src/ui/edit/mod.rs @@ -857,7 +857,7 @@ impl BaseEdit { } true } - async fn handle_touch_end(&self, atom: &mut PropertyAtomicGuard, mut touch_pos: Point) -> bool { + async fn handle_touch_end(&self, mut touch_pos: Point) -> bool { //t!("handle_touch_end({touch_pos:?})"); self.abs_to_local(&mut touch_pos); @@ -865,6 +865,7 @@ impl BaseEdit { match state { TouchStateAction::Inactive => return false, TouchStateAction::Started { pos: _, instant: _ } | TouchStateAction::SetCursorPos => { + let atom = &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_touch_end")); self.touch_set_cursor_pos(atom, touch_pos).await; self.redraw(atom).await; } @@ -980,7 +981,7 @@ impl BaseEdit { editor.selected_text() }; - //d!("Select {seltext:?} from {clip_mouse_pos:?} (unclipped: {mouse_pos:?}) to ({sel_start}, {sel_end})"); + //d!("Select {seltext:?} from {clip_mouse_pos:?} (unclipped: {mouse_pos:?})"); // Android editor impl detail: selection disappears when anchor == index // But we disallow this so it should never happen. Just making a note of it here. @@ -1047,6 +1048,7 @@ impl BaseEdit { } async fn redraw_select(&self, batch_id: BatchGuardId) { + //t!("redraw_select"); let sel_instrs = self.regen_select_mesh().await; let phone_sel_instrs = self.regen_phone_select_handle_mesh().await; let draw_calls = vec![ @@ -1315,13 +1317,10 @@ impl BaseEdit { // Nothing changed. Just return. if !is_text_changed && !is_select_changed && !is_compose_changed { - t!("Skipping update since nothing changed"); + //t!("Skipping update since nothing changed"); return } - self.eval_rect().await; - self.behave.apply_cursor_scroll().await; - //t!("is_text_changed={is_text_changed}, is_select_changed={is_select_changed}, is_compose_changed={is_compose_changed}"); // Only redraw once we have the parent_rect // Can happen when we receive an Android event before the canvas is ready @@ -1331,6 +1330,9 @@ impl BaseEdit { // Text changed - finish any active selection if is_text_changed || is_compose_changed { + self.eval_rect().await; + self.behave.apply_cursor_scroll().await; + self.pause_blinking(); //assert!(state.text != self.text.get()); self.finish_select(atom); @@ -1338,6 +1340,7 @@ impl BaseEdit { } else if is_select_changed { // Redrawing the entire text just for select changes is expensive self.redraw_cursor(atom.batch_id).await; + //t!("handle_android_event calling redraw_select"); self.redraw_select(atom.batch_id).await; } } @@ -1360,13 +1363,17 @@ impl UIObject for BaseEdit { fn init(&self) { let mut guard = self.editor.lock_blocking(); assert!(guard.is_none()); - *guard = Some(Editor::new( + let mut editor = Editor::new( self.text.clone(), self.font_size.clone(), self.text_color.clone(), self.window_scale.clone(), self.lineheight.clone(), - )); + ); + let atom = &mut PropertyAtomicGuard::none(); + self.text.set(atom, "the quick brown fox jumped over the"); + smol::block_on(editor.on_text_prop_changed()); + *guard = Some(editor); } async fn start(self: Arc, ex: ExecutorPtr) { @@ -1758,12 +1765,10 @@ impl UIObject for BaseEdit { return false } - let atom = &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_touch")); - match phase { TouchPhase::Started => self.handle_touch_start(touch_pos).await, TouchPhase::Moved => self.handle_touch_move(touch_pos).await, - TouchPhase::Ended => self.handle_touch_end(atom, touch_pos).await, + TouchPhase::Ended => self.handle_touch_end(touch_pos).await, TouchPhase::Cancelled => false, } } diff --git a/bin/app/src/ui/mod.rs b/bin/app/src/ui/mod.rs index d352bfef6..ffd233640 100644 --- a/bin/app/src/ui/mod.rs +++ b/bin/app/src/ui/mod.rs @@ -65,8 +65,10 @@ macro_rules! t { ($($arg:tt)*) => { trace!(target: "scene::on_modify", $($arg)*) pub trait UIObject: Sync { fn priority(&self) -> u32; + /// Called after schema and scenegraph is init but before miniquad starts. fn init(&self) {} + /// Done after miniquad has started and the first window draw has been done. async fn start(self: Arc, _ex: ExecutorPtr) {} /// Clear all buffers and caches