|
|
@@ -21,7 +21,7 @@ use std::{
|
|
|
fs::File,
|
|
|
io::{BufRead, BufReader},
|
|
|
path::{Path, PathBuf},
|
|
|
- sync::{Arc, LazyLock},
|
|
|
+ sync::Arc,
|
|
|
};
|
|
|
|
|
|
use crate::{
|
|
|
@@ -30,35 +30,19 @@ use crate::{
|
|
|
text,
|
|
|
};
|
|
|
|
|
|
-use super::default;
|
|
|
-
|
|
|
-#[cfg(target_os = "android")]
|
|
|
-pub fn get_emoji_list_path() -> PathBuf {
|
|
|
- crate::android::get_external_storage_path().join("emoji.txt")
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(not(target_os = "android"))]
|
|
|
-pub fn get_emoji_list_path() -> PathBuf {
|
|
|
- dirs::data_local_dir().unwrap().join("darkfi/emoji.txt")
|
|
|
-}
|
|
|
+use super::default::DEFAULT_EMOJI_LIST;
|
|
|
|
|
|
pub type EmojiMeshesPtr = Arc<AsyncMutex<EmojiMeshes>>;
|
|
|
|
|
|
pub struct EmojiMeshes {
|
|
|
render_api: RenderApi,
|
|
|
emoji_size: f32,
|
|
|
- emoji_list: LazyLock<Vec<String>>,
|
|
|
meshes: Vec<DrawMesh>,
|
|
|
}
|
|
|
|
|
|
impl EmojiMeshes {
|
|
|
pub fn new(render_api: RenderApi, emoji_size: f32) -> EmojiMeshesPtr {
|
|
|
- Arc::new(AsyncMutex::new(Self {
|
|
|
- render_api,
|
|
|
- emoji_size,
|
|
|
- emoji_list: LazyLock::new(load_emoji_list),
|
|
|
- meshes: vec![],
|
|
|
- }))
|
|
|
+ Arc::new(AsyncMutex::new(Self { render_api, emoji_size, meshes: vec![] }))
|
|
|
}
|
|
|
|
|
|
pub fn clear(&mut self) {
|
|
|
@@ -66,14 +50,13 @@ impl EmojiMeshes {
|
|
|
}
|
|
|
|
|
|
pub async fn get(&mut self, i: usize) -> DrawMesh {
|
|
|
- let emoji_list = self.get_list();
|
|
|
- assert!(i < emoji_list.len());
|
|
|
- self.meshes.reserve_exact(emoji_list.len());
|
|
|
+ assert!(i < DEFAULT_EMOJI_LIST.len());
|
|
|
+ self.meshes.reserve_exact(DEFAULT_EMOJI_LIST.len());
|
|
|
|
|
|
if i >= self.meshes.len() {
|
|
|
//d!("EmojiMeshes loading new glyphs");
|
|
|
for j in self.meshes.len()..=i {
|
|
|
- let emoji = &self.emoji_list[j];
|
|
|
+ let emoji = DEFAULT_EMOJI_LIST[j];
|
|
|
let mesh = self.gen_emoji_mesh(emoji).await;
|
|
|
self.meshes.push(mesh);
|
|
|
}
|
|
|
@@ -100,85 +83,7 @@ impl EmojiMeshes {
|
|
|
_ => panic!("Expected Draw instruction for emoji"),
|
|
|
};
|
|
|
|
|
|
- // Emoji's vary in size. We make them all a consistent size.
|
|
|
- // We need to scale the mesh to match emoji_size.
|
|
|
- // TODO: Implement proper scaling for text2 API
|
|
|
- /*
|
|
|
- let bbox = layout.metrics().bounds;
|
|
|
- let orig_w = bbox.width().max(1.0);
|
|
|
- let orig_h = bbox.height().max(1.0);
|
|
|
- let w = self.emoji_size;
|
|
|
- let h = self.emoji_size * orig_h / orig_w;
|
|
|
-
|
|
|
- // Create a new mesh with the scaled size centered at origin
|
|
|
- let x = -w / 2.;
|
|
|
- let y = -h / 2.;
|
|
|
- let mut mesh_builder = MeshBuilder::new(gfxtag!("emoji_mesh"));
|
|
|
- */
|
|
|
-
|
|
|
// For now, just return the original mesh since scaling is complex with textures
|
|
|
mesh
|
|
|
}
|
|
|
-
|
|
|
- pub fn get_list<'a>(&'a self) -> &'a Vec<String> {
|
|
|
- LazyLock::force(&self.emoji_list)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fn load_emoji_list() -> Vec<String> {
|
|
|
- match load_custom_emoji_list(&get_emoji_list_path()) {
|
|
|
- Some(emojis) => emojis,
|
|
|
- None => default::create_default_emoji_list(),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fn load_custom_emoji_list(path: &Path) -> Option<Vec<String>> {
|
|
|
- let file = File::open(path).ok()?;
|
|
|
- let reader = BufReader::new(file);
|
|
|
-
|
|
|
- let mut emojis = vec![];
|
|
|
- for mut line in reader.lines().map_while(Result::ok) {
|
|
|
- remove_whitespace(&mut line);
|
|
|
- let line = strip_comment(&line);
|
|
|
- if line.is_empty() {
|
|
|
- continue
|
|
|
- }
|
|
|
- let emoji = unescape_unicode(line)?;
|
|
|
- emojis.push(emoji);
|
|
|
- }
|
|
|
- Some(emojis)
|
|
|
-}
|
|
|
-
|
|
|
-fn unescape_unicode(input: &str) -> Option<String> {
|
|
|
- let re = regex::Regex::new(r"\\u\{([0-9A-Fa-f]+)\}").unwrap();
|
|
|
-
|
|
|
- // There is no way to bail from a failed regex so we use this workaround instead.
|
|
|
- let mut failed = false;
|
|
|
- let result = re
|
|
|
- .replace_all(input, |caps: ®ex::Captures| {
|
|
|
- let Ok(code) = u32::from_str_radix(&caps[1], 16) else {
|
|
|
- failed = true;
|
|
|
- return String::new()
|
|
|
- };
|
|
|
- let Some(chr) = char::from_u32(code) else {
|
|
|
- failed = true;
|
|
|
- return String::new()
|
|
|
- };
|
|
|
- chr.to_string()
|
|
|
- })
|
|
|
- .into_owned();
|
|
|
-
|
|
|
- if failed {
|
|
|
- return None
|
|
|
- }
|
|
|
-
|
|
|
- Some(result)
|
|
|
-}
|
|
|
-
|
|
|
-fn remove_whitespace(s: &mut String) {
|
|
|
- s.retain(|c| !c.is_whitespace());
|
|
|
-}
|
|
|
-
|
|
|
-fn strip_comment(s: &str) -> &str {
|
|
|
- s.split('#').next().unwrap_or(s)
|
|
|
}
|