Преглед изворни кода

wallet: make TextShaper non-async which reduces overall need for AsyncMutex throughout code.

darkfi пре 1 година
родитељ
комит
22f1a10d72

+ 27 - 17
bin/darkwallet/src/text/mod.rs

@@ -16,7 +16,6 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use async_lock::Mutex;
 use freetype as ft;
 use harfbuzz_sys::{
     freetype::hb_ft_font_create_referenced, hb_buffer_add_utf8, hb_buffer_create,
@@ -28,7 +27,7 @@ use harfbuzz_sys::{
 use std::{
     collections::HashMap,
     os,
-    sync::{Arc, Weak},
+    sync::{Arc, Mutex as SyncMutex, Weak},
 };
 
 use crate::gfx::Rectangle;
@@ -63,7 +62,7 @@ pub use wrap::{glyph_str, wrap};
 
 // Notes:
 // * All ft init and face creation should happen at startup.
-// * FT faces protected behind an async Mutex
+// * FT faces protected behind a Mutex
 // * Glyph cache. Key is (glyph_id, font_size)
 // * Glyph texture cache: (glyph_id, font_size, color)
 
@@ -136,9 +135,13 @@ impl<'a> Iterator for GlyphPositionIter<'a> {
     }
 }
 
+struct TextShaperInternal {
+    font_faces: FtFaces,
+    cache: TextShaperCache,
+}
+
 pub struct TextShaper {
-    font_faces: Mutex<FtFaces>,
-    cache: Mutex<TextShaperCache>,
+    intern: SyncMutex<TextShaperInternal>,
 }
 
 impl TextShaper {
@@ -155,13 +158,15 @@ impl TextShaper {
         let ft_face = ftlib.new_memory_face2(font_data, 0).unwrap();
         faces.push(ft_face);
 
-        Arc::new(Self { font_faces: Mutex::new(FtFaces(faces)), cache: Mutex::new(HashMap::new()) })
+        Arc::new(Self {
+            intern: SyncMutex::new(TextShaperInternal {
+                font_faces: FtFaces(faces),
+                cache: HashMap::new(),
+            }),
+        })
     }
 
-    pub fn split_into_substrs(
-        font_faces: &Vec<FreetypeFace>,
-        text: String,
-    ) -> Vec<(usize, String)> {
+    fn split_into_substrs(font_faces: &Vec<FreetypeFace>, text: String) -> Vec<(usize, String)> {
         let mut current_idx = 0;
         let mut current_str = String::new();
         let mut substrs = vec![];
@@ -196,20 +201,21 @@ impl TextShaper {
         substrs
     }
 
-    pub async fn shape(&self, text: String, font_size: f32, window_scale: f32) -> Vec<Glyph> {
+    pub fn shape(&self, text: String, font_size: f32, window_scale: f32) -> Vec<Glyph> {
         //debug!(target: "text", "shape('{}', {})", text, font_size);
         // Lock font faces
         // Freetype faces are not threadsafe
-        let mut faces = self.font_faces.lock().await;
-        let mut cache = self.cache.lock().await;
+        let mut intern = self.intern.lock().unwrap();
+        //let faces = &mut intern.font_faces;
+        //let cache = &mut intern.cache;
 
-        let substrs = Self::split_into_substrs(&faces.0, text.clone());
+        let substrs = Self::split_into_substrs(&intern.font_faces.0, text.clone());
 
         let mut glyphs: Vec<Glyph> = vec![];
 
         for (face_idx, text) in substrs {
             //debug!("substr {}", text);
-            let face = &mut faces.0[face_idx];
+            let face = &mut intern.font_faces.0[face_idx];
             if face.has_fixed_sizes() {
                 // emojis required a fixed size
                 //face.set_char_size(109 * 64, 0, 72, 72).unwrap();
@@ -267,6 +273,8 @@ impl TextShaper {
             'iter_glyphs: for (i, (position, info)) in
                 glyph_pos_iter.iter().zip(glyph_infos_iter.iter()).enumerate()
             {
+                let face = &mut intern.font_faces.0[face_idx];
+
                 let glyph_id = info.codepoint as u32;
                 // Index within this substr
                 let curr_cluster = info.cluster as usize;
@@ -299,9 +307,10 @@ impl TextShaper {
                     },
                     face_idx,
                 };
+
                 //debug!(target: "text", "cache_key: {:?}", cache_key);
                 'load_sprite: {
-                    if let Some(sprite) = cache.get(&cache_key) {
+                    if let Some(sprite) = intern.cache.get(&cache_key) {
                         let Some(sprite) = sprite.upgrade() else {
                             break 'load_sprite;
                         };
@@ -322,6 +331,7 @@ impl TextShaper {
                     }
                 }
 
+                let face = &mut intern.font_faces.0[face_idx];
                 let mut flags = ft::face::LoadFlag::DEFAULT;
                 if face.has_color() {
                     flags |= ft::face::LoadFlag::COLOR;
@@ -387,7 +397,7 @@ impl TextShaper {
                     has_color: face.has_color(),
                 });
 
-                cache.insert(cache_key, Arc::downgrade(&sprite));
+                intern.cache.insert(cache_key, Arc::downgrade(&sprite));
 
                 let glyph = Glyph {
                     glyph_id,

+ 5 - 5
bin/darkwallet/src/ui/chatview/mod.rs

@@ -444,7 +444,7 @@ impl ChatView {
             debug!(target: "ui::chatview", "Mark sent message as confirmed");
         } else {
             // Insert the privmsg since it doesn't already exist
-            if msgbuf.insert_privmsg(timest, msg_id, nick, text).await.is_none() {
+            if msgbuf.insert_privmsg(timest, msg_id, nick, text).is_none() {
                 // Not visible so no need to redraw
                 return
             }
@@ -466,7 +466,7 @@ impl ChatView {
 
         // Add message to page
         let mut msgbuf = self.msgbuf.lock().await;
-        let Some(privmsg) = msgbuf.insert_privmsg(timest, msg_id, nick, text).await else { return };
+        let Some(privmsg) = msgbuf.insert_privmsg(timest, msg_id, nick, text) else { return };
         privmsg.confirmed = false;
         self.redraw_cached(&mut msgbuf).await;
         self.bgload_cv.notify();
@@ -560,7 +560,7 @@ impl ChatView {
             let chatmsg: ChatMsg = deserialize(&v).unwrap();
             debug!(target: "ui::chatview", "{timest:?} {chatmsg:?}");
 
-            let msg_height = msgbuf.push_privmsg(timest, msg_id, chatmsg.nick, chatmsg.text).await;
+            let msg_height = msgbuf.push_privmsg(timest, msg_id, chatmsg.nick, chatmsg.text);
 
             remaining_load_height -= msg_height;
             if remaining_load_height <= 0. {
@@ -688,7 +688,7 @@ impl ChatView {
     async fn redraw_all(&self) {
         debug!(target: "ui::chatview", "redraw_all()");
         let mut msgbuf = self.msgbuf.lock().await;
-        msgbuf.adjust_params().await;
+        msgbuf.adjust_params();
         msgbuf.clear_meshes();
         self.redraw_cached(&mut msgbuf).await;
     }
@@ -790,7 +790,7 @@ impl UIObject for ChatView {
         let rect = self.rect.get();
 
         let mut msgbuf = self.msgbuf.lock().await;
-        msgbuf.adjust_window_scale().await;
+        msgbuf.adjust_window_scale();
         msgbuf.adjust_width(rect.w);
         msgbuf.clear_meshes();
 

+ 41 - 56
bin/darkwallet/src/ui/chatview/page.rs

@@ -76,7 +76,7 @@ pub struct PrivMessage {
 }
 
 impl PrivMessage {
-    pub async fn new(
+    pub fn new(
         font_size: f32,
         timestamp_font_size: f32,
         window_scale: f32,
@@ -93,10 +93,10 @@ impl PrivMessage {
         render_api: &RenderApi,
     ) -> Message {
         let timestr = Self::gen_timestr(timestamp);
-        let time_glyphs = text_shaper.shape(timestr, timestamp_font_size, window_scale).await;
+        let time_glyphs = text_shaper.shape(timestr, timestamp_font_size, window_scale);
 
         let linetext = format!("{nick} {text}");
-        let unwrapped_glyphs = text_shaper.shape(linetext, font_size, window_scale).await;
+        let unwrapped_glyphs = text_shaper.shape(linetext, font_size, window_scale);
 
         let mut atlas = text::Atlas::new(render_api);
         atlas.push(&time_glyphs);
@@ -283,7 +283,7 @@ impl PrivMessage {
     }
 
     /// clear_mesh() must be called after this.
-    async fn adjust_params(
+    fn adjust_params(
         &mut self,
         font_size: f32,
         timestamp_font_size: f32,
@@ -298,10 +298,10 @@ impl PrivMessage {
         self.window_scale = window_scale;
 
         let timestr = Self::gen_timestr(self.timestamp);
-        self.time_glyphs = text_shaper.shape(timestr, timestamp_font_size, window_scale).await;
+        self.time_glyphs = text_shaper.shape(timestr, timestamp_font_size, window_scale);
 
         let linetext = format!("{} {}", self.nick, self.text);
-        self.unwrapped_glyphs = text_shaper.shape(linetext, font_size, window_scale).await;
+        self.unwrapped_glyphs = text_shaper.shape(linetext, font_size, window_scale);
 
         let texture_id = self.atlas.texture_id;
 
@@ -357,7 +357,7 @@ pub struct DateMessage {
 }
 
 impl DateMessage {
-    pub async fn new(
+    pub fn new(
         font_size: f32,
         window_scale: f32,
 
@@ -369,7 +369,7 @@ impl DateMessage {
         let datestr = Self::datestr(timestamp);
         let timestamp = Self::timest_to_midnight(timestamp);
 
-        let glyphs = text_shaper.shape(datestr, font_size, window_scale).await;
+        let glyphs = text_shaper.shape(datestr, font_size, window_scale);
 
         let mut atlas = text::Atlas::new(render_api);
         atlas.push(&glyphs);
@@ -393,7 +393,7 @@ impl DateMessage {
     }
 
     /// clear_mesh() must be called after this.
-    async fn adjust_params(
+    fn adjust_params(
         &mut self,
         font_size: f32,
         window_scale: f32,
@@ -404,7 +404,7 @@ impl DateMessage {
         self.window_scale = window_scale;
 
         let datestr = Self::datestr(self.timestamp);
-        self.glyphs = text_shaper.shape(datestr, font_size, window_scale).await;
+        self.glyphs = text_shaper.shape(datestr, font_size, window_scale);
 
         let texture_id = self.atlas.texture_id;
 
@@ -488,7 +488,7 @@ impl Message {
         }
     }
 
-    async fn adjust_params(
+    fn adjust_params(
         &mut self,
         font_size: f32,
         timestamp_font_size: f32,
@@ -499,21 +499,16 @@ impl Message {
         render_api: &RenderApi,
     ) -> GfxTextureId {
         match self {
-            Self::Priv(m) => {
-                m.adjust_params(
-                    font_size,
-                    timestamp_font_size,
-                    window_scale,
-                    line_width,
-                    timestamp_width,
-                    text_shaper,
-                    render_api,
-                )
-                .await
-            }
-            Self::Date(m) => {
-                m.adjust_params(font_size, window_scale, text_shaper, render_api).await
-            }
+            Self::Priv(m) => m.adjust_params(
+                font_size,
+                timestamp_font_size,
+                window_scale,
+                line_width,
+                timestamp_width,
+                text_shaper,
+                render_api,
+            ),
+            Self::Date(m) => m.adjust_params(font_size, window_scale, text_shaper, render_api),
         }
     }
 
@@ -691,17 +686,17 @@ impl MessageBuffer {
         self.node.upgrade().unwrap()
     }
 
-    pub async fn adjust_window_scale(&mut self) {
+    pub fn adjust_window_scale(&mut self) {
         let window_scale = self.window_scale.get();
         if self.old_window_scale == window_scale {
             return
         }
 
-        self.adjust_params().await;
+        self.adjust_params();
     }
 
     /// This will force a reload of everything
-    pub async fn adjust_params(&mut self) {
+    pub fn adjust_params(&mut self) {
         let window_scale = self.window_scale.get();
         let font_size = self.font_size.get();
         let timestamp_font_size = self.timestamp_font_size.get();
@@ -710,17 +705,15 @@ impl MessageBuffer {
         debug!(target: "ui::chatview::page", "{:?}: freeing old textures", self.node());
 
         for msg in &mut self.msgs {
-            let old_texture_id = msg
-                .adjust_params(
-                    font_size,
-                    timestamp_font_size,
-                    window_scale,
-                    self.line_width,
-                    timestamp_width,
-                    &self.text_shaper,
-                    &self.render_api,
-                )
-                .await;
+            let old_texture_id = msg.adjust_params(
+                font_size,
+                timestamp_font_size,
+                window_scale,
+                self.line_width,
+                timestamp_width,
+                &self.text_shaper,
+                &self.render_api,
+            );
 
             self.freed.add_texture(old_texture_id);
         }
@@ -800,7 +793,7 @@ impl MessageBuffer {
         return true
     }
 
-    pub async fn insert_privmsg(
+    pub fn insert_privmsg(
         &mut self,
         timest: Timestamp,
         msg_id: MessageId,
@@ -825,8 +818,7 @@ impl MessageBuffer {
             timestamp_width,
             &self.text_shaper,
             &self.render_api,
-        )
-        .await;
+        );
 
         if self.msgs.is_empty() {
             let msg_idx = self.msgs.len();
@@ -864,7 +856,7 @@ impl MessageBuffer {
         return self.msgs[idx].get_privmsg_mut();
     }
 
-    pub async fn push_privmsg(
+    pub fn push_privmsg(
         &mut self,
         timest: Timestamp,
         msg_id: MessageId,
@@ -889,8 +881,7 @@ impl MessageBuffer {
             timestamp_width,
             &self.text_shaper,
             &self.render_api,
-        )
-        .await;
+        );
 
         let msg_height = msg.height(self.line_height.get());
 
@@ -977,7 +968,7 @@ impl MessageBuffer {
 
                 if let Some(newer_date) = last_date {
                     if newer_date != older_date {
-                        let datemsg = self.get_date_msg(newer_date, font_size, window_scale).await;
+                        let datemsg = self.get_date_msg(newer_date, font_size, window_scale);
                         let datemsg = unsafe { &mut *(datemsg as *mut Message) };
                         //debug!(target: "ui::chatview", "Adding date: {idx} {datemsg:?}");
                         yield datemsg;
@@ -990,19 +981,14 @@ impl MessageBuffer {
             }
 
             if let Some(date) = last_date {
-                let datemsg = self.get_date_msg(date, font_size, window_scale).await;
+                let datemsg = self.get_date_msg(date, font_size, window_scale);
                 let datemsg = unsafe { &mut *(datemsg as *mut Message) };
                 yield datemsg;
             }
         })
     }
 
-    async fn get_date_msg(
-        &mut self,
-        date: NaiveDate,
-        font_size: f32,
-        window_scale: f32,
-    ) -> &mut Message {
+    fn get_date_msg(&mut self, date: NaiveDate, font_size: f32, window_scale: f32) -> &mut Message {
         let dt = date.and_hms_opt(0, 0, 0).unwrap();
         let timest = Local.from_local_datetime(&dt).unwrap().timestamp_millis() as u64;
 
@@ -1013,8 +999,7 @@ impl MessageBuffer {
                 timest,
                 &self.text_shaper,
                 &self.render_api,
-            )
-            .await;
+            );
             self.date_msgs.insert(date, datemsg);
         }
 

+ 19 - 19
bin/darkwallet/src/ui/editbox.rs

@@ -199,14 +199,14 @@ impl ComposingText {
     }
 
     /// Set composing text.
-    async fn compose(&mut self, text: String, font_size: f32, window_scale: f32) {
+    fn compose(&mut self, text: String, font_size: f32, window_scale: f32) {
         assert!(self.is_active);
         self.compose_text = text;
 
         self.region_start = self.commit_text.len();
         self.region_end = self.region_start + self.compose_text.len();
 
-        let glyphs = self.text_shaper.shape(self.get_text(), font_size, window_scale).await;
+        let glyphs = self.text_shaper.shape(self.get_text(), font_size, window_scale);
         self.glyphs = glyphs;
     }
 
@@ -293,7 +293,7 @@ pub struct EditBox {
     z_index: PropertyUint32,
     debug: PropertyBool,
 
-    composer: AsyncMutex<ComposingText>,
+    composer: SyncMutex<ComposingText>,
 
     mouse_btn_held: AtomicBool,
     cursor_is_visible: AtomicBool,
@@ -344,7 +344,7 @@ impl EditBox {
         let node_id = node_ref.id;
 
         // Must do this whenever the text changes
-        let glyphs = text_shaper.shape(text.get(), font_size.get(), window_scale.get()).await;
+        let glyphs = text_shaper.shape(text.get(), font_size.get(), window_scale.get());
 
         let self_ = Arc::new(Self {
             node,
@@ -380,7 +380,7 @@ impl EditBox {
             z_index,
             debug,
 
-            composer: AsyncMutex::new(ComposingText::new(text_shaper)),
+            composer: SyncMutex::new(ComposingText::new(text_shaper)),
 
             mouse_btn_held: AtomicBool::new(false),
             cursor_is_visible: AtomicBool::new(true),
@@ -399,10 +399,10 @@ impl EditBox {
     }
 
     /// This MUST be called whenever the text property is changed.
-    async fn regen_glyphs(&self) {
+    fn regen_glyphs(&self) {
         let font_size = self.font_size.get();
         let window_scale = self.window_scale.get();
-        let glyphs = self.text_shaper.shape(self.text.get(), font_size, window_scale).await;
+        let glyphs = self.text_shaper.shape(self.text.get(), font_size, window_scale);
         // TODO: we aren't freeing textures
         *self.glyphs.lock().unwrap() = glyphs;
     }
@@ -428,7 +428,7 @@ impl EditBox {
         let mut glyphs = self.glyphs.lock().unwrap().clone();
 
         // We clone composer. FYI we do destructive mods on it.
-        let composer = self.composer.lock().await.clone();
+        let composer = self.composer.lock().unwrap().clone();
         let has_compose = composer.has_compose();
         let under_start = composer.pos + composer.glyph_compose_start();
         let under_end = composer.pos + composer.glyph_compose_end();
@@ -495,7 +495,7 @@ impl EditBox {
         let mut cursor_pos = self.cursor_pos.get() as usize;
         let mut glyphs = self.glyphs.lock().unwrap().clone();
         // Add composer glyphs too
-        let composer = self.composer.lock().await.clone();
+        let composer = self.composer.lock().unwrap().clone();
         if cursor_pos >= composer.pos {
             cursor_pos += composer.glyphs.len();
         }
@@ -780,7 +780,7 @@ impl EditBox {
     async fn insert_char(&self, key: char) {
         if !self.selected.is_null(0).unwrap() {
             self.delete_highlighted();
-            self.regen_glyphs().await;
+            self.regen_glyphs();
         };
 
         let mut text = String::new();
@@ -813,7 +813,7 @@ impl EditBox {
         self.cursor_pos.set(cursor_pos + 1);
 
         self.pause_blinking();
-        self.regen_glyphs().await;
+        self.regen_glyphs();
         self.apply_cursor_scrolling();
         self.redraw().await;
     }
@@ -941,7 +941,7 @@ impl EditBox {
                 };
 
                 self.pause_blinking();
-                self.regen_glyphs().await;
+                self.regen_glyphs();
                 self.apply_cursor_scrolling();
                 self.redraw().await;
             }
@@ -969,7 +969,7 @@ impl EditBox {
                 };
 
                 self.pause_blinking();
-                self.regen_glyphs().await;
+                self.regen_glyphs();
                 self.apply_cursor_scrolling();
                 self.redraw().await;
             }
@@ -1028,7 +1028,7 @@ impl EditBox {
 
         // Clear the composer state and add the glyphs
         let (compose_idx, compose_glyphs) = {
-            let mut composer = self.composer.lock().await;
+            let mut composer = self.composer.lock().unwrap();
             composer.reset()
         };
 
@@ -1235,7 +1235,7 @@ impl EditBox {
         // Force complete redraw if the window scale changed
         let window_scale = self.window_scale.get();
         if self.old_window_scale.swap(window_scale, Ordering::Relaxed) != window_scale {
-            self.regen_glyphs().await;
+            self.regen_glyphs();
 
             let text_mesh = std::mem::replace(&mut *self.text_mesh.lock().unwrap(), None);
             // We're finished with these so clean up.
@@ -1327,7 +1327,7 @@ impl UIObject for EditBox {
             self_.selected.set_null(Role::Internal, 0).unwrap();
             self_.selected.set_null(Role::Internal, 1).unwrap();
             self_.scroll.set(0.);
-            self_.regen_glyphs().await;
+            self_.regen_glyphs();
             self_.redraw().await;
         }
         async fn redraw(self_: Arc<EditBox>) {
@@ -1505,10 +1505,10 @@ impl UIObject for EditBox {
         let window_scale = self.window_scale.get();
 
         {
-            let mut composer = self.composer.lock().await;
+            let mut composer = self.composer.lock().unwrap();
 
             composer.activate_or_cont(self.cursor_pos.get() as usize);
-            composer.compose(suggest_text.to_string(), font_size, window_scale).await;
+            composer.compose(suggest_text.to_string(), font_size, window_scale);
 
             if is_commit {
                 composer.commit();
@@ -1528,7 +1528,7 @@ impl UIObject for EditBox {
         }
 
         {
-            let mut composer = self.composer.lock().await;
+            let mut composer = self.composer.lock().unwrap();
             composer.set_compose_region(start, end);
         }
         self.redraw().await;

+ 4 - 6
bin/darkwallet/src/ui/text.rs

@@ -94,8 +94,7 @@ impl Text {
             baseline.get(),
             debug.get(),
             window_scale.get(),
-        )
-        .await;
+        );
 
         let self_ = Arc::new(Self {
             node,
@@ -120,7 +119,7 @@ impl Text {
         Pimpl::Text(self_)
     }
 
-    async fn regen_mesh(
+    fn regen_mesh(
         render_api: &RenderApi,
         text_shaper: &TextShaper,
         text: String,
@@ -131,7 +130,7 @@ impl Text {
         window_scale: f32,
     ) -> TextRenderInfo {
         debug!(target: "ui::text", "Rendering label '{}'", text);
-        let glyphs = text_shaper.shape(text, font_size, window_scale).await;
+        let glyphs = text_shaper.shape(text, font_size, window_scale);
         let atlas = text::make_texture_atlas(render_api, &glyphs);
 
         let mut mesh = MeshBuilder::new();
@@ -190,8 +189,7 @@ impl Text {
             self.baseline.get(),
             self.debug.get(),
             self.window_scale.get(),
-        )
-        .await;
+        );
 
         *self.render_info.lock().unwrap() = render_info.clone();